From c23869e602da98371245dc69601e4108364539c6 Mon Sep 17 00:00:00 2001 From: nlf Date: Tue, 13 Dec 2022 11:09:45 -0800 Subject: [PATCH] fix: properly handle directory, file, git and alias specs in overrides --- workspaces/arborist/lib/override-set.js | 29 +++++- workspaces/arborist/test/override-set.js | 108 +++++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/workspaces/arborist/lib/override-set.js b/workspaces/arborist/lib/override-set.js index 742e3f08ec534..bfc5a5d7906ee 100644 --- a/workspaces/arborist/lib/override-set.js +++ b/workspaces/arborist/lib/override-set.js @@ -50,9 +50,36 @@ class OverrideSet { continue } - if (semver.intersects(edge.spec, rule.keySpec)) { + // if keySpec is * we found our override + if (rule.keySpec === '*') { return rule } + + let spec = npa(`${edge.name}@${edge.spec}`) + if (spec.type === 'alias') { + spec = spec.subSpec + } + + if (spec.type === 'git') { + if (spec.gitRange && semver.intersects(spec.gitRange, rule.keySpec)) { + return rule + } + + continue + } + + if (spec.type === 'range' || spec.type === 'version') { + if (semver.intersects(spec.fetchSpec, rule.keySpec)) { + return rule + } + + continue + } + + // if we got this far, the spec type is one of tag, directory or file + // which means we have no real way to make version comparisons, so we + // just accept the override + return rule } return this diff --git a/workspaces/arborist/test/override-set.js b/workspaces/arborist/test/override-set.js index b5695d36b0553..705996b443b22 100644 --- a/workspaces/arborist/test/override-set.js +++ b/workspaces/arborist/test/override-set.js @@ -163,4 +163,112 @@ t.test('constructor', async (t) => { const barEdgeRule = overrides.getEdgeRule({ name: 'bar', spec: '^1' }) t.equal(barEdgeRule.value, '*', 'when rule is omitted entirely value is *') }) + + t.test('version specs work', async (t) => { + const overrides = new OverrideSet({ + overrides: { + foo: { + bar: '$bar', + }, + 'baz@^1.0.0': { + 'buzz@^1.0.0': '$buzz', + }, + }, + }) + + const fooEdgeRule = overrides.getEdgeRule({ name: 'foo', spec: '^1.0.0' }) + const barEdgeRule = fooEdgeRule.getEdgeRule({ name: 'bar', spec: '1.0.0' }) + t.equal(barEdgeRule.value, '$bar', 'got a rule back') + + const bazEdgeRule = overrides.getEdgeRule({ name: 'baz', spec: '^1.0.0' }) + const buzzEdgeRule = bazEdgeRule.getEdgeRule({ name: 'buzz', spec: '1.0.0' }) + t.equal(buzzEdgeRule.value, '$buzz', 'got a rule back') + }) + + t.test('directory specs work', async (t) => { + const overrides = new OverrideSet({ + overrides: { + foo: { + bar: '$bar', + }, + 'baz@^1.0.0': { + 'buzz@^1.0.0': '$buzz', + }, + }, + }) + + const fooEdgeRule = overrides.getEdgeRule({ name: 'foo', spec: '^1.0.0' }) + const barEdgeRule = fooEdgeRule.getEdgeRule({ name: 'bar', spec: 'file:../bar' }) + t.equal(barEdgeRule.value, '$bar', 'got a rule back') + + const bazEdgeRule = overrides.getEdgeRule({ name: 'baz', spec: '^1.0.0' }) + const buzzEdgeRule = bazEdgeRule.getEdgeRule({ name: 'buzz', spec: 'file:../buzz' }) + t.equal(buzzEdgeRule.value, '$buzz', 'got a rule back') + }) + + t.test('file specs work', async (t) => { + const overrides = new OverrideSet({ + overrides: { + foo: { + bar: '$bar', + }, + 'baz@^1.0.0': { + 'buzz@^1.0.0': '$buzz', + }, + }, + }) + + const fooEdgeRule = overrides.getEdgeRule({ name: 'foo', spec: '^1.0.0' }) + const barEdgeRule = fooEdgeRule.getEdgeRule({ name: 'bar', spec: 'file:../bar.tgz' }) + t.equal(barEdgeRule.value, '$bar', 'got a rule back') + + const bazEdgeRule = overrides.getEdgeRule({ name: 'baz', spec: '^1.0.0' }) + const buzzEdgeRule = bazEdgeRule.getEdgeRule({ name: 'buzz', spec: 'file:../buzz.tgz' }) + t.equal(buzzEdgeRule.value, '$buzz', 'got a rule back') + }) + + t.test('alias specs work', async (t) => { + const overrides = new OverrideSet({ + overrides: { + foo: { + bar: '$bar', + }, + 'baz@^1.0.0': { + 'buzz@^1.0.0': '$buzz', + }, + }, + }) + + const fooEdgeRule = overrides.getEdgeRule({ name: 'foo', spec: '^1.0.0' }) + const barEdgeRule = fooEdgeRule.getEdgeRule({ name: 'bar', spec: 'npm:bar2@^1.0.0' }) + t.equal(barEdgeRule.value, '$bar', 'got a rule back') + + const bazEdgeRule = overrides.getEdgeRule({ name: 'baz', spec: '^1.0.0' }) + const buzzEdgeRule = bazEdgeRule.getEdgeRule({ name: 'buzz', spec: 'npm:buzz2@^1.0.0' }) + t.equal(buzzEdgeRule.value, '$buzz', 'got a rule back') + }) + + t.test('git specs work', async (t) => { + const overrides = new OverrideSet({ + overrides: { + foo: { + bar: '$bar', + }, + 'baz@^1.0.0': { + 'buzz@^1.0.0': '$buzz', + }, + }, + }) + + const fooEdgeRule = overrides.getEdgeRule({ name: 'foo', spec: '^1.0.0' }) + const barEdgeRule = fooEdgeRule.getEdgeRule({ name: 'bar', spec: 'github:foo/bar' }) + t.equal(barEdgeRule.value, '$bar', 'got a rule back') + + const bazEdgeRule = overrides.getEdgeRule({ name: 'baz', spec: '^1.0.0' }) + const buzzEdgeRule = bazEdgeRule.getEdgeRule({ name: 'buzz', spec: 'github:baz/buzz#semver:^1.0.0' }) + t.equal(buzzEdgeRule.value, '$buzz', 'got a rule back') + + const outOfRangeRule = bazEdgeRule.getEdgeRule({ name: 'buzz', spec: 'github:baz/buzz#semver:^2.0.0' }) + t.equal(outOfRangeRule.name, 'baz', 'no match - returned parent') + }) })