@npmcli/arborist
Advanced tools
Comparing version 1.0.1 to 1.0.2
@@ -1026,2 +1026,3 @@ // mixin implementing the buildIdealTree method | ||
strictPeerDeps: this[_strictPeerDeps], | ||
force: this[_force], | ||
} | ||
@@ -1044,3 +1045,3 @@ } | ||
// of functionality that ought to have its own unit tests more conveniently. | ||
[_placeDep] (dep, node, edge, peerEntryEdge = null) { | ||
[_placeDep] (dep, node, edge, peerEntryEdge = null, peerPath = []) { | ||
if (edge.to && | ||
@@ -1062,3 +1063,3 @@ !edge.error && | ||
for (let check = start; check; check = check.resolveParent) { | ||
const cp = this[_canPlaceDep](dep, check, edge, peerEntryEdge) | ||
const cp = this[_canPlaceDep](dep, check, edge, peerEntryEdge, peerPath) | ||
@@ -1101,3 +1102,6 @@ // anything other than a conflict is fine to proceed with | ||
if (canPlace === KEEP) { | ||
dep.parent = null | ||
if (edge.peer && !target.children.get(edge.name).satisfies(edge)) { | ||
// this is an overridden peer dep | ||
this[_warnPeerConflict](edge) | ||
} | ||
return [] | ||
@@ -1109,3 +1113,15 @@ } | ||
const placed = [dep] | ||
const newDep = new dep.constructor({ | ||
name: dep.name, | ||
pkg: dep.package, | ||
resolved: dep.resolved, | ||
integrity: dep.integrity, | ||
legacyPeerDeps: this.legacyPeerDeps, | ||
error: dep.errors[0], | ||
...(dep.target ? { target: dep.target } : {}), | ||
}) | ||
if (this[_loadFailures].has(dep)) | ||
this[_loadFailures].add(newDep) | ||
const placed = [newDep] | ||
const oldChild = target.children.get(edge.name) | ||
@@ -1121,19 +1137,24 @@ if (oldChild) { | ||
for (const [name, edge] of oldChild.edgesOut.entries()) { | ||
if (!dep.edgesOut.has(name) && edge.to) | ||
if (!newDep.edgesOut.has(name) && edge.to) | ||
oldDeps.push(edge.to) | ||
} | ||
dep.replace(oldChild) | ||
this[_pruneForReplacement](dep, oldDeps) | ||
newDep.replace(oldChild) | ||
this[_pruneForReplacement](newDep, oldDeps) | ||
// this may also create some invalid edges, for example if we're | ||
// intentionally causing something to get nested which was previously | ||
// placed in this location. | ||
for (const edge of dep.edgesIn) { | ||
if (edge.invalid) { | ||
this[_depsQueue].push(edge.from) | ||
this[_depsSeen].delete(edge.from) | ||
for (const edgeIn of newDep.edgesIn) { | ||
if (edgeIn.invalid && edgeIn !== edge) { | ||
this[_depsQueue].push(edgeIn.from) | ||
this[_depsSeen].delete(edgeIn.from) | ||
} | ||
} | ||
} else | ||
dep.parent = target | ||
newDep.parent = target | ||
if (edge.peer && !newDep.satisfies(edge)) { | ||
// this is an overridden peer dep | ||
this[_warnPeerConflict](edge) | ||
} | ||
// If the edge is not an error, then we're updating something, and | ||
@@ -1143,3 +1164,3 @@ // MAY end up putting a better/identical node further up the tree in | ||
// now-unnecessary node. | ||
if (edge.valid && edge.to.parent !== target && dep.canReplace(edge.to)) | ||
if (edge.valid && edge.to.parent !== target && newDep.canReplace(edge.to)) | ||
edge.to.parent = null | ||
@@ -1150,3 +1171,3 @@ | ||
// skip over it! | ||
for (const edgeIn of dep.edgesIn) { | ||
for (const edgeIn of newDep.edgesIn) { | ||
if (edgeIn !== edge && !edgeIn.valid && !this[_depsSeen].has(edge.from)) { | ||
@@ -1161,8 +1182,8 @@ this.addTracker('idealTree', edgeIn.from.name, edgeIn.from.location) | ||
if (this.idealTree) { | ||
for (const node of this.idealTree.inventory.query('name', dep.name)) { | ||
if (node !== dep && | ||
for (const node of this.idealTree.inventory.query('name', newDep.name)) { | ||
if (node !== newDep && | ||
node.isDescendantOf(target) && | ||
!node.inShrinkwrap && | ||
!node.inBundle && | ||
node.canReplaceWith(dep)) { | ||
node.canReplaceWith(newDep)) { | ||
// don't prune if the dupe is necessary! | ||
@@ -1180,5 +1201,5 @@ // root (a, d) | ||
node.parent.parent !== target && | ||
node.parent.parent.resolve(dep.name) | ||
node.parent.parent.resolve(newDep.name) | ||
if (!mask || mask === dep || node.canReplaceWith(mask)) | ||
if (!mask || mask === newDep || node.canReplaceWith(mask)) | ||
node.parent = null | ||
@@ -1190,22 +1211,15 @@ } | ||
// also place its unmet or invalid peer deps at this location | ||
// note that dep has now been removed from the virtualRoot set | ||
// note that newDep has now been removed from the virtualRoot set | ||
// by virtue of being placed in the target's node_modules. | ||
const peers = [] | ||
// double loop so that we don't yank things out and then fail to find | ||
// them in the virtualRoot's children. | ||
for (const peerEdge of dep.edgesOut.values()) { | ||
// loop through any peer deps from the thing we just placed, and place | ||
// those ones as well. it's safe to do this with the virtual nodes, | ||
// because we're copying rather than moving them out of the virtual root, | ||
// otherwise they'd be gone and the peer set would change throughout | ||
// this loop. | ||
for (const peerEdge of newDep.edgesOut.values()) { | ||
if (!peerEdge.peer || peerEdge.valid) | ||
continue | ||
const peer = virtualRoot.children.get(peerEdge.name) | ||
// since we re-use virtualRoots, it's possible that the node was | ||
// already placed somewhere in the tree, and thus plucked off the | ||
// virtual root. however, in that case, it should have been no | ||
// longer a missing/invalid peer dep, so something is messed up. | ||
if (peer) | ||
peers.push([peer, peerEdge]) | ||
} | ||
for (const [peer, peerEdge] of peers) { | ||
const peerPlaced = this[_placeDep]( | ||
peer, dep, peerEdge, peerEntryEdge || edge) | ||
peer, newDep, peerEdge, peerEntryEdge || edge) | ||
placed.push(...peerPlaced) | ||
@@ -1259,7 +1273,5 @@ } | ||
// original edge that caused us to load the family of peer dependencies. | ||
[_canPlaceDep] (dep, target, edge, peerEntryEdge = null) { | ||
[_canPlaceDep] (dep, target, edge, peerEntryEdge = null, peerPath = []) { | ||
const entryEdge = peerEntryEdge || edge | ||
const source = this[_peerSetSource].get(dep) | ||
const virtualRoot = dep.parent | ||
const vrEdge = virtualRoot.edgesOut.get(edge.name) | ||
@@ -1281,3 +1293,3 @@ const isSource = target === source | ||
if (tryReplace && dep.canReplace(current)) { | ||
const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge) | ||
const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath) | ||
/* istanbul ignore else - It's extremely rare that a replaceable | ||
@@ -1292,2 +1304,4 @@ * node would be a conflict, if the current one wasn't a conflict, | ||
// ok, can't replace the current with new one, but maybe current is ok? | ||
// no need to check if it's a peer that's valid to be here, because | ||
// peers are always placed along with their entry source | ||
if (edge.satisfiedBy(current)) | ||
@@ -1298,3 +1312,3 @@ return KEEP | ||
if (this[_preferDedupe] && !tryReplace && dep.canReplace(current)) { | ||
const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge) | ||
const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath) | ||
/* istanbul ignore else - It's extremely rare that a replaceable | ||
@@ -1351,3 +1365,3 @@ * node would be a conflict, if the current one wasn't a conflict, | ||
if (canReplace) { | ||
const ret = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge) | ||
const ret = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath) | ||
/* istanbul ignore else - extremely rare that the peer set would | ||
@@ -1371,14 +1385,2 @@ * conflict if we can replace the node in question, but theoretically | ||
if (vrEdge && vrEdge.satisfiedBy(current)) { | ||
/* istanbul ignore else - If the virtual root was satisfied, in | ||
* such a way that it was an override, and it's NOT forced, and is | ||
* ours, or is in strict mode, then it would have crashed during | ||
* the creation of the peerSet. Nevertheless, this is a good check | ||
* to ensure we're not warning when we should be conflicting. */ | ||
if (this[_force] || !isMine && !this[_strictPeerDeps]) { | ||
this[_warnPeerConflict](edge) | ||
return KEEP | ||
} | ||
} | ||
// no justification for overriding, and no agreement possible. | ||
@@ -1406,17 +1408,4 @@ return CONFLICT | ||
// is unbounded in its dependency list. | ||
if (!targetEdge.satisfiedBy(dep)) { | ||
if (isSource) { | ||
// conflicted peer dep. accept what's there, if overriding | ||
/* istanbul ignore else - If it's the source, and the source's edge | ||
* is not valid, then either we crashed when creating the peer set, | ||
* or it's forced, or it's not ours and not strict. Keep this check | ||
* to avoid relying on action at a distance, however. */ | ||
if (this[_force] || !isMine && !this[_strictPeerDeps]) { | ||
this[_warnPeerConflict](edge) | ||
return KEEP | ||
} | ||
} | ||
if (!targetEdge.satisfiedBy(dep)) | ||
return CONFLICT | ||
} | ||
} | ||
@@ -1440,3 +1429,3 @@ | ||
// no objections! ok to place here | ||
return this[_canPlacePeers](dep, target, edge, OK, peerEntryEdge) | ||
return this[_canPlacePeers](dep, target, edge, OK, peerEntryEdge, peerPath) | ||
} | ||
@@ -1448,6 +1437,8 @@ | ||
// the tree. | ||
[_canPlacePeers] (dep, target, edge, ret, peerEntryEdge) { | ||
if (!dep.parent || peerEntryEdge) | ||
[_canPlacePeers] (dep, target, edge, ret, peerEntryEdge, peerPath) { | ||
// do not go in cycles when we're resolving a peer group | ||
if (!dep.parent || peerEntryEdge && peerPath.includes(dep)) | ||
return ret | ||
peerPath = [...peerPath, dep] | ||
for (const peer of dep.parent.children.values()) { | ||
@@ -1457,11 +1448,9 @@ if (peer === dep) | ||
const peerEdge = dep.edgesOut.get(peer.name) || | ||
[...peer.edgesIn].find(e => e.peer) | ||
/* istanbul ignore if - pretty sure this is impossible, but just | ||
being cautious */ | ||
// we only have to pick the first one, because ALL peer edgesIn will | ||
// be checked before we decide to accept an existing dep in the tree | ||
const peerEdge = [...peer.edgesIn].find(e => e.peer && e !== edge) | ||
if (!peerEdge) | ||
continue | ||
const canPlacePeer = this[_canPlaceDep](peer, target, peerEdge, edge) | ||
const canPlacePeer = this[_canPlaceDep](peer, target, peerEdge, edge, peerPath) | ||
if (canPlacePeer !== CONFLICT) | ||
@@ -1588,2 +1577,3 @@ continue | ||
throw node.errors[0] | ||
const set = optionalSet(node) | ||
@@ -1590,0 +1580,0 @@ for (const node of set) |
@@ -403,3 +403,3 @@ // mixin implementing the reify method | ||
// entirely, since we can't possibly reify it. | ||
const res = node.resolved ? this[_registryResolved](node.resolved) | ||
const res = node.resolved ? `${node.name}@${this[_registryResolved](node.resolved)}` | ||
: node.package.name && node.version | ||
@@ -406,0 +406,0 @@ ? `${node.package.name}@${node.version}` |
{ | ||
"name": "@npmcli/arborist", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "Manage node_modules trees", | ||
@@ -5,0 +5,0 @@ "dependencies": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
282878
6831