partial
1.x, 1.2, * as the bounds they mean: [lowest allowed, first not allowed).
export function partial(spec: string): [string, string | undefined] | undefined { if (spec === "" || spec === "*" || spec === "x" || spec === "X") return ["0.0.0", undefined]; const parts = spec.split("."); const nums = parts.map((p) => (/^[xX*]$/.test(p) ? undefined : Number(p))); if (nums.some((n) => n !== undefined && Number.isNaN(n))) return undefined; const [maj, min, pat] = nums; if (maj === undefined) return ["0.0.0", undefined]; if (min === undefined) return [`${maj}.0.0`, `${maj + 1}.0.0`]; if (pat === undefined) return [`${maj}.${min}.0`, `${maj}.${min + 1}.0`]; return undefined; }