Semantic Version Comparator CLI
A Node CLI that compares two semantic versions and reports whether the first is lower, equal, or higher, handling prerelease tags by semver precedence rules.
Project
node-semver-compare
Entry point: semver.mjs
Install
node --versionRun
node semver.mjs 1.2.3-alpha 1.2.3Test
node --test semver.test.mjsExpected output
Prints which version is greater, or reports equality, following semver precedence.Dependencies
- node >=20
What it does
Compares two semantic versions with the precedence rules that matter: numeric fields compare numerically, and a prerelease sorts before its release.
function parse(v) {
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+([0-9A-Za-z.-]+))?$/.exec(v.trim());
if (!match) throw new Error('invalid version: ' + v);
return { core: [Number(match[1]), Number(match[2]), Number(match[3])], pre: match[4] ?? null };
}
function comparePre(a, b) {
if (a === b) return 0;
if (a === null) return 1;
if (b === null) return -1;
const ap = a.split('.'); const bp = b.split('.');
for (let i = 0; i < Math.max(ap.length, bp.length); i++) {
const x = ap[i]; const y = bp[i];
if (x === undefined) return -1;
if (y === undefined) return 1;
const nx = /^\d+$/.test(x); const ny = /^\d+$/.test(y);
if (nx && ny) { if (+x !== +y) return +x < +y ? -1 : 1; }
else if (x !== y) return x < y ? -1 : 1;
}
return 0;
}
function compare(a, b) {
const pa = parse(a); const pb = parse(b);
for (let i = 0; i < 3; i++) if (pa.core[i] !== pb.core[i]) return pa.core[i] < pb.core[i] ? -1 : 1;
return comparePre(pa.pre, pb.pre);
}
const [a, b] = process.argv.slice(2);
console.log(a + ' ' + ['<', '=', '>'][compare(a, b) + 1] + ' ' + b);
Build metadata is ignored for precedence, which is exactly what the specification requires and a common source of disagreement.
Run and verify
node semver.mjs 1.2.3-alpha 1.2.3
node semver.mjs 2.0.0 1.9.9
Run the prerelease comparison first, then a major-version comparison to see numeric ordering.
Expected Output
The prerelease sorts before its release, and 2.0.0 outranks 1.9.9. The output is:
1.2.3-alpha < 1.2.3
2.0.0 > 1.9.9
A build-metadata suffix does not affect precedence, and an invalid version string fails with a parse error rather than a wrong comparison.
Limitations
It implements the precedence rules but not ranges or caret/tilde operators; range matching is a larger piece of work.