From cbca3e5ade99a4a187326874ef473a294cf93c48 Mon Sep 17 00:00:00 2001 From: Marc Bernard Date: Thu, 24 Apr 2025 21:50:34 +0200 Subject: [PATCH 1/2] fix: prerelease identifier --- internal/re.js | 10 ++++++---- test/classes/semver.js | 17 ++++++++++++++++- test/fixtures/valid-versions.js | 31 +++++++++++++++++++++++++++++++ test/functions/coerce.js | 7 +++++++ 4 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/valid-versions.js diff --git a/internal/re.js b/internal/re.js index 2a956ba0..0a1c0e65 100644 --- a/internal/re.js +++ b/internal/re.js @@ -76,12 +76,14 @@ createToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + // ## Pre-release Version Identifier // A numeric identifier, or a non-numeric identifier. +// Non-numberic identifiers include numberic identifiers but can be longer. +// Therefore non-numberic identifiers must go first. -createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NUMERICIDENTIFIER] -}|${src[t.NONNUMERICIDENTIFIER]})`) +createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER] +}|${src[t.NUMERICIDENTIFIER]})`) -createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NUMERICIDENTIFIERLOOSE] -}|${src[t.NONNUMERICIDENTIFIER]})`) +createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER] +}|${src[t.NUMERICIDENTIFIERLOOSE]})`) // ## Pre-release Version // Hyphen, followed by one or more dot-separated pre-release version diff --git a/test/classes/semver.js b/test/classes/semver.js index 946fa417..f4abad04 100644 --- a/test/classes/semver.js +++ b/test/classes/semver.js @@ -3,7 +3,22 @@ const SemVer = require('../../classes/semver') const increments = require('../fixtures/increments.js') const comparisons = require('../fixtures/comparisons.js') const equality = require('../fixtures/equality.js') -const invalidVersions = require('../fixtures/invalid-versions') +const invalidVersions = require('../fixtures/invalid-versions.js') +const validVersions = require('../fixtures/valid-versions.js') + +test('valid versions', t => { + t.plan(validVersions.length) + validVersions.forEach(([v, major, minor, patch, prerelease, build]) => t.test(v, t => { + const s = new SemVer(v) + t.strictSame(s.major, major) + t.strictSame(s.minor, minor) + t.strictSame(s.patch, patch) + t.strictSame(s.prerelease, prerelease) + t.strictSame(s.build, build) + t.strictSame(s.raw, v) + t.end() + })) +}) test('comparisons', t => { t.plan(comparisons.length) diff --git a/test/fixtures/valid-versions.js b/test/fixtures/valid-versions.js new file mode 100644 index 00000000..e2bf3d11 --- /dev/null +++ b/test/fixtures/valid-versions.js @@ -0,0 +1,31 @@ +// [version, major, minor, patch, prerelease[], build[]] +module.exports = [ + ['1.0.0', 1, 0, 0, [], []], + ['2.1.0', 2, 1, 0, [], []], + ['3.2.1', 3, 2, 1, [], []], + ['v1.2.3', 1, 2, 3, [], []], + + // prerelease + ['1.2.3-0', 1, 2, 3, [0], []], + ['1.2.3-123', 1, 2, 3, [123], []], + ['1.2.3-1.2.3', 1, 2, 3, [1, 2, 3], []], + ['1.2.3-1a', 1, 2, 3, ['1a'], []], + ['1.2.3-a1', 1, 2, 3, ['a1'], []], + ['1.2.3-alpha', 1, 2, 3, ['alpha'], []], + ['1.2.3-alpha.1', 1, 2, 3, ['alpha', 1], []], + ['1.2.3-alpha-1', 1, 2, 3, ['alpha-1'], []], + ['1.2.3-alpha-.-beta', 1, 2, 3, ['alpha-', '-beta'], []], + + // build + ['1.2.3+456', 1, 2, 3, [], ['456']], + ['1.2.3+build', 1, 2, 3, [], ['build']], + ['1.2.3+new-build', 1, 2, 3, [], ['new-build']], + ['1.2.3+build.1', 1, 2, 3, [], ['build', '1']], + ['1.2.3+build.1a', 1, 2, 3, [], ['build', '1a']], + ['1.2.3+build.a1', 1, 2, 3, [], ['build', 'a1']], + ['1.2.3+build.alpha', 1, 2, 3, [], ['build', 'alpha']], + ['1.2.3+build.alpha.beta', 1, 2, 3, [], ['build', 'alpha', 'beta']], + + // mixed + ['1.2.3-alpha+build', 1, 2, 3, ['alpha'], ['build']], +] diff --git a/test/functions/coerce.js b/test/functions/coerce.js index 24e2ff76..4ecc3c0d 100644 --- a/test/functions/coerce.js +++ b/test/functions/coerce.js @@ -118,6 +118,13 @@ test('coerce tests', (t) => { ['1.2.3.4-rc.5', '1.2.3', { includePrerelease: true }], ['1.2.3.4+rev.6', '1.2.3', { includePrerelease: true }], + ['1.0.0-1a', '1.0.0-1a', { includePrerelease: true }], + ['1.0.0-alpha.12ab', '1.0.0-alpha.12ab', { includePrerelease: true }], + ['1.0.0-alpha.1234.23cd', '1.0.0-alpha.1234.23cd', { includePrerelease: true }], + ['1.0.0-nightly.abc123', '1.0.0-nightly.abc123', { includePrerelease: true }], + ['1.0.0-nightly.abcdef', '1.0.0-nightly.abcdef', { includePrerelease: true }], + ['1.0.0-nightly.123456', '1.0.0-nightly.123456', { includePrerelease: true }], + ['1+rev.6', '1.0.0+rev.6', { includePrerelease: true }], ['1.2+rev.6', '1.2.0+rev.6', { includePrerelease: true }], ['1.2.3+rev.6', '1.2.3+rev.6', { includePrerelease: true }], From 14325dd82fa2f136b14020876f60c3dd4f18c3f6 Mon Sep 17 00:00:00 2001 From: Marc Bernard Date: Thu, 24 Apr 2025 22:07:10 +0200 Subject: [PATCH 2/2] revert semver.inc --- classes/semver.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/classes/semver.js b/classes/semver.js index 6fbc062b..97049a40 100644 --- a/classes/semver.js +++ b/classes/semver.js @@ -1,6 +1,6 @@ const debug = require('../internal/debug') const { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants') -const { safeRe: re, safeSrc: src, t } = require('../internal/re') +const { safeRe: re, t } = require('../internal/re') const parseOptions = require('../internal/parse-options') const { compareIdentifiers } = require('../internal/identifiers') @@ -182,8 +182,7 @@ class SemVer { } // Avoid an invalid semver results if (identifier) { - const r = new RegExp(`^${this.options.loose ? src[t.PRERELEASELOOSE] : src[t.PRERELEASE]}$`) - const match = `-${identifier}`.match(r) + const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE]) if (!match || match[1] !== identifier) { throw new Error(`invalid identifier: ${identifier}`) }