Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: properly handle directory, file, git and alias specs in overrides #5960

Merged
merged 1 commit into from
Dec 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion workspaces/arborist/lib/override-set.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
108 changes: 108 additions & 0 deletions workspaces/arborist/test/override-set.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
})
})