diff --git a/lib/nce.ts b/lib/nce.ts index 83cbadcf..7360f273 100644 --- a/lib/nce.ts +++ b/lib/nce.ts @@ -234,7 +234,7 @@ export const restrictiveRange = ( r1: semver.Range, r2: semver.Range, ignoredRanges: string[], - debug: Debugger, + debug: (str: string) => void, ): semver.Range => { debug(`${chalk.white('Compare:')} ${chalk.blue(r1.raw)} ${chalk.white('and')} ${chalk.blue(r2.raw)}`); @@ -248,10 +248,37 @@ export const restrictiveRange = ( return r2; } - const minVersion1 = semver.minVersion(r1, rangeOptions) || new semver.SemVer('*'); - const minVersion2 = semver.minVersion(r2, rangeOptions) || new semver.SemVer('*'); - const sortedR1: semver.Comparator[][] = sortRangeSet(r1.set); - const sortedR2: semver.Comparator[][] = sortRangeSet(r2.set); + if (!r1.intersects(r2, rangeOptions)) { + debug( + `${chalk.red('No intersection')} ${chalk.white('between')} ${chalk.blue(r1.raw)} ${chalk.white( + 'and', + )} ${chalk.blue(r2.raw)}, ${chalk.white('returning')} ${chalk.green(r1.raw)}`, + ); + return r1; + } else if (!r2.intersects(r1, rangeOptions)) { + debug( + `${chalk.red('No intersection')} ${chalk.white('between')} ${chalk.blue(r2.raw)} ${chalk.white( + 'and', + )} ${chalk.blue(r1.raw)}, ${chalk.white('returning')} ${chalk.green(r2.raw)}`, + ); + return r2; + } + + let minVersion1 = semver.minVersion(r1, rangeOptions) || new semver.SemVer('*'); + let minVersion2 = semver.minVersion(r2, rangeOptions) || new semver.SemVer('*'); + let sortedR1: semver.Comparator[][] = sortRangeSet(r1.set); + let sortedR2: semver.Comparator[][] = sortRangeSet(r2.set); + + while (minVersion1.major !== minVersion2.major) { + if (minVersion1.major > minVersion2.major) { + sortedR2 = sortedR2.slice(1); + } else { + sortedR1 = sortedR1.slice(1); + } + + minVersion1 = semver.minVersion(setToRange(sortedR1), rangeOptions) || new semver.SemVer('*'); + minVersion2 = semver.minVersion(setToRange(sortedR2), rangeOptions) || new semver.SemVer('*'); + } if (!semver.eq(minVersion1, minVersion2, rangeOptions)) { const minSemver = semver.compare(minVersion1, minVersion2) === -1 ? minVersion2 : minVersion1; diff --git a/tests/check-engines-from-cli.spec.ts b/tests/check-engines-from-cli.spec.ts index e8dcade0..f73f5aa0 100644 --- a/tests/check-engines-from-cli.spec.ts +++ b/tests/check-engines-from-cli.spec.ts @@ -1,4 +1,3 @@ -import chalk from 'chalk'; import { execaCommand, Options } from 'execa'; import { resolve } from 'node:path'; import { describe, expect, it } from 'vitest'; @@ -33,7 +32,7 @@ describe('check engines from cli', () => { '[TITLE] npm * → >=6.0.0 \n' + '[TITLE] yarn * → ^1.22.4 \n' + '[TITLE] \n' + - `[TITLE] Run ${chalk.cyan('nce -u')} to upgrade package.json.\n` + + `[TITLE] Run nce -u to upgrade package.json.\n` + '[SUCCESS] Output computed engines range constraints...\n' + '[STARTED] Updating package.json...\n' + '[SKIPPED] Update is disabled by default.\n' + @@ -45,7 +44,7 @@ describe('check engines from cli', () => { '[SUCCESS] npm * → >=6.0.0 \n' + '[SUCCESS] yarn * → ^1.22.4 \n' + '[SUCCESS] \n' + - `[SUCCESS] Run ${chalk.cyan('nce -u')} to upgrade package.json.`, + `[SUCCESS] Run nce -u to upgrade package.json.`, ); }, 10000); @@ -78,7 +77,7 @@ describe('check engines from cli', () => { '[TITLE] npm * → >=6.0.0 \n' + '[TITLE] yarn * → ^1.22.4 \n' + '[TITLE] \n' + - `[TITLE] Run ${chalk.cyan('nce -u')} to upgrade package.json.\n` + + `[TITLE] Run nce -u to upgrade package.json.\n` + '[SUCCESS] Output computed engines range constraints...\n' + '[STARTED] Updating package.json...\n' + '[SKIPPED] Update is disabled by default.\n' + @@ -90,7 +89,7 @@ describe('check engines from cli', () => { '[SUCCESS] npm * → >=6.0.0 \n' + '[SUCCESS] yarn * → ^1.22.4 \n' + '[SUCCESS] \n' + - `[SUCCESS] Run ${chalk.cyan('nce -u')} to upgrade package.json.`, + `[SUCCESS] Run nce -u to upgrade package.json.`, ); }, 10000); @@ -123,7 +122,7 @@ describe('check engines from cli', () => { '[TITLE] npm * → >=6.0.0 \n' + '[TITLE] yarn * → ^1.22.4 \n' + '[TITLE] \n' + - `[TITLE] Run ${chalk.cyan('nce -u')} to upgrade package.json.\n` + + `[TITLE] Run nce -u to upgrade package.json.\n` + '[SUCCESS] Output computed engines range constraints...\n' + '[STARTED] Updating package.json...\n' + '[SKIPPED] Update is disabled by default.\n' + @@ -135,7 +134,7 @@ describe('check engines from cli', () => { '[SUCCESS] npm * → >=6.0.0 \n' + '[SUCCESS] yarn * → ^1.22.4 \n' + '[SUCCESS] \n' + - `[SUCCESS] Run ${chalk.cyan('nce -u')} to upgrade package.json.`, + `[SUCCESS] Run nce -u to upgrade package.json.`, ); }, 10000); }); diff --git a/tests/restrictive-range.spec.ts b/tests/restrictive-range.spec.ts new file mode 100644 index 00000000..7a56f7e7 --- /dev/null +++ b/tests/restrictive-range.spec.ts @@ -0,0 +1,30 @@ +import * as semver from 'semver'; +import { describe, expect, it } from 'vitest'; + +import { restrictiveRange } from '../lib/nce.js'; + +describe('restrictive range', () => { + it('should set minimum version', async () => { + const a = new semver.Range('^16.14.0 || >=18.0.0'); + const b = new semver.Range('^16.13.0 || ^18.10.0'); + const expected = new semver.Range('^16.14.0 || ^18.10.0'); + const result = restrictiveRange(a, b, [], (_: string) => {}); + expect(result.range).toEqual(expected.range); + }); + + it('should a if no intersection', async () => { + const a = new semver.Range('^1.0.0'); + const b = new semver.Range('>=2.0.0'); + const expected = new semver.Range('^1.0.0'); + const result = restrictiveRange(a, b, [], (_: string) => {}); + expect(result.range).toEqual(expected.range); + }); + + it('should drop major and apply min version', async () => { + const a = new semver.Range('^14.18.0 || ^16.14.0 || >=18.0.0'); + const b = new semver.Range('^16.13.0 || ^18.10.0'); + const expected = new semver.Range('^16.14.0 || ^18.10.0'); + const result = restrictiveRange(a, b, [], (_: string) => {}); + expect(result.range).toEqual(expected.range); + }); +});