@npmcli/arborist 9.1.2 → 9.1.4
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/lib/arborist/build-ideal-tree.js +47 -14
- package/lib/arborist/reify.js +5 -15
- package/lib/audit-report.js +55 -72
- package/lib/node.js +9 -0
- package/package.json +3 -3
|
@@ -6,7 +6,7 @@ const pacote = require('pacote')
|
|
|
6
6
|
const cacache = require('cacache')
|
|
7
7
|
const { callLimit: promiseCallLimit } = require('promise-call-limit')
|
|
8
8
|
const realpath = require('../../lib/realpath.js')
|
|
9
|
-
const { resolve, dirname } = require('node:path')
|
|
9
|
+
const { resolve, dirname, sep } = require('node:path')
|
|
10
10
|
const treeCheck = require('../tree-check.js')
|
|
11
11
|
const { readdirScoped } = require('@npmcli/fs')
|
|
12
12
|
const { lstat, readlink } = require('node:fs/promises')
|
|
@@ -192,9 +192,11 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
async #checkEngineAndPlatform () {
|
|
195
|
-
const { engineStrict, npmVersion, nodeVersion } = this.options
|
|
195
|
+
const { engineStrict, npmVersion, nodeVersion, omit = [] } = this.options
|
|
196
|
+
const omitSet = new Set(omit)
|
|
197
|
+
|
|
196
198
|
for (const node of this.idealTree.inventory.values()) {
|
|
197
|
-
if (!node.optional) {
|
|
199
|
+
if (!node.optional && !node.shouldOmit(omitSet)) {
|
|
198
200
|
try {
|
|
199
201
|
// if devEngines is present in the root node we ignore the engines check
|
|
200
202
|
if (!(node.isRoot && node.package.devEngines)) {
|
|
@@ -1224,15 +1226,31 @@ This is a one-time fix-up, please be patient...
|
|
|
1224
1226
|
const { installLinks, legacyPeerDeps } = this
|
|
1225
1227
|
const isWorkspace = this.idealTree.workspaces && this.idealTree.workspaces.has(spec.name)
|
|
1226
1228
|
|
|
1227
|
-
// spec is a directory, link it
|
|
1229
|
+
// spec is a directory, link it if:
|
|
1230
|
+
// - it's a workspace, OR
|
|
1231
|
+
// - it's a project-internal file: dependency (always linked), OR
|
|
1232
|
+
// - it's external and installLinks is false
|
|
1228
1233
|
// TODO post arborist refactor, will need to check for installStrategy=linked
|
|
1229
|
-
|
|
1234
|
+
let isProjectInternalFileSpec = false
|
|
1235
|
+
if (edge?.rawSpec.startsWith('file:../') || edge?.rawSpec.startsWith('file:./')) {
|
|
1236
|
+
const targetPath = resolve(parent.realpath, edge.rawSpec.slice(5))
|
|
1237
|
+
const resolvedProjectRoot = resolve(this.idealTree.realpath)
|
|
1238
|
+
// Check if the target is within the project root
|
|
1239
|
+
isProjectInternalFileSpec = targetPath.startsWith(resolvedProjectRoot + sep) || targetPath === resolvedProjectRoot
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// When using --install-links, we need to handle transitive file dependencies specially
|
|
1243
|
+
// If the parent was installed (not linked) due to --install-links, and this is a file: dep, we should also install it rather than link it
|
|
1244
|
+
const parentWasInstalled = parent && !parent.isLink && parent.resolved?.startsWith('file:')
|
|
1245
|
+
const isTransitiveFileDep = spec.type === 'directory' && parentWasInstalled && installLinks
|
|
1246
|
+
|
|
1247
|
+
// Decide whether to link or copy the dependency
|
|
1248
|
+
const shouldLink = (isWorkspace || isProjectInternalFileSpec || !installLinks) && !isTransitiveFileDep
|
|
1249
|
+
if (spec.type === 'directory' && shouldLink) {
|
|
1230
1250
|
return this.#linkFromSpec(name, spec, parent, edge)
|
|
1231
1251
|
}
|
|
1232
1252
|
|
|
1233
|
-
// if the spec matches a workspace name, then see if the workspace node will
|
|
1234
|
-
// satisfy the edge. if it does, we return the workspace node to make sure it
|
|
1235
|
-
// takes priority.
|
|
1253
|
+
// if the spec matches a workspace name, then see if the workspace node will satisfy the edge. if it does, we return the workspace node to make sure it takes priority.
|
|
1236
1254
|
if (isWorkspace) {
|
|
1237
1255
|
const existingNode = this.idealTree.edgesOut.get(spec.name).to
|
|
1238
1256
|
if (existingNode && existingNode.isWorkspace && existingNode.satisfies(edge)) {
|
|
@@ -1240,6 +1258,15 @@ This is a one-time fix-up, please be patient...
|
|
|
1240
1258
|
}
|
|
1241
1259
|
}
|
|
1242
1260
|
|
|
1261
|
+
// For file: dependencies that we're installing (not linking), ensure proper resolution
|
|
1262
|
+
if (isTransitiveFileDep && edge) {
|
|
1263
|
+
// For transitive file deps, resolve relative to the parent's original source location
|
|
1264
|
+
const parentOriginalPath = parent.resolved.slice(5) // Remove 'file:' prefix
|
|
1265
|
+
const relativePath = edge.rawSpec.slice(5) // Remove 'file:' prefix
|
|
1266
|
+
const absolutePath = resolve(parentOriginalPath, relativePath)
|
|
1267
|
+
spec = npa.resolve(name, `file:${absolutePath}`)
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1243
1270
|
// spec isn't a directory, and either isn't a workspace or the workspace we have
|
|
1244
1271
|
// doesn't satisfy the edge. try to fetch a manifest and build a node from that.
|
|
1245
1272
|
return this.#fetchManifest(spec)
|
|
@@ -1292,6 +1319,12 @@ This is a one-time fix-up, please be patient...
|
|
|
1292
1319
|
.sort(({ name: a }, { name: b }) => localeCompare(a, b))
|
|
1293
1320
|
|
|
1294
1321
|
for (const edge of peerEdges) {
|
|
1322
|
+
// node.parent gets mutated during loop execution due to recursive #nodeFromEdge calls.
|
|
1323
|
+
// When a compatible peer is found (e.g. a@1.1.0 replaces a@1.2.0), the original node loses its parent.
|
|
1324
|
+
// if node is detached/removed from the tree, or has no parent, so no need to check remaining edgesOut for that node.
|
|
1325
|
+
if (!node.parent) {
|
|
1326
|
+
break
|
|
1327
|
+
}
|
|
1295
1328
|
// already placed this one, and we're happy with it.
|
|
1296
1329
|
if (edge.valid && edge.to) {
|
|
1297
1330
|
continue
|
|
@@ -1476,11 +1509,6 @@ This is a one-time fix-up, please be patient...
|
|
|
1476
1509
|
const needPrune = metaFromDisk && (mutateTree || flagsSuspect)
|
|
1477
1510
|
if (this.#prune && needPrune) {
|
|
1478
1511
|
this.#idealTreePrune()
|
|
1479
|
-
for (const node of this.idealTree.inventory.values()) {
|
|
1480
|
-
if (node.extraneous) {
|
|
1481
|
-
node.parent = null
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
1512
|
}
|
|
1485
1513
|
|
|
1486
1514
|
timeEnd()
|
|
@@ -1514,7 +1542,12 @@ This is a one-time fix-up, please be patient...
|
|
|
1514
1542
|
|
|
1515
1543
|
#idealTreePrune () {
|
|
1516
1544
|
for (const node of this.idealTree.inventory.values()) {
|
|
1517
|
-
|
|
1545
|
+
// optional peer dependencies are meant to be added to the tree
|
|
1546
|
+
// through an explicit required dependency (most commonly in the
|
|
1547
|
+
// root package.json), at which point they won't be optional so
|
|
1548
|
+
// any dependencies still marked as both optional and peer at
|
|
1549
|
+
// this point can be pruned as a special kind of extraneous
|
|
1550
|
+
if (node.extraneous || (node.peer && node.optional)) {
|
|
1518
1551
|
node.parent = null
|
|
1519
1552
|
}
|
|
1520
1553
|
}
|
package/lib/arborist/reify.js
CHANGED
|
@@ -84,9 +84,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
84
84
|
#bundleUnpacked = new Set() // the nodes we unpack to read their bundles
|
|
85
85
|
#dryRun
|
|
86
86
|
#nmValidated = new Set()
|
|
87
|
-
#
|
|
88
|
-
#omitPeer
|
|
89
|
-
#omitOptional
|
|
87
|
+
#omit
|
|
90
88
|
#retiredPaths = {}
|
|
91
89
|
#retiredUnchanged = {}
|
|
92
90
|
#savePrefix
|
|
@@ -110,10 +108,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
110
108
|
throw er
|
|
111
109
|
}
|
|
112
110
|
|
|
113
|
-
|
|
114
|
-
this.#omitDev = omit.has('dev')
|
|
115
|
-
this.#omitOptional = omit.has('optional')
|
|
116
|
-
this.#omitPeer = omit.has('peer')
|
|
111
|
+
this.#omit = new Set(options.omit)
|
|
117
112
|
|
|
118
113
|
// start tracker block
|
|
119
114
|
this.addTracker('reify')
|
|
@@ -562,12 +557,11 @@ module.exports = cls => class Reifier extends cls {
|
|
|
562
557
|
// adding to the trash list will skip reifying, and delete them
|
|
563
558
|
// if they are currently in the tree and otherwise untouched.
|
|
564
559
|
[_addOmitsToTrashList] () {
|
|
565
|
-
if (!this.#
|
|
560
|
+
if (!this.#omit.size) {
|
|
566
561
|
return
|
|
567
562
|
}
|
|
568
563
|
|
|
569
564
|
const timeEnd = time.start('reify:trashOmits')
|
|
570
|
-
|
|
571
565
|
for (const node of this.idealTree.inventory.values()) {
|
|
572
566
|
const { top } = node
|
|
573
567
|
|
|
@@ -583,12 +577,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
583
577
|
}
|
|
584
578
|
|
|
585
579
|
// omit node if the dep type matches any omit flags that were set
|
|
586
|
-
if (
|
|
587
|
-
node.peer && this.#omitPeer ||
|
|
588
|
-
node.dev && this.#omitDev ||
|
|
589
|
-
node.optional && this.#omitOptional ||
|
|
590
|
-
node.devOptional && this.#omitOptional && this.#omitDev
|
|
591
|
-
) {
|
|
580
|
+
if (node.shouldOmit(this.#omit)) {
|
|
592
581
|
this[_addNodeToTrashList](node)
|
|
593
582
|
}
|
|
594
583
|
}
|
|
@@ -896,6 +885,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
896
885
|
// Replace the host with the registry host while keeping the path intact
|
|
897
886
|
resolvedURL.hostname = registryURL.hostname
|
|
898
887
|
resolvedURL.port = registryURL.port
|
|
888
|
+
resolvedURL.protocol = registryURL.protocol
|
|
899
889
|
|
|
900
890
|
// Make sure we don't double-include the path if it's already there
|
|
901
891
|
const registryPath = registryURL.pathname.replace(/\/$/, '')
|
package/lib/audit-report.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// an object representing the set of vulnerabilities in a tree
|
|
2
|
-
/* eslint camelcase: "off" */
|
|
3
2
|
|
|
4
3
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
5
4
|
const npa = require('npm-package-arg')
|
|
@@ -8,16 +7,15 @@ const pickManifest = require('npm-pick-manifest')
|
|
|
8
7
|
const Vuln = require('./vuln.js')
|
|
9
8
|
const Calculator = require('@npmcli/metavuln-calculator')
|
|
10
9
|
|
|
11
|
-
const _getReport = Symbol('getReport')
|
|
12
|
-
const _fixAvailable = Symbol('fixAvailable')
|
|
13
|
-
const _checkTopNode = Symbol('checkTopNode')
|
|
14
|
-
const _init = Symbol('init')
|
|
15
|
-
const _omit = Symbol('omit')
|
|
16
10
|
const { log, time } = require('proc-log')
|
|
17
11
|
|
|
18
12
|
const npmFetch = require('npm-registry-fetch')
|
|
19
13
|
|
|
20
14
|
class AuditReport extends Map {
|
|
15
|
+
#omit
|
|
16
|
+
error = null
|
|
17
|
+
topVulns = new Map()
|
|
18
|
+
|
|
21
19
|
static load (tree, opts) {
|
|
22
20
|
return new AuditReport(tree, opts).run()
|
|
23
21
|
}
|
|
@@ -91,22 +89,18 @@ class AuditReport extends Map {
|
|
|
91
89
|
|
|
92
90
|
constructor (tree, opts = {}) {
|
|
93
91
|
super()
|
|
94
|
-
|
|
95
|
-
this[_omit] = new Set(omit || [])
|
|
96
|
-
this.topVulns = new Map()
|
|
97
|
-
|
|
92
|
+
this.#omit = new Set(opts.omit || [])
|
|
98
93
|
this.calculator = new Calculator(opts)
|
|
99
|
-
this.error = null
|
|
100
94
|
this.options = opts
|
|
101
95
|
this.tree = tree
|
|
102
96
|
this.filterSet = opts.filterSet
|
|
103
97
|
}
|
|
104
98
|
|
|
105
99
|
async run () {
|
|
106
|
-
this.report = await this
|
|
100
|
+
this.report = await this.#getReport()
|
|
107
101
|
log.silly('audit report', this.report)
|
|
108
102
|
if (this.report) {
|
|
109
|
-
await this
|
|
103
|
+
await this.#init()
|
|
110
104
|
}
|
|
111
105
|
return this
|
|
112
106
|
}
|
|
@@ -116,7 +110,7 @@ class AuditReport extends Map {
|
|
|
116
110
|
return !!(vuln && vuln.isVulnerable(node))
|
|
117
111
|
}
|
|
118
112
|
|
|
119
|
-
async
|
|
113
|
+
async #init () {
|
|
120
114
|
const timeEnd = time.start('auditReport:init')
|
|
121
115
|
|
|
122
116
|
const promises = []
|
|
@@ -148,7 +142,7 @@ class AuditReport extends Map {
|
|
|
148
142
|
if (!seen.has(k)) {
|
|
149
143
|
const p = []
|
|
150
144
|
for (const node of this.tree.inventory.query('packageName', name)) {
|
|
151
|
-
if (!shouldAudit(node
|
|
145
|
+
if (!this.shouldAudit(node)) {
|
|
152
146
|
continue
|
|
153
147
|
}
|
|
154
148
|
|
|
@@ -171,7 +165,15 @@ class AuditReport extends Map {
|
|
|
171
165
|
vuln.nodes.add(node)
|
|
172
166
|
for (const { from: dep, spec } of node.edgesIn) {
|
|
173
167
|
if (dep.isTop && !vuln.topNodes.has(dep)) {
|
|
174
|
-
this
|
|
168
|
+
vuln.fixAvailable = this.#fixAvailable(vuln, spec)
|
|
169
|
+
if (vuln.fixAvailable !== true) {
|
|
170
|
+
// now we know the top node is vulnerable, and cannot be
|
|
171
|
+
// upgraded out of the bad place without --force. But, there's
|
|
172
|
+
// no need to add it to the actual vulns list, because nothing
|
|
173
|
+
// depends on root.
|
|
174
|
+
this.topVulns.set(vuln.name, vuln)
|
|
175
|
+
vuln.topNodes.add(dep)
|
|
176
|
+
}
|
|
175
177
|
} else {
|
|
176
178
|
// calculate a metavuln, if necessary
|
|
177
179
|
const calc = this.calculator.calculate(dep.packageName, advisory)
|
|
@@ -214,33 +216,14 @@ class AuditReport extends Map {
|
|
|
214
216
|
timeEnd()
|
|
215
217
|
}
|
|
216
218
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (vuln.fixAvailable !== true) {
|
|
221
|
-
// now we know the top node is vulnerable, and cannot be
|
|
222
|
-
// upgraded out of the bad place without --force. But, there's
|
|
223
|
-
// no need to add it to the actual vulns list, because nothing
|
|
224
|
-
// depends on root.
|
|
225
|
-
this.topVulns.set(vuln.name, vuln)
|
|
226
|
-
vuln.topNodes.add(topNode)
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// check whether the top node is vulnerable.
|
|
231
|
-
// check whether we can get out of the bad place with --force, and if
|
|
232
|
-
// so, whether that update is SemVer Major
|
|
233
|
-
[_fixAvailable] (topNode, vuln, spec) {
|
|
234
|
-
// this will always be set to at least {name, versions:{}}
|
|
235
|
-
const paku = vuln.packument
|
|
236
|
-
|
|
219
|
+
// given the spec, see if there is a fix available at all, and note whether or not it's a semver major fix or not (i.e. will need --force)
|
|
220
|
+
#fixAvailable (vuln, spec) {
|
|
221
|
+
// TODO we return true, false, OR an object here. this is probably a bad pattern.
|
|
237
222
|
if (!vuln.testSpec(spec)) {
|
|
238
223
|
return true
|
|
239
224
|
}
|
|
240
225
|
|
|
241
|
-
//
|
|
242
|
-
// somewhere other than the registry, and we got something vulnerable,
|
|
243
|
-
// then we're stuck with it.
|
|
226
|
+
// even if we HAVE a packument, if we're looking for it somewhere other than the registry and we have something vulnerable then we're stuck with it.
|
|
244
227
|
const specObj = npa(spec)
|
|
245
228
|
if (!specObj.registry) {
|
|
246
229
|
return false
|
|
@@ -250,15 +233,13 @@ class AuditReport extends Map {
|
|
|
250
233
|
spec = specObj.subSpec.rawSpec
|
|
251
234
|
}
|
|
252
235
|
|
|
253
|
-
//
|
|
254
|
-
// still check to see if the node is fixable with a different version,
|
|
255
|
-
// and if that is a semver major bump.
|
|
236
|
+
// we don't provide fixes for top nodes other than root, but we still check to see if the node is fixable with a different version, and note if that is a semver major bump.
|
|
256
237
|
try {
|
|
257
238
|
const {
|
|
258
239
|
_isSemVerMajor: isSemVerMajor,
|
|
259
240
|
version,
|
|
260
241
|
name,
|
|
261
|
-
} = pickManifest(
|
|
242
|
+
} = pickManifest(vuln.packument, spec, {
|
|
262
243
|
...this.options,
|
|
263
244
|
before: null,
|
|
264
245
|
avoid: vuln.range,
|
|
@@ -274,7 +255,7 @@ class AuditReport extends Map {
|
|
|
274
255
|
throw new Error('do not call AuditReport.set() directly')
|
|
275
256
|
}
|
|
276
257
|
|
|
277
|
-
async
|
|
258
|
+
async #getReport () {
|
|
278
259
|
// if we're not auditing, just return false
|
|
279
260
|
if (this.options.audit === false || this.options.offline === true || this.tree.inventory.size === 1) {
|
|
280
261
|
return null
|
|
@@ -282,7 +263,7 @@ class AuditReport extends Map {
|
|
|
282
263
|
|
|
283
264
|
const timeEnd = time.start('auditReport:getReport')
|
|
284
265
|
try {
|
|
285
|
-
const body = prepareBulkData(
|
|
266
|
+
const body = this.prepareBulkData()
|
|
286
267
|
log.silly('audit', 'bulk request', body)
|
|
287
268
|
|
|
288
269
|
// no sense asking if we don't have anything to audit,
|
|
@@ -309,37 +290,39 @@ class AuditReport extends Map {
|
|
|
309
290
|
timeEnd()
|
|
310
291
|
}
|
|
311
292
|
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// return true if we should audit this one
|
|
315
|
-
const shouldAudit = (node, omit, filterSet) =>
|
|
316
|
-
!node.version ? false
|
|
317
|
-
: node.isRoot ? false
|
|
318
|
-
: filterSet && filterSet.size !== 0 && !filterSet.has(node) ? false
|
|
319
|
-
: omit.size === 0 ? true
|
|
320
|
-
: !( // otherwise, just ensure we're not omitting this one
|
|
321
|
-
node.dev && omit.has('dev') ||
|
|
322
|
-
node.optional && omit.has('optional') ||
|
|
323
|
-
node.devOptional && omit.has('dev') && omit.has('optional') ||
|
|
324
|
-
node.peer && omit.has('peer')
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
const prepareBulkData = (tree, omit, filterSet) => {
|
|
328
|
-
const payload = {}
|
|
329
|
-
for (const name of tree.inventory.query('packageName')) {
|
|
330
|
-
const set = new Set()
|
|
331
|
-
for (const node of tree.inventory.query('packageName', name)) {
|
|
332
|
-
if (!shouldAudit(node, omit, filterSet)) {
|
|
333
|
-
continue
|
|
334
|
-
}
|
|
335
293
|
|
|
336
|
-
|
|
294
|
+
// return true if we should audit this one
|
|
295
|
+
shouldAudit (node) {
|
|
296
|
+
if (
|
|
297
|
+
!node.version ||
|
|
298
|
+
node.isRoot ||
|
|
299
|
+
(this.filterSet && this.filterSet?.size !== 0 && !this.filterSet?.has(node))
|
|
300
|
+
) {
|
|
301
|
+
return false
|
|
337
302
|
}
|
|
338
|
-
if (
|
|
339
|
-
|
|
303
|
+
if (this.#omit.size === 0) {
|
|
304
|
+
return true
|
|
305
|
+
}
|
|
306
|
+
return !node.shouldOmit(this.#omit)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
prepareBulkData () {
|
|
310
|
+
const payload = {}
|
|
311
|
+
for (const name of this.tree.inventory.query('packageName')) {
|
|
312
|
+
const set = new Set()
|
|
313
|
+
for (const node of this.tree.inventory.query('packageName', name)) {
|
|
314
|
+
if (!this.shouldAudit(node)) {
|
|
315
|
+
continue
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
set.add(node.version)
|
|
319
|
+
}
|
|
320
|
+
if (set.size) {
|
|
321
|
+
payload[name] = [...set]
|
|
322
|
+
}
|
|
340
323
|
}
|
|
324
|
+
return payload
|
|
341
325
|
}
|
|
342
|
-
return payload
|
|
343
326
|
}
|
|
344
327
|
|
|
345
328
|
module.exports = AuditReport
|
package/lib/node.js
CHANGED
|
@@ -489,6 +489,15 @@ class Node {
|
|
|
489
489
|
return false
|
|
490
490
|
}
|
|
491
491
|
|
|
492
|
+
shouldOmit (omitSet) {
|
|
493
|
+
return (
|
|
494
|
+
this.peer && omitSet.has('peer') ||
|
|
495
|
+
this.dev && omitSet.has('dev') ||
|
|
496
|
+
this.optional && omitSet.has('optional') ||
|
|
497
|
+
this.devOptional && omitSet.has('optional') && omitSet.has('dev')
|
|
498
|
+
)
|
|
499
|
+
}
|
|
500
|
+
|
|
492
501
|
getBundler (path = []) {
|
|
493
502
|
// made a cycle, definitely not bundled!
|
|
494
503
|
if (path.includes(this)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/arborist",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.4",
|
|
4
4
|
"description": "Manage node_modules trees",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@isaacs/string-locale-compare": "^1.1.0",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@npmcli/eslint-config": "^5.0.1",
|
|
43
43
|
"@npmcli/mock-registry": "^1.0.0",
|
|
44
|
-
"@npmcli/template-oss": "4.
|
|
44
|
+
"@npmcli/template-oss": "4.24.4",
|
|
45
45
|
"benchmark": "^2.1.4",
|
|
46
46
|
"minify-registry-metadata": "^4.0.0",
|
|
47
47
|
"nock": "^13.3.3",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
},
|
|
94
94
|
"templateOSS": {
|
|
95
95
|
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
|
|
96
|
-
"version": "4.
|
|
96
|
+
"version": "4.24.4",
|
|
97
97
|
"content": "../../scripts/template-oss/index.js"
|
|
98
98
|
}
|
|
99
99
|
}
|