From 86535f0f9e50be9beb6a77208d240fc27f0d005b Mon Sep 17 00:00:00 2001 From: madtisa Date: Fri, 22 Dec 2023 02:49:50 +0300 Subject: [PATCH 01/12] feat: preserve pre-release and build parts of a version on coerce (#592) Introduces the new coerce option `full`, if set, allowing to preserve pre-release and build parts of a version. --- README.md | 4 ++++ functions/coerce.js | 20 +++++++++++----- internal/re.js | 8 +++++++ test/functions/coerce.js | 51 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 74 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f7348a08..ba407bb6 100644 --- a/README.md +++ b/README.md @@ -529,6 +529,10 @@ tuple. For example, `1.2.3.4` will return `2.3.4` in rtl mode, not `4.0.0`. `1.2.3/4` will return `4.0.0`, because the `4` is not a part of any other overlapping SemVer tuple. +If the `options.full` flag is set, then the `coerce` result will contain +prerelease and build parts of a version. For example, `1.2.3.4-rc.1+rev.2` +will preserve prerelease `rc.1` and build `rev.2` in the result. + ### Clean * `clean(version)`: Clean a string to be a valid semver if possible diff --git a/functions/coerce.js b/functions/coerce.js index febbff9c..3fe3efe2 100644 --- a/functions/coerce.js +++ b/functions/coerce.js @@ -19,34 +19,42 @@ const coerce = (version, options) => { let match = null if (!options.rtl) { - match = version.match(re[t.COERCE]) + match = version.match(options.full ? re[t.COERCEFULL] : re[t.COERCE]) } else { // Find the right-most coercible string that does not share // a terminus with a more left-ward coercible string. // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' + // With full option set, '1.2.3.4-pre.1.2' wants to coerce '2.3.4-pre.1.2', not '1.2' // // Walk through the string checking with a /g regexp - // Manually set the index so as to pick up overlapping matches. + // Manually set the index so, as to pick up overlapping matches. // Stop when we get a match that ends at the string end, since no // coercible string can be more right-ward without the same terminus. + const coerceRtlRegex = options.full ? re[t.COERCERTLFULL] : re[t.COERCERTL] let next - while ((next = re[t.COERCERTL].exec(version)) && + while ((next = coerceRtlRegex.exec(version)) && (!match || match.index + match[0].length !== version.length) ) { if (!match || next.index + next[0].length !== match.index + match[0].length) { match = next } - re[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length + coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length } // leave it in a clean state - re[t.COERCERTL].lastIndex = -1 + coerceRtlRegex.lastIndex = -1 } if (match === null) { return null } - return parse(`${match[2]}.${match[3] || '0'}.${match[4] || '0'}`, options) + const major = match[2] + const minor = match[3] || '0' + const patch = match[4] || '0' + const prerelease = options.full && match[5] ? `-${match[5]}` : '' + const build = options.full && match[6] ? `+${match[6]}` : '' + + return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options) } module.exports = coerce diff --git a/internal/re.js b/internal/re.js index 21150b3e..bcdf4ba5 100644 --- a/internal/re.js +++ b/internal/re.js @@ -159,7 +159,15 @@ createToken('COERCE', `${'(^|[^\\d])' + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + `(?:$|[^\\d])`) +createToken('COERCEFULL', `${'(^|[^\\d])' + + '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + + `(?:${src[t.PRERELEASE]})?` + + `(?:${src[t.BUILD]})?` + + `(?:$|[^\\d])`) createToken('COERCERTL', src[t.COERCE], true) +createToken('COERCERTLFULL', src[t.COERCEFULL], true) // Tilde ranges. // Meaning is "reasonably at or greater than" diff --git a/test/functions/coerce.js b/test/functions/coerce.js index ad9f199f..8f05f8fd 100644 --- a/test/functions/coerce.js +++ b/test/functions/coerce.js @@ -110,13 +110,58 @@ test('coerce tests', (t) => { ['1.2.3/6', '6.0.0', { rtl: true }], ['1.2.3.4', '2.3.4', { rtl: true }], ['1.2.3.4xyz', '2.3.4', { rtl: true }], + + ['1-rc.5', '1.0.0-rc.5', { full: true }, true], + ['1.2-rc.5', '1.2.0-rc.5', { full: true }, true], + ['1.2.3-rc.5', '1.2.3-rc.5', { full: true }, true], + ['1.2.3-rc.5/a', '1.2.3-rc.5', { full: true }, true], + ['1.2.3.4-rc.5', '1.2.3', { full: true }, true], + ['1.2.3.4+rev.6', '1.2.3', { full: true }, true], + + ['1+rev.6', '1.0.0+rev.6', { full: true }, true], + ['1.2+rev.6', '1.2.0+rev.6', { full: true }, true], + ['1.2.3+rev.6', '1.2.3+rev.6', { full: true }, true], + ['1.2.3+rev.6/a', '1.2.3+rev.6', { full: true }, true], + ['1.2.3.4-rc.5', '1.2.3', { full: true }, true], + ['1.2.3.4+rev.6', '1.2.3', { full: true }, true], + + ['1-rc.5+rev.6', '1.0.0-rc.5+rev.6', { full: true }, true], + ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { full: true }, true], + ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { full: true }, true], + ['1.2.3-rc.5+rev.6/a', '1.2.3-rc.5+rev.6', { full: true }, true], + + ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { rtl: true, full: true }, true], + ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { rtl: true, full: true }, true], + ['1.2.3.4-rc.5+rev.6', '2.3.4-rc.5+rev.6', { rtl: true, full: true }, true], + ['1.2.3.4-rc.5', '2.3.4-rc.5', { rtl: true, full: true }, true], + ['1.2.3.4+rev.6', '2.3.4+rev.6', { rtl: true, full: true }, true], + ['1.2.3.4-rc.5+rev.6/7', '7.0.0', { rtl: true, full: true }, true], + ['1.2.3.4-rc/7.5+rev.6', '7.5.0+rev.6', { rtl: true, full: true }, true], + ['1.2.3.4/7-rc.5+rev.6', '7.0.0-rc.5+rev.6', { rtl: true, full: true }, true], ] - coerceToValid.forEach(([input, expected, options]) => { - const msg = `coerce(${input}) should become ${expected}` - t.same((coerce(input, options) || {}).version, expected, msg) + coerceToValid.forEach(([input, expected, options, shouldParse]) => { + const coerceExpression = `coerce(${input}, ${JSON.stringify(options)})` + const coercedVersion = coerce(input, options) || {} + let expectedText = expected + + if (shouldParse) { + const expectedVersion = parse(expected) + expectedText = expectedVersion.version + t.equal( + expectedVersion.compare(coercedVersion), + 0, + `${coerceExpression} should be equal to ${expectedVersion}` + ) + } + t.same( + coercedVersion.version, + expectedText, + `${coerceExpression} should become ${expectedText}` + ) }) t.same(valid(coerce('42.6.7.9.3-alpha')), '42.6.7') + t.same(valid(coerce('42.6.7-alpha+rev.1', { full: true })), '42.6.7-alpha') t.same(valid(coerce('v2')), '2.0.0') t.end() From 5f425d7e9eecfd7a6549dd1950c9b1d424a82522 Mon Sep 17 00:00:00 2001 From: madtisa <97251780+madtisa@users.noreply.github.com> Date: Thu, 4 Jan 2024 19:34:42 +0300 Subject: [PATCH 02/12] Change option name to includePrerelease --- README.md | 2 +- functions/coerce.js | 10 ++++---- test/functions/coerce.js | 50 ++++++++++++++++++++-------------------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index ba407bb6..a9d3a278 100644 --- a/README.md +++ b/README.md @@ -529,7 +529,7 @@ tuple. For example, `1.2.3.4` will return `2.3.4` in rtl mode, not `4.0.0`. `1.2.3/4` will return `4.0.0`, because the `4` is not a part of any other overlapping SemVer tuple. -If the `options.full` flag is set, then the `coerce` result will contain +If the `options.includePrerelease` flag is set, then the `coerce` result will contain prerelease and build parts of a version. For example, `1.2.3.4-rc.1+rev.2` will preserve prerelease `rc.1` and build `rev.2` in the result. diff --git a/functions/coerce.js b/functions/coerce.js index 3fe3efe2..b7cfe835 100644 --- a/functions/coerce.js +++ b/functions/coerce.js @@ -19,18 +19,18 @@ const coerce = (version, options) => { let match = null if (!options.rtl) { - match = version.match(options.full ? re[t.COERCEFULL] : re[t.COERCE]) + match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE]) } else { // Find the right-most coercible string that does not share // a terminus with a more left-ward coercible string. // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' - // With full option set, '1.2.3.4-pre.1.2' wants to coerce '2.3.4-pre.1.2', not '1.2' + // With includePrerelease option set, '1.2.3.4-pre.1.2' wants to coerce '2.3.4-pre.1.2', not '1.2' // // Walk through the string checking with a /g regexp // Manually set the index so, as to pick up overlapping matches. // Stop when we get a match that ends at the string end, since no // coercible string can be more right-ward without the same terminus. - const coerceRtlRegex = options.full ? re[t.COERCERTLFULL] : re[t.COERCERTL] + const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL] let next while ((next = coerceRtlRegex.exec(version)) && (!match || match.index + match[0].length !== version.length) @@ -52,8 +52,8 @@ const coerce = (version, options) => { const major = match[2] const minor = match[3] || '0' const patch = match[4] || '0' - const prerelease = options.full && match[5] ? `-${match[5]}` : '' - const build = options.full && match[6] ? `+${match[6]}` : '' + const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : '' + const build = options.includePrerelease && match[6] ? `+${match[6]}` : '' return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options) } diff --git a/test/functions/coerce.js b/test/functions/coerce.js index 8f05f8fd..0f622abd 100644 --- a/test/functions/coerce.js +++ b/test/functions/coerce.js @@ -111,33 +111,33 @@ test('coerce tests', (t) => { ['1.2.3.4', '2.3.4', { rtl: true }], ['1.2.3.4xyz', '2.3.4', { rtl: true }], - ['1-rc.5', '1.0.0-rc.5', { full: true }, true], - ['1.2-rc.5', '1.2.0-rc.5', { full: true }, true], - ['1.2.3-rc.5', '1.2.3-rc.5', { full: true }, true], - ['1.2.3-rc.5/a', '1.2.3-rc.5', { full: true }, true], - ['1.2.3.4-rc.5', '1.2.3', { full: true }, true], - ['1.2.3.4+rev.6', '1.2.3', { full: true }, true], + ['1-rc.5', '1.0.0-rc.5', { includePrerelease: true }, true], + ['1.2-rc.5', '1.2.0-rc.5', { includePrerelease: true }, true], + ['1.2.3-rc.5', '1.2.3-rc.5', { includePrerelease: true }, true], + ['1.2.3-rc.5/a', '1.2.3-rc.5', { includePrerelease: true }, true], + ['1.2.3.4-rc.5', '1.2.3', { includePrerelease: true }, true], + ['1.2.3.4+rev.6', '1.2.3', { includePrerelease: true }, true], - ['1+rev.6', '1.0.0+rev.6', { full: true }, true], - ['1.2+rev.6', '1.2.0+rev.6', { full: true }, true], - ['1.2.3+rev.6', '1.2.3+rev.6', { full: true }, true], - ['1.2.3+rev.6/a', '1.2.3+rev.6', { full: true }, true], - ['1.2.3.4-rc.5', '1.2.3', { full: true }, true], - ['1.2.3.4+rev.6', '1.2.3', { full: true }, true], + ['1+rev.6', '1.0.0+rev.6', { includePrerelease: true }, true], + ['1.2+rev.6', '1.2.0+rev.6', { includePrerelease: true }, true], + ['1.2.3+rev.6', '1.2.3+rev.6', { includePrerelease: true }, true], + ['1.2.3+rev.6/a', '1.2.3+rev.6', { includePrerelease: true }, true], + ['1.2.3.4-rc.5', '1.2.3', { includePrerelease: true }, true], + ['1.2.3.4+rev.6', '1.2.3', { includePrerelease: true }, true], - ['1-rc.5+rev.6', '1.0.0-rc.5+rev.6', { full: true }, true], - ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { full: true }, true], - ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { full: true }, true], - ['1.2.3-rc.5+rev.6/a', '1.2.3-rc.5+rev.6', { full: true }, true], + ['1-rc.5+rev.6', '1.0.0-rc.5+rev.6', { includePrerelease: true }, true], + ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { includePrerelease: true }, true], + ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { includePrerelease: true }, true], + ['1.2.3-rc.5+rev.6/a', '1.2.3-rc.5+rev.6', { includePrerelease: true }, true], - ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { rtl: true, full: true }, true], - ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { rtl: true, full: true }, true], - ['1.2.3.4-rc.5+rev.6', '2.3.4-rc.5+rev.6', { rtl: true, full: true }, true], - ['1.2.3.4-rc.5', '2.3.4-rc.5', { rtl: true, full: true }, true], - ['1.2.3.4+rev.6', '2.3.4+rev.6', { rtl: true, full: true }, true], - ['1.2.3.4-rc.5+rev.6/7', '7.0.0', { rtl: true, full: true }, true], - ['1.2.3.4-rc/7.5+rev.6', '7.5.0+rev.6', { rtl: true, full: true }, true], - ['1.2.3.4/7-rc.5+rev.6', '7.0.0-rc.5+rev.6', { rtl: true, full: true }, true], + ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { rtl: true, includePrerelease: true }, true], + ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { rtl: true, includePrerelease: true }, true], + ['1.2.3.4-rc.5+rev.6', '2.3.4-rc.5+rev.6', { rtl: true, includePrerelease: true }, true], + ['1.2.3.4-rc.5', '2.3.4-rc.5', { rtl: true, includePrerelease: true }, true], + ['1.2.3.4+rev.6', '2.3.4+rev.6', { rtl: true, includePrerelease: true }, true], + ['1.2.3.4-rc.5+rev.6/7', '7.0.0', { rtl: true, includePrerelease: true }, true], + ['1.2.3.4-rc/7.5+rev.6', '7.5.0+rev.6', { rtl: true, includePrerelease: true }, true], + ['1.2.3.4/7-rc.5+rev.6', '7.0.0-rc.5+rev.6', { rtl: true, includePrerelease: true }, true], ] coerceToValid.forEach(([input, expected, options, shouldParse]) => { const coerceExpression = `coerce(${input}, ${JSON.stringify(options)})` @@ -161,7 +161,7 @@ test('coerce tests', (t) => { }) t.same(valid(coerce('42.6.7.9.3-alpha')), '42.6.7') - t.same(valid(coerce('42.6.7-alpha+rev.1', { full: true })), '42.6.7-alpha') + t.same(valid(coerce('42.6.7-alpha+rev.1', { includePrerelease: true })), '42.6.7-alpha') t.same(valid(coerce('v2')), '2.0.0') t.end() From 3b5c580ba400931f22a49751f66039dca1b4ff63 Mon Sep 17 00:00:00 2001 From: madtisa <97251780+madtisa@users.noreply.github.com> Date: Thu, 4 Jan 2024 19:41:27 +0300 Subject: [PATCH 03/12] Fix line too long --- functions/coerce.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/coerce.js b/functions/coerce.js index b7cfe835..fb3c8020 100644 --- a/functions/coerce.js +++ b/functions/coerce.js @@ -24,7 +24,7 @@ const coerce = (version, options) => { // Find the right-most coercible string that does not share // a terminus with a more left-ward coercible string. // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' - // With includePrerelease option set, '1.2.3.4-pre.1.2' wants to coerce '2.3.4-pre.1.2', not '1.2' + // With includePrerelease option set, '1.2.3.4-rc.1.2' wants to coerce '2.3.4-rc.1.2', not '1.2' // // Walk through the string checking with a /g regexp // Manually set the index so, as to pick up overlapping matches. From 4a2d45f06b066560cf2e32f20dab84108b55496d Mon Sep 17 00:00:00 2001 From: madtisa <97251780+madtisa@users.noreply.github.com> Date: Thu, 4 Jan 2024 19:42:20 +0300 Subject: [PATCH 04/12] Fix line too long --- functions/coerce.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/coerce.js b/functions/coerce.js index fb3c8020..e65ddcc9 100644 --- a/functions/coerce.js +++ b/functions/coerce.js @@ -24,7 +24,7 @@ const coerce = (version, options) => { // Find the right-most coercible string that does not share // a terminus with a more left-ward coercible string. // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' - // With includePrerelease option set, '1.2.3.4-rc.1.2' wants to coerce '2.3.4-rc.1.2', not '1.2' + // With includePrerelease option set, '1.2.3.4-rc.1' wants to coerce '2.3.4-rc.1', not '1.2' // // Walk through the string checking with a /g regexp // Manually set the index so, as to pick up overlapping matches. From e735962b5db770d695e1985fffbb7566741fa218 Mon Sep 17 00:00:00 2001 From: madtisa <97251780+madtisa@users.noreply.github.com> Date: Thu, 4 Jan 2024 19:45:21 +0300 Subject: [PATCH 05/12] Remove redundant comma --- functions/coerce.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/coerce.js b/functions/coerce.js index e65ddcc9..d20374c4 100644 --- a/functions/coerce.js +++ b/functions/coerce.js @@ -27,7 +27,7 @@ const coerce = (version, options) => { // With includePrerelease option set, '1.2.3.4-rc.1' wants to coerce '2.3.4-rc.1', not '1.2' // // Walk through the string checking with a /g regexp - // Manually set the index so, as to pick up overlapping matches. + // Manually set the index so as to pick up overlapping matches. // Stop when we get a match that ends at the string end, since no // coercible string can be more right-ward without the same terminus. const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL] From b3bba183bdd7aeac278cd9ccd88ea44f5716a9d5 Mon Sep 17 00:00:00 2001 From: madtisa <97251780+madtisa@users.noreply.github.com> Date: Thu, 4 Jan 2024 19:54:40 +0300 Subject: [PATCH 06/12] Extract duplicate coerce regex part to separate token --- internal/re.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/internal/re.js b/internal/re.js index bcdf4ba5..cbcc5798 100644 --- a/internal/re.js +++ b/internal/re.js @@ -154,15 +154,12 @@ createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`) // Coercion. // Extract anything that could conceivably be a part of a valid semver -createToken('COERCE', `${'(^|[^\\d])' + +createToken('COERCEPLAIN', `${'(^|[^\\d])' + '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + - `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + - `(?:$|[^\\d])`) -createToken('COERCEFULL', `${'(^|[^\\d])' + - '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + - `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + - `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`) +createToken('COERCE', `${t.COERCEPLAIN}(?:$|[^\\d])`) +createToken('COERCEFULL', `${COERCEPLAIN}` + `(?:${src[t.PRERELEASE]})?` + `(?:${src[t.BUILD]})?` + `(?:$|[^\\d])`) From 0bcf798532cf57a635332101f9a77854e898b9a5 Mon Sep 17 00:00:00 2001 From: madtisa <97251780+madtisa@users.noreply.github.com> Date: Thu, 4 Jan 2024 20:00:27 +0300 Subject: [PATCH 07/12] Correct comment about includePrerelease usage --- functions/coerce.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/coerce.js b/functions/coerce.js index d20374c4..b378dcea 100644 --- a/functions/coerce.js +++ b/functions/coerce.js @@ -24,7 +24,7 @@ const coerce = (version, options) => { // Find the right-most coercible string that does not share // a terminus with a more left-ward coercible string. // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' - // With includePrerelease option set, '1.2.3.4-rc.1' wants to coerce '2.3.4-rc.1', not '1.2' + // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.4' // // Walk through the string checking with a /g regexp // Manually set the index so as to pick up overlapping matches. From 0fceca5df489d6b646767a0b5b440c7d8d338bfb Mon Sep 17 00:00:00 2001 From: madtisa <97251780+madtisa@users.noreply.github.com> Date: Thu, 4 Jan 2024 20:30:00 +0300 Subject: [PATCH 08/12] Fix comparing versions with builds --- test/functions/coerce.js | 71 +++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/test/functions/coerce.js b/test/functions/coerce.js index 0f622abd..c7b25f00 100644 --- a/test/functions/coerce.js +++ b/test/functions/coerce.js @@ -111,52 +111,47 @@ test('coerce tests', (t) => { ['1.2.3.4', '2.3.4', { rtl: true }], ['1.2.3.4xyz', '2.3.4', { rtl: true }], - ['1-rc.5', '1.0.0-rc.5', { includePrerelease: true }, true], - ['1.2-rc.5', '1.2.0-rc.5', { includePrerelease: true }, true], - ['1.2.3-rc.5', '1.2.3-rc.5', { includePrerelease: true }, true], - ['1.2.3-rc.5/a', '1.2.3-rc.5', { includePrerelease: true }, true], - ['1.2.3.4-rc.5', '1.2.3', { includePrerelease: true }, true], - ['1.2.3.4+rev.6', '1.2.3', { includePrerelease: true }, true], + ['1-rc.5', '1.0.0-rc.5', { includePrerelease: true }], + ['1.2-rc.5', '1.2.0-rc.5', { includePrerelease: true }], + ['1.2.3-rc.5', '1.2.3-rc.5', { includePrerelease: true }], + ['1.2.3-rc.5/a', '1.2.3-rc.5', { includePrerelease: true }], + ['1.2.3.4-rc.5', '1.2.3', { includePrerelease: true }], + ['1.2.3.4+rev.6', '1.2.3', { includePrerelease: true }], - ['1+rev.6', '1.0.0+rev.6', { includePrerelease: true }, true], - ['1.2+rev.6', '1.2.0+rev.6', { includePrerelease: true }, true], - ['1.2.3+rev.6', '1.2.3+rev.6', { includePrerelease: true }, true], - ['1.2.3+rev.6/a', '1.2.3+rev.6', { includePrerelease: true }, true], - ['1.2.3.4-rc.5', '1.2.3', { includePrerelease: true }, true], - ['1.2.3.4+rev.6', '1.2.3', { includePrerelease: true }, 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 }], + ['1.2.3+rev.6/a', '1.2.3+rev.6', { includePrerelease: true }], + ['1.2.3.4-rc.5', '1.2.3', { includePrerelease: true }], + ['1.2.3.4+rev.6', '1.2.3', { includePrerelease: true }], - ['1-rc.5+rev.6', '1.0.0-rc.5+rev.6', { includePrerelease: true }, true], - ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { includePrerelease: true }, true], - ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { includePrerelease: true }, true], - ['1.2.3-rc.5+rev.6/a', '1.2.3-rc.5+rev.6', { includePrerelease: true }, true], + ['1-rc.5+rev.6', '1.0.0-rc.5+rev.6', { includePrerelease: true }], + ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { includePrerelease: true }], + ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { includePrerelease: true }], + ['1.2.3-rc.5+rev.6/a', '1.2.3-rc.5+rev.6', { includePrerelease: true }], - ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { rtl: true, includePrerelease: true }, true], - ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { rtl: true, includePrerelease: true }, true], - ['1.2.3.4-rc.5+rev.6', '2.3.4-rc.5+rev.6', { rtl: true, includePrerelease: true }, true], - ['1.2.3.4-rc.5', '2.3.4-rc.5', { rtl: true, includePrerelease: true }, true], - ['1.2.3.4+rev.6', '2.3.4+rev.6', { rtl: true, includePrerelease: true }, true], - ['1.2.3.4-rc.5+rev.6/7', '7.0.0', { rtl: true, includePrerelease: true }, true], - ['1.2.3.4-rc/7.5+rev.6', '7.5.0+rev.6', { rtl: true, includePrerelease: true }, true], - ['1.2.3.4/7-rc.5+rev.6', '7.0.0-rc.5+rev.6', { rtl: true, includePrerelease: true }, true], + ['1.2-rc.5+rev.6', '1.2.0-rc.5+rev.6', { rtl: true, includePrerelease: true }], + ['1.2.3-rc.5+rev.6', '1.2.3-rc.5+rev.6', { rtl: true, includePrerelease: true }], + ['1.2.3.4-rc.5+rev.6', '2.3.4-rc.5+rev.6', { rtl: true, includePrerelease: true }], + ['1.2.3.4-rc.5', '2.3.4-rc.5', { rtl: true, includePrerelease: true }], + ['1.2.3.4+rev.6', '2.3.4+rev.6', { rtl: true, includePrerelease: true }], + ['1.2.3.4-rc.5+rev.6/7', '7.0.0', { rtl: true, includePrerelease: true }], + ['1.2.3.4-rc/7.5+rev.6', '7.5.0+rev.6', { rtl: true, includePrerelease: true }], + ['1.2.3.4/7-rc.5+rev.6', '7.0.0-rc.5+rev.6', { rtl: true, includePrerelease: true }], ] - coerceToValid.forEach(([input, expected, options, shouldParse]) => { + coerceToValid.forEach(([input, expected, options]) => { const coerceExpression = `coerce(${input}, ${JSON.stringify(options)})` const coercedVersion = coerce(input, options) || {} - let expectedText = expected - - if (shouldParse) { - const expectedVersion = parse(expected) - expectedText = expectedVersion.version - t.equal( - expectedVersion.compare(coercedVersion), - 0, - `${coerceExpression} should be equal to ${expectedVersion}` - ) - } + const expectedVersion = parse(expected) + t.equal( + expectedVersion.compare(coercedVersion) || expectedVersion.compareBuild(coercedVersion), + 0, + `${coerceExpression} should be equal to ${expectedVersion}` + ) t.same( coercedVersion.version, - expectedText, - `${coerceExpression} should become ${expectedText}` + expected, + `${coerceExpression} should become ${expected}` ) }) From 5e340305d0b26b43ee2e28d085f2188242f8c0cc Mon Sep 17 00:00:00 2001 From: madtisa Date: Thu, 4 Jan 2024 23:54:52 +0300 Subject: [PATCH 09/12] Fix coerce token creation --- internal/re.js | 4 ++-- test/functions/coerce.js | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/internal/re.js b/internal/re.js index cbcc5798..fd8920e7 100644 --- a/internal/re.js +++ b/internal/re.js @@ -158,8 +158,8 @@ createToken('COERCEPLAIN', `${'(^|[^\\d])' + '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`) -createToken('COERCE', `${t.COERCEPLAIN}(?:$|[^\\d])`) -createToken('COERCEFULL', `${COERCEPLAIN}` + +createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`) +createToken('COERCEFULL', src[t.COERCEPLAIN] + `(?:${src[t.PRERELEASE]})?` + `(?:${src[t.BUILD]})?` + `(?:$|[^\\d])`) diff --git a/test/functions/coerce.js b/test/functions/coerce.js index c7b25f00..a7d413f5 100644 --- a/test/functions/coerce.js +++ b/test/functions/coerce.js @@ -148,11 +148,6 @@ test('coerce tests', (t) => { 0, `${coerceExpression} should be equal to ${expectedVersion}` ) - t.same( - coercedVersion.version, - expected, - `${coerceExpression} should become ${expected}` - ) }) t.same(valid(coerce('42.6.7.9.3-alpha')), '42.6.7') From e3cecc0a29be84b881bba53d147f6e7a46116c74 Mon Sep 17 00:00:00 2001 From: madtisa Date: Fri, 5 Jan 2024 01:15:56 +0300 Subject: [PATCH 10/12] Increase version comparison readability --- test/functions/coerce.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/functions/coerce.js b/test/functions/coerce.js index a7d413f5..e9a80432 100644 --- a/test/functions/coerce.js +++ b/test/functions/coerce.js @@ -143,9 +143,9 @@ test('coerce tests', (t) => { const coerceExpression = `coerce(${input}, ${JSON.stringify(options)})` const coercedVersion = coerce(input, options) || {} const expectedVersion = parse(expected) - t.equal( - expectedVersion.compare(coercedVersion) || expectedVersion.compareBuild(coercedVersion), - 0, + t.ok( + expectedVersion.compare(coercedVersion) === 0 && + expectedVersion.compareBuild(coercedVersion) === 0, `${coerceExpression} should be equal to ${expectedVersion}` ) }) From 1e5890a3d7d339652092030ba9e8ff368a3b1f03 Mon Sep 17 00:00:00 2001 From: Gar Date: Fri, 5 Jan 2024 07:31:00 -0800 Subject: [PATCH 11/12] fixup: explicit tests instead of boolean logic --- test/functions/coerce.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/functions/coerce.js b/test/functions/coerce.js index e9a80432..8cabd4b6 100644 --- a/test/functions/coerce.js +++ b/test/functions/coerce.js @@ -143,10 +143,10 @@ test('coerce tests', (t) => { const coerceExpression = `coerce(${input}, ${JSON.stringify(options)})` const coercedVersion = coerce(input, options) || {} const expectedVersion = parse(expected) - t.ok( - expectedVersion.compare(coercedVersion) === 0 && - expectedVersion.compareBuild(coercedVersion) === 0, - `${coerceExpression} should be equal to ${expectedVersion}` + t.equal(expectedVersion.compare(coercedVersion), 0, + `${coerceExpression} should be equal to ${expectedVersion}`) + t.equal(expectedVersion.compareBuild(coercedVersion), 0, + `${coerceExpression} build should be equal to ${expectedVersion}`) ) }) From aceaf8b6d45eb723f2839d5ef37b6f174326aa89 Mon Sep 17 00:00:00 2001 From: Gar Date: Fri, 5 Jan 2024 07:39:36 -0800 Subject: [PATCH 12/12] fixup: Update test/functions/coerce.js --- test/functions/coerce.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/functions/coerce.js b/test/functions/coerce.js index 8cabd4b6..24e2ff76 100644 --- a/test/functions/coerce.js +++ b/test/functions/coerce.js @@ -147,7 +147,6 @@ test('coerce tests', (t) => { `${coerceExpression} should be equal to ${expectedVersion}`) t.equal(expectedVersion.compareBuild(coercedVersion), 0, `${coerceExpression} build should be equal to ${expectedVersion}`) - ) }) t.same(valid(coerce('42.6.7.9.3-alpha')), '42.6.7')