@npmcli/arborist 9.0.2 → 9.1.0
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.
- package/README.md +13 -47
- package/lib/arborist/load-virtual.js +12 -0
- package/lib/arborist/reify.js +48 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -267,53 +267,19 @@ are updated by arborist when necessary whenever the tree is modified in
|
|
|
267
267
|
such a way that the dependency graph can change, and are relevant when
|
|
268
268
|
pruning nodes from the tree.
|
|
269
269
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
|
274
|
-
|
|
275
|
-
| X
|
|
276
|
-
| | | |
|
|
277
|
-
|
|
278
|
-
| |
|
|
279
|
-
| |
|
|
280
|
-
| |
|
|
281
|
-
|
|
282
|
-
| |
|
|
283
|
-
| | | | | not in lock | or only depended on | optional |
|
|
284
|
-
| | | | | | by optionalDeps | |
|
|
285
|
-
|------------+------+-----+----------+-------------+---------------------+-------------------|
|
|
286
|
-
| | | X | X | X | Optional dependency | if pruning EITHER |
|
|
287
|
-
| | | | | not in lock | of dep(s) in the | dev OR optional |
|
|
288
|
-
| | | | | | dev hierarchy | |
|
|
289
|
-
|------------+------+-----+----------+-------------+---------------------+-------------------|
|
|
290
|
-
| | | | | X | BOTH a non-optional | if pruning BOTH |
|
|
291
|
-
| | | | | in lock | dep within the dev | dev AND optional |
|
|
292
|
-
| | | | | | hierarchy, AND a | |
|
|
293
|
-
| | | | | | dep within the | |
|
|
294
|
-
| | | | | | optional hierarchy | |
|
|
295
|
-
|------------+------+-----+----------+-------------+---------------------+-------------------|
|
|
296
|
-
| | X | | | | peer dependency, or | if pruning peers |
|
|
297
|
-
| | | | | | only depended on by | |
|
|
298
|
-
| | | | | | peer dependencies | |
|
|
299
|
-
|------------+------+-----+----------+-------------+---------------------+-------------------|
|
|
300
|
-
| | X | X | | X | peer dependency of | if pruning peer |
|
|
301
|
-
| | | | | not in lock | dev node hierarchy | OR dev deps |
|
|
302
|
-
|------------+------+-----+----------+-------------+---------------------+-------------------|
|
|
303
|
-
| | X | | X | X | peer dependency of | if pruning peer |
|
|
304
|
-
| | | | | not in lock | optional nodes, or | OR optional deps |
|
|
305
|
-
| | | | | | peerOptional dep | |
|
|
306
|
-
|------------+------+-----+----------+-------------+---------------------+-------------------|
|
|
307
|
-
| | X | X | X | X | peer optional deps | if pruning peer |
|
|
308
|
-
| | | | | not in lock | of the dev dep | OR optional OR |
|
|
309
|
-
| | | | | | hierarchy | dev |
|
|
310
|
-
|------------+------+-----+----------+-------------+---------------------+-------------------|
|
|
311
|
-
| | X | | | X | BOTH a non-optional | if pruning peers |
|
|
312
|
-
| | | | | in lock | peer dep within the | OR: |
|
|
313
|
-
| | | | | | dev hierarchy, AND | BOTH optional |
|
|
314
|
-
| | | | | | a peer optional dep | AND dev deps |
|
|
315
|
-
+------------+------+-----+----------+-------------+---------------------+-------------------+
|
|
316
|
-
```
|
|
270
|
+
| extraneous | peer | dev | optional | devOptional | meaning | prune? |
|
|
271
|
+
|:----------:|:----:|:---:|:--------:|:----------------:|:-------------------------------------------------------------------------------------------------|:-------------------------------------------------------|
|
|
272
|
+
| | | | | | production dep | never |
|
|
273
|
+
| X | N/A | N/A | N/A | N/A | nothing depends on this, it is trash | always |
|
|
274
|
+
| | | X | | X<br>not in lock | devDependency, or only depended<br>on by devDependencies | if pruning dev |
|
|
275
|
+
| | | | X | X<br>not in lock | optionalDependency, or only depended<br>on by optionalDeps | if pruning optional |
|
|
276
|
+
| | | X | X | X<br>not in lock | Optional dependency of dep(s) in the<br>dev hierarchy | if pruning EITHER<br>dev OR optional |
|
|
277
|
+
| | | | | X<br>in lock | BOTH a non-optional dep within the<br>dev hierarchy, AND a dep within<br>the optional hierarchy | if pruning BOTH<br>dev AND optional |
|
|
278
|
+
| | X | | | | peer dependency, or only depended<br>on by peer dependencies | if pruning peers |
|
|
279
|
+
| | X | X | | X<br>not in lock | peer dependency of dev node hierarchy | if pruning peer OR<br>dev deps |
|
|
280
|
+
| | X | | X | X<br>not in lock | peer dependency of optional nodes, or<br>peerOptional dep | if pruning peer OR<br>optional deps |
|
|
281
|
+
| | X | X | X | X<br>not in lock | peer optional deps of the dev dep hierarchy | if pruning peer OR<br>optional OR dev |
|
|
282
|
+
| | X | | | X<br>in lock | BOTH a non-optional peer dep within the<br>dev hierarchy, AND a peer optional dep | if pruning peer deps OR:<br>BOTH optional AND dev deps |
|
|
317
283
|
|
|
318
284
|
* If none of these flags are set, then the node is required by the
|
|
319
285
|
dependency and/or peerDependency hierarchy. It should not be pruned.
|
|
@@ -200,6 +200,18 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
200
200
|
const targetPath = resolve(this.path, meta.resolved)
|
|
201
201
|
const targetLoc = relpath(this.path, targetPath)
|
|
202
202
|
const target = nodes.get(targetLoc)
|
|
203
|
+
|
|
204
|
+
if (!target) {
|
|
205
|
+
const err = new Error(
|
|
206
|
+
`Missing target in lock file: "${targetLoc}" is referenced by "${location}" but does not exist.
|
|
207
|
+
To fix:
|
|
208
|
+
1. rm package-lock.json
|
|
209
|
+
2. npm install`
|
|
210
|
+
)
|
|
211
|
+
err.code = 'EMISSINGTARGET'
|
|
212
|
+
throw err
|
|
213
|
+
}
|
|
214
|
+
|
|
203
215
|
const link = this.#loadLink(location, targetLoc, target, meta)
|
|
204
216
|
nodes.set(location, link)
|
|
205
217
|
nodes.set(targetLoc, link.target)
|
package/lib/arborist/reify.js
CHANGED
|
@@ -825,7 +825,14 @@ module.exports = cls => class Reifier extends cls {
|
|
|
825
825
|
// symlink
|
|
826
826
|
const dir = dirname(node.path)
|
|
827
827
|
const target = node.realpath
|
|
828
|
-
|
|
828
|
+
|
|
829
|
+
let rel
|
|
830
|
+
if (node.resolved?.startsWith('file:')) {
|
|
831
|
+
rel = this.#calculateRelativePath(node, dir, target, nm)
|
|
832
|
+
} else {
|
|
833
|
+
rel = relative(dir, target)
|
|
834
|
+
}
|
|
835
|
+
|
|
829
836
|
await mkdir(dir, { recursive: true })
|
|
830
837
|
return symlink(rel, node.path, 'junction')
|
|
831
838
|
}
|
|
@@ -843,6 +850,36 @@ module.exports = cls => class Reifier extends cls {
|
|
|
843
850
|
}) : p).then(() => node)
|
|
844
851
|
}
|
|
845
852
|
|
|
853
|
+
#calculateRelativePath (node, dir, target) {
|
|
854
|
+
// Check if the node is affected by a root override
|
|
855
|
+
let hasRootOverride = [...node.edgesIn].some(edge => edge.from.isRoot && edge.overrides)
|
|
856
|
+
// If not set via edges, see if the root package.json explicitly lists an override
|
|
857
|
+
if (!hasRootOverride && node.root) {
|
|
858
|
+
const rootPackage = node.root.target
|
|
859
|
+
hasRootOverride = !!(rootPackage &&
|
|
860
|
+
rootPackage.package.overrides &&
|
|
861
|
+
rootPackage.package.overrides[node.name])
|
|
862
|
+
}
|
|
863
|
+
if (!hasRootOverride) {
|
|
864
|
+
return relative(dir, target)
|
|
865
|
+
}
|
|
866
|
+
// If an override is detected, attempt to retrieve the override spec from the root package.json
|
|
867
|
+
const overrideSpec = node.root?.target?.package?.overrides?.[node.name]
|
|
868
|
+
if (typeof overrideSpec === 'string' && overrideSpec.startsWith('file:')) {
|
|
869
|
+
const overridePath = overrideSpec.replace(/^file:/, '')
|
|
870
|
+
const rootDir = node.root.target.path
|
|
871
|
+
return relative(dir, resolve(rootDir, overridePath))
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// Fallback: derive the package name from node.resolved in a platform-agnostic way
|
|
875
|
+
const filePath = node.resolved.replace(/^file:/, '')
|
|
876
|
+
// A node.package.name could be different than the folder name
|
|
877
|
+
const pathParts = filePath.split(/[\\/]/)
|
|
878
|
+
const packageName = pathParts[pathParts.length - 1]
|
|
879
|
+
|
|
880
|
+
return join('..', packageName)
|
|
881
|
+
}
|
|
882
|
+
|
|
846
883
|
#registryResolved (resolved) {
|
|
847
884
|
// the default registry url is a magic value meaning "the currently
|
|
848
885
|
// configured registry".
|
|
@@ -858,9 +895,19 @@ module.exports = cls => class Reifier extends cls {
|
|
|
858
895
|
if ((this.options.replaceRegistryHost === resolvedURL.hostname) ||
|
|
859
896
|
this.options.replaceRegistryHost === 'always') {
|
|
860
897
|
const registryURL = new URL(this.registry)
|
|
898
|
+
|
|
861
899
|
// Replace the host with the registry host while keeping the path intact
|
|
862
900
|
resolvedURL.hostname = registryURL.hostname
|
|
863
901
|
resolvedURL.port = registryURL.port
|
|
902
|
+
|
|
903
|
+
// Make sure we don't double-include the path if it's already there
|
|
904
|
+
const registryPath = registryURL.pathname.replace(/\/$/, '')
|
|
905
|
+
|
|
906
|
+
if (registryPath && registryPath !== '/' && !resolvedURL.pathname.startsWith(registryPath)) {
|
|
907
|
+
// Since hostname is changed, we need to ensure the registry path is included
|
|
908
|
+
resolvedURL.pathname = registryPath + resolvedURL.pathname
|
|
909
|
+
}
|
|
910
|
+
|
|
864
911
|
return resolvedURL.toString()
|
|
865
912
|
}
|
|
866
913
|
return resolved
|