import type { Comparator } from "./types.ts";
export function compareNumber( a: number, b: number,): 1 | 0 | -1 { if (isNaN(a) || isNaN(b)) throw new Error("Comparison against non-numbers"); return a === b ? 0 : a < b ? -1 : 1;}
export function checkIdentifier( v1: ReadonlyArray<string | number> = [], v2: ReadonlyArray<string | number> = [],): 1 | 0 | -1 { if (v1.length && !v2.length) return -1; if (!v1.length && v2.length) return 1; return 0;}
export function compareIdentifier( v1: ReadonlyArray<string | number> = [], v2: ReadonlyArray<string | number> = [],): 1 | 0 | -1 { const length = Math.max(v1.length, v2.length); for (let i = 0; i < length; i++) { const a = v1[i]; const b = v2[i]; if (a === undefined && b === undefined) return 0; if (b === undefined) return 1; if (a === undefined) return -1; if (typeof a === "string" && typeof b === "number") return 1; if (typeof a === "number" && typeof b === "string") return -1; if (a < b) return -1; if (a > b) return 1; } return 0;}
const NUMERIC_IDENTIFIER = "0|[1-9]\\d*";
const NON_NUMERIC_IDENTIFIER = "\\d*[a-zA-Z-][a-zA-Z0-9-]*";
const VERSION_CORE = `(?<major>${NUMERIC_IDENTIFIER})\\.(?<minor>${NUMERIC_IDENTIFIER})\\.(?<patch>${NUMERIC_IDENTIFIER})`;
const PRERELEASE_IDENTIFIER = `(?:${NUMERIC_IDENTIFIER}|${NON_NUMERIC_IDENTIFIER})`;
const PRERELEASE = `(?:-(?<prerelease>${PRERELEASE_IDENTIFIER}(?:\\.${PRERELEASE_IDENTIFIER})*))`;
const BUILD_IDENTIFIER = "[0-9A-Za-z-]+";
const BUILD = `(?:\\+(?<buildmetadata>${BUILD_IDENTIFIER}(?:\\.${BUILD_IDENTIFIER})*))`;
const FULL_VERSION = `v?${VERSION_CORE}${PRERELEASE}?${BUILD}?`;
export const FULL_REGEXP = new RegExp(`^${FULL_VERSION}$`);
const COMPARATOR = "(?:<|>)?=?";
const WILDCARD_IDENTIFIER = `x|X|\\*`;
const XRANGE_IDENTIFIER = `${NUMERIC_IDENTIFIER}|${WILDCARD_IDENTIFIER}`;
export const XRANGE = `[v=\\s]*(?<major>${XRANGE_IDENTIFIER})(?:\\.(?<minor>${XRANGE_IDENTIFIER})(?:\\.(?<patch>${XRANGE_IDENTIFIER})${PRERELEASE}?${BUILD}?)?)?`;
export const OPERATOR_XRANGE_REGEXP = new RegExp( `^(?<operator>~>?|\\^|${COMPARATOR})\\s*${XRANGE}$`,);
export const COMPARATOR_REGEXP = new RegExp( `^(?<operator>${COMPARATOR})\\s*(${FULL_VERSION})$|^$`,);
export function isValidNumber(value: unknown): value is number { return ( typeof value === "number" && !Number.isNaN(value) && (!Number.isFinite(value) || (0 <= value && value <= Number.MAX_SAFE_INTEGER)) );}
export const MAX_LENGTH = 256;
export function isValidString(value: unknown): value is string { return ( typeof value === "string" && value.length > 0 && value.length <= MAX_LENGTH && /[0-9A-Za-z-]+/.test(value) );}
const NUMERIC_IDENTIFIER_REGEXP = new RegExp(`^${NUMERIC_IDENTIFIER}$`);export function parsePrerelease(prerelease: string) { return prerelease .split(".") .filter(Boolean) .map((id: string) => { if (NUMERIC_IDENTIFIER_REGEXP.test(id)) { const number = Number(id); if (isValidNumber(number)) return number; } return id; });}
export function parseBuild(buildmetadata: string) { return buildmetadata.split(".").filter(Boolean);}
export function parseNumber(input: string, errorMessage: string) { const number = Number(input); if (!isValidNumber(number)) throw new TypeError(errorMessage); return number;}
export function isWildcardComparator(c: Comparator): boolean { return ( Number.isNaN(c.major) && Number.isNaN(c.minor) && Number.isNaN(c.patch) && (c.prerelease === undefined || c.prerelease.length === 0) && (c.build === undefined || c.build.length === 0) );}