UNPKG

dmclc

Version:

Dolphin Minecraft Launcher Core

278 lines (277 loc) 11.2 kB
/* * Ported from Fabric Loader. * Copyright 2016 FabricMC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { SemanticVersion } from "./SemanticVersion.js"; import { VersionParsingException } from "./VersionParsingException.js"; /** * Parser for a superset of the semantic version format described at <a href="https://semver.org">semver.org</a>. * * <p>This superset allows additionally * <ul><li>Arbitrary number of {@code <version core>} components, but at least 1 * <li>{@code x}, {@code X} or {@code *} for the last {@code <version core>} component with {@code storeX} if not the first * <li>Arbitrary {@code <build>} contents * </ul> */ class SemanticVersionImpl extends SemanticVersion { static DOT_SEPARATED_ID = /|[-0-9A-Za-z]+(\.[-0-9A-Za-z]+)*/; static UNSIGNED_INTEGER = /0|[1-9][0-9]*/; components = []; prerelease; build; friendlyName = ""; static of(version, storeX) { const buildDelimPos = version.indexOf("+"); let build = null; if (buildDelimPos >= 0) { build = version.substring(buildDelimPos + 1); version = version.substring(0, buildDelimPos); } const dashDelimPos = version.indexOf("-"); let prerelease = null; if (dashDelimPos >= 0) { prerelease = version.substring(dashDelimPos + 1); version = version.substring(0, dashDelimPos); } if (prerelease != null && !prerelease.match(SemanticVersionImpl.DOT_SEPARATED_ID)) { throw new VersionParsingException("Invalid prerelease string '" + prerelease + "'!"); } if (version.endsWith(".")) { throw new VersionParsingException("Negative version number component found!"); } else if (version.startsWith(".")) { throw new VersionParsingException("Missing version component!"); } const componentStrings = version.split("."); if (componentStrings.length < 1) { throw new VersionParsingException("Did not provide version numbers!"); } let components = []; let firstWildcardIdx = -1; for (let i = 0; i < componentStrings.length; i++) { const compStr = componentStrings[i]; if (storeX) { if (compStr === "x" || compStr === "X" || compStr === "*") { if (prerelease != null) { throw new VersionParsingException("Pre-release versions are not allowed to use X-ranges!"); } components[i] = SemanticVersion.COMPONENT_WILDCARD; if (firstWildcardIdx < 0) firstWildcardIdx = i; continue; } else if (i > 0 && components[i - 1] == SemanticVersion.COMPONENT_WILDCARD) { throw new VersionParsingException("Interjacent wildcard (1.x.2) are disallowed!"); } } if (compStr.trim() === "") { throw new VersionParsingException("Missing version number component!"); } try { components[i] = parseInt(compStr); if (components[i] < 0) { throw new VersionParsingException("Negative version number component '" + compStr + "'!"); } } catch { throw new VersionParsingException("Could not parse version number component '" + compStr + "'!"); } } if (storeX && components.length == 1 && components[0] == SemanticVersion.COMPONENT_WILDCARD) { throw new VersionParsingException("Versions of form 'x' or 'X' not allowed!"); } // strip extra wildcards (1.x.x -> 1.x) if (firstWildcardIdx > 0 && components.length > firstWildcardIdx + 1) { components = components.slice(0, firstWildcardIdx + 1); } return new SemanticVersionImpl(components, prerelease, build); } constructor(components, prerelease, build) { super(); if (components.length == 0 || components[0] == SemanticVersion.COMPONENT_WILDCARD) throw new Error("Invalid components: " + components); this.components = components; this.prerelease = prerelease; this.build = build; this.buildFriendlyName(); } buildFriendlyName() { const fnBuilder = []; let first = true; for (const i of this.components) { if (first) { first = false; } else { fnBuilder.push("."); } if (i == SemanticVersion.COMPONENT_WILDCARD) { fnBuilder.push("x"); } else { fnBuilder.push(i); } } if (this.prerelease != null) { fnBuilder.push("-"); fnBuilder.push(this.prerelease); } if (this.build != null) { fnBuilder.push("+"); fnBuilder.push(this.build); } this.friendlyName = fnBuilder.join(""); } getVersionComponentCount() { return this.components.length; } getVersionComponent(pos) { if (pos < 0) { throw new Error("Tried to access negative version number component!"); } else if (pos >= this.components.length) { // Repeat "x" if x-range, otherwise repeat "0". return this.components[this.components.length - 1] == SemanticVersion.COMPONENT_WILDCARD ? SemanticVersion.COMPONENT_WILDCARD : 0; } else { return this.components[pos]; } } getVersionComponents() { return Array.from(this.components); } getPrereleaseKey() { return this.prerelease; } getBuildKey() { return this.build; } getFriendlyString() { return this.friendlyName; } equals(o) { if (!(o instanceof SemanticVersionImpl)) { return false; } else { if (!this.equalsComponentsExactly(o)) { return false; } return this.prerelease === o.prerelease && this.build === o.build; } } toString() { return this.getFriendlyString(); } hasWildcard() { for (const i of this.components) { if (i < 0) { return true; } } return false; } equalsComponentsExactly(other) { for (let i = 0; i < Math.max(this.getVersionComponentCount(), other.getVersionComponentCount()); i++) { if (this.getVersionComponent(i) != other.getVersionComponent(i)) { return false; } } return true; } compareTo(other) { if (!(other instanceof SemanticVersion)) { return this.getFriendlyString().localeCompare(other.getFriendlyString()); } const o = other; for (let i = 0; i < Math.max(this.getVersionComponentCount(), o.getVersionComponentCount()); i++) { const first = this.getVersionComponent(i); const second = o.getVersionComponent(i); if (first == SemanticVersion.COMPONENT_WILDCARD || second == SemanticVersion.COMPONENT_WILDCARD) { continue; } const compare = first - second; if (compare != 0) return compare; } const prereleaseA = this.getPrereleaseKey(); const prereleaseB = o.getPrereleaseKey(); if (prereleaseA !== null || prereleaseB !== null) { if (prereleaseA !== null && prereleaseB !== null) { const prereleaseATokenizer = prereleaseA.split("."); const prereleaseBTokenizer = prereleaseB.split("."); // while (prereleaseATokenizer.hasMoreElements()) { // if (prereleaseBTokenizer.hasMoreElements()) { // String partA = prereleaseATokenizer.nextToken(); // String partB = prereleaseBTokenizer.nextToken(); // if (SemanticVersionImpl.UNSIGNED_INTEGER.matcher(partA).matches()) { // if (SemanticVersionImpl.UNSIGNED_INTEGER.matcher(partB).matches()) { // this.int compare = Integer.compare(partA.length(), partB.length()); // if (compare != 0) return compare; // } else { // return -1; // } // } else { // if (SemanticVersionImpl.UNSIGNED_INTEGER.matcher(partB).matches()) { // return 1; // } // } // this.int compare = partA.compareTo(partB); // if (compare != 0) return compare; // } else { // return 1; // } // } for (let i = 0; i < prereleaseATokenizer.length; i++) { if (prereleaseBTokenizer.length > i) { const partA = prereleaseATokenizer[i]; const partB = prereleaseBTokenizer[i]; if (partA.match(SemanticVersionImpl.UNSIGNED_INTEGER)) { if (partB.match(SemanticVersionImpl.UNSIGNED_INTEGER)) { const compare = partA.length - partB.length; if (compare != 0) return compare; } else { return -1; } } else { if (partB.match(SemanticVersionImpl.UNSIGNED_INTEGER)) { return 1; } } const compare = partA.localeCompare(partB); if (compare != 0) return compare; } else return 1; } return prereleaseBTokenizer.length > prereleaseATokenizer.length ? -1 : 0; } else if (prereleaseA) { return o.hasWildcard() ? 0 : -1; } else { return this.hasWildcard() ? 0 : 1; } } else { return 0; } } } export { SemanticVersionImpl };