mirror of https://gitee.com/openkylin/npm.git
2031 lines
63 KiB
JavaScript
2031 lines
63 KiB
JavaScript
const t = require('tap')
|
|
const PlaceDep = require('../lib/place-dep.js')
|
|
const { KEEP } = require('../lib/can-place-dep.js')
|
|
|
|
// for diffing trees when we place something
|
|
const { strict } = require('tcompare')
|
|
|
|
const { normalizePaths } = require('./fixtures/utils.js')
|
|
|
|
const Node = require('../lib/node.js')
|
|
const Link = require('../lib/link.js')
|
|
const OverrideSet = require('../lib/override-set.js')
|
|
|
|
t.test('placement tests', t => {
|
|
const path = '/some/path'
|
|
|
|
// boilerplate so we can define a bunch of test cases declaratively
|
|
const runTest = (desc, options) => {
|
|
const {
|
|
// the tree we're placing a dep within
|
|
tree,
|
|
// the location of the node with the dependency
|
|
nodeLoc,
|
|
// the dep being added
|
|
dep,
|
|
// array of nodes representing the dep's peer group
|
|
peerSet,
|
|
// an extra function for running assertions after placement
|
|
test,
|
|
// do we expect this to fail with ERESOLVE?
|
|
error = false,
|
|
// --prefer-dedupe set?
|
|
preferDedupe = false,
|
|
// --force set?
|
|
force = false,
|
|
// is this the thing the user is explicitly installing?
|
|
explicitRequest,
|
|
// the names passed to `npm update foo bar baz` for example.
|
|
updateNames = [],
|
|
// an audit report, telling us which nodes are vulnerable
|
|
auditReport = null,
|
|
// --legacy-bundling set?
|
|
legacyBundling = false,
|
|
// --strict-peer-deps set?
|
|
strictPeerDeps = false,
|
|
// --legacy-peer-deps set?
|
|
legacyPeerDeps = false,
|
|
// installing with --global or --global-style?
|
|
globalStyle = false,
|
|
} = options
|
|
|
|
const node = tree.inventory.get(nodeLoc)
|
|
const edge = node.edgesOut.get(dep.name)
|
|
if (!dep.satisfies(edge)) {
|
|
edge.peerConflicted = true
|
|
}
|
|
const vr = new Node({
|
|
sourceReference: node,
|
|
path: node.path,
|
|
pkg: { ...node.package },
|
|
children: peerSet,
|
|
})
|
|
dep.parent = vr
|
|
|
|
// mark any invalid edges in the virtual root as peerConflicted
|
|
for (const child of vr.children.values()) {
|
|
for (const edgeIn of child.edgesIn) {
|
|
if (edgeIn.invalid) {
|
|
edgeIn.peerConflicted = true
|
|
}
|
|
}
|
|
}
|
|
|
|
const place = () => {
|
|
return new PlaceDep({
|
|
edge,
|
|
dep,
|
|
preferDedupe,
|
|
force,
|
|
explicitRequest,
|
|
updateNames,
|
|
auditReport,
|
|
legacyBundling,
|
|
strictPeerDeps,
|
|
legacyPeerDeps,
|
|
globalStyle,
|
|
})
|
|
}
|
|
|
|
t.test(desc, t => {
|
|
const before = normalizePaths(tree.toJSON())
|
|
|
|
// the 'error' arg is the ERESOLVE we expect to get
|
|
if (error) {
|
|
const thrown = t.throws(place)
|
|
t.matchSnapshot(normalizePaths(thrown), 'thrown error')
|
|
const after = normalizePaths(tree.toJSON())
|
|
t.strictSame(before, after, 'tree should not change')
|
|
t.end()
|
|
|
|
// any time we have an error, we should NOT get that error
|
|
// when run in force or legacyPeerDeps mode
|
|
runTest(desc + ', force', {
|
|
...options,
|
|
error: false,
|
|
force: true,
|
|
legacyPeerDeps: false,
|
|
})
|
|
if (!edge.peer && !legacyPeerDeps) {
|
|
runTest(desc + ', legacyPeerDeps', {
|
|
...options,
|
|
error: false,
|
|
force: false,
|
|
legacyPeerDeps: true,
|
|
peerSet: [],
|
|
})
|
|
}
|
|
return
|
|
}
|
|
|
|
const warnings = []
|
|
const onwarn = (level, ...msg) => {
|
|
if (level === 'warn') {
|
|
warnings.push(msg)
|
|
}
|
|
}
|
|
|
|
process.on('log', onwarn)
|
|
let pd
|
|
try {
|
|
pd = place()
|
|
} catch (er) {
|
|
console.error(require('util').inspect(er, { depth: Infinity }))
|
|
throw er
|
|
}
|
|
process.removeListener('log', onwarn)
|
|
|
|
if (test) {
|
|
test(t, tree, pd)
|
|
}
|
|
|
|
const after = normalizePaths(tree.toJSON())
|
|
const { diff } = strict(after, before)
|
|
|
|
if (pd.needEvaluation.size) {
|
|
t.matchSnapshot([...pd.needEvaluation]
|
|
.map(n => `${n.location} ${n.version}`))
|
|
}
|
|
t.matchSnapshot(diff, 'changes to tree')
|
|
t.matchSnapshot(normalizePaths(warnings), 'warnings')
|
|
t.matchSnapshot([pd, ...pd.allChildren].map(c => {
|
|
if (c.canPlace && c.canPlace.canPlace === KEEP) {
|
|
t.equal(c.placed, null, 'should not place if result is KEEP')
|
|
}
|
|
return normalizePaths({
|
|
...(c.parent ? { parent: c.parent.name } : {}),
|
|
edge: `{ ${
|
|
c.edge.from.location || 'ROOT'
|
|
} ${c.edge.type} ${c.edge.name}@${c.edge.spec} }`,
|
|
dep: `${c.dep.name}@${c.dep.version}`,
|
|
canPlace: c.canPlace && c.canPlace.canPlace,
|
|
canPlaceSelf: c.canPlaceSelf && c.canPlaceSelf.canPlaceSelf,
|
|
placed: c.placed && c.placed.location,
|
|
checks: new Map([...pd.checks].map(([target, cpd]) =>
|
|
[target.location, [cpd.canPlace, cpd.canPlaceSelf]])),
|
|
})
|
|
}), 'placements')
|
|
|
|
t.end()
|
|
})
|
|
}
|
|
|
|
runTest('basic placement of a production dep', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1' } },
|
|
}),
|
|
dep: new Node({ pkg: { name: 'foo', version: '1.0.0' } }),
|
|
nodeLoc: '',
|
|
})
|
|
|
|
runTest('explicit placement of a production dep', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1' } },
|
|
}),
|
|
dep: new Node({ pkg: { name: 'foo', version: '1.0.0' } }),
|
|
nodeLoc: '',
|
|
explicitRequest: true,
|
|
})
|
|
|
|
runTest('dedupe a transitive dependency', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1', baz: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'foo', version: '1.0.0', dependencies: { bar: '1' } } },
|
|
{ pkg: { name: 'baz', version: '1.0.0', dependencies: { bar: '1' } } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'bar', version: '1.0.0' } }),
|
|
nodeLoc: 'node_modules/foo',
|
|
})
|
|
|
|
runTest('upgrade a transitive dependency', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1', baz: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'foo', version: '1.0.0', dependencies: { bar: '1' } } },
|
|
{ pkg: { name: 'baz', version: '1.0.0', dependencies: { bar: '1' } } },
|
|
{ pkg: { name: 'bar', version: '1.0.0' } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'bar', version: '1.0.1' } }),
|
|
nodeLoc: 'node_modules/foo',
|
|
})
|
|
|
|
runTest('nest a transitive dependency', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1', baz: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'foo', version: '1.0.0', dependencies: { bar: '1' } } },
|
|
{ pkg: { name: 'baz', version: '1.0.0', dependencies: { bar: '1.0.0' } } },
|
|
{ pkg: { name: 'bar', version: '1.0.1' } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'bar', version: '1.0.0' } }),
|
|
nodeLoc: 'node_modules/baz',
|
|
test: (t, tree) => {
|
|
const foobar = tree.children.get('foo').resolve('bar')
|
|
t.equal(foobar.location, 'node_modules/bar')
|
|
t.equal(foobar.version, '1.0.1')
|
|
const bazbar = tree.children.get('baz').resolve('bar')
|
|
t.equal(bazbar.location, 'node_modules/baz/node_modules/bar')
|
|
t.equal(bazbar.version, '1.0.0')
|
|
},
|
|
})
|
|
|
|
runTest('accept an older transitive dependency', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1', baz: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'foo', version: '1.0.0', dependencies: { bar: '1' } } },
|
|
{ pkg: { name: 'baz', version: '1.0.0', dependencies: { bar: '1.0.0' } } },
|
|
{ pkg: { name: 'bar', version: '1.0.0' } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'bar', version: '1.0.1' } }),
|
|
nodeLoc: 'node_modules/foo',
|
|
test: (t, tree) => {
|
|
const foobar = tree.children.get('foo').resolve('bar')
|
|
t.equal(foobar.location, 'node_modules/bar')
|
|
t.equal(foobar.version, '1.0.0')
|
|
const bazbar = tree.children.get('baz').resolve('bar')
|
|
t.equal(bazbar.location, 'node_modules/bar')
|
|
t.equal(bazbar.version, '1.0.0')
|
|
},
|
|
})
|
|
|
|
runTest('nest even though unnecessary, because legacy bundling', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1', baz: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'foo', version: '1.0.0', dependencies: { bar: '1' } } },
|
|
{ pkg: { name: 'baz', version: '1.0.0', dependencies: { bar: '1.0.0' } } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'bar', version: '1.0.0' } }),
|
|
nodeLoc: 'node_modules/foo',
|
|
legacyBundling: true,
|
|
test: (t, tree) => {
|
|
const foobar = tree.children.get('foo').resolve('bar')
|
|
t.equal(foobar.location, 'node_modules/foo/node_modules/bar')
|
|
t.equal(foobar.version, '1.0.0')
|
|
const bazbar = tree.children.get('baz').resolve('bar')
|
|
t.equal(bazbar, null)
|
|
},
|
|
})
|
|
|
|
runTest('nest because globalStyle', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1', baz: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'foo', version: '1.0.0', dependencies: { bar: '1' } } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'bar', version: '1.0.0' } }),
|
|
nodeLoc: 'node_modules/foo',
|
|
globalStyle: true,
|
|
test: (t, tree) => {
|
|
const foobar = tree.children.get('foo').resolve('bar')
|
|
t.equal(foobar.location, 'node_modules/foo/node_modules/bar')
|
|
},
|
|
})
|
|
|
|
runTest('nest only 1 level due to globalStyle', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1', baz: '1' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'foo',
|
|
version: '1.0.0',
|
|
dependencies: { bar: '1' },
|
|
},
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
dependencies: { baz: '' },
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'baz', version: '1.0.0' } }),
|
|
nodeLoc: 'node_modules/foo/node_modules/bar',
|
|
globalStyle: true,
|
|
test: (t, tree) => {
|
|
const foobar = tree.children.get('foo').resolve('bar')
|
|
const foobarbaz = foobar.resolve('baz')
|
|
t.equal(foobar.location, 'node_modules/foo/node_modules/bar')
|
|
t.equal(foobarbaz.location, 'node_modules/foo/node_modules/baz')
|
|
},
|
|
})
|
|
|
|
runTest('prefer to dedupe rather than nest', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1', baz: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'foo', version: '1.0.0', dependencies: { bar: '1' } } },
|
|
{ pkg: { name: 'baz', version: '1.0.0', dependencies: { bar: '1.0.0' } } },
|
|
{ pkg: { name: 'bar', version: '1.0.1' } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'bar', version: '1.0.0' } }),
|
|
nodeLoc: 'node_modules/baz',
|
|
preferDedupe: true,
|
|
test: (t, tree) => {
|
|
const foobar = tree.children.get('foo').resolve('bar')
|
|
t.equal(foobar.location, 'node_modules/bar')
|
|
t.equal(foobar.version, '1.0.0')
|
|
const bazbar = tree.children.get('baz').resolve('bar')
|
|
t.equal(bazbar.location, 'node_modules/bar')
|
|
t.equal(bazbar.version, '1.0.0')
|
|
},
|
|
})
|
|
|
|
runTest('dep with load error', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1' } },
|
|
}),
|
|
dep: new Node({
|
|
error: Object.assign(new Error('oops'), { code: 'testing' }),
|
|
name: 'foo',
|
|
}),
|
|
nodeLoc: '',
|
|
})
|
|
|
|
// root -> (x, y@1)
|
|
// +-- x -> (y@1.1)
|
|
// | +-- y@1.1.0 (replacing with 1.1.2, got KEEP at the root)
|
|
// +-- y@1.1.2 (updated already from 1.0.0)
|
|
runTest('keep, but dedupe', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { x: '', y: '1', z: 'file:z' } },
|
|
children: [
|
|
{ pkg: { name: 'y', version: '1.1.2' } },
|
|
{
|
|
pkg: { name: 'x', version: '1.0.0', dependencies: { y: '1.1' } },
|
|
children: [{ pkg: { name: 'y', version: '1.1.0' } }],
|
|
},
|
|
],
|
|
fsChildren: [
|
|
{
|
|
path: `${path}/z`,
|
|
pkg: { name: 'z', version: '1.2.3', dependencies: { y: '1' } },
|
|
// this will get deduped out
|
|
children: [{ pkg: { name: 'y', version: '1.1.2' } }],
|
|
},
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'y', version: '1.1.2' } }),
|
|
updateNames: ['y'],
|
|
nodeLoc: 'node_modules/x',
|
|
test: (t, tree) => {
|
|
const x = tree.children.get('x')
|
|
const y = x.resolve('y')
|
|
t.equal(y.location, 'node_modules/y')
|
|
t.equal(y.version, '1.1.2')
|
|
const z = tree.inventory.get('z')
|
|
const zy = z.resolve('y')
|
|
t.equal(zy.location, y.location, 'y bundled under z is removed')
|
|
},
|
|
})
|
|
|
|
// y depends on z@1, everything else depends on z@2, so every y has a z dupe
|
|
// root -> (y@1, x, z@2, a, k@file:k)
|
|
// +-- a -> (y@1.0.0, z@2.0.0)
|
|
// | +-- z@2.0.0
|
|
// | +-- y@1.0.0 -> (z@1, file:v) (will not be deduped)
|
|
// | +fs v@1.0.0 -> (z@2)
|
|
// | | +-- z@2.0.0
|
|
// | +-- z@1.0.0
|
|
// +-- z@2.1.0
|
|
// +-- f@1.0.0 (will be pruned upon replacement)
|
|
// +-- y@1.1.0 -> (z@1, f) (replacing with 1.2.2)
|
|
// | +-- z@1.0.0
|
|
// +-- x -> (y@1.2, z@2)
|
|
// +-- y@1.2.0 -> (z@1, w@1) (got REPLACE at the root, will dedupe)
|
|
// +-- z@1.0.0
|
|
// root/k -> (y@1.2)
|
|
// +-- y@1.2.0 -> (z@1) (will dedupe)
|
|
// +-- z@1.0.0 (will be pruned when y sibling removed)
|
|
runTest('replace higher up, and dedupe descendants', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { y: '1', z: '2', a: '', x: '' } },
|
|
children: [
|
|
{
|
|
pkg: { name: 'a', version: '1.0.0', dependencies: { y: '1.0.0', z: '2.0.0' } },
|
|
children: [
|
|
{ pkg: { name: 'z', version: '2.0.0' } },
|
|
{
|
|
pkg: { name: 'y', dependencies: { z: '1' } },
|
|
children: [{ pkg: { name: 'z', version: '1.0.0' } }],
|
|
},
|
|
],
|
|
},
|
|
{ pkg: { name: 'f', version: '1.0.0', dependencies: { g: '' } } },
|
|
{ pkg: { name: 'g', version: '1.0.0' } },
|
|
{
|
|
pkg: { name: 'y', version: '1.1.0', dependencies: { z: '1', f: '' } },
|
|
children: [{ pkg: { name: 'z', version: '1.0.0' } }],
|
|
},
|
|
{ pkg: { name: 'z', version: '2.1.0' } },
|
|
{
|
|
pkg: { name: 'x', version: '1.0.0', dependencies: { y: '1.2', z: '2' } },
|
|
children: [{
|
|
pkg: { name: 'y', version: '1.2.0', dependencies: { z: '1' } },
|
|
children: [{ pkg: { name: 'z', version: '1.0.0' } }],
|
|
}],
|
|
},
|
|
],
|
|
// root/k -> (y@1.2)
|
|
// +-- y@1.2.0 -> (z@1) (will dedupe)
|
|
// +-- z@1.0.0
|
|
fsChildren: [
|
|
{
|
|
pkg: { name: 'k', dependencies: { y: '1.2' } },
|
|
path: `${path}/k`,
|
|
children: [
|
|
{ pkg: { name: 'y', version: '1.2.0', dependencies: { z: '1' } } },
|
|
{ pkg: { name: 'z', version: '1.0.0' } },
|
|
],
|
|
},
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'y', version: '1.2.2', dependencies: { z: '1' } } }),
|
|
auditReport: {
|
|
isVulnerable: node => node.name === 'y' && node.version === '1.2.0',
|
|
},
|
|
nodeLoc: 'node_modules/x',
|
|
test: (t, tree) => {
|
|
const x = tree.children.get('x')
|
|
const y = x.resolve('y')
|
|
t.equal(y.location, 'node_modules/y')
|
|
t.equal(y.version, '1.2.2')
|
|
t.equal(tree.resolve('f'), null)
|
|
t.equal(tree.resolve('g'), null)
|
|
const z = tree.resolve('z')
|
|
t.equal(z.location, 'node_modules/z')
|
|
t.equal(z.version, '2.1.0')
|
|
const k = tree.inventory.get('k')
|
|
t.equal(k.children.size, 0, 'children of fsChild all deduped out')
|
|
},
|
|
})
|
|
|
|
// root -> (a@1, b)
|
|
// +-- a@1.0.0
|
|
// +-- b -> (c@link:c, a@1.1)
|
|
// +-- a@1.1.0
|
|
// root/node_modules/b/c -> (a@1.1.1)
|
|
// +-- a@1.1.1
|
|
//
|
|
// place a@1.1.1 for b, dedupe all other a's
|
|
runTest('replace higher up, and dedupe descendants', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', b: '' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0' } },
|
|
{
|
|
pkg: {
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
c: 'file:c',
|
|
a: '1.1',
|
|
},
|
|
},
|
|
fsChildren: [
|
|
{
|
|
path: `${path}/node_modules/b/c`,
|
|
pkg: {
|
|
name: 'c',
|
|
version: '1.0.0',
|
|
dependencies: { a: '1.1.1' },
|
|
},
|
|
children: [{ pkg: { name: 'a', version: '1.1.1' } }],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'a', version: '1.1.1' } }),
|
|
nodeLoc: 'node_modules/b',
|
|
test: (t, tree) => {
|
|
const a = [...tree.inventory.query('name', 'a')].map(a => a.location)
|
|
t.strictSame(a, ['node_modules/a'], 'should be left with one a')
|
|
},
|
|
})
|
|
|
|
// a -> (b@1, c@1)
|
|
// +-- c@1
|
|
// +-- b -> PEEROPTIONAL(v) (c@2)
|
|
// +-- c@2 -> (v)
|
|
// place v for c@2, should end up at a, skipping over b
|
|
runTest('skip over peer dependents in the ancestry walkup', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '' } },
|
|
children: [
|
|
{
|
|
pkg: { name: 'a', version: '1.0.0', dependencies: { b: '1.0.0', c: '1.0.0' } },
|
|
},
|
|
{ pkg: { name: 'c', version: '1.0.0' } },
|
|
{
|
|
pkg: {
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
dependencies: { c: '2' },
|
|
peerDependencies: { v: '' },
|
|
},
|
|
children: [{
|
|
pkg: { name: 'c', version: '2.0.0', dependencies: { v: '1' } },
|
|
}],
|
|
},
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'v', version: '1.0.0' } }),
|
|
nodeLoc: 'node_modules/b/node_modules/c',
|
|
test: (t, tree) => t.ok(tree.children.get('v')),
|
|
})
|
|
|
|
// root -> (a@1, x)
|
|
// x -> (a@2, b@1)
|
|
// a@1 -> (b@1)
|
|
// a@2 -> (b@2)
|
|
// b@1 -> (c@1)
|
|
// b@2 -> (c@2)
|
|
//
|
|
// root
|
|
// +-- c@1
|
|
// +-- b@1
|
|
// +-- x
|
|
// +-- b@1
|
|
// +-- a
|
|
// +-- b@2
|
|
// place c@2 for b@2, should land in a
|
|
runTest('do not shadow inappropriately', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { x: '', a: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0' } },
|
|
{ pkg: { name: 'c', version: '1.0.0' } },
|
|
{
|
|
pkg: { name: 'x', version: '1.0.0', dependencies: { a: '2', b: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'b', version: '1.0.0', dependencies: { c: '1' } } },
|
|
{
|
|
pkg: { name: 'a', version: '2.0.0', dependencies: { b: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'b', version: '2.0.0', dependencies: { c: '2' } } },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'c', version: '2.0.0' } }),
|
|
nodeLoc: 'node_modules/x/node_modules/a/node_modules/b',
|
|
test: (t, tree) => {
|
|
const c = tree.children.get('c')
|
|
const x = tree.children.get('x')
|
|
const xa = x.resolve('a')
|
|
const xab = xa.resolve('b')
|
|
const xabc = xab.resolve('c')
|
|
t.equal(c.version, '1.0.0')
|
|
t.equal(xabc.parent, xa)
|
|
t.equal(xab.parent, xa)
|
|
t.equal(xa.parent, x)
|
|
},
|
|
})
|
|
|
|
// pathologically nested dep cycle
|
|
// a1 -> b1 -> a2 -> b2 -> a1
|
|
runTest('pathologically nested dependency cycle', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', dependencies: { b: '1' } } },
|
|
{
|
|
pkg: { name: 'b', version: '1.0.0', dependencies: { a: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '2.0.0', dependencies: { b: '2' } } },
|
|
{
|
|
pkg: { name: 'b', version: '2.0.0', dependencies: { a: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', dependencies: { b: '1' } } },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'b', version: '1.0.0', dependencies: { a: '2' } },
|
|
}),
|
|
nodeLoc: 'node_modules/b/node_modules/b/node_modules/a',
|
|
})
|
|
|
|
// peer dep shenanigans
|
|
runTest('basic placement of a production dep with peer deps', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { foo: '1' } },
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'foo', version: '1.0.0', peerDependencies: { bar: '' } },
|
|
}),
|
|
nodeLoc: '',
|
|
peerSet: [
|
|
{ pkg: { name: 'bar', version: '1.0.0', peerDependencies: { baz: '' } } },
|
|
{ pkg: { name: 'baz', version: '1.0.0' } },
|
|
],
|
|
})
|
|
|
|
runTest('bounce off an existing dep that is newer, preferDedupe', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { name: 'project', version: '1.2.3', dependencies: { a: '1', c: '2.0.0' } },
|
|
children: [
|
|
{ pkg: { name: 'b', version: '2.3.4' } },
|
|
{ pkg: { name: 'c', version: '2.0.0', dependencies: { b: '2.0.0' } } },
|
|
{ pkg: { name: 'a', version: '1.2.3', dependencies: { b: '2' } } },
|
|
],
|
|
}),
|
|
nodeLoc: 'node_modules/c',
|
|
dep: new Node({
|
|
pkg: { name: 'b', version: '2.0.0', peerDependencies: { a: '3' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'a', version: '3.0.0' } },
|
|
],
|
|
preferDedupe: true,
|
|
})
|
|
|
|
runTest('peer with peers', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { name: 'project', version: '1.2.3', dependencies: { a: '1.x' } },
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'a', version: '1.2.3', peerDependencies: { b: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '1.2.3', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.2.3' } },
|
|
],
|
|
})
|
|
|
|
runTest('cycle of peers', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { name: 'project', version: '1.2.3', dependencies: { a: '1.x' } },
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'a', version: '1.2.3', peerDependencies: { b: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '1.2.3', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.2.3', peerDependencies: { a: '1' } } },
|
|
],
|
|
})
|
|
|
|
runTest('cycle of peers hanging off entry node', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { name: 'project', version: '1.2.3', dependencies: { a: '1.x' } },
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'a', version: '1.2.3', peerDependencies: { b: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '1.2.3', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.2.3', peerDependencies: { d: '1' } } },
|
|
{ pkg: { name: 'd', version: '1.2.3', peerDependencies: { b: '1' } } },
|
|
],
|
|
})
|
|
|
|
runTest('peers with peerConflicted edges in peerSet', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { name: 'project', version: '1.2.3', dependencies: { a: '1.x' } },
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'a', version: '1.2.3', peerDependencies: { b: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '1.2.3', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.2.3', peerDependencies: { b: '2', a: '2' } } },
|
|
],
|
|
})
|
|
|
|
runTest('peers with peerConflicted edges in peerSet from dependent', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
c: '2.x',
|
|
},
|
|
},
|
|
children: [
|
|
{ pkg: { name: 'c', version: '2.0.1', peerDependencies: { b: '2', a: '2' } } },
|
|
],
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'a', version: '1.2.3', peerDependencies: { b: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '1.2.3', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '2.2.3', peerDependencies: { b: '2', a: '2' } } },
|
|
],
|
|
})
|
|
|
|
runTest('peers with peerConflicted edges in peerSet from dependent', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
c: '2.x',
|
|
},
|
|
},
|
|
children: [
|
|
{ pkg: { name: 'c', version: '2.0.1', peerDependencies: { b: '2', a: '2' } } },
|
|
],
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'a', version: '1.2.3', peerDependencies: { b: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '1.2.3', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '2.2.3', peerDependencies: { b: '2', a: '2' } } },
|
|
],
|
|
})
|
|
|
|
runTest('replacing existing peer set', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
c: '2.x',
|
|
},
|
|
},
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.1', peerDependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.1', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '2.0.1', peerDependencies: { b: '2', a: '2' } } },
|
|
],
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'a', version: '1.2.3', peerDependencies: { b: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '1.2.3', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '2.2.3', peerDependencies: { b: '2', a: '2' } } },
|
|
],
|
|
explicitRequest: true,
|
|
})
|
|
|
|
runTest('existing peer set which can be pushed deeper, no current', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
d: '2.x',
|
|
},
|
|
},
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.1', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.1', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.1' } },
|
|
],
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'd', version: '2.2.2', peerDependencies: { b: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '2.2.2', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.2.2' } },
|
|
],
|
|
explicitRequest: true,
|
|
})
|
|
|
|
runTest('existing peer set which can be pushed deeper, with invalid current', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
d: '2.x',
|
|
},
|
|
},
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.1', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.1', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.1' } },
|
|
{ pkg: { name: 'd', version: '1.1.1', peerDependencies: { b: '1' } } },
|
|
],
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'd', version: '2.2.2', peerDependencies: { b: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '2.2.2', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.2.2' } },
|
|
],
|
|
explicitRequest: true,
|
|
})
|
|
|
|
// root -> (a@1, d@1)
|
|
// a@1.0.1 -> (b@1)
|
|
// b@1.0.1 -> PEER(c@1)
|
|
// d@1.1.1 -> PEER(b@1)
|
|
// d@1.2.2 -> PEER(b@2)
|
|
// b@2.2.2 -> PEER(c@2)
|
|
//
|
|
// root
|
|
// +-- a@1.0.1
|
|
// +-- b@1.0.1 <-- can be pushed under a, along with c & d
|
|
// +-- c@1.0.1
|
|
// +-- d@1.0.1
|
|
// PLACE(d@1.2.2<b@2.2.2, c@2.2.2>)
|
|
runTest('existing peer set which can be pushed deeper, with valid current', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
d: '1.x',
|
|
},
|
|
},
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.1', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.1', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.1' } },
|
|
{ pkg: { name: 'd', version: '1.1.1', peerDependencies: { b: '1' } } },
|
|
],
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'd', version: '1.2.2', peerDependencies: { b: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '2.2.2', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.2.2' } },
|
|
],
|
|
explicitRequest: true,
|
|
})
|
|
|
|
runTest('existing peer set which can be pushed deeper, conflict on peer', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
d: '1.x',
|
|
},
|
|
},
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.1', dependencies: { bb: '1' } } },
|
|
{ pkg: { name: 'bb', version: '1.0.1', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.1' } },
|
|
{ pkg: { name: 'd', version: '1.1.1', peerDependencies: { c: '1' } } },
|
|
],
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'd', version: '1.2.2', peerDependencies: { b: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '2.2.2', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.2.2' } },
|
|
],
|
|
explicitRequest: true,
|
|
})
|
|
|
|
runTest('existing peer set cannot be pushed deeper, but new dep set can', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
d: '2.x',
|
|
},
|
|
},
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.1', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'd', version: '2.2.2', peerDependencies: { b: '2' } } },
|
|
{ pkg: { name: 'b', version: '2.2.2', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.2.2' } },
|
|
],
|
|
}),
|
|
nodeLoc: 'node_modules/a',
|
|
dep: new Node({
|
|
pkg: { name: 'b', version: '1.0.1', peerDependencies: { c: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'c', version: '1.0.1' } },
|
|
],
|
|
explicitRequest: true,
|
|
})
|
|
|
|
runTest('nest peer set under dependent node', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
d: '2.x',
|
|
},
|
|
},
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.1', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'd', version: '2.2.2', peerDependencies: { b: '2' } } },
|
|
{ pkg: { name: 'b', version: '2.2.2', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.2.2' } },
|
|
],
|
|
}),
|
|
nodeLoc: 'node_modules/a',
|
|
dep: new Node({
|
|
pkg: { name: 'b', version: '1.0.1', peerDependencies: { c: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'c', version: '1.0.1' } },
|
|
],
|
|
explicitRequest: true,
|
|
})
|
|
|
|
// root -> (a@1, d@2)
|
|
// a@1 -> PEER(b@1)
|
|
// b@1 -> PEER(c@1)
|
|
// b@2 -> PEER(c@2)
|
|
// d@2 -> PEER(b@2)
|
|
//
|
|
// root
|
|
// +-- a@1
|
|
// +-- b@2 (peer from d@2)
|
|
// +-- c@2 (peer from b@2)
|
|
// +-- d@2
|
|
// place b@1(c@1) for a@1, expect ERESOLVE, because b conflicts, and
|
|
// neither can be pushed deeper.
|
|
runTest('existing peer set cannot be pushed deeper, neither can new set', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
d: '2.x',
|
|
},
|
|
},
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.1', peerDependencies: { b: '1' } } },
|
|
{ pkg: { name: 'd', version: '2.2.2', peerDependencies: { b: '2' } } },
|
|
{ pkg: { name: 'b', version: '2.2.2', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.2.2' } },
|
|
],
|
|
}),
|
|
nodeLoc: 'node_modules/a',
|
|
dep: new Node({
|
|
pkg: { name: 'b', version: '1.0.1', peerDependencies: { c: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'c', version: '1.0.1' } },
|
|
],
|
|
explicitRequest: true,
|
|
error: true,
|
|
})
|
|
|
|
// root -> (a@1, d@1)
|
|
// a@1 -> (bb@1) PEER(c)
|
|
// bb@1 -> PEER(c@1)
|
|
// d@1.1.1 -> PEER(c@1)
|
|
// d@1.2.2 -> PEER(b@2)
|
|
// b@2 -> PEER(c@2)
|
|
//
|
|
// root
|
|
// +-- a@1 -> (bb@1) PEER(c)
|
|
// +-- bb@1 -> PEER(c@1)
|
|
// +-- c@1
|
|
// +-- d@1.1.1 -> PEER(c@1)
|
|
//
|
|
// place d@1.2.2(b@2 c@2) and receive ERESOLVE, because
|
|
// the c@2 peer dep cannot be placed.
|
|
runTest('existing peer set cannot be pushed deeper, neither can new set, conflict on peer xyz', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
d: '1.x',
|
|
},
|
|
},
|
|
children: [
|
|
// the bb dep could be nested, but it has a peerDep on c, and
|
|
// a would be fine with the c@2, but can't nest its c@1 dep
|
|
{ pkg: { name: 'a', version: '1.0.1', dependencies: { bb: '1' }, peerDependencies: { c: '*' } } },
|
|
{ pkg: { name: 'bb', version: '1.0.1', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.1' } },
|
|
{ pkg: { name: 'd', version: '1.1.1', peerDependencies: { c: '1' } } },
|
|
],
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'd', version: '1.2.2', peerDependencies: { b: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '2.2.2', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.2.2' } },
|
|
],
|
|
explicitRequest: true,
|
|
error: true,
|
|
})
|
|
|
|
// root -> (a@1, d@1)
|
|
// a@1.0.1 -> (bb@1), PEER(c)
|
|
// bb@1.0.1 -> (cc@1), PEER(c)
|
|
// cc@1.0.1 -> PEER(dd@1)
|
|
// dd@1.0.1 -> PEER(c@1)
|
|
// d@1.0.1 -> PEER(c)
|
|
// d@1.2.2 -> PEER(b@2)
|
|
// b@2.2.2 -> PEER(c@2)
|
|
//
|
|
// root
|
|
// +-- a@1.0.1
|
|
// +-- bb@1.0.1
|
|
// +-- cc@1.0.1
|
|
// +-- dd@1.0.1
|
|
// +-- c@1.0.1
|
|
// +-- d@1.1.1
|
|
//
|
|
// PLACE d@1.2.2 in root. peerSet(b@2, c@2)
|
|
// REPLACE d@1.0.1
|
|
// OK b@2 (no current, no conflicting edges)
|
|
// c@1.0.1 -> c@2.2.2?
|
|
// entry edges:
|
|
// root->(a): no replacement
|
|
// a->(c): replacement satisfies
|
|
// a->(bb): not a peer edge
|
|
// >> can replace
|
|
// a->(bb):
|
|
// bb->(c): replacement satisfies
|
|
// bb->(cc): not a peer edge
|
|
// root->(d): is cpd peerEntryEdge, skip
|
|
// bb->(cc): no replacement
|
|
// dd->(cc): not a peer edge
|
|
// >> can replace
|
|
|
|
runTest('existing peer set cannot be pushed deeper, neither can new set, conflict on deep peer', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
d: '1.x',
|
|
},
|
|
},
|
|
children: [
|
|
// the bb dep could be nested, but it has a peerDep on c, and
|
|
// a would be fine with the c@2, but can't nest its c@1 dep
|
|
{ pkg: { name: 'a', version: '1.0.1', dependencies: { bb: '1' }, peerDependencies: { c: '*' } } },
|
|
{ pkg: { name: 'bb', version: '1.0.1', dependencies: { cc: '1' }, peerDependencies: { c: '*' } } },
|
|
{ pkg: { name: 'cc', version: '1.0.1', peerDependencies: { dd: '1' } } },
|
|
{ pkg: { name: 'dd', version: '1.0.1', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.1' } },
|
|
{ pkg: { name: 'd', version: '1.1.1', peerDependencies: { c: '1' } } },
|
|
],
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'd', version: '1.2.2', peerDependencies: { b: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '2.2.2', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.2.2' } },
|
|
],
|
|
explicitRequest: true,
|
|
error: true,
|
|
})
|
|
|
|
runTest('existing peer set cannot be pushed deeper, neither can new set, replacement satisfies', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
name: 'project',
|
|
version: '1.2.3',
|
|
dependencies: {
|
|
a: '1.x',
|
|
d: '1.x',
|
|
},
|
|
},
|
|
children: [
|
|
// the bb dep could be nested, but it has a peerDep on c, and
|
|
// a would be fine with the c@2, but can't nest its c@1 dep
|
|
{ pkg: { name: 'a', version: '1.0.1', dependencies: { bb: '1' }, peerDependencies: { c: '*' } } },
|
|
{ pkg: { name: 'bb', version: '1.0.1', dependencies: { cc: '1' }, peerDependencies: { c: '*' } } },
|
|
{ pkg: { name: 'cc', version: '1.0.1', dependencies: { dd: '1' }, peerDependencies: { c: '*' } } },
|
|
{ pkg: { name: 'dd', version: '1.0.1', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.1' } },
|
|
{ pkg: { name: 'd', version: '1.1.1', peerDependencies: { c: '1' } } },
|
|
],
|
|
}),
|
|
nodeLoc: '',
|
|
dep: new Node({
|
|
pkg: { name: 'd', version: '1.2.2', peerDependencies: { b: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '2.2.2', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.2.2' } },
|
|
],
|
|
explicitRequest: true,
|
|
})
|
|
|
|
// root -> (a)
|
|
// a -> (b, c) PEER(p)
|
|
// b -> (c@1, d@2) PEER(p)
|
|
// c@1 -> (d@1) PEER(p)
|
|
// c@2 -> (d@2) PEER(p)
|
|
// d@1 -> PEER(p@1)
|
|
// d@2 -> PEER(p@2)
|
|
// root
|
|
// +-- a
|
|
// +-- b
|
|
// | +-- c@1
|
|
// | +-- d@1 <-- cannot place p@1 peer dep!
|
|
// +-- p@2
|
|
// +-- c@2
|
|
// +-- d@2
|
|
runTest('peer all the way down, conflict but not ours', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: { b: '', c: '' },
|
|
peerDependencies: { p: '' },
|
|
},
|
|
},
|
|
{
|
|
pkg: {
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
dependencies: { c: '1', d: '2' },
|
|
peerDependencies: { p: '' },
|
|
},
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'c',
|
|
version: '1.0.0',
|
|
dependencies: { d: '1' }, // <-- the dep we'll try to place
|
|
peerDependencies: { p: '' },
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{ pkg: { name: 'p', version: '2.0.0' } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { p: '' } } },
|
|
{ pkg: { name: 'd', version: '2.0.0', peerDependencies: { p: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'd', version: '1.0.0', peerDependencies: { p: '1' } },
|
|
}),
|
|
peerSet: [{ pkg: { name: 'p', version: '1.0.0' } }],
|
|
nodeLoc: 'node_modules/b/node_modules/c',
|
|
})
|
|
|
|
// root -> (a@1, b@2)
|
|
// a@1 -> PEER(b@1)
|
|
// b@1 -> PEER(c@1)
|
|
// c@1 -> PEER(d@1)
|
|
// d@1 -> PEER(e@1)
|
|
// e@1 -> PEER(a@1)
|
|
// a@2 -> PEER(b@2)
|
|
// b@2 -> PEER(c@2)
|
|
// c@2 -> PEER(d@2)
|
|
// d@2 -> PEER(e@2)
|
|
// e@2 -> PEER(a@2)
|
|
// root
|
|
// +-- a@1
|
|
// +-- b@1
|
|
// +-- c@1
|
|
// +-- d@1
|
|
// +-- e@1
|
|
// place b@2, peerSet (c@2, d@2, e@2, a@2)
|
|
runTest('prod dep directly on conflicted peer, newer', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', b: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.0', peerDependencies: { d: '1' } } },
|
|
{ pkg: { name: 'd', version: '1.0.0', peerDependencies: { e: '1' } } },
|
|
{ pkg: { name: 'e', version: '1.0.0', peerDependencies: { a: '1' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'b', version: '2.0.0', peerDependencies: { c: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'a', version: '2.0.0', peerDependencies: { b: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { d: '2' } } },
|
|
{ pkg: { name: 'd', version: '2.0.0', peerDependencies: { e: '2' } } },
|
|
{ pkg: { name: 'e', version: '2.0.0', peerDependencies: { a: '2' } } },
|
|
],
|
|
nodeLoc: '',
|
|
error: true,
|
|
})
|
|
|
|
runTest('prod dep directly on conflicted peer, force, end of first step', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', b: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '2.0.0', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { d: '2' } } },
|
|
{ pkg: { name: 'd', version: '2.0.0', peerDependencies: { e: '2' } } },
|
|
{ pkg: { name: 'e', version: '2.0.0', peerDependencies: { a: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'a', version: '2.0.0', peerDependencies: { b: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'a', version: '2.0.0', peerDependencies: { b: '2' } } },
|
|
{ pkg: { name: 'b', version: '2.0.0', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { d: '2' } } },
|
|
{ pkg: { name: 'd', version: '2.0.0', peerDependencies: { e: '2' } } },
|
|
{ pkg: { name: 'e', version: '2.0.0', peerDependencies: { a: '2' } } },
|
|
],
|
|
nodeLoc: 'node_modules/e',
|
|
force: true,
|
|
})
|
|
|
|
// same as above test, but this time, the root has a@2, and
|
|
// we are attempting to add b@1
|
|
runTest('prod dep directly on conflicted peer, older', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '2', b: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '2.0.0', peerDependencies: { b: '2' } } },
|
|
{ pkg: { name: 'b', version: '2.0.0', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { d: '2' } } },
|
|
{ pkg: { name: 'd', version: '2.0.0', peerDependencies: { e: '2' } } },
|
|
{ pkg: { name: 'e', version: '2.0.0', peerDependencies: { a: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'b', version: '1.0.0', peerDependencies: { c: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { b: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.0', peerDependencies: { d: '1' } } },
|
|
{ pkg: { name: 'd', version: '1.0.0', peerDependencies: { e: '1' } } },
|
|
{ pkg: { name: 'e', version: '1.0.0', peerDependencies: { a: '1' } } },
|
|
],
|
|
nodeLoc: '',
|
|
error: true,
|
|
})
|
|
|
|
runTest('prod dep directly on conflicted peer, older, force', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '2', b: '1' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '2.0.0', peerDependencies: { b: '2' } } },
|
|
{ pkg: { name: 'b', version: '2.0.0', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { d: '2' } } },
|
|
{ pkg: { name: 'd', version: '2.0.0', peerDependencies: { e: '2' } } },
|
|
{ pkg: { name: 'e', version: '2.0.0', peerDependencies: { a: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'b', version: '1.0.0', peerDependencies: { c: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { b: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.0', peerDependencies: { d: '1' } } },
|
|
{ pkg: { name: 'd', version: '1.0.0', peerDependencies: { e: '1' } } },
|
|
{ pkg: { name: 'e', version: '1.0.0', peerDependencies: { a: '1' } } },
|
|
],
|
|
nodeLoc: '',
|
|
force: true,
|
|
})
|
|
|
|
// root -> (c@1||2, a@2)
|
|
// a@1 -> PEER(b@1)
|
|
// a@2 -> PEER(b@2)
|
|
// b@1 -> PEER(c@1)
|
|
// b@2 -> PEER(c@2)
|
|
// c@1 -> PEER(d@1)
|
|
// c@2 -> PEER(d@2)
|
|
//
|
|
// root
|
|
// +-- a@1
|
|
// +-- b@1
|
|
// +-- c@1
|
|
// +-- d@1
|
|
//
|
|
// place a@2 peerSet(b@2, c@2, d@2)
|
|
//
|
|
// peer group (c@1, d@1) can be replaced, because the entry node c has a
|
|
// valid replacement.
|
|
|
|
runTest('have replacement for conflicted entry node', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '2', c: '1||2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.0', peerDependencies: { d: '1' } } },
|
|
{ pkg: { name: 'd', version: '1.0.0' } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'a', version: '2.0.0', peerDependencies: { b: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'b', version: '2.0.0', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { d: '2' } } },
|
|
{ pkg: { name: 'd', version: '2.0.0' } },
|
|
],
|
|
nodeLoc: '',
|
|
})
|
|
|
|
// v@4 -> PEER(a@1||2)
|
|
// y@1 -> PEER(d@1)
|
|
// a@1 -> PEER(b@1)
|
|
// b@1 -> PEER(c@1)
|
|
// c@1 -> PEER(d@1)
|
|
// d@1 -> PEER(e@1)
|
|
// e@1 -> PEER(a@1)
|
|
// a@2 -> PEER(b@2)
|
|
// b@2 -> PEER(c@2)
|
|
// c@2 -> PEER(d@2)
|
|
// d@2 -> PEER(e@2)
|
|
// e@2 -> PEER(a@2)
|
|
//
|
|
// root
|
|
// +-- v@4
|
|
// +-- a@2
|
|
// +-- b@2
|
|
// +-- c@2
|
|
// +-- d@2
|
|
// +-- e@2
|
|
//
|
|
// place y@1 (a@1, b@1, c@1, d@1, e@1), OK, because all peers replaced
|
|
runTest('replacing overlapping peer sets', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { v: '4', y: '1' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'v',
|
|
version: '4.0.0',
|
|
peerDependencies: { a: '1||2', x: '2' },
|
|
peerDependenciesMeta: { x: { optional: true } },
|
|
},
|
|
},
|
|
{ pkg: { name: 'a', version: '2.0.0', peerDependencies: { b: '2' } } },
|
|
{ pkg: { name: 'b', version: '2.0.0', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { d: '2' } } },
|
|
{ pkg: { name: 'd', version: '2.0.0', peerDependencies: { e: '2' } } },
|
|
{ pkg: { name: 'e', version: '2.0.0', peerDependencies: { a: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'y', version: '1.0.0', peerDependencies: { d: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.0', peerDependencies: { d: '1' } } },
|
|
{ pkg: { name: 'd', version: '1.0.0', peerDependencies: { e: '1' } } },
|
|
{ pkg: { name: 'e', version: '1.0.0', peerDependencies: { a: '1' } } },
|
|
],
|
|
nodeLoc: '',
|
|
})
|
|
|
|
// same as above, but the new peer set only overlaps _part_ of the existing
|
|
// v@4 -> PEER(a@1||2)
|
|
// y@1 -> PEER(d@1)
|
|
// a@1 -> PEER(c@1)
|
|
// c@1 -> PEER(e@1)
|
|
// e@1 -> PEER(a@1)
|
|
// a@2 -> PEER(b@2)
|
|
// b@2 -> PEER(c@2)
|
|
// c@2 -> PEER(d@2)
|
|
// d@2 -> PEER(e@2)
|
|
// e@2 -> PEER(a@2)
|
|
//
|
|
// root
|
|
// +-- v@4
|
|
// +-- a@2
|
|
// +-- b@2
|
|
// +-- c@2
|
|
// +-- d@2
|
|
// +-- e@2
|
|
//
|
|
// place y@1 (a@1, c@1, e@1), OK, because all peers replaced
|
|
runTest('replacing partially overlapping peer sets, subset', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { v: '4', y: '1' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'v',
|
|
version: '4.0.0',
|
|
peerDependencies: { a: '1||2', x: '2' },
|
|
peerDependenciesMeta: { x: { optional: true } },
|
|
},
|
|
},
|
|
{ pkg: { name: 'a', version: '2.0.0', peerDependencies: { b: '2' } } },
|
|
{ pkg: { name: 'b', version: '2.0.0', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { d: '2' } } },
|
|
{ pkg: { name: 'd', version: '2.0.0', peerDependencies: { e: '2' } } },
|
|
{ pkg: { name: 'e', version: '2.0.0', peerDependencies: { a: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'y', version: '1.0.0', peerDependencies: { d: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.0', peerDependencies: { e: '1' } } },
|
|
{ pkg: { name: 'e', version: '1.0.0', peerDependencies: { a: '1' } } },
|
|
],
|
|
nodeLoc: '',
|
|
})
|
|
|
|
// same as above, but now the existing one has 3, replacment has 5
|
|
// v@4 -> PEER(a@1||2)
|
|
// y@1 -> PEER(d@1)
|
|
// a@1 -> PEER(b@1)
|
|
// b@1 -> PEER(c@1)
|
|
// c@1 -> PEER(d@1)
|
|
// d@1 -> PEER(e@1)
|
|
// e@1 -> PEER(a@1)
|
|
// a@2 -> PEER(c@2)
|
|
// c@2 -> PEER(e@2)
|
|
// e@2 -> PEER(a@2)
|
|
//
|
|
// root
|
|
// +-- v@4
|
|
// +-- a@2
|
|
// +-- c@2
|
|
// +-- e@2
|
|
//
|
|
// place y@1 (a@1, b@1, c@1, d@1, e@1), OK, because all peers replaced
|
|
runTest('replacing partially overlapping peer sets, superset', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { v: '4', y: '1' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'v',
|
|
version: '4.0.0',
|
|
peerDependencies: { a: '1||2', x: '2' },
|
|
peerDependenciesMeta: { x: { optional: true } },
|
|
},
|
|
},
|
|
{ pkg: { name: 'a', version: '2.0.0', peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { e: '2' } } },
|
|
{ pkg: { name: 'e', version: '2.0.0', peerDependencies: { a: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'y', version: '1.0.0', peerDependencies: { d: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', peerDependencies: { c: '1' } } },
|
|
{ pkg: { name: 'c', version: '1.0.0', peerDependencies: { d: '1' } } },
|
|
{ pkg: { name: 'd', version: '1.0.0', peerDependencies: { e: '1' } } },
|
|
{ pkg: { name: 'e', version: '1.0.0', peerDependencies: { a: '1' } } },
|
|
],
|
|
nodeLoc: '',
|
|
})
|
|
|
|
// partly overlapping peer sets that diverge
|
|
// v -> PEER(a@1||2, x@1)
|
|
// a@1 -> PEER(c@1, d@1)
|
|
// a@2 -> PEER(c@2, e@1)
|
|
// x@1 -> PEER(y@1)
|
|
// y@1 -> PEER(a@1||2)
|
|
// w -> PEER(a@1, j@1)
|
|
// j@1 -> PEER(y@1)
|
|
// root
|
|
// +-- v
|
|
// +-- a@2
|
|
// +-- c@2
|
|
// +-- e@1
|
|
// +-- x@1
|
|
// +-- y@1
|
|
// place w(a@1, j@1, y@1, c@1, d@1), OK
|
|
runTest('replacing partially overlapping divergent peer sets', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { v: '', w: '' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'v',
|
|
version: '1.0.0',
|
|
peerDependencies: { a: '1||2', x: '1' },
|
|
},
|
|
},
|
|
{ pkg: { name: 'a', version: '2.0.0', peerDependencies: { c: '2', e: '1' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0' } },
|
|
{ pkg: { name: 'e', version: '1.0.0' } },
|
|
{ pkg: { name: 'x', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0', peerDependencies: { a: '1||2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'w', version: '1.0.0', peerDependencies: { a: '1', j: '1' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { c: '1', d: '1' } } },
|
|
{ pkg: { name: 'j', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0', peerDependencies: { a: '1||2' } } },
|
|
{ pkg: { name: 'c', version: '1.0.0' } },
|
|
{ pkg: { name: 'd', version: '1.0.0' } },
|
|
],
|
|
nodeLoc: '',
|
|
})
|
|
|
|
// root -> (a@1, b@2)
|
|
// a@1 -> PEER(x@1)
|
|
// x@1 -> PEER(y@1)
|
|
// b@2 -> PEER(k@2)
|
|
// k@2 -> PEER(y@2)
|
|
// root
|
|
// +-- a@1
|
|
// +-- x@1
|
|
// +-- y@1
|
|
// place b@2(k@2, y@2) and get a conflict on the y peerdep
|
|
runTest('fail with ERESOLVE on deep peer dep', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', b: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { x: '1' } } },
|
|
{ pkg: { name: 'x', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'b', version: '2.0.0', peerDependencies: { k: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'k', version: '2.0.0', peerDependencies: { y: '2' } } },
|
|
{ pkg: { name: 'y', version: '2.0.0' } },
|
|
],
|
|
nodeLoc: '',
|
|
error: true,
|
|
})
|
|
|
|
// same as above, but not ours, so we override it
|
|
// root -> (v)
|
|
// v -> (a@1, b@2)
|
|
// a@1 -> PEER(x@1)
|
|
// x@1 -> PEER(y@1)
|
|
// b@2 -> PEER(k@2)
|
|
// k@2 -> PEER(y@2)
|
|
// root
|
|
// +-- v
|
|
// +-- a@1
|
|
// +-- x@1
|
|
// +-- y@1
|
|
// place b@2(k@2, y@2) and override a conflict on the y peerdep
|
|
runTest('warn ERESOLVE on deep peer dep', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { v: '' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'v',
|
|
version: '1.0.0',
|
|
dependencies: { a: '1', b: '2' },
|
|
// this keeps either the a or b set from nesting the conflicted y
|
|
peerDependencies: { y: '' },
|
|
},
|
|
},
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { x: '1' } } },
|
|
{ pkg: { name: 'x', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'b', version: '2.0.0', peerDependencies: { k: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'k', version: '2.0.0', peerDependencies: { y: '2' } } },
|
|
{ pkg: { name: 'y', version: '2.0.0' } },
|
|
],
|
|
nodeLoc: 'node_modules/v',
|
|
})
|
|
runTest('warn ERESOLVE on deep peer dep, step 2', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { v: '' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'v',
|
|
version: '1.0.0',
|
|
dependencies: { a: '1', b: '2' },
|
|
peerDependencies: { y: '' },
|
|
},
|
|
},
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { x: '1' } } },
|
|
{ pkg: { name: 'x', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
{ pkg: { name: 'b', version: '2.0.0', peerDependencies: { k: '2' } } },
|
|
{ pkg: { name: 'k', version: '2.0.0', peerDependencies: { y: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'y', version: '2.0.0' } }),
|
|
nodeLoc: 'node_modules/k',
|
|
})
|
|
runTest('warn ERESOLVE on deep peer dep, step 2, but with override', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { v: '' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'v',
|
|
version: '1.0.0',
|
|
dependencies: { a: '1', b: '2' },
|
|
peerDependencies: { y: '' },
|
|
},
|
|
},
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { x: '1' } } },
|
|
{ pkg: { name: 'x', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
{ pkg: { name: 'b', version: '2.0.0', peerDependencies: { k: '2' } } },
|
|
{ pkg: { name: 'k', version: '2.0.0', peerDependencies: { y: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'y', version: '1.0.0' } }),
|
|
nodeLoc: 'node_modules/k',
|
|
})
|
|
runTest('warn ERESOLVE on deep peer dep, step 2, override, no current', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { v: '' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'v',
|
|
version: '1.0.0',
|
|
dependencies: { a: '1', b: '2' },
|
|
peerDependencies: { y: '' },
|
|
},
|
|
},
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { x: '1' } } },
|
|
{ pkg: { name: 'x', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
// prod dep on k to exercise some isMine checking code paths
|
|
{ pkg: { name: 'b', version: '2.0.0', dependencies: { k: '2' }, peerDependencies: { c: '2' } } },
|
|
{ pkg: { name: 'c', version: '2.0.0', peerDependencies: { k: '2' } } },
|
|
{ pkg: { name: 'k', version: '2.0.0', peerDependencies: { y: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'y', version: '1.0.0' } }),
|
|
nodeLoc: 'node_modules/k',
|
|
})
|
|
runTest('warn ERESOLVE on less deep peer dep, step 2, override, no current', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { v: '' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'v',
|
|
version: '1.0.0',
|
|
dependencies: { a: '1', b: '2' },
|
|
peerDependencies: { y: '' },
|
|
},
|
|
},
|
|
{ pkg: { name: 'a', version: '1.0.0', peerDependencies: { x: '1' } } },
|
|
{ pkg: { name: 'x', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
// prod dep, and no peer dep, on k to exercise some isMine checks
|
|
{ pkg: { name: 'b', version: '2.0.0', dependencies: { k: '2' }, peerDependencies: { y: '' } } },
|
|
{ pkg: { name: 'k', version: '2.0.0', peerDependencies: { y: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'y', version: '1.0.0' } }),
|
|
nodeLoc: 'node_modules/k',
|
|
})
|
|
|
|
runTest('clobber and nest a peer set in favor of a root dep', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', x: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'x', version: '2.0.0', peerDependencies: { y: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'y', version: '2.0.0' } },
|
|
],
|
|
explicitRequest: true,
|
|
nodeLoc: '',
|
|
})
|
|
runTest('clobber and nest a peer set in favor of a root dep, step 2', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', x: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
{ pkg: { name: 'x', version: '2.0.0', peerDependencies: { y: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'y', version: '2.0.0' },
|
|
}),
|
|
nodeLoc: 'node_modules/x',
|
|
})
|
|
|
|
runTest('clobber and nest a non-peer dep in favor of a root dep peer', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', x: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', dependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'x', version: '2.0.0', peerDependencies: { y: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'y', version: '2.0.0' } },
|
|
],
|
|
explicitRequest: true,
|
|
nodeLoc: '',
|
|
})
|
|
runTest('clobber and nest a non-peer dep in favor of a root dep peer, step 2', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', x: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', dependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
{ pkg: { name: 'x', version: '2.0.0', peerDependencies: { y: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'y', version: '2.0.0' },
|
|
}),
|
|
nodeLoc: 'node_modules/x',
|
|
})
|
|
|
|
runTest('nest peer set of non-root dep', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', k: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
{ pkg: { name: 'k', version: '2.0.0', dependencies: { x: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'x', version: '2.0.0', peerDependencies: { y: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'y', version: '2.0.0' } },
|
|
],
|
|
nodeLoc: 'node_modules/k',
|
|
test: (t, tree) => {
|
|
const k = tree.children.get('k')
|
|
const x = k.resolve('x')
|
|
const y = x.resolve('y')
|
|
t.equal(y.location, 'node_modules/k/node_modules/y')
|
|
t.equal(x.location, 'node_modules/k/node_modules/x')
|
|
},
|
|
})
|
|
runTest('nest peer set of non-root dep, step 2', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', k: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', dependencies: { b: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
{
|
|
pkg: { name: 'k', version: '2.0.0', dependencies: { x: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'x', version: '2.0.0', peerDependencies: { y: '2' } } },
|
|
],
|
|
},
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'y', version: '2.0.0' } }),
|
|
nodeLoc: 'node_modules/k/node_modules/x',
|
|
test: (t, tree) => {
|
|
const k = tree.children.get('k')
|
|
const x = k.resolve('x')
|
|
const y = x.resolve('y')
|
|
t.equal(y.location, 'node_modules/k/node_modules/y')
|
|
t.equal(x.location, 'node_modules/k/node_modules/x')
|
|
},
|
|
})
|
|
runTest('replace peer set of non-root dep already in root, step 2', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '1', k: '2' } },
|
|
children: [
|
|
{ pkg: { name: 'a', version: '1.0.0', dependencies: { b: '1', y: '1' } } },
|
|
{ pkg: { name: 'b', version: '1.0.0', peerDependencies: { y: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0' } },
|
|
{ pkg: { name: 'k', version: '2.0.0', dependencies: { l: '2' } } },
|
|
{ pkg: { name: 'l', version: '2.0.0', dependencies: { x: '2', y: '2' } } },
|
|
{ pkg: { name: 'x', version: '2.0.0', peerDependencies: { y: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'y', version: '2.0.0' } }),
|
|
nodeLoc: 'node_modules/x',
|
|
test: (t, tree) => {
|
|
const k = tree.children.get('k')
|
|
const x = k.resolve('x')
|
|
const y = x.resolve('y')
|
|
t.equal(y.location, 'node_modules/y')
|
|
t.equal(x.location, 'node_modules/x')
|
|
t.equal(y.version, '2.0.0')
|
|
},
|
|
})
|
|
|
|
runTest('place a link dep', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { x: 'file:x' } },
|
|
fsChildren: [
|
|
{ path: `${path}/x`, pkg: { name: 'x', version: '1.2.3' } },
|
|
],
|
|
}),
|
|
dep: new Link({
|
|
realpath: `${path}/x`,
|
|
pkg: { name: 'x', version: '1.2.3' },
|
|
}),
|
|
nodeLoc: '',
|
|
})
|
|
|
|
const overrides = new OverrideSet({
|
|
overrides: { bar: '2' },
|
|
})
|
|
runTest('place a dep with an override', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: {
|
|
dependencies: { foo: '1' },
|
|
overrides: { bar: '2' },
|
|
},
|
|
overrides,
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'foo', version: '1.0.0' },
|
|
overrides,
|
|
}),
|
|
nodeLoc: '',
|
|
})
|
|
|
|
// https://github.com/npm/arborist/issues/325
|
|
runTest('prune competing peerSet that can be nested, 1', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
j: '1',
|
|
x: '',
|
|
y: '',
|
|
},
|
|
},
|
|
},
|
|
{ pkg: { name: 'j', version: '1.0.0' } },
|
|
{ pkg: { name: 'x', version: '1.0.0', peerDependencies: { j: '1' } } },
|
|
],
|
|
}),
|
|
dep: new Node({
|
|
pkg: { name: 'y', version: '1.0.0', peerDependencies: { j: '2' } },
|
|
}),
|
|
peerSet: [
|
|
{ pkg: { name: 'j', version: '2.0.0' } },
|
|
],
|
|
nodeLoc: 'node_modules/a',
|
|
})
|
|
|
|
runTest('prune competing peerSet that can be nested, 2', {
|
|
tree: new Node({
|
|
path,
|
|
pkg: { dependencies: { a: '' } },
|
|
children: [
|
|
{
|
|
pkg: {
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
j: '1',
|
|
x: '',
|
|
y: '',
|
|
},
|
|
},
|
|
},
|
|
{ pkg: { name: 'j', version: '1.0.0' } },
|
|
{ pkg: { name: 'x', version: '1.0.0', peerDependencies: { j: '1' } } },
|
|
{ pkg: { name: 'y', version: '1.0.0', peerDependencies: { j: '2' } } },
|
|
],
|
|
}),
|
|
dep: new Node({ pkg: { name: 'j', version: '2.0.0' } }),
|
|
nodeLoc: 'node_modules/y',
|
|
test: (t, tree, pd) => {
|
|
t.equal(tree.children.get('x'), undefined)
|
|
t.equal(tree.children.get('j').version, '2.0.0')
|
|
t.equal([...pd.needEvaluation][0], tree.children.get('a'))
|
|
},
|
|
})
|
|
|
|
t.end()
|
|
})
|