@npmcli/arborist 9.4.1 → 9.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -950,7 +950,7 @@ This is a one-time fix-up, please be patient...
|
|
|
950
950
|
tree: pd,
|
|
951
951
|
getChildren: pd => pd.children,
|
|
952
952
|
visit: pd => {
|
|
953
|
-
const { placed, edge, canPlace: cpd } = pd
|
|
953
|
+
const { placed, edge, canPlace: cpd, parent } = pd
|
|
954
954
|
// if we didn't place anything, nothing to do here
|
|
955
955
|
if (!placed) {
|
|
956
956
|
return
|
|
@@ -1011,8 +1011,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1011
1011
|
return
|
|
1012
1012
|
}
|
|
1013
1013
|
|
|
1014
|
-
// lastly, also check for the missing deps of the node we placed,
|
|
1015
|
-
// and any holes created by pruning out conflicted peer sets.
|
|
1014
|
+
// lastly, also check for the missing deps of the node we placed, and any holes created by pruning out conflicted peer sets.
|
|
1016
1015
|
this.#depsQueue.push(placed)
|
|
1017
1016
|
for (const dep of pd.needEvaluation) {
|
|
1018
1017
|
this.#depsSeen.delete(dep)
|
|
@@ -1020,16 +1019,14 @@ This is a one-time fix-up, please be patient...
|
|
|
1020
1019
|
}
|
|
1021
1020
|
|
|
1022
1021
|
// pre-fetch any problem edges, since we'll need these soon
|
|
1023
|
-
// if it fails at this point, though, don't worry because it
|
|
1024
|
-
//
|
|
1025
|
-
// fail later anyway.
|
|
1022
|
+
// if it fails at this point, though, don't worry because it may well be an optional dep that has gone missing
|
|
1023
|
+
// it'll fail later anyway
|
|
1026
1024
|
for (const e of this.#problemEdges(placed)) {
|
|
1027
|
-
// XXX This is somehow load bearing. This makes tests that print
|
|
1028
|
-
//
|
|
1029
|
-
// can't be changed or removed till we figure out why
|
|
1025
|
+
// XXX This is somehow load bearing. This makes tests that print the ideal tree of a tree with tarball dependencies fail
|
|
1026
|
+
// This can't be changed or removed till we figure out why
|
|
1030
1027
|
// The test is named "tarball deps with transitive tarball deps"
|
|
1031
1028
|
promises.push(() =>
|
|
1032
|
-
this.#fetchManifest(npa.resolve(e.name, e.spec, fromPath(placed, e)))
|
|
1029
|
+
this.#fetchManifest(npa.resolve(e.name, e.spec, fromPath(placed, e)), parent)
|
|
1033
1030
|
.catch(() => null)
|
|
1034
1031
|
)
|
|
1035
1032
|
}
|
|
@@ -1047,26 +1044,18 @@ This is a one-time fix-up, please be patient...
|
|
|
1047
1044
|
return this.#buildDepStep()
|
|
1048
1045
|
}
|
|
1049
1046
|
|
|
1050
|
-
// loads a node from an edge, and then loads its peer deps (and their
|
|
1051
|
-
// peer deps, on down the line) into a virtual root parent.
|
|
1047
|
+
// loads a node from an edge, and then loads its peer deps (and their peer deps, on down the line) into a virtual root parent.
|
|
1052
1048
|
async #nodeFromEdge (edge, parent_, secondEdge, required) {
|
|
1053
|
-
// create a virtual root node with the same deps as the node that
|
|
1054
|
-
//
|
|
1055
|
-
// a context where they're likely to be resolvable.
|
|
1056
|
-
// Note that the virtual root will also have virtual copies of the
|
|
1057
|
-
// targets of any child Links, so that they resolve appropriately.
|
|
1049
|
+
// create a virtual root node with the same deps as the node that is requesting this one, so that we can get all the peer deps in a context where they're likely to be resolvable.
|
|
1050
|
+
// Note that the virtual root will also have virtual copies of the targets of any child Links, so that they resolve appropriately.
|
|
1058
1051
|
const parent = parent_ || this.#virtualRoot(edge.from)
|
|
1059
1052
|
|
|
1060
1053
|
const spec = npa.resolve(edge.name, edge.spec, edge.from.path)
|
|
1061
1054
|
const first = await this.#nodeFromSpec(edge.name, spec, parent, edge)
|
|
1062
1055
|
|
|
1063
|
-
// we might have a case where the parent has a peer dependency on
|
|
1064
|
-
//
|
|
1065
|
-
//
|
|
1066
|
-
// we're unnecessarily triggering an ERESOLVE.
|
|
1067
|
-
// If we have a second edge to worry about, and it's not satisfied
|
|
1068
|
-
// by the first node, try a second and see if that satisfies the
|
|
1069
|
-
// original edge here.
|
|
1056
|
+
// we might have a case where the parent has a peer dependency on `foo@*` which resolves to v2, but another dep in the set has a peerDependency on `foo@1`.
|
|
1057
|
+
// In that case, if we force it to be v2, we're unnecessarily triggering an ERESOLVE.
|
|
1058
|
+
// If we have a second edge to worry about, and it's not satisfied by the first node, try a second and see if that satisfies the original edge here.
|
|
1070
1059
|
const spec2 = secondEdge && npa.resolve(
|
|
1071
1060
|
edge.name,
|
|
1072
1061
|
secondEdge.spec,
|
|
@@ -1210,11 +1199,12 @@ This is a one-time fix-up, please be patient...
|
|
|
1210
1199
|
return problems
|
|
1211
1200
|
}
|
|
1212
1201
|
|
|
1213
|
-
async #fetchManifest (spec) {
|
|
1202
|
+
async #fetchManifest (spec, parent) {
|
|
1214
1203
|
const options = {
|
|
1215
1204
|
...this.options,
|
|
1216
1205
|
avoid: this.#avoidRange(spec.name),
|
|
1217
1206
|
fullMetadata: true,
|
|
1207
|
+
_isRoot: parent?.isProjectRoot || parent?.isWorkspace,
|
|
1218
1208
|
}
|
|
1219
1209
|
// get the intended spec and stored metadata from yarn.lock file,
|
|
1220
1210
|
// if available and valid.
|
|
@@ -1231,10 +1221,8 @@ This is a one-time fix-up, please be patient...
|
|
|
1231
1221
|
}
|
|
1232
1222
|
|
|
1233
1223
|
async #nodeFromSpec (name, spec, parent, edge) {
|
|
1234
|
-
// pacote will slap integrity on its options, so we have to clone
|
|
1235
|
-
// the
|
|
1236
|
-
// Don't bother to load the manifest for link deps, because the target
|
|
1237
|
-
// might be within another package that doesn't exist yet.
|
|
1224
|
+
// pacote will slap integrity on its options, so we have to clone the object so it doesn't get mutated.
|
|
1225
|
+
// Don't bother to load the manifest for link deps, because the target might be within another package that doesn't exist yet.
|
|
1238
1226
|
const { installLinks, legacyPeerDeps } = this
|
|
1239
1227
|
const isWorkspace = this.idealTree.workspaces && this.idealTree.workspaces.has(spec.name)
|
|
1240
1228
|
|
|
@@ -1287,7 +1275,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1287
1275
|
|
|
1288
1276
|
// spec isn't a directory, and either isn't a workspace or the workspace we have
|
|
1289
1277
|
// doesn't satisfy the edge. try to fetch a manifest and build a node from that.
|
|
1290
|
-
return this.#fetchManifest(spec)
|
|
1278
|
+
return this.#fetchManifest(spec, parent)
|
|
1291
1279
|
.then(pkg => new Node({ name, pkg, parent, installLinks, legacyPeerDeps }), error => {
|
|
1292
1280
|
error.requiredBy = edge.from.location || '.'
|
|
1293
1281
|
|
|
@@ -113,7 +113,11 @@ module.exports = cls => class IsolatedReifier extends cls {
|
|
|
113
113
|
})
|
|
114
114
|
// local `file:` deps are in fsChildren but are not workspaces.
|
|
115
115
|
// they are already handled as workspace-like proxies above and should not go through the external/store extraction path.
|
|
116
|
-
|
|
116
|
+
// Links with file: resolved paths (from `npm link`) should also be treated as local dependencies and symlinked directly instead of being extracted into the store.
|
|
117
|
+
const isLocalFileDep = next.isLink && next.resolved?.startsWith('file:')
|
|
118
|
+
if (isLocalFileDep && !idealTree.fsChildren.has(next) && !idealTree.fsChildren.has(next.target)) {
|
|
119
|
+
this.idealGraph.workspaces.push(await this.#workspaceProxy(next.target))
|
|
120
|
+
} else if (!next.isProjectRoot && !next.isWorkspace && !next.inert && !idealTree.fsChildren.has(next) && !idealTree.fsChildren.has(next.target)) {
|
|
117
121
|
this.idealGraph.external.push(await this.#externalProxy(next))
|
|
118
122
|
}
|
|
119
123
|
}
|
|
@@ -157,6 +161,7 @@ module.exports = cls => class IsolatedReifier extends cls {
|
|
|
157
161
|
...this.options,
|
|
158
162
|
resolved: node.resolved,
|
|
159
163
|
integrity: node.integrity,
|
|
164
|
+
// TODO _isRoot
|
|
160
165
|
})
|
|
161
166
|
const Arborist = this.constructor
|
|
162
167
|
const arb = new Arborist({ ...this.options, path: dir })
|
package/lib/arborist/reify.js
CHANGED
|
@@ -117,9 +117,11 @@ module.exports = cls => class Reifier extends cls {
|
|
|
117
117
|
// of Node/Link trees
|
|
118
118
|
log.warn('reify', 'The "linked" install strategy is EXPERIMENTAL and may contain bugs.')
|
|
119
119
|
this.idealTree = await this.createIsolatedTree()
|
|
120
|
-
this
|
|
121
|
-
this
|
|
122
|
-
|
|
120
|
+
if (this.actualTree) {
|
|
121
|
+
this.#linkedActualForDiff = this.#buildLinkedActualForDiff(
|
|
122
|
+
this.idealTree, this.actualTree
|
|
123
|
+
)
|
|
124
|
+
}
|
|
123
125
|
}
|
|
124
126
|
await this[_diffTrees]()
|
|
125
127
|
await this.#reifyPackages()
|
|
@@ -735,6 +737,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
735
737
|
...this.options,
|
|
736
738
|
resolved: node.resolved,
|
|
737
739
|
integrity: node.integrity,
|
|
740
|
+
_isRoot: node.parent?.isProjectRoot || node.parent?.isWorkspace,
|
|
738
741
|
})
|
|
739
742
|
// store nodes don't use Node class so node.package doesn't get updated
|
|
740
743
|
if (node.isInStore) {
|
|
@@ -815,6 +818,10 @@ module.exports = cls => class Reifier extends cls {
|
|
|
815
818
|
if (combined.has(child.path) || !existsSync(child.path)) {
|
|
816
819
|
continue
|
|
817
820
|
}
|
|
821
|
+
// Skip store links whose ideal realpath doesn't exist on disk yet — the store hash changed and the symlink needs recreating via ADD.
|
|
822
|
+
if (child.isLink && child.resolved?.startsWith('file:.store/') && !existsSync(child.realpath)) {
|
|
823
|
+
continue
|
|
824
|
+
}
|
|
818
825
|
let entry
|
|
819
826
|
if (child.isLink) {
|
|
820
827
|
entry = new IsolatedLink(child)
|
package/lib/optional-set.js
CHANGED
|
@@ -26,7 +26,7 @@ const optionalSet = node => {
|
|
|
26
26
|
|
|
27
27
|
// now that we've hit the boundary, gather the rest of the nodes in
|
|
28
28
|
// the optional section that don't have dependents outside the set.
|
|
29
|
-
return gatherDepSet(set, edge => !set.has(edge.to))
|
|
29
|
+
return gatherDepSet(set, edge => !set.has(edge.to) && !edge.from?.inert)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
module.exports = optionalSet
|
package/lib/override-set.js
CHANGED
|
@@ -195,8 +195,29 @@ class OverrideSet {
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
// The override sets are incomparable.
|
|
199
|
-
|
|
198
|
+
// The override sets are incomparable (e.g. siblings like the "react" and "react-dom" children of the root override set). Check if they have semantically conflicting rules before treating this as an error.
|
|
199
|
+
if (this.haveConflictingRules(first, second)) {
|
|
200
|
+
log.silly('Conflicting override sets', first, second)
|
|
201
|
+
return undefined
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// The override sets are structurally incomparable but have compatible rules. Fall back to their nearest common ancestor so the node still has a valid override set.
|
|
205
|
+
return this.findCommonAncestor(first, second)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
static findCommonAncestor (first, second) {
|
|
209
|
+
const firstAncestors = []
|
|
210
|
+
for (const ancestor of first.ancestry()) {
|
|
211
|
+
firstAncestors.push(ancestor)
|
|
212
|
+
}
|
|
213
|
+
for (const secondAnc of second.ancestry()) {
|
|
214
|
+
for (const firstAnc of firstAncestors) {
|
|
215
|
+
if (firstAnc.isEqual(secondAnc)) {
|
|
216
|
+
return firstAnc
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return null
|
|
200
221
|
}
|
|
201
222
|
|
|
202
223
|
static doOverrideSetsConflict (first, second) {
|