I'm attempting to sort a list of tags in order to find the highest tag number. The tags are from a third-party source like Dockerhub, and are in a mixed format (not all semver) i.e.
const tagList = ['0.0.1', '0.0.2', '0.0.3-alpha1', '1.10-alpine3', '1.9.2']
I've been trying to use the compare-versions library but it falls over on non-semantic versions.
I've previously used a python library to sort tags like this:
from packaging.version import LegacyVersion
tag_list = ['0.0.1', '0.0.2', '0.0.3-alpha1', '1.10-alpine3', '1.9.2']
sorted_tags = sorted(tag_list, key=LegacyVersion)
Is there any equivalent package for nodejs, or failing that, a way of sorting these tags?
So far, I have only been able to find compare-versions, but this isn't sufficient. I tried the following:
import { compareVersions } from 'compare-versions';
const versions = ['0.0.1', '0.0.2', '0.0.3-alpha1', '1.10-alpine3', '1.9.2'];
let latest;
try {
latest = versions.sort(compareVersions).pop();
} catch {
latest = versions.sort((a,b)=>a-b).pop();
};
console.log(latest);
1.10-alpine3
1.9.2
When I remove the try/catch and just force it to use the compareVersions
sort function, I get the following error:
/Users/banbone/project/node_modules/compare-versions/lib/umd/index.js:14
throw new Error(`Invalid argument not valid semver ('${version}' received)`);
^
Error: Invalid argument not valid semver ('1.10-alpine3' received)
at validateAndParse (/Users/banbone/project/node_modules/compare-versions/lib/umd/index.js:14:19)
at compareVersions (/Users/banbone/project/node_modules/compare-versions/lib/umd/index.js:53:20)
at Array.sort (<anonymous>)
at file:///Users/banbone/project/test.js:5:19
at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
at async loadESM (node:internal/process/esm_loader:28:7)
at async handleMainPromise (node:internal/modules/run_main:113:12)
Node.js v21.2.0
Version like 1.10-alpine3 violates Semantic Versioning, it must have three numbers and an optional label.
A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor version, and Z is the patch version. Each element MUST increase numerically. For instance: 1.9.0 -> 1.10.0 -> 1.11.0.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
You can use the semver's coerce function to parse the version into a valid semantic version before performing the comparison.
const semver = require("semver");
const versions = ["0.0.1", "0.0.2", "0.0.3-alpha1", "1.10-alpine3", "1.9.2"];
const latest = versions
.map((x) => ({ origin: x, coerced: semver.coerce(x).toString() }))
.sort((x, y) => (semver.gt(x.coerced, y.coerced) ? 1 : -1))
.map((x) => x.origin);
console.log(latest);
//[ '0.0.1', '0.0.2', '0.0.3-alpha1', '1.9.2', '1.10-alpine3' ]