Skip to content

Instantly share code, notes, and snippets.

@iwill
Last active January 19, 2024 12:42
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save iwill/a83038623ba4fef6abb9efca87ae9ccb to your computer and use it in GitHub Desktop.
Save iwill/a83038623ba4fef6abb9efca87ae9ccb to your computer and use it in GitHub Desktop.
JavaScript - Comparison of Semantic Versioning
/**
* Semantic Versioning Comparing
* #see https://semver.org/
* #see https://stackoverflow.com/a/65687141/456536
* #see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator#options
*/
function semverCompare(a, b) {
if (a.startsWith(b + "-")) return -1
if (b.startsWith(a + "-")) return 1
return a.localeCompare(b, undefined, { numeric: true, sensitivity: "case", caseFirst: "upper" })
}
@iwill
Copy link
Author

iwill commented May 17, 2022

Test function

function test(a, exp, b) {
    const signs = {
        "-1": "<",
         "0": "=",
         "1":  ">"
    }
    let sign = signs[semverCompare(a, b)]
    let res = [a, sign, b]
    if (sign != exp) res.push("// ❌ exp: " + exp + ", got: " + sign)
    console.log(res.join(" "))
}

Test cases

The results with ❌ are known issues which I prefer not to fix.

See also the comparing results from semvercompare.azurewebsites.net

  1. Test cases from https://semver.org/#spec-item-11
// 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1
test("1.0.0", "<", "2.0.0")
test("2.0.0", "<", "2.1.0")
test("2.1.0", "<", "2.1.1")

// 1.0.0-alpha < 1.0.0
test("1.0.0-alpha", "<", "1.0.0")

// 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
test("1.0.0-alpha", "<", "1.0.0-alpha.1")
test("1.0.0-alpha.1", "<", "1.0.0-alpha.beta")
test("1.0.0-alpha.beta", "<", "1.0.0-beta")
test("1.0.0-beta", "<", "1.0.0-beta.2")
test("1.0.0-beta.2", "<", "1.0.0-beta.11")
test("1.0.0-beta.11", "<", "1.0.0-rc.1")
test("1.0.0-rc.1", "<", "1.0.0")

// Build metadata MUST be ignored when determining version precedence.
test("1.0.0", "=", "1.0.0+asdf") // ❌ exp: =, got: <
test("1.0.0+qwer", "=", "1.0.0+asdf") // ❌ exp: =, got: >

// Workaround via `v.replace(/\+.*/, "")`
test("1.0.0", "=", "1.0.0+asdf".replace(/\+.*/, ""))
test("1.0.0+qwer".replace(/\+.*/, ""), "=", "1.0.0+asdf".replace(/\+.*/, ""))
  1. Test cases from npm / node-semver
test("0.0.0", ">", "0.0.0-foo")
test("0.0.1", ">", "0.0.0")
test("1.0.0", ">", "0.9.9")
test("0.10.0", ">", "0.9.0")
test("0.99.0", ">", "0.10.0")
test("2.0.0", ">", "1.2.3")
test("1.2.3", ">", "1.2.3-asdf")
test("1.2.3", ">", "1.2.3-4")
test("1.2.3", ">", "1.2.3-4-foo")
test("1.2.3-5-foo", ">", "1.2.3-5") // ❌ exp: >, got: <
test("1.2.3-5", ">", "1.2.3-4")
test("1.2.3-5-foo", ">", "1.2.3-5-Foo")
test("3.0.0", ">", "2.7.2+asdf")
test("1.2.3-a.10", ">", "1.2.3-a.5")
test("1.2.3-a.b", ">", "1.2.3-a.5")
test("1.2.3-a.b", ">", "1.2.3-a")
test("1.2.3-a.b.c.10.d.5", ">", "1.2.3-a.b.c.5.d.100")
test("1.2.3-r2", ">", "1.2.3-r100") // ❌ exp: >, got: <
test("1.2.3-r100", ">", "1.2.3-R2")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment