@npmcli/arborist 4.2.1 → 5.0.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 +10 -0
- package/bin/actual.js +16 -20
- package/bin/audit.js +23 -26
- package/bin/funding.js +35 -31
- package/bin/ideal.js +11 -18
- package/bin/index.js +92 -63
- package/bin/lib/logging.js +62 -26
- package/bin/lib/options.js +117 -53
- package/bin/lib/print-tree.js +2 -3
- package/bin/lib/timers.js +17 -15
- package/bin/license.js +44 -34
- package/bin/prune.js +21 -22
- package/bin/reify.js +21 -22
- package/bin/shrinkwrap.js +5 -10
- package/bin/virtual.js +11 -15
- package/lib/add-rm-pkg-deps.js +12 -11
- package/lib/arborist/build-ideal-tree.js +62 -31
- package/lib/arborist/index.js +1 -3
- package/lib/arborist/load-actual.js +7 -2
- package/lib/arborist/rebuild.js +4 -3
- package/lib/arborist/reify.js +34 -10
- package/lib/audit-report.js +7 -8
- package/lib/get-workspace-nodes.js +4 -1
- package/lib/shrinkwrap.js +10 -7
- package/lib/tracker.js +6 -17
- package/package.json +10 -8
|
@@ -14,6 +14,7 @@ const fs = require('fs')
|
|
|
14
14
|
const lstat = promisify(fs.lstat)
|
|
15
15
|
const readlink = promisify(fs.readlink)
|
|
16
16
|
const { depth } = require('treeverse')
|
|
17
|
+
const log = require('proc-log')
|
|
17
18
|
|
|
18
19
|
const {
|
|
19
20
|
OK,
|
|
@@ -248,7 +249,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
248
249
|
try {
|
|
249
250
|
c()
|
|
250
251
|
} catch (er) {
|
|
251
|
-
|
|
252
|
+
log.warn(er.code, er.message, {
|
|
252
253
|
package: er.pkgid,
|
|
253
254
|
required: er.required,
|
|
254
255
|
current: er.current,
|
|
@@ -269,6 +270,22 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
269
270
|
this[_complete] = !!options.complete
|
|
270
271
|
this[_preferDedupe] = !!options.preferDedupe
|
|
271
272
|
this[_legacyBundling] = !!options.legacyBundling
|
|
273
|
+
|
|
274
|
+
// validates list of update names, they must
|
|
275
|
+
// be dep names only, no semver ranges are supported
|
|
276
|
+
for (const name of update.names) {
|
|
277
|
+
const spec = npa(name)
|
|
278
|
+
const validationError =
|
|
279
|
+
new TypeError(`Update arguments must not contain package version specifiers
|
|
280
|
+
|
|
281
|
+
Try using the package name instead, e.g:
|
|
282
|
+
npm update ${spec.name}`)
|
|
283
|
+
validationError.code = 'EUPDATEARGS'
|
|
284
|
+
|
|
285
|
+
if (spec.fetchSpec !== 'latest') {
|
|
286
|
+
throw validationError
|
|
287
|
+
}
|
|
288
|
+
}
|
|
272
289
|
this[_updateNames] = update.names
|
|
273
290
|
|
|
274
291
|
this[_updateAll] = update.all
|
|
@@ -320,7 +337,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
320
337
|
// Load on a new Arborist object, so the Nodes aren't the same,
|
|
321
338
|
// or else it'll get super confusing when we change them!
|
|
322
339
|
.then(async root => {
|
|
323
|
-
if (!this[_updateAll] && !this[_global] && !root.meta.loadedFromDisk) {
|
|
340
|
+
if ((!this[_updateAll] && !this[_global] && !root.meta.loadedFromDisk) || (this[_global] && this[_updateNames].length)) {
|
|
324
341
|
await new this.constructor(this.options).loadActual({ root })
|
|
325
342
|
const tree = root.target
|
|
326
343
|
// even though we didn't load it from a package-lock.json FILE,
|
|
@@ -516,7 +533,6 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
516
533
|
saveBundle,
|
|
517
534
|
saveType,
|
|
518
535
|
path: this.path,
|
|
519
|
-
log: this.log,
|
|
520
536
|
})
|
|
521
537
|
})
|
|
522
538
|
}
|
|
@@ -586,7 +602,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
586
602
|
// be printed by npm-audit-report as if they can be fixed, because
|
|
587
603
|
// they can't.
|
|
588
604
|
if (bundler) {
|
|
589
|
-
|
|
605
|
+
log.warn(`audit fix ${node.name}@${node.version}`,
|
|
590
606
|
`${node.location}\nis a bundled dependency of\n${
|
|
591
607
|
bundler.name}@${bundler.version} at ${bundler.location}\n` +
|
|
592
608
|
'It cannot be fixed automatically.\n' +
|
|
@@ -621,14 +637,14 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
621
637
|
if (!node.isProjectRoot && !node.isWorkspace) {
|
|
622
638
|
// not something we're going to fix, sorry. have to cd into
|
|
623
639
|
// that directory and fix it yourself.
|
|
624
|
-
|
|
640
|
+
log.warn('audit', 'Manual fix required in linked project ' +
|
|
625
641
|
`at ./${node.location} for ${name}@${simpleRange}.\n` +
|
|
626
642
|
`'cd ./${node.location}' and run 'npm audit' for details.`)
|
|
627
643
|
continue
|
|
628
644
|
}
|
|
629
645
|
|
|
630
646
|
if (!fixAvailable) {
|
|
631
|
-
|
|
647
|
+
log.warn('audit', `No fix available for ${name}@${simpleRange}`)
|
|
632
648
|
continue
|
|
633
649
|
}
|
|
634
650
|
|
|
@@ -636,7 +652,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
636
652
|
const breakingMessage = isSemVerMajor
|
|
637
653
|
? 'a SemVer major change'
|
|
638
654
|
: 'outside your stated dependency range'
|
|
639
|
-
|
|
655
|
+
log.warn('audit', `Updating ${name} to ${version},` +
|
|
640
656
|
`which is ${breakingMessage}.`)
|
|
641
657
|
|
|
642
658
|
await this[_add](node, { add: [`${name}@${version}`] })
|
|
@@ -711,7 +727,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
711
727
|
const heading = ancient ? 'ancient lockfile' : 'old lockfile'
|
|
712
728
|
if (ancient || !this.options.lockfileVersion ||
|
|
713
729
|
this.options.lockfileVersion >= defaultLockfileVersion) {
|
|
714
|
-
|
|
730
|
+
log.warn(heading,
|
|
715
731
|
`
|
|
716
732
|
The ${meta.type} file was created with an old version of npm,
|
|
717
733
|
so supplemental metadata must be fetched from the registry.
|
|
@@ -728,7 +744,7 @@ This is a one-time fix-up, please be patient...
|
|
|
728
744
|
}
|
|
729
745
|
|
|
730
746
|
queue.push(async () => {
|
|
731
|
-
|
|
747
|
+
log.silly('inflate', node.location)
|
|
732
748
|
const { resolved, version, path, name, location, integrity } = node
|
|
733
749
|
// don't try to hit the registry for linked deps
|
|
734
750
|
const useResolved = resolved && (
|
|
@@ -737,8 +753,7 @@ This is a one-time fix-up, please be patient...
|
|
|
737
753
|
const id = useResolved ? resolved
|
|
738
754
|
: version || `file:${node.path}`
|
|
739
755
|
const spec = npa.resolve(name, id, dirname(path))
|
|
740
|
-
const
|
|
741
|
-
const t = `idealTree:inflate:${sloc}`
|
|
756
|
+
const t = `idealTree:inflate:${location}`
|
|
742
757
|
this.addTracker(t)
|
|
743
758
|
await pacote.manifest(spec, {
|
|
744
759
|
...this.options,
|
|
@@ -749,7 +764,7 @@ This is a one-time fix-up, please be patient...
|
|
|
749
764
|
node.package = { ...mani, _id: `${mani.name}@${mani.version}` }
|
|
750
765
|
}).catch((er) => {
|
|
751
766
|
const warning = `Could not fetch metadata for ${name}@${id}`
|
|
752
|
-
|
|
767
|
+
log.warn(heading, warning, er)
|
|
753
768
|
})
|
|
754
769
|
this.finishTracker(t)
|
|
755
770
|
})
|
|
@@ -778,7 +793,7 @@ This is a one-time fix-up, please be patient...
|
|
|
778
793
|
this[_depsQueue].push(tree)
|
|
779
794
|
// XXX also push anything that depends on a node with a name
|
|
780
795
|
// in the override list
|
|
781
|
-
|
|
796
|
+
log.silly('idealTree', 'buildDeps')
|
|
782
797
|
this.addTracker('idealTree', tree.name, '')
|
|
783
798
|
return this[_buildDepStep]()
|
|
784
799
|
.then(() => process.emit('timeEnd', 'idealTree:buildDeps'))
|
|
@@ -1217,7 +1232,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1217
1232
|
if (this[_manifests].has(spec.raw)) {
|
|
1218
1233
|
return this[_manifests].get(spec.raw)
|
|
1219
1234
|
} else {
|
|
1220
|
-
|
|
1235
|
+
log.silly('fetch manifest', spec.raw)
|
|
1221
1236
|
const p = pacote.manifest(spec, options)
|
|
1222
1237
|
.then(mani => {
|
|
1223
1238
|
this[_manifests].set(spec.raw, mani)
|
|
@@ -1234,24 +1249,40 @@ This is a one-time fix-up, please be patient...
|
|
|
1234
1249
|
// Don't bother to load the manifest for link deps, because the target
|
|
1235
1250
|
// might be within another package that doesn't exist yet.
|
|
1236
1251
|
const { legacyPeerDeps } = this
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1252
|
+
|
|
1253
|
+
// spec is a directory, link it
|
|
1254
|
+
if (spec.type === 'directory') {
|
|
1255
|
+
return this[_linkFromSpec](name, spec, parent, edge)
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// if the spec matches a workspace name, then see if the workspace node will
|
|
1259
|
+
// satisfy the edge. if it does, we return the workspace node to make sure it
|
|
1260
|
+
// takes priority.
|
|
1261
|
+
if (this.idealTree.workspaces && this.idealTree.workspaces.has(spec.name)) {
|
|
1262
|
+
const existingNode = this.idealTree.edgesOut.get(spec.name).to
|
|
1263
|
+
if (existingNode && existingNode.isWorkspace && existingNode.satisfies(edge)) {
|
|
1264
|
+
return edge.to
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// spec isn't a directory, and either isn't a workspace or the workspace we have
|
|
1269
|
+
// doesn't satisfy the edge. try to fetch a manifest and build a node from that.
|
|
1270
|
+
return this[_fetchManifest](spec)
|
|
1271
|
+
.then(pkg => new Node({ name, pkg, parent, legacyPeerDeps }), error => {
|
|
1272
|
+
error.requiredBy = edge.from.location || '.'
|
|
1273
|
+
|
|
1274
|
+
// failed to load the spec, either because of enotarget or
|
|
1275
|
+
// fetch failure of some other sort. save it so we can verify
|
|
1276
|
+
// later that it's optional, otherwise the error is fatal.
|
|
1277
|
+
const n = new Node({
|
|
1278
|
+
name,
|
|
1279
|
+
parent,
|
|
1280
|
+
error,
|
|
1281
|
+
legacyPeerDeps,
|
|
1254
1282
|
})
|
|
1283
|
+
this[_loadFailures].add(n)
|
|
1284
|
+
return n
|
|
1285
|
+
})
|
|
1255
1286
|
}
|
|
1256
1287
|
|
|
1257
1288
|
[_linkFromSpec] (name, spec, parent, edge) {
|
package/lib/arborist/index.js
CHANGED
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
|
|
29
29
|
const { resolve } = require('path')
|
|
30
30
|
const { homedir } = require('os')
|
|
31
|
-
const procLog = require('proc-log')
|
|
32
31
|
const { depth } = require('treeverse')
|
|
33
32
|
const { saveTypeMap } = require('../add-rm-pkg-deps.js')
|
|
34
33
|
|
|
@@ -74,7 +73,6 @@ class Arborist extends Base {
|
|
|
74
73
|
path: options.path || '.',
|
|
75
74
|
cache: options.cache || `${homedir()}/.npm/_cacache`,
|
|
76
75
|
packumentCache: options.packumentCache || new Map(),
|
|
77
|
-
log: options.log || procLog,
|
|
78
76
|
workspacesEnabled: options.workspacesEnabled !== false,
|
|
79
77
|
lockfileVersion: lockfileVersion(options.lockfileVersion),
|
|
80
78
|
}
|
|
@@ -94,7 +92,7 @@ class Arborist extends Base {
|
|
|
94
92
|
|
|
95
93
|
// returns an array of the actual nodes for all the workspaces
|
|
96
94
|
workspaceNodes (tree, workspaces) {
|
|
97
|
-
return getWorkspaceNodes(tree, workspaces
|
|
95
|
+
return getWorkspaceNodes(tree, workspaces)
|
|
98
96
|
}
|
|
99
97
|
|
|
100
98
|
// returns a set of workspace nodes and all their deps
|
|
@@ -212,7 +212,8 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
212
212
|
const promises = []
|
|
213
213
|
for (const path of tree.workspaces.values()) {
|
|
214
214
|
if (!this[_cache].has(path)) {
|
|
215
|
-
|
|
215
|
+
// workspace overrides use the root overrides
|
|
216
|
+
const p = this[_loadFSNode]({ path, root: this[_actualTree], useRootOverrides: true })
|
|
216
217
|
.then(node => this[_loadFSTree](node))
|
|
217
218
|
promises.push(p)
|
|
218
219
|
}
|
|
@@ -240,7 +241,7 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
240
241
|
this[_actualTree] = root
|
|
241
242
|
}
|
|
242
243
|
|
|
243
|
-
[_loadFSNode] ({ path, parent, real, root, loadOverrides }) {
|
|
244
|
+
[_loadFSNode] ({ path, parent, real, root, loadOverrides, useRootOverrides }) {
|
|
244
245
|
if (!real) {
|
|
245
246
|
return realpath(path, this[_rpcache], this[_stcache])
|
|
246
247
|
.then(
|
|
@@ -250,6 +251,7 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
250
251
|
real,
|
|
251
252
|
root,
|
|
252
253
|
loadOverrides,
|
|
254
|
+
useRootOverrides,
|
|
253
255
|
}),
|
|
254
256
|
// if realpath fails, just provide a dummy error node
|
|
255
257
|
error => new Node({
|
|
@@ -289,6 +291,9 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
289
291
|
parent,
|
|
290
292
|
root,
|
|
291
293
|
loadOverrides,
|
|
294
|
+
...(useRootOverrides && root.overrides
|
|
295
|
+
? { overrides: root.overrides.getNodeRule({ name: pkg.name, version: pkg.version }) }
|
|
296
|
+
: {}),
|
|
292
297
|
})
|
|
293
298
|
})
|
|
294
299
|
.then(node => {
|
package/lib/arborist/rebuild.js
CHANGED
|
@@ -13,6 +13,7 @@ const {
|
|
|
13
13
|
isNodeGypPackage,
|
|
14
14
|
defaultGypInstallScript,
|
|
15
15
|
} = require('@npmcli/node-gyp')
|
|
16
|
+
const log = require('proc-log')
|
|
16
17
|
|
|
17
18
|
const boolEnv = b => b ? '1' : ''
|
|
18
19
|
const sortNodes = (a, b) =>
|
|
@@ -297,7 +298,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
297
298
|
|
|
298
299
|
const timer = `build:run:${event}:${location}`
|
|
299
300
|
process.emit('time', timer)
|
|
300
|
-
|
|
301
|
+
log.info('run', pkg._id, event, location, pkg.scripts[event])
|
|
301
302
|
const env = {
|
|
302
303
|
npm_package_resolved: resolved,
|
|
303
304
|
npm_package_integrity: integrity,
|
|
@@ -319,7 +320,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
319
320
|
}
|
|
320
321
|
const p = runScript(runOpts).catch(er => {
|
|
321
322
|
const { code, signal } = er
|
|
322
|
-
|
|
323
|
+
log.info('run', pkg._id, event, { code, signal })
|
|
323
324
|
throw er
|
|
324
325
|
}).then(({ args, code, signal, stdout, stderr }) => {
|
|
325
326
|
this.scriptsRun.add({
|
|
@@ -333,7 +334,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
333
334
|
stdout,
|
|
334
335
|
stderr,
|
|
335
336
|
})
|
|
336
|
-
|
|
337
|
+
log.info('run', pkg._id, event, { code, signal })
|
|
337
338
|
})
|
|
338
339
|
|
|
339
340
|
await (this[_doHandleOptionalFailure]
|
package/lib/arborist/reify.js
CHANGED
|
@@ -5,8 +5,10 @@ const pacote = require('pacote')
|
|
|
5
5
|
const AuditReport = require('../audit-report.js')
|
|
6
6
|
const { subset, intersects } = require('semver')
|
|
7
7
|
const npa = require('npm-package-arg')
|
|
8
|
+
const semver = require('semver')
|
|
8
9
|
const debug = require('../debug.js')
|
|
9
10
|
const walkUp = require('walk-up-path')
|
|
11
|
+
const log = require('proc-log')
|
|
10
12
|
|
|
11
13
|
const { dirname, resolve, relative } = require('path')
|
|
12
14
|
const { depth: dfwalk } = require('treeverse')
|
|
@@ -389,7 +391,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
389
391
|
[_addNodeToTrashList] (node, retire = false) {
|
|
390
392
|
const paths = [node.path, ...node.binPaths]
|
|
391
393
|
const moves = this[_retiredPaths]
|
|
392
|
-
|
|
394
|
+
log.silly('reify', 'mark', retire ? 'retired' : 'deleted', paths)
|
|
393
395
|
for (const path of paths) {
|
|
394
396
|
if (retire) {
|
|
395
397
|
const retired = retirePath(path)
|
|
@@ -412,7 +414,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
412
414
|
this[_addNodeToTrashList](diff.actual, true)
|
|
413
415
|
}
|
|
414
416
|
}
|
|
415
|
-
|
|
417
|
+
log.silly('reify', 'moves', moves)
|
|
416
418
|
const movePromises = Object.entries(moves)
|
|
417
419
|
.map(([from, to]) => this[_renamePath](from, to))
|
|
418
420
|
return promiseAllRejectLate(movePromises)
|
|
@@ -531,7 +533,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
531
533
|
return promiseAllRejectLate(unlinks)
|
|
532
534
|
.then(() => {
|
|
533
535
|
if (failures.length) {
|
|
534
|
-
|
|
536
|
+
log.warn('cleanup', 'Failed to remove some directories', failures)
|
|
535
537
|
}
|
|
536
538
|
})
|
|
537
539
|
.then(() => process.emit('timeEnd', 'reify:rollback:createSparse'))
|
|
@@ -623,7 +625,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
623
625
|
this[_nmValidated].add(nm)
|
|
624
626
|
return
|
|
625
627
|
}
|
|
626
|
-
|
|
628
|
+
log.warn('reify', 'Removing non-directory', nm)
|
|
627
629
|
await rimraf(nm)
|
|
628
630
|
}
|
|
629
631
|
|
|
@@ -646,8 +648,8 @@ module.exports = cls => class Reifier extends cls {
|
|
|
646
648
|
'please re-try this operation once it completes\n' +
|
|
647
649
|
'so that the damage can be corrected, or perform\n' +
|
|
648
650
|
'a fresh install with no lockfile if the problem persists.'
|
|
649
|
-
|
|
650
|
-
|
|
651
|
+
log.warn('reify', warning)
|
|
652
|
+
log.verbose('reify', 'unrecognized node in tree', node.path)
|
|
651
653
|
node.parent = null
|
|
652
654
|
node.fsParent = null
|
|
653
655
|
this[_addNodeToTrashList](node)
|
|
@@ -690,7 +692,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
690
692
|
[_warnDeprecated] (node) {
|
|
691
693
|
const { _id, deprecated } = node.package
|
|
692
694
|
if (deprecated) {
|
|
693
|
-
|
|
695
|
+
log.warn('deprecated', `${_id}: ${deprecated}`)
|
|
694
696
|
}
|
|
695
697
|
}
|
|
696
698
|
|
|
@@ -700,7 +702,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
700
702
|
return (node.optional ? p.catch(er => {
|
|
701
703
|
const set = optionalSet(node)
|
|
702
704
|
for (node of set) {
|
|
703
|
-
|
|
705
|
+
log.verbose('reify', 'failed optional dependency', node.path)
|
|
704
706
|
this[_addNodeToTrashList](node)
|
|
705
707
|
}
|
|
706
708
|
}) : p).then(() => node)
|
|
@@ -715,7 +717,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
715
717
|
// Shrinkwrap and Node classes carefully, so for now, just treat
|
|
716
718
|
// the default reg as the magical animal that it has been.
|
|
717
719
|
return resolved && resolved
|
|
718
|
-
.replace(/^https?:\/\/registry
|
|
720
|
+
.replace(/^https?:\/\/registry\.npmjs\.org\//, this.registry)
|
|
719
721
|
}
|
|
720
722
|
|
|
721
723
|
// bundles are *sort of* like shrinkwraps, in that the branch is defined
|
|
@@ -1128,7 +1130,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1128
1130
|
|
|
1129
1131
|
return promiseAllRejectLate(promises).then(() => {
|
|
1130
1132
|
if (failures.length) {
|
|
1131
|
-
|
|
1133
|
+
log.warn('cleanup', 'Failed to remove some directories', failures)
|
|
1132
1134
|
}
|
|
1133
1135
|
})
|
|
1134
1136
|
.then(() => process.emit('timeEnd', 'reify:trash'))
|
|
@@ -1273,6 +1275,21 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1273
1275
|
}
|
|
1274
1276
|
}
|
|
1275
1277
|
|
|
1278
|
+
// Returns true if any of the edges from this node has a semver
|
|
1279
|
+
// range definition that is an exact match to the version installed
|
|
1280
|
+
// e.g: should return true if for a given an installed version 1.0.0,
|
|
1281
|
+
// range is either =1.0.0 or 1.0.0
|
|
1282
|
+
const exactVersion = node => {
|
|
1283
|
+
for (const edge of node.edgesIn) {
|
|
1284
|
+
try {
|
|
1285
|
+
if (semver.subset(edge.spec, node.version)) {
|
|
1286
|
+
return false
|
|
1287
|
+
}
|
|
1288
|
+
} catch {}
|
|
1289
|
+
}
|
|
1290
|
+
return true
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1276
1293
|
// helper that retrieves an array of nodes that were
|
|
1277
1294
|
// potentially updated during the reify process, in order
|
|
1278
1295
|
// to limit the number of nodes to check and update, only
|
|
@@ -1284,6 +1301,8 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1284
1301
|
const filterDirectDependencies = node =>
|
|
1285
1302
|
!node.isRoot && node.resolveParent.isRoot
|
|
1286
1303
|
&& (!names || names.includes(node.name))
|
|
1304
|
+
&& exactVersion(node) // skip update for exact ranges
|
|
1305
|
+
|
|
1287
1306
|
const directDeps = this.idealTree.inventory
|
|
1288
1307
|
.filter(filterDirectDependencies)
|
|
1289
1308
|
|
|
@@ -1351,6 +1370,10 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1351
1370
|
devDependencies = {},
|
|
1352
1371
|
optionalDependencies = {},
|
|
1353
1372
|
peerDependencies = {},
|
|
1373
|
+
// bundleDependencies is not required by PackageJson like the other fields here
|
|
1374
|
+
// PackageJson also doesn't omit an empty array for this field so defaulting this
|
|
1375
|
+
// to an empty array would add that field to every package.json file.
|
|
1376
|
+
bundleDependencies,
|
|
1354
1377
|
} = tree.package
|
|
1355
1378
|
|
|
1356
1379
|
pkgJson.update({
|
|
@@ -1358,6 +1381,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1358
1381
|
devDependencies,
|
|
1359
1382
|
optionalDependencies,
|
|
1360
1383
|
peerDependencies,
|
|
1384
|
+
bundleDependencies,
|
|
1361
1385
|
})
|
|
1362
1386
|
await pkgJson.save()
|
|
1363
1387
|
}
|
package/lib/audit-report.js
CHANGED
|
@@ -13,7 +13,7 @@ const _fixAvailable = Symbol('fixAvailable')
|
|
|
13
13
|
const _checkTopNode = Symbol('checkTopNode')
|
|
14
14
|
const _init = Symbol('init')
|
|
15
15
|
const _omit = Symbol('omit')
|
|
16
|
-
const
|
|
16
|
+
const log = require('proc-log')
|
|
17
17
|
|
|
18
18
|
const fetch = require('npm-registry-fetch')
|
|
19
19
|
|
|
@@ -98,14 +98,13 @@ class AuditReport extends Map {
|
|
|
98
98
|
this.calculator = new Calculator(opts)
|
|
99
99
|
this.error = null
|
|
100
100
|
this.options = opts
|
|
101
|
-
this.log = opts.log || procLog
|
|
102
101
|
this.tree = tree
|
|
103
102
|
this.filterSet = opts.filterSet
|
|
104
103
|
}
|
|
105
104
|
|
|
106
105
|
async run () {
|
|
107
106
|
this.report = await this[_getReport]()
|
|
108
|
-
|
|
107
|
+
log.silly('audit report', this.report)
|
|
109
108
|
if (this.report) {
|
|
110
109
|
await this[_init]()
|
|
111
110
|
}
|
|
@@ -304,7 +303,7 @@ class AuditReport extends Map {
|
|
|
304
303
|
|
|
305
304
|
async [_getReport] () {
|
|
306
305
|
// if we're not auditing, just return false
|
|
307
|
-
if (this.options.audit === false || this.tree.inventory.size === 1) {
|
|
306
|
+
if (this.options.audit === false || this.options.offline === true || this.tree.inventory.size === 1) {
|
|
308
307
|
return null
|
|
309
308
|
}
|
|
310
309
|
|
|
@@ -313,7 +312,7 @@ class AuditReport extends Map {
|
|
|
313
312
|
try {
|
|
314
313
|
// first try the super fast bulk advisory listing
|
|
315
314
|
const body = prepareBulkData(this.tree, this[_omit], this.filterSet)
|
|
316
|
-
|
|
315
|
+
log.silly('audit', 'bulk request', body)
|
|
317
316
|
|
|
318
317
|
// no sense asking if we don't have anything to audit,
|
|
319
318
|
// we know it'll be empty
|
|
@@ -331,7 +330,7 @@ class AuditReport extends Map {
|
|
|
331
330
|
|
|
332
331
|
return await res.json()
|
|
333
332
|
} catch (er) {
|
|
334
|
-
|
|
333
|
+
log.silly('audit', 'bulk request failed', String(er.body))
|
|
335
334
|
// that failed, try the quick audit endpoint
|
|
336
335
|
const body = prepareData(this.tree, this.options)
|
|
337
336
|
const res = await fetch('/-/npm/v1/security/audits/quick', {
|
|
@@ -344,8 +343,8 @@ class AuditReport extends Map {
|
|
|
344
343
|
return AuditReport.auditToBulk(await res.json())
|
|
345
344
|
}
|
|
346
345
|
} catch (er) {
|
|
347
|
-
|
|
348
|
-
|
|
346
|
+
log.verbose('audit error', er)
|
|
347
|
+
log.silly('audit error', String(er.body))
|
|
349
348
|
this.error = er
|
|
350
349
|
return null
|
|
351
350
|
} finally {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// Get the actual nodes corresponding to a root node's child workspaces,
|
|
2
2
|
// given a list of workspace names.
|
|
3
|
+
|
|
4
|
+
const log = require('proc-log')
|
|
3
5
|
const relpath = require('./relpath.js')
|
|
4
|
-
|
|
6
|
+
|
|
7
|
+
const getWorkspaceNodes = (tree, workspaces) => {
|
|
5
8
|
const wsMap = tree.workspaces
|
|
6
9
|
if (!wsMap) {
|
|
7
10
|
log.warn('workspaces', 'filter set, but no workspaces present')
|
package/lib/shrinkwrap.js
CHANGED
|
@@ -33,7 +33,7 @@ const mismatch = (a, b) => a && b && a !== b
|
|
|
33
33
|
// After calling this.commit(), any nodes not present in the tree will have
|
|
34
34
|
// been removed from the shrinkwrap data as well.
|
|
35
35
|
|
|
36
|
-
const
|
|
36
|
+
const log = require('proc-log')
|
|
37
37
|
const YarnLock = require('./yarn-lock.js')
|
|
38
38
|
const { promisify } = require('util')
|
|
39
39
|
const rimraf = promisify(require('rimraf'))
|
|
@@ -80,8 +80,8 @@ const swKeyOrder = [
|
|
|
80
80
|
]
|
|
81
81
|
|
|
82
82
|
// used to rewrite from yarn registry to npm registry
|
|
83
|
-
const yarnRegRe = /^https?:\/\/registry
|
|
84
|
-
const npmRegRe = /^https?:\/\/registry
|
|
83
|
+
const yarnRegRe = /^https?:\/\/registry\.yarnpkg\.com\//
|
|
84
|
+
const npmRegRe = /^https?:\/\/registry\.npmjs\.org\//
|
|
85
85
|
|
|
86
86
|
// sometimes resolved: is weird or broken, or something npa can't handle
|
|
87
87
|
const specFromResolved = resolved => {
|
|
@@ -329,14 +329,12 @@ class Shrinkwrap {
|
|
|
329
329
|
newline = '\n',
|
|
330
330
|
shrinkwrapOnly = false,
|
|
331
331
|
hiddenLockfile = false,
|
|
332
|
-
log = procLog,
|
|
333
332
|
lockfileVersion,
|
|
334
333
|
} = options
|
|
335
334
|
|
|
336
335
|
this.lockfileVersion = hiddenLockfile ? 3
|
|
337
336
|
: lockfileVersion ? parseInt(lockfileVersion, 10)
|
|
338
337
|
: null
|
|
339
|
-
this.log = log
|
|
340
338
|
this[_awaitingUpdate] = new Map()
|
|
341
339
|
this.tree = null
|
|
342
340
|
this.path = resolve(path || '.')
|
|
@@ -476,8 +474,13 @@ class Shrinkwrap {
|
|
|
476
474
|
// all good! hidden lockfile is the newest thing in here.
|
|
477
475
|
return data
|
|
478
476
|
}).catch(er => {
|
|
479
|
-
|
|
480
|
-
this.
|
|
477
|
+
/* istanbul ignore else */
|
|
478
|
+
if (typeof this.filename === 'string') {
|
|
479
|
+
const rel = relpath(this.path, this.filename)
|
|
480
|
+
log.verbose('shrinkwrap', `failed to load ${rel}`, er)
|
|
481
|
+
} else {
|
|
482
|
+
log.verbose('shrinkwrap', `failed to load ${this.path}`, er)
|
|
483
|
+
}
|
|
481
484
|
this.loadingError = er
|
|
482
485
|
this.loadedFromDisk = false
|
|
483
486
|
this.ancientLockfile = false
|
package/lib/tracker.js
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
const _progress = Symbol('_progress')
|
|
2
2
|
const _onError = Symbol('_onError')
|
|
3
|
-
const
|
|
3
|
+
const npmlog = require('npmlog')
|
|
4
4
|
|
|
5
5
|
module.exports = cls => class Tracker extends cls {
|
|
6
6
|
constructor (options = {}) {
|
|
7
7
|
super(options)
|
|
8
|
-
this.log = options.log || procLog
|
|
9
8
|
this[_progress] = new Map()
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
addTracker (section, subsection = null, key = null) {
|
|
13
|
-
// TrackerGroup type object not found
|
|
14
|
-
if (!this.log.newGroup) {
|
|
15
|
-
return
|
|
16
|
-
}
|
|
17
|
-
|
|
18
12
|
if (section === null || section === undefined) {
|
|
19
13
|
this[_onError](`Tracker can't be null or undefined`)
|
|
20
14
|
}
|
|
@@ -31,13 +25,13 @@ module.exports = cls => class Tracker extends cls {
|
|
|
31
25
|
this[_onError](`Tracker "${section}" already exists`)
|
|
32
26
|
} else if (!hasTracker && subsection === null) {
|
|
33
27
|
// 1. no existing tracker, no subsection
|
|
34
|
-
// Create a new tracker from
|
|
28
|
+
// Create a new tracker from npmlog
|
|
35
29
|
// starts progress bar
|
|
36
30
|
if (this[_progress].size === 0) {
|
|
37
|
-
|
|
31
|
+
npmlog.enableProgress()
|
|
38
32
|
}
|
|
39
33
|
|
|
40
|
-
this[_progress].set(section,
|
|
34
|
+
this[_progress].set(section, npmlog.newGroup(section))
|
|
41
35
|
} else if (!hasTracker && subsection !== null) {
|
|
42
36
|
// 2. no parent tracker and subsection
|
|
43
37
|
this[_onError](`Parent tracker "${section}" does not exist`)
|
|
@@ -53,11 +47,6 @@ module.exports = cls => class Tracker extends cls {
|
|
|
53
47
|
}
|
|
54
48
|
|
|
55
49
|
finishTracker (section, subsection = null, key = null) {
|
|
56
|
-
// TrackerGroup type object not found
|
|
57
|
-
if (!this.log.newGroup) {
|
|
58
|
-
return
|
|
59
|
-
}
|
|
60
|
-
|
|
61
50
|
if (section === null || section === undefined) {
|
|
62
51
|
this[_onError](`Tracker can't be null or undefined`)
|
|
63
52
|
}
|
|
@@ -88,7 +77,7 @@ module.exports = cls => class Tracker extends cls {
|
|
|
88
77
|
// remove progress bar if all
|
|
89
78
|
// trackers are finished
|
|
90
79
|
if (this[_progress].size === 0) {
|
|
91
|
-
|
|
80
|
+
npmlog.disableProgress()
|
|
92
81
|
}
|
|
93
82
|
} else if (!hasTracker && subsection === null) {
|
|
94
83
|
// 1. no existing parent tracker, no subsection
|
|
@@ -103,7 +92,7 @@ module.exports = cls => class Tracker extends cls {
|
|
|
103
92
|
}
|
|
104
93
|
|
|
105
94
|
[_onError] (msg) {
|
|
106
|
-
|
|
95
|
+
npmlog.disableProgress()
|
|
107
96
|
throw new Error(msg)
|
|
108
97
|
}
|
|
109
98
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/arborist",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Manage node_modules trees",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@isaacs/string-locale-compare": "^1.1.0",
|
|
7
7
|
"@npmcli/installed-package-contents": "^1.0.7",
|
|
8
8
|
"@npmcli/map-workspaces": "^2.0.0",
|
|
9
|
-
"@npmcli/metavuln-calculator": "^
|
|
9
|
+
"@npmcli/metavuln-calculator": "^3.0.0",
|
|
10
10
|
"@npmcli/move-file": "^1.1.0",
|
|
11
11
|
"@npmcli/name-from-folder": "^1.0.1",
|
|
12
12
|
"@npmcli/node-gyp": "^1.0.3",
|
|
13
13
|
"@npmcli/package-json": "^1.0.1",
|
|
14
|
-
"@npmcli/run-script": "^
|
|
14
|
+
"@npmcli/run-script": "^3.0.0",
|
|
15
15
|
"bin-links": "^3.0.0",
|
|
16
16
|
"cacache": "^15.0.3",
|
|
17
17
|
"common-ancestor-path": "^1.0.1",
|
|
@@ -19,13 +19,15 @@
|
|
|
19
19
|
"json-stringify-nice": "^1.1.4",
|
|
20
20
|
"mkdirp": "^1.0.4",
|
|
21
21
|
"mkdirp-infer-owner": "^2.0.0",
|
|
22
|
+
"nopt": "^5.0.0",
|
|
22
23
|
"npm-install-checks": "^4.0.0",
|
|
23
|
-
"npm-package-arg": "^
|
|
24
|
-
"npm-pick-manifest": "^
|
|
25
|
-
"npm-registry-fetch": "^
|
|
26
|
-
"
|
|
24
|
+
"npm-package-arg": "^9.0.0",
|
|
25
|
+
"npm-pick-manifest": "^7.0.0",
|
|
26
|
+
"npm-registry-fetch": "^13.0.0",
|
|
27
|
+
"npmlog": "^6.0.1",
|
|
28
|
+
"pacote": "^13.0.2",
|
|
27
29
|
"parse-conflict-json": "^2.0.1",
|
|
28
|
-
"proc-log": "^
|
|
30
|
+
"proc-log": "^2.0.0",
|
|
29
31
|
"promise-all-reject-late": "^1.0.0",
|
|
30
32
|
"promise-call-limit": "^1.0.1",
|
|
31
33
|
"read-package-json-fast": "^2.0.2",
|