@glion/util-semver 0.15.3 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +11 -12
package/dist/index.js
CHANGED
|
@@ -359,7 +359,8 @@ var Range = class {
|
|
|
359
359
|
constructor(range) {
|
|
360
360
|
if (range.length > 1e3) throw new RangeParseError(`${range.slice(0, 50)}...`, `range string too long (max ${MAX_RANGE_STRING_LENGTH} characters)`);
|
|
361
361
|
this.raw = range;
|
|
362
|
-
|
|
362
|
+
const tokens = splitTokens(range);
|
|
363
|
+
this.comparators = tokens.map(parseToken);
|
|
363
364
|
}
|
|
364
365
|
/**
|
|
365
366
|
* Test if a version satisfies this range.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/parse.ts","../src/compare.ts","../src/range.ts","../src/collection.ts"],"sourcesContent":["/**\n * Error thrown when a version string cannot be parsed.\n */\nexport class VersionParseError extends Error {\n override readonly name = \"VersionParseError\";\n readonly input: string;\n readonly reason: string;\n\n constructor(input: string, reason: string) {\n super(`Invalid version format ('${input}') — ${reason}`);\n\n this.input = input;\n this.reason = reason;\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, VersionParseError);\n }\n }\n}\n\n/**\n * Error thrown when a range token cannot be parsed.\n */\nexport class RangeParseError extends Error {\n override readonly name = \"RangeParseError\";\n readonly token: string;\n readonly reason: string;\n\n constructor(token: string, reason: string) {\n super(`Invalid range token ('${token}') — ${reason}`);\n\n this.token = token;\n this.reason = reason;\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, RangeParseError);\n }\n }\n}\n","/**\n * Represents a semantic version with major, minor, and patch components.\n */\nexport interface Hl7Version {\n major: number;\n minor: number;\n patch: number;\n}\n\n/**\n * Comparison operators supported in version ranges.\n */\nexport type ComparisonOperator = \"=\" | \"<\" | \"<=\" | \">\" | \">=\";\n\n/**\n * Internal representation of a version range comparator.\n */\nexport interface Comparator {\n op: ComparisonOperator;\n v: Hl7Version;\n}\n\n/**\n * Result of a comparison operation.\n */\nexport type ComparisonResult = -1 | 0 | 1;\n\n/**\n * Security constraints for input validation.\n */\nexport const MAX_VERSION_STRING_LENGTH = 100;\nexport const MAX_RANGE_STRING_LENGTH = 1000;\nexport const MAX_SAFE_VERSION_COMPONENT = 2 ** 31 - 1; // Max safe int32 for interop\n","import { VersionParseError } from \"./errors\";\nimport type { Hl7Version } from \"./types\";\nimport { MAX_SAFE_VERSION_COMPONENT, MAX_VERSION_STRING_LENGTH } from \"./types\";\n\n// Regex for parsing version strings\nconst VERSION_RE = /^\\s*(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?\\s*$/;\n\n/**\n * Parses a version string into a structured version object.\n *\n * @example\n * ```typescript\n * const v = parse(\"2.5.1\");\n * // => { major: 2, minor: 5, patch: 1 }\n *\n * parse(\"2\");\n * // => { major: 2, minor: 0, patch: 0 }\n *\n * parse(\"HELLO\");\n * // => throws VersionParseError\n * ```;\n *\n * @param input - Version string to parse (e.g., \"2.5.1\", \"2.3\", \"2\")\n * @returns Structured version with major, minor, and patch components\n * @throws {VersionParseError} If the input format is invalid or exceeds safety\n * limits\n */\nexport function parse(input: string): Hl7Version {\n // Length check to prevent ReDoS attacks\n if (input.length > MAX_VERSION_STRING_LENGTH) {\n throw new VersionParseError(\n `${input.slice(0, 50)}...`,\n `version string too long (max ${MAX_VERSION_STRING_LENGTH} characters)`\n );\n }\n\n const match = VERSION_RE.exec(input);\n if (!match) {\n throw new VersionParseError(\n input,\n \"expected format: major.minor.patch (e.g., '2.5.1' or '2.3')\"\n );\n }\n\n // Regex ensures digits-only, Number() on digits always yields valid integers\n const major = Number(match[1]);\n const minor = match[2] === undefined ? 0 : Number(match[2]);\n const patch = match[3] === undefined ? 0 : Number(match[3]);\n\n // Validate range to prevent integer overflow and ensure interoperability\n if (major > MAX_SAFE_VERSION_COMPONENT) {\n throw new VersionParseError(\n input,\n `major version ${major} exceeds maximum ${MAX_SAFE_VERSION_COMPONENT}`\n );\n }\n if (minor > MAX_SAFE_VERSION_COMPONENT) {\n throw new VersionParseError(\n input,\n `minor version ${minor} exceeds maximum ${MAX_SAFE_VERSION_COMPONENT}`\n );\n }\n if (patch > MAX_SAFE_VERSION_COMPONENT) {\n throw new VersionParseError(\n input,\n `patch version ${patch} exceeds maximum ${MAX_SAFE_VERSION_COMPONENT}`\n );\n }\n\n return { major, minor, patch };\n}\n\n/**\n * Converts a version string to canonical format (major.minor.patch).\n *\n * @example\n * ```typescript\n * clean(\"2\"); // => \"2.0.0\"\n * clean(\"2.5\"); // => \"2.5.0\"\n * clean(\" 2.5 \"); // => \"2.5.0\"\n * ```;\n *\n * @param input - Version string to clean\n * @returns Canonical version string\n * @throws {VersionParseError} If the input format is invalid\n */\nexport function clean(input: string): string {\n const v = parse(input);\n return `${v.major}.${v.minor}.${v.patch}`;\n}\n\n/**\n * Checks if a string is a valid version format.\n * This function never throws - use it for validation.\n *\n * @example\n * ```typescript\n * valid(\"2.5.1\"); // => true\n * valid(\"2\"); // => true\n * valid(\"HELLO\"); // => false\n * valid(\"2.\"); // => false\n * ```;\n *\n * @param input - Version string to validate\n * @returns True if valid, false otherwise\n */\nexport function valid(input: string): boolean {\n try {\n parse(input);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Internal helper to ensure a value is a parsed Hl7Version object.\n * Parses strings, returns objects as-is.\n *\n * @internal\n */\nexport function ensure(v: string | Hl7Version): Hl7Version {\n if (typeof v === \"string\") {\n return parse(v);\n }\n return v;\n}\n\n/**\n * Increments a version component and resets all lower components to zero.\n *\n * @example\n * ```typescript\n * increment(\"2.5.1\", \"major\"); // => \"3.0.0\"\n * increment(\"2.5.1\", \"minor\"); // => \"2.6.0\"\n * increment(\"2.5.1\", \"patch\"); // => \"2.5.2\"\n *\n * // Works with partial versions too\n * increment(\"2\", \"minor\"); // => \"2.1.0\"\n * increment(\"2.5\", \"patch\"); // => \"2.5.1\"\n * ```;\n *\n * @param version - Version string to increment\n * @param release - Component to increment: 'major', 'minor', or 'patch'\n * @returns New version string with incremented component\n * @throws {VersionParseError} If version string is invalid\n */\nexport function increment(\n version: string,\n release: \"major\" | \"minor\" | \"patch\"\n): string {\n const v = parse(version);\n\n // biome-ignore lint/style/useDefaultSwitchClause: default case in the switch statement is unreachable\n switch (release) {\n case \"major\": {\n return `${v.major + 1}.0.0`;\n }\n case \"minor\": {\n return `${v.major}.${v.minor + 1}.0`;\n }\n case \"patch\": {\n return `${v.major}.${v.minor}.${v.patch + 1}`;\n }\n }\n}\n","import { ensure } from \"./parse\";\nimport type { ComparisonResult, Hl7Version } from \"./types\";\n\n/**\n * Compares two versions and returns their relationship.\n *\n * @example\n * ```typescript\n * compare(\"2.5.1\", \"2.5.0\"); // => 1\n * compare(\"2.3\", \"2.5\"); // => -1\n * compare(\"2.5.1\", \"2.5.1\"); // => 0\n *\n * // Works with parsed versions too\n * const v1 = parse(\"2.5.1\");\n * const v2 = parse(\"2.5.0\");\n * compare(v1, v2); // => 1\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns -1 if a < b, 0 if a = b, 1 if a > b\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function compare(\n a: string | Hl7Version,\n b: string | Hl7Version\n): ComparisonResult {\n const va = ensure(a);\n const vb = ensure(b);\n\n // Compare in order: major, minor, patch\n for (const key of [\"major\", \"minor\", \"patch\"] as const) {\n if (va[key] !== vb[key]) {\n return va[key] < vb[key] ? -1 : 1;\n }\n }\n return 0;\n}\n\n/**\n * Checks if two versions are equal.\n *\n * @example\n * ```typescript\n * eq(\"2.5.1\", \"2.5.1\"); // => true\n * eq(\"2.5\", \"2.5.0\"); // => true (normalized)\n * eq(\"2.5.1\", \"2.5.0\"); // => false\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns True if versions are equal, false otherwise\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function eq(a: string | Hl7Version, b: string | Hl7Version): boolean {\n return compare(a, b) === 0;\n}\n\n/**\n * Checks if first version is less than second version.\n *\n * @example\n * ```typescript\n * lt(\"2.3.0\", \"2.5.1\"); // => true\n * lt(\"2.5.1\", \"2.5.1\"); // => false\n * lt(\"2.5.1\", \"2.3.0\"); // => false\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns True if a < b, false otherwise\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function lt(a: string | Hl7Version, b: string | Hl7Version): boolean {\n return compare(a, b) === -1;\n}\n\n/**\n * Checks if first version is less than or equal to second version.\n *\n * @example\n * ```typescript\n * lte(\"2.3.0\", \"2.5.1\"); // => true\n * lte(\"2.5.1\", \"2.5.1\"); // => true\n * lte(\"2.5.1\", \"2.3.0\"); // => false\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns True if a <= b, false otherwise\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function lte(a: string | Hl7Version, b: string | Hl7Version): boolean {\n return compare(a, b) !== 1;\n}\n\n/**\n * Checks if first version is greater than second version.\n *\n * @example\n * ```typescript\n * gt(\"2.5.1\", \"2.3.0\"); // => true\n * gt(\"2.5.1\", \"2.5.1\"); // => false\n * gt(\"2.3.0\", \"2.5.1\"); // => false\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns True if a > b, false otherwise\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function gt(a: string | Hl7Version, b: string | Hl7Version): boolean {\n return compare(a, b) === 1;\n}\n\n/**\n * Checks if first version is greater than or equal to second version.\n *\n * @example\n * ```typescript\n * gte(\"2.5.1\", \"2.3.0\"); // => true\n * gte(\"2.5.1\", \"2.5.1\"); // => true\n * gte(\"2.3.0\", \"2.5.1\"); // => false\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns True if a >= b, false otherwise\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function gte(a: string | Hl7Version, b: string | Hl7Version): boolean {\n return compare(a, b) !== -1;\n}\n\n/**\n * Determines the highest-level component that differs between two versions.\n *\n * @example\n * ```typescript\n * diff(\"2.5.1\", \"3.0.0\"); // => \"major\"\n * diff(\"2.5.1\", \"2.6.0\"); // => \"minor\"\n * diff(\"2.5.1\", \"2.5.2\"); // => \"patch\"\n * diff(\"2.5.1\", \"2.5.1\"); // => null (equal)\n *\n * // Works with partial versions\n * diff(\"2\", \"2.0.0\"); // => null (normalized to same)\n * diff(\"2.5\", \"2.6\"); // => \"minor\"\n * ```;\n *\n * @param v1 - First version (string or parsed object)\n * @param v2 - Second version (string or parsed object)\n * @returns 'major', 'minor', 'patch', or null if versions are equal\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function diff(\n v1: string | Hl7Version,\n v2: string | Hl7Version\n): \"major\" | \"minor\" | \"patch\" | null {\n const a = ensure(v1);\n const b = ensure(v2);\n\n if (a.major !== b.major) {\n return \"major\";\n }\n if (a.minor !== b.minor) {\n return \"minor\";\n }\n if (a.patch !== b.patch) {\n return \"patch\";\n }\n return null;\n}\n","import { compare } from \"./compare\";\nimport { RangeParseError } from \"./errors\";\nimport { parse } from \"./parse\";\nimport type { Comparator } from \"./types\";\nimport { MAX_RANGE_STRING_LENGTH } from \"./types\";\n\n// Regex for parsing range tokens\nconst RANGE_TOKEN_RE = /^(<=|>=|<|>|=)?\\s*(\\d+(?:\\.\\d+){0,2})$/;\n\n// Whitespace splitter for range expressions\nconst WS_RE = /\\s+/;\n\n/**\n * Splits a range string into individual tokens.\n *\n * @internal\n */\nfunction splitTokens(range: string): string[] {\n const trimmed = range.trim();\n return trimmed.length === 0 ? [] : trimmed.split(WS_RE);\n}\n\n/**\n * Parses a single range token into a comparator.\n *\n * @internal\n */\nfunction parseToken(token: string): Comparator {\n const m = RANGE_TOKEN_RE.exec(token);\n if (!m) {\n throw new RangeParseError(\n token,\n \"expected format: [operator]version (e.g., '>=2.5' or '2.3')\"\n );\n }\n\n // m[1] is optional operator, m[2] is required version (guaranteed by regex)\n const op = (m[1] || \"=\") as Comparator[\"op\"];\n // biome-ignore lint/style/noNonNullAssertion: Non-null assertion safe: regex guarantees m[2] exists\n const v = parse(m[2] || \"\");\n return { op, v };\n}\n\n/**\n * Maps comparison operators to test functions.\n *\n * @internal\n */\nconst OP_TEST: Record<Comparator[\"op\"], (cmp: number) => boolean> = {\n \"<\": (c) => c < 0,\n \"<=\": (c) => c <= 0,\n \"=\": (c) => c === 0,\n \">\": (c) => c > 0,\n \">=\": (c) => c >= 0,\n};\n\n/**\n * Pre-parsed range expression for efficient reuse.\n *\n * Parse a range once and reuse it for multiple version checks,\n * avoiding repeated parsing overhead.\n *\n * @example\n * ```typescript\n * // Parse once\n * const range = new Range(\">=2.0 <3.0\");\n *\n * // Reuse many times (much faster than re-parsing)\n * satisfies(\"2.5.1\", range); // => true\n * satisfies(\"2.3.0\", range); // => true\n * satisfies(\"3.0.0\", range); // => false\n * ```;\n */\nexport class Range {\n readonly comparators: readonly Comparator[];\n readonly raw: string;\n\n constructor(range: string) {\n // Length check for range string to prevent ReDoS attacks\n if (range.length > MAX_RANGE_STRING_LENGTH) {\n throw new RangeParseError(\n `${range.slice(0, 50)}...`,\n `range string too long (max ${MAX_RANGE_STRING_LENGTH} characters)`\n );\n }\n\n this.raw = range;\n const tokens = splitTokens(range);\n this.comparators = tokens.map(parseToken);\n }\n\n /**\n * Test if a version satisfies this range.\n *\n * @param version - Version string to test\n * @returns True if version satisfies all comparators\n * @throws {VersionParseError} If version string is invalid\n */\n test(version: string): boolean {\n if (this.comparators.length === 0) {\n return false;\n }\n\n const v = parse(version);\n for (const c of this.comparators) {\n const cmp = compare(v, c.v);\n if (!OP_TEST[c.op](cmp)) {\n return false;\n }\n }\n return true;\n }\n}\n\n/**\n * Checks if a version satisfies a range expression.\n *\n * Range expressions consist of one or more space-separated comparators.\n * Each comparator is an optional operator followed by a version.\n *\n * Supported operators:\n *\n * - `=` (or no operator): exact match\n * - `<`: less than\n * - `<=`: less than or equal\n * - `>`: greater than\n * - `>=`: greater than or equal\n *\n * Multiple comparators create AND conditions - all must be satisfied.\n *\n * For performance when checking many versions against the same range,\n * use a Range object instead of a string.\n *\n * @example\n * ```typescript\n * // String range (parsed every call)\n * satisfies(\"2.5.1\", \">=2.0 <3.0\"); // => true\n * satisfies(\"2.5.1\", \"2.5.1\"); // => true (exact match)\n * satisfies(\"2.5.1\", \">=2.6\"); // => false\n *\n * // Range object (parse once, reuse many times - much faster)\n * const range = new Range(\">=2.0 <3.0\");\n * satisfies(\"2.5.1\", range); // => true\n * satisfies(\"2.3.0\", range); // => true\n * satisfies(\"3.0.0\", range); // => false\n * ```;\n *\n * @param version - Version string to test\n * @param range - Range expression string or pre-parsed Range object\n * @returns True if version satisfies all comparators, false for empty range\n * @throws {VersionParseError} If version string is invalid\n * @throws {RangeParseError} If range expression is invalid or exceeds length\n * limit\n */\nexport function satisfies(version: string, range: string | Range): boolean {\n const rangeObj = range instanceof Range ? range : new Range(range);\n return rangeObj.test(version);\n}\n","import { compare } from \"./compare\";\nimport { satisfies } from \"./range\";\nimport type { Range } from \"./range\";\n\n/**\n * Sorts an array of version strings in ascending order.\n *\n * @example\n * ```typescript\n * sort([\"2.5\", \"2.3.1\", \"2.10.0\"]);\n * // => [\"2.3.1\", \"2.5\", \"2.10.0\"]\n *\n * sort([\"2.10\", \"2.9\", \"2.8\"]);\n * // => [\"2.8\", \"2.9\", \"2.10\"]\n * ```;\n *\n * @param versions - Array of version strings to sort\n * @returns New sorted array (does not mutate input)\n * @throws {VersionParseError} If any version string is invalid\n */\nexport function sort(versions: string[]): string[] {\n return [...versions].toSorted((a, b) => compare(a, b));\n}\n\n/**\n * Finds the highest version that satisfies a range.\n *\n * @example\n * ```typescript\n * maxSatisfying([\"2.3.0\", \"2.5.1\", \"3.0.0\"], \">=2.0 <3.0\");\n * // => \"2.5.1\"\n *\n * maxSatisfying([\"2.3.0\", \"2.5.1\"], \">=3.0\");\n * // => null (no matches)\n *\n * // Use Range object for better performance with many versions\n * const range = new Range(\">=2.0 <3.0\");\n * maxSatisfying([\"2.3.0\", \"2.5.1\", \"3.0.0\"], range);\n * // => \"2.5.1\"\n * ```;\n *\n * @param versions - Array of version strings to search\n * @param range - Range expression string or pre-parsed Range object\n * @returns Highest matching version, or null if none match\n * @throws {VersionParseError} If any version string is invalid\n * @throws {RangeParseError} If range expression is invalid\n */\nexport function maxSatisfying(\n versions: string[],\n range: string | Range\n): string | null {\n let max: string | null = null;\n\n for (const version of versions) {\n if (\n satisfies(version, range) &&\n (max === null || compare(version, max) === 1)\n ) {\n max = version;\n }\n }\n\n return max;\n}\n\n/**\n * Finds the lowest version that satisfies a range.\n *\n * @example\n * ```typescript\n * minSatisfying([\"2.3.0\", \"2.5.1\", \"3.0.0\"], \">=2.0 <3.0\");\n * // => \"2.3.0\"\n *\n * minSatisfying([\"2.3.0\", \"2.5.1\"], \">=3.0\");\n * // => null (no matches)\n *\n * // Use Range object for better performance with many versions\n * const range = new Range(\">=2.0 <3.0\");\n * minSatisfying([\"2.3.0\", \"2.5.1\", \"3.0.0\"], range);\n * // => \"2.3.0\"\n * ```;\n *\n * @param versions - Array of version strings to search\n * @param range - Range expression string or pre-parsed Range object\n * @returns Lowest matching version, or null if none match\n * @throws {VersionParseError} If any version string is invalid\n * @throws {RangeParseError} If range expression is invalid\n */\nexport function minSatisfying(\n versions: string[],\n range: string | Range\n): string | null {\n let min: string | null = null;\n\n for (const version of versions) {\n if (\n satisfies(version, range) &&\n (min === null || compare(version, min) === -1)\n ) {\n min = version;\n }\n }\n\n return min;\n}\n"],"mappings":";;;;AAGA,IAAa,oBAAb,MAAa,0BAA0B,MAAM;CAC3C,OAAyB;CACzB;CACA;CAEA,YAAY,OAAe,QAAgB;AACzC,QAAM,4BAA4B,MAAM,OAAO,SAAS;AAExD,OAAK,QAAQ;AACb,OAAK,SAAS;AAGd,MAAI,MAAM,kBACR,OAAM,kBAAkB,MAAM,kBAAkB;;;;;;AAQtD,IAAa,kBAAb,MAAa,wBAAwB,MAAM;CACzC,OAAyB;CACzB;CACA;CAEA,YAAY,OAAe,QAAgB;AACzC,QAAM,yBAAyB,MAAM,OAAO,SAAS;AAErD,OAAK,QAAQ;AACb,OAAK,SAAS;AAGd,MAAI,MAAM,kBACR,OAAM,kBAAkB,MAAM,gBAAgB;;;;;ACNpD,MAAa,0BAA0B;AACvC,MAAa,6BAA6B,KAAK,KAAK;;;AC3BpD,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;AAsBnB,SAAgB,MAAM,OAA2B;AAE/C,KAAI,MAAM,SAAA,IACR,OAAM,IAAI,kBACR,GAAG,MAAM,MAAM,GAAG,GAAG,CAAC,MACtB,+CACD;CAGH,MAAM,QAAQ,WAAW,KAAK,MAAM;AACpC,KAAI,CAAC,MACH,OAAM,IAAI,kBACR,OACA,8DACD;CAIH,MAAM,QAAQ,OAAO,MAAM,GAAG;CAC9B,MAAM,QAAQ,MAAM,OAAO,KAAA,IAAY,IAAI,OAAO,MAAM,GAAG;CAC3D,MAAM,QAAQ,MAAM,OAAO,KAAA,IAAY,IAAI,OAAO,MAAM,GAAG;AAG3D,KAAI,QAAQ,2BACV,OAAM,IAAI,kBACR,OACA,iBAAiB,MAAM,mBAAmB,6BAC3C;AAEH,KAAI,QAAQ,2BACV,OAAM,IAAI,kBACR,OACA,iBAAiB,MAAM,mBAAmB,6BAC3C;AAEH,KAAI,QAAQ,2BACV,OAAM,IAAI,kBACR,OACA,iBAAiB,MAAM,mBAAmB,6BAC3C;AAGH,QAAO;EAAE;EAAO;EAAO;EAAO;;;;;;;;;;;;;;;;AAiBhC,SAAgB,MAAM,OAAuB;CAC3C,MAAM,IAAI,MAAM,MAAM;AACtB,QAAO,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE;;;;;;;;;;;;;;;;;AAkBpC,SAAgB,MAAM,OAAwB;AAC5C,KAAI;AACF,QAAM,MAAM;AACZ,SAAO;SACD;AACN,SAAO;;;;;;;;;AAUX,SAAgB,OAAO,GAAoC;AACzD,KAAI,OAAO,MAAM,SACf,QAAO,MAAM,EAAE;AAEjB,QAAO;;;;;;;;;;;;;;;;;;;;;AAsBT,SAAgB,UACd,SACA,SACQ;CACR,MAAM,IAAI,MAAM,QAAQ;AAGxB,SAAQ,SAAR;EACE,KAAK,QACH,QAAO,GAAG,EAAE,QAAQ,EAAE;EAExB,KAAK,QACH,QAAO,GAAG,EAAE,MAAM,GAAG,EAAE,QAAQ,EAAE;EAEnC,KAAK,QACH,QAAO,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;AC3IhD,SAAgB,QACd,GACA,GACkB;CAClB,MAAM,KAAK,OAAO,EAAE;CACpB,MAAM,KAAK,OAAO,EAAE;AAGpB,MAAK,MAAM,OAAO;EAAC;EAAS;EAAS;EAAQ,CAC3C,KAAI,GAAG,SAAS,GAAG,KACjB,QAAO,GAAG,OAAO,GAAG,OAAO,KAAK;AAGpC,QAAO;;;;;;;;;;;;;;;;;AAkBT,SAAgB,GAAG,GAAwB,GAAiC;AAC1E,QAAO,QAAQ,GAAG,EAAE,KAAK;;;;;;;;;;;;;;;;;AAkB3B,SAAgB,GAAG,GAAwB,GAAiC;AAC1E,QAAO,QAAQ,GAAG,EAAE,KAAK;;;;;;;;;;;;;;;;;AAkB3B,SAAgB,IAAI,GAAwB,GAAiC;AAC3E,QAAO,QAAQ,GAAG,EAAE,KAAK;;;;;;;;;;;;;;;;;AAkB3B,SAAgB,GAAG,GAAwB,GAAiC;AAC1E,QAAO,QAAQ,GAAG,EAAE,KAAK;;;;;;;;;;;;;;;;;AAkB3B,SAAgB,IAAI,GAAwB,GAAiC;AAC3E,QAAO,QAAQ,GAAG,EAAE,KAAK;;;;;;;;;;;;;;;;;;;;;;AAuB3B,SAAgB,KACd,IACA,IACoC;CACpC,MAAM,IAAI,OAAO,GAAG;CACpB,MAAM,IAAI,OAAO,GAAG;AAEpB,KAAI,EAAE,UAAU,EAAE,MAChB,QAAO;AAET,KAAI,EAAE,UAAU,EAAE,MAChB,QAAO;AAET,KAAI,EAAE,UAAU,EAAE,MAChB,QAAO;AAET,QAAO;;;;ACnKT,MAAM,iBAAiB;AAGvB,MAAM,QAAQ;;;;;;AAOd,SAAS,YAAY,OAAyB;CAC5C,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,QAAQ,WAAW,IAAI,EAAE,GAAG,QAAQ,MAAM,MAAM;;;;;;;AAQzD,SAAS,WAAW,OAA2B;CAC7C,MAAM,IAAI,eAAe,KAAK,MAAM;AACpC,KAAI,CAAC,EACH,OAAM,IAAI,gBACR,OACA,8DACD;AAOH,QAAO;EAAE,IAHG,EAAE,MAAM;EAGP,GADH,MAAM,EAAE,MAAM,GAAG;EACX;;;;;;;AAQlB,MAAM,UAA8D;CAClE,MAAM,MAAM,IAAI;CAChB,OAAO,MAAM,KAAK;CAClB,MAAM,MAAM,MAAM;CAClB,MAAM,MAAM,IAAI;CAChB,OAAO,MAAM,KAAK;CACnB;;;;;;;;;;;;;;;;;;AAmBD,IAAa,QAAb,MAAmB;CACjB;CACA;CAEA,YAAY,OAAe;AAEzB,MAAI,MAAM,SAAA,IACR,OAAM,IAAI,gBACR,GAAG,MAAM,MAAM,GAAG,GAAG,CAAC,MACtB,8BAA8B,wBAAwB,cACvD;AAGH,OAAK,MAAM;AAEX,OAAK,cADU,YAAY,MAAM,CACP,IAAI,WAAW;;;;;;;;;CAU3C,KAAK,SAA0B;AAC7B,MAAI,KAAK,YAAY,WAAW,EAC9B,QAAO;EAGT,MAAM,IAAI,MAAM,QAAQ;AACxB,OAAK,MAAM,KAAK,KAAK,aAAa;GAChC,MAAM,MAAM,QAAQ,GAAG,EAAE,EAAE;AAC3B,OAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CACrB,QAAO;;AAGX,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CX,SAAgB,UAAU,SAAiB,OAAgC;AAEzE,SADiB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,MAAM,EAClD,KAAK,QAAQ;;;;;;;;;;;;;;;;;;;;ACxI/B,SAAgB,KAAK,UAA8B;AACjD,QAAO,CAAC,GAAG,SAAS,CAAC,UAAU,GAAG,MAAM,QAAQ,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;AA0BxD,SAAgB,cACd,UACA,OACe;CACf,IAAI,MAAqB;AAEzB,MAAK,MAAM,WAAW,SACpB,KACE,UAAU,SAAS,MAAM,KACxB,QAAQ,QAAQ,QAAQ,SAAS,IAAI,KAAK,GAE3C,OAAM;AAIV,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;AA0BT,SAAgB,cACd,UACA,OACe;CACf,IAAI,MAAqB;AAEzB,MAAK,MAAM,WAAW,SACpB,KACE,UAAU,SAAS,MAAM,KACxB,QAAQ,QAAQ,QAAQ,SAAS,IAAI,KAAK,IAE3C,OAAM;AAIV,QAAO"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/parse.ts","../src/compare.ts","../src/range.ts","../src/collection.ts"],"sourcesContent":["/**\n * Error thrown when a version string cannot be parsed.\n */\nexport class VersionParseError extends Error {\n override readonly name = \"VersionParseError\";\n readonly input: string;\n readonly reason: string;\n\n constructor(input: string, reason: string) {\n super(`Invalid version format ('${input}') — ${reason}`);\n\n this.input = input;\n this.reason = reason;\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, VersionParseError);\n }\n }\n}\n\n/**\n * Error thrown when a range token cannot be parsed.\n */\nexport class RangeParseError extends Error {\n override readonly name = \"RangeParseError\";\n readonly token: string;\n readonly reason: string;\n\n constructor(token: string, reason: string) {\n super(`Invalid range token ('${token}') — ${reason}`);\n\n this.token = token;\n this.reason = reason;\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, RangeParseError);\n }\n }\n}\n","/**\n * Represents a semantic version with major, minor, and patch components.\n */\nexport interface Hl7Version {\n major: number;\n minor: number;\n patch: number;\n}\n\n/**\n * Comparison operators supported in version ranges.\n */\nexport type ComparisonOperator = \"=\" | \"<\" | \"<=\" | \">\" | \">=\";\n\n/**\n * Internal representation of a version range comparator.\n */\nexport interface Comparator {\n op: ComparisonOperator;\n v: Hl7Version;\n}\n\n/**\n * Result of a comparison operation.\n */\nexport type ComparisonResult = -1 | 0 | 1;\n\n/**\n * Security constraints for input validation.\n */\nexport const MAX_VERSION_STRING_LENGTH = 100;\nexport const MAX_RANGE_STRING_LENGTH = 1000;\nexport const MAX_SAFE_VERSION_COMPONENT = 2 ** 31 - 1; // Max safe int32 for interop\n","import { VersionParseError } from \"./errors\";\nimport type { Hl7Version } from \"./types\";\nimport { MAX_SAFE_VERSION_COMPONENT, MAX_VERSION_STRING_LENGTH } from \"./types\";\n\n// Regex for parsing version strings\nconst VERSION_RE = /^\\s*(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?\\s*$/;\n\n/**\n * Parses a version string into a structured version object.\n *\n * @example\n * ```typescript\n * const v = parse(\"2.5.1\");\n * // => { major: 2, minor: 5, patch: 1 }\n *\n * parse(\"2\");\n * // => { major: 2, minor: 0, patch: 0 }\n *\n * parse(\"HELLO\");\n * // => throws VersionParseError\n * ```;\n *\n * @param input - Version string to parse (e.g., \"2.5.1\", \"2.3\", \"2\")\n * @returns Structured version with major, minor, and patch components\n * @throws {VersionParseError} If the input format is invalid or exceeds safety\n * limits\n */\nexport function parse(input: string): Hl7Version {\n // Length check to prevent ReDoS attacks\n if (input.length > MAX_VERSION_STRING_LENGTH) {\n throw new VersionParseError(\n `${input.slice(0, 50)}...`,\n `version string too long (max ${MAX_VERSION_STRING_LENGTH} characters)`\n );\n }\n\n const match = VERSION_RE.exec(input);\n if (!match) {\n throw new VersionParseError(\n input,\n \"expected format: major.minor.patch (e.g., '2.5.1' or '2.3')\"\n );\n }\n\n // Regex ensures digits-only, Number() on digits always yields valid integers\n const major = Number(match[1]);\n const minor = match[2] === undefined ? 0 : Number(match[2]);\n const patch = match[3] === undefined ? 0 : Number(match[3]);\n\n // Validate range to prevent integer overflow and ensure interoperability\n if (major > MAX_SAFE_VERSION_COMPONENT) {\n throw new VersionParseError(\n input,\n `major version ${major} exceeds maximum ${MAX_SAFE_VERSION_COMPONENT}`\n );\n }\n if (minor > MAX_SAFE_VERSION_COMPONENT) {\n throw new VersionParseError(\n input,\n `minor version ${minor} exceeds maximum ${MAX_SAFE_VERSION_COMPONENT}`\n );\n }\n if (patch > MAX_SAFE_VERSION_COMPONENT) {\n throw new VersionParseError(\n input,\n `patch version ${patch} exceeds maximum ${MAX_SAFE_VERSION_COMPONENT}`\n );\n }\n\n return { major, minor, patch };\n}\n\n/**\n * Converts a version string to canonical format (major.minor.patch).\n *\n * @example\n * ```typescript\n * clean(\"2\"); // => \"2.0.0\"\n * clean(\"2.5\"); // => \"2.5.0\"\n * clean(\" 2.5 \"); // => \"2.5.0\"\n * ```;\n *\n * @param input - Version string to clean\n * @returns Canonical version string\n * @throws {VersionParseError} If the input format is invalid\n */\nexport function clean(input: string): string {\n const v = parse(input);\n return `${v.major}.${v.minor}.${v.patch}`;\n}\n\n/**\n * Checks if a string is a valid version format.\n * This function never throws - use it for validation.\n *\n * @example\n * ```typescript\n * valid(\"2.5.1\"); // => true\n * valid(\"2\"); // => true\n * valid(\"HELLO\"); // => false\n * valid(\"2.\"); // => false\n * ```;\n *\n * @param input - Version string to validate\n * @returns True if valid, false otherwise\n */\nexport function valid(input: string): boolean {\n try {\n parse(input);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Internal helper to ensure a value is a parsed Hl7Version object.\n * Parses strings, returns objects as-is.\n *\n * @internal\n */\nexport function ensure(v: string | Hl7Version): Hl7Version {\n if (typeof v === \"string\") {\n return parse(v);\n }\n return v;\n}\n\n/**\n * Increments a version component and resets all lower components to zero.\n *\n * @example\n * ```typescript\n * increment(\"2.5.1\", \"major\"); // => \"3.0.0\"\n * increment(\"2.5.1\", \"minor\"); // => \"2.6.0\"\n * increment(\"2.5.1\", \"patch\"); // => \"2.5.2\"\n *\n * // Works with partial versions too\n * increment(\"2\", \"minor\"); // => \"2.1.0\"\n * increment(\"2.5\", \"patch\"); // => \"2.5.1\"\n * ```;\n *\n * @param version - Version string to increment\n * @param release - Component to increment: 'major', 'minor', or 'patch'\n * @returns New version string with incremented component\n * @throws {VersionParseError} If version string is invalid\n */\nexport function increment(\n version: string,\n release: \"major\" | \"minor\" | \"patch\"\n): string {\n const v = parse(version);\n\n // biome-ignore lint/style/useDefaultSwitchClause: default case in the switch statement is unreachable\n switch (release) {\n case \"major\": {\n return `${v.major + 1}.0.0`;\n }\n case \"minor\": {\n return `${v.major}.${v.minor + 1}.0`;\n }\n case \"patch\": {\n return `${v.major}.${v.minor}.${v.patch + 1}`;\n }\n }\n}\n","import { ensure } from \"./parse\";\nimport type { ComparisonResult, Hl7Version } from \"./types\";\n\n/**\n * Compares two versions and returns their relationship.\n *\n * @example\n * ```typescript\n * compare(\"2.5.1\", \"2.5.0\"); // => 1\n * compare(\"2.3\", \"2.5\"); // => -1\n * compare(\"2.5.1\", \"2.5.1\"); // => 0\n *\n * // Works with parsed versions too\n * const v1 = parse(\"2.5.1\");\n * const v2 = parse(\"2.5.0\");\n * compare(v1, v2); // => 1\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns -1 if a < b, 0 if a = b, 1 if a > b\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function compare(\n a: string | Hl7Version,\n b: string | Hl7Version\n): ComparisonResult {\n const va = ensure(a);\n const vb = ensure(b);\n\n // Compare in order: major, minor, patch\n for (const key of [\"major\", \"minor\", \"patch\"] as const) {\n if (va[key] !== vb[key]) {\n return va[key] < vb[key] ? -1 : 1;\n }\n }\n return 0;\n}\n\n/**\n * Checks if two versions are equal.\n *\n * @example\n * ```typescript\n * eq(\"2.5.1\", \"2.5.1\"); // => true\n * eq(\"2.5\", \"2.5.0\"); // => true (normalized)\n * eq(\"2.5.1\", \"2.5.0\"); // => false\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns True if versions are equal, false otherwise\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function eq(a: string | Hl7Version, b: string | Hl7Version): boolean {\n return compare(a, b) === 0;\n}\n\n/**\n * Checks if first version is less than second version.\n *\n * @example\n * ```typescript\n * lt(\"2.3.0\", \"2.5.1\"); // => true\n * lt(\"2.5.1\", \"2.5.1\"); // => false\n * lt(\"2.5.1\", \"2.3.0\"); // => false\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns True if a < b, false otherwise\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function lt(a: string | Hl7Version, b: string | Hl7Version): boolean {\n return compare(a, b) === -1;\n}\n\n/**\n * Checks if first version is less than or equal to second version.\n *\n * @example\n * ```typescript\n * lte(\"2.3.0\", \"2.5.1\"); // => true\n * lte(\"2.5.1\", \"2.5.1\"); // => true\n * lte(\"2.5.1\", \"2.3.0\"); // => false\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns True if a <= b, false otherwise\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function lte(a: string | Hl7Version, b: string | Hl7Version): boolean {\n return compare(a, b) !== 1;\n}\n\n/**\n * Checks if first version is greater than second version.\n *\n * @example\n * ```typescript\n * gt(\"2.5.1\", \"2.3.0\"); // => true\n * gt(\"2.5.1\", \"2.5.1\"); // => false\n * gt(\"2.3.0\", \"2.5.1\"); // => false\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns True if a > b, false otherwise\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function gt(a: string | Hl7Version, b: string | Hl7Version): boolean {\n return compare(a, b) === 1;\n}\n\n/**\n * Checks if first version is greater than or equal to second version.\n *\n * @example\n * ```typescript\n * gte(\"2.5.1\", \"2.3.0\"); // => true\n * gte(\"2.5.1\", \"2.5.1\"); // => true\n * gte(\"2.3.0\", \"2.5.1\"); // => false\n * ```;\n *\n * @param a - First version (string or parsed object)\n * @param b - Second version (string or parsed object)\n * @returns True if a >= b, false otherwise\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function gte(a: string | Hl7Version, b: string | Hl7Version): boolean {\n return compare(a, b) !== -1;\n}\n\n/**\n * Determines the highest-level component that differs between two versions.\n *\n * @example\n * ```typescript\n * diff(\"2.5.1\", \"3.0.0\"); // => \"major\"\n * diff(\"2.5.1\", \"2.6.0\"); // => \"minor\"\n * diff(\"2.5.1\", \"2.5.2\"); // => \"patch\"\n * diff(\"2.5.1\", \"2.5.1\"); // => null (equal)\n *\n * // Works with partial versions\n * diff(\"2\", \"2.0.0\"); // => null (normalized to same)\n * diff(\"2.5\", \"2.6\"); // => \"minor\"\n * ```;\n *\n * @param v1 - First version (string or parsed object)\n * @param v2 - Second version (string or parsed object)\n * @returns 'major', 'minor', 'patch', or null if versions are equal\n * @throws {VersionParseError} If either input is an invalid version string\n */\nexport function diff(\n v1: string | Hl7Version,\n v2: string | Hl7Version\n): \"major\" | \"minor\" | \"patch\" | null {\n const a = ensure(v1);\n const b = ensure(v2);\n\n if (a.major !== b.major) {\n return \"major\";\n }\n if (a.minor !== b.minor) {\n return \"minor\";\n }\n if (a.patch !== b.patch) {\n return \"patch\";\n }\n return null;\n}\n","import { compare } from \"./compare\";\nimport { RangeParseError } from \"./errors\";\nimport { parse } from \"./parse\";\nimport type { Comparator } from \"./types\";\nimport { MAX_RANGE_STRING_LENGTH } from \"./types\";\n\n// Regex for parsing range tokens\nconst RANGE_TOKEN_RE = /^(<=|>=|<|>|=)?\\s*(\\d+(?:\\.\\d+){0,2})$/;\n\n// Whitespace splitter for range expressions\nconst WS_RE = /\\s+/;\n\n/**\n * Splits a range string into individual tokens.\n *\n * @internal\n */\nfunction splitTokens(range: string): string[] {\n const trimmed = range.trim();\n return trimmed.length === 0 ? [] : trimmed.split(WS_RE);\n}\n\n/**\n * Parses a single range token into a comparator.\n *\n * @internal\n */\nfunction parseToken(token: string): Comparator {\n const m = RANGE_TOKEN_RE.exec(token);\n if (!m) {\n throw new RangeParseError(\n token,\n \"expected format: [operator]version (e.g., '>=2.5' or '2.3')\"\n );\n }\n\n // m[1] is optional operator, m[2] is required version (guaranteed by regex)\n const op = (m[1] || \"=\") as Comparator[\"op\"];\n // biome-ignore lint/style/noNonNullAssertion: Non-null assertion safe: regex guarantees m[2] exists\n const v = parse(m[2] || \"\");\n return { op, v };\n}\n\n/**\n * Maps comparison operators to test functions.\n *\n * @internal\n */\nconst OP_TEST: Record<Comparator[\"op\"], (cmp: number) => boolean> = {\n \"<\": (c) => c < 0,\n \"<=\": (c) => c <= 0,\n \"=\": (c) => c === 0,\n \">\": (c) => c > 0,\n \">=\": (c) => c >= 0,\n};\n\n/**\n * Pre-parsed range expression for efficient reuse.\n *\n * Parse a range once and reuse it for multiple version checks,\n * avoiding repeated parsing overhead.\n *\n * @example\n * ```typescript\n * // Parse once\n * const range = new Range(\">=2.0 <3.0\");\n *\n * // Reuse many times (much faster than re-parsing)\n * satisfies(\"2.5.1\", range); // => true\n * satisfies(\"2.3.0\", range); // => true\n * satisfies(\"3.0.0\", range); // => false\n * ```;\n */\nexport class Range {\n readonly comparators: readonly Comparator[];\n readonly raw: string;\n\n constructor(range: string) {\n // Length check for range string to prevent ReDoS attacks\n if (range.length > MAX_RANGE_STRING_LENGTH) {\n throw new RangeParseError(\n `${range.slice(0, 50)}...`,\n `range string too long (max ${MAX_RANGE_STRING_LENGTH} characters)`\n );\n }\n\n this.raw = range;\n const tokens = splitTokens(range);\n this.comparators = tokens.map(parseToken);\n }\n\n /**\n * Test if a version satisfies this range.\n *\n * @param version - Version string to test\n * @returns True if version satisfies all comparators\n * @throws {VersionParseError} If version string is invalid\n */\n test(version: string): boolean {\n if (this.comparators.length === 0) {\n return false;\n }\n\n const v = parse(version);\n for (const c of this.comparators) {\n const cmp = compare(v, c.v);\n if (!OP_TEST[c.op](cmp)) {\n return false;\n }\n }\n return true;\n }\n}\n\n/**\n * Checks if a version satisfies a range expression.\n *\n * Range expressions consist of one or more space-separated comparators.\n * Each comparator is an optional operator followed by a version.\n *\n * Supported operators:\n *\n * - `=` (or no operator): exact match\n * - `<`: less than\n * - `<=`: less than or equal\n * - `>`: greater than\n * - `>=`: greater than or equal\n *\n * Multiple comparators create AND conditions - all must be satisfied.\n *\n * For performance when checking many versions against the same range,\n * use a Range object instead of a string.\n *\n * @example\n * ```typescript\n * // String range (parsed every call)\n * satisfies(\"2.5.1\", \">=2.0 <3.0\"); // => true\n * satisfies(\"2.5.1\", \"2.5.1\"); // => true (exact match)\n * satisfies(\"2.5.1\", \">=2.6\"); // => false\n *\n * // Range object (parse once, reuse many times - much faster)\n * const range = new Range(\">=2.0 <3.0\");\n * satisfies(\"2.5.1\", range); // => true\n * satisfies(\"2.3.0\", range); // => true\n * satisfies(\"3.0.0\", range); // => false\n * ```;\n *\n * @param version - Version string to test\n * @param range - Range expression string or pre-parsed Range object\n * @returns True if version satisfies all comparators, false for empty range\n * @throws {VersionParseError} If version string is invalid\n * @throws {RangeParseError} If range expression is invalid or exceeds length\n * limit\n */\nexport function satisfies(version: string, range: string | Range): boolean {\n const rangeObj = range instanceof Range ? range : new Range(range);\n return rangeObj.test(version);\n}\n","import { compare } from \"./compare\";\nimport { satisfies } from \"./range\";\nimport type { Range } from \"./range\";\n\n/**\n * Sorts an array of version strings in ascending order.\n *\n * @example\n * ```typescript\n * sort([\"2.5\", \"2.3.1\", \"2.10.0\"]);\n * // => [\"2.3.1\", \"2.5\", \"2.10.0\"]\n *\n * sort([\"2.10\", \"2.9\", \"2.8\"]);\n * // => [\"2.8\", \"2.9\", \"2.10\"]\n * ```;\n *\n * @param versions - Array of version strings to sort\n * @returns New sorted array (does not mutate input)\n * @throws {VersionParseError} If any version string is invalid\n */\nexport function sort(versions: string[]): string[] {\n return [...versions].toSorted((a, b) => compare(a, b));\n}\n\n/**\n * Finds the highest version that satisfies a range.\n *\n * @example\n * ```typescript\n * maxSatisfying([\"2.3.0\", \"2.5.1\", \"3.0.0\"], \">=2.0 <3.0\");\n * // => \"2.5.1\"\n *\n * maxSatisfying([\"2.3.0\", \"2.5.1\"], \">=3.0\");\n * // => null (no matches)\n *\n * // Use Range object for better performance with many versions\n * const range = new Range(\">=2.0 <3.0\");\n * maxSatisfying([\"2.3.0\", \"2.5.1\", \"3.0.0\"], range);\n * // => \"2.5.1\"\n * ```;\n *\n * @param versions - Array of version strings to search\n * @param range - Range expression string or pre-parsed Range object\n * @returns Highest matching version, or null if none match\n * @throws {VersionParseError} If any version string is invalid\n * @throws {RangeParseError} If range expression is invalid\n */\nexport function maxSatisfying(\n versions: string[],\n range: string | Range\n): string | null {\n let max: string | null = null;\n\n for (const version of versions) {\n if (\n satisfies(version, range) &&\n (max === null || compare(version, max) === 1)\n ) {\n max = version;\n }\n }\n\n return max;\n}\n\n/**\n * Finds the lowest version that satisfies a range.\n *\n * @example\n * ```typescript\n * minSatisfying([\"2.3.0\", \"2.5.1\", \"3.0.0\"], \">=2.0 <3.0\");\n * // => \"2.3.0\"\n *\n * minSatisfying([\"2.3.0\", \"2.5.1\"], \">=3.0\");\n * // => null (no matches)\n *\n * // Use Range object for better performance with many versions\n * const range = new Range(\">=2.0 <3.0\");\n * minSatisfying([\"2.3.0\", \"2.5.1\", \"3.0.0\"], range);\n * // => \"2.3.0\"\n * ```;\n *\n * @param versions - Array of version strings to search\n * @param range - Range expression string or pre-parsed Range object\n * @returns Lowest matching version, or null if none match\n * @throws {VersionParseError} If any version string is invalid\n * @throws {RangeParseError} If range expression is invalid\n */\nexport function minSatisfying(\n versions: string[],\n range: string | Range\n): string | null {\n let min: string | null = null;\n\n for (const version of versions) {\n if (\n satisfies(version, range) &&\n (min === null || compare(version, min) === -1)\n ) {\n min = version;\n }\n }\n\n return min;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glion/util-semver",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Tiny, fast HL7v2 version and range utilities (basic comparators only)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"health",
|
|
@@ -33,23 +33,22 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@types/node": "
|
|
37
|
-
"@vitest/coverage-v8": "4.1.
|
|
36
|
+
"@types/node": "25.6.0",
|
|
37
|
+
"@vitest/coverage-v8": "4.1.11",
|
|
38
38
|
"publint": "0.3.18",
|
|
39
|
-
"tsdown": "0.21.
|
|
40
|
-
"typescript": "
|
|
41
|
-
"vitest": "4.1.
|
|
42
|
-
"@glion/check-readme": "0.
|
|
43
|
-
"@glion/testing": "0.
|
|
44
|
-
"@glion/tsconfig": "0.
|
|
39
|
+
"tsdown": "0.21.10",
|
|
40
|
+
"typescript": "6.0.3",
|
|
41
|
+
"vitest": "4.1.11",
|
|
42
|
+
"@glion/check-readme": "0.18.0",
|
|
43
|
+
"@glion/testing": "0.18.0",
|
|
44
|
+
"@glion/tsconfig": "0.18.0"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
|
-
"node": ">=
|
|
47
|
+
"node": ">=22"
|
|
48
48
|
},
|
|
49
|
-
"packageManager": "pnpm@10.14.0",
|
|
50
49
|
"scripts": {
|
|
51
50
|
"build": "tsdown && tsc --emitDeclarationOnly",
|
|
52
|
-
"check-types": "tsc --noEmit",
|
|
51
|
+
"check-types": "tsc --noEmit && tsc --noEmit -p tests/tsconfig.json",
|
|
53
52
|
"check:readme": "glion-check-readme",
|
|
54
53
|
"test": "vitest run",
|
|
55
54
|
"test:coverage": "vitest run --coverage",
|