@npmcli/config 10.9.1 → 10.11.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.
@@ -1,4 +1,5 @@
1
1
  const Definition = require('./definition.js')
2
+ const parseAllowScriptsList = require('../parse-allow-scripts-list.js')
2
3
 
3
4
  const ciInfo = require('ci-info')
4
5
  const querystring = require('node:querystring')
@@ -153,7 +154,7 @@ const definitions = {
153
154
  defaultDescription: `
154
155
  'public' for new packages, existing packages it will not change the current level
155
156
  `,
156
- type: [null, 'restricted', 'public'],
157
+ type: [null, 'restricted', 'public', 'private'],
157
158
  description: `
158
159
  If you do not want your scoped package to be publicly viewable (and
159
160
  installable) set \`--access=restricted\`.
@@ -164,17 +165,23 @@ const definitions = {
164
165
  packages. Specifying a value of \`restricted\` or \`public\` during
165
166
  publish will change the access for an existing package the same way that
166
167
  \`npm access set status\` would.
168
+
169
+ The value \`private\` is an alias for \`restricted\`.
167
170
  `,
168
- flatten,
171
+ flatten (key, obj, flatOptions) {
172
+ const value = obj[key]
173
+ flatOptions.access = value === 'private' ? 'restricted' : value
174
+ },
169
175
  }),
170
176
  all: new Definition('all', {
171
177
  default: false,
172
178
  type: Boolean,
173
179
  short: 'a',
174
180
  description: `
175
- When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show
176
- all outdated or installed packages, rather than only those directly
177
- depended upon by the current project.
181
+ Show or act on all packages, not just the ones your project directly
182
+ depends on. For \`npm outdated\` and \`npm ls\` this lists every outdated
183
+ or installed package. For \`npm approve-scripts\` and \`npm deny-scripts\`
184
+ it selects every package with pending install scripts.
178
185
  `,
179
186
  flatten,
180
187
  }),
@@ -247,6 +254,31 @@ const definitions = {
247
254
  `,
248
255
  flatten,
249
256
  }),
257
+ 'allow-scripts': new Definition('allow-scripts', {
258
+ default: '',
259
+ type: [String, Array],
260
+ hint: '<package-list>',
261
+ description: `
262
+ Comma-separated list of packages whose install-time lifecycle scripts
263
+ (\`preinstall\`, \`install\`, \`postinstall\`, and \`prepare\` for
264
+ non-registry dependencies) are allowed to run.
265
+
266
+ This setting is intended for one-off and global contexts: \`npm exec\`,
267
+ \`npx\`, and \`npm install -g\`, where no project \`package.json\` is
268
+ involved. For team-wide policy in a project, use the \`allowScripts\`
269
+ field in \`package.json\` (which also supports explicit denials), or
270
+ configure it in \`.npmrc\`. Passing \`--allow-scripts\` on the command
271
+ line during a project-scoped \`npm install\`, \`ci\`, \`update\`, or
272
+ \`rebuild\` is an error.
273
+
274
+ Each name is matched against a dependency's resolved identity, not
275
+ against the package's self-reported name. \`--ignore-scripts\` and
276
+ \`--dangerously-allow-all-scripts\` both override this setting.
277
+ `,
278
+ flatten (key, obj, flatOptions) {
279
+ flatOptions.allowScripts = parseAllowScriptsList(obj[key])
280
+ },
281
+ }),
250
282
  also: new Definition('also', {
251
283
  default: null,
252
284
  type: [null, 'dev', 'development'],
@@ -308,6 +340,9 @@ const definitions = {
308
340
  Across sources, the standard precedence applies (cli > env > project >
309
341
  user > global), so a higher-priority source can always relax or
310
342
  override a lower-priority one.
343
+
344
+ Packages whose names match \`min-release-age-exclude\` are exempt from
345
+ this filter.
311
346
  `,
312
347
  flatten,
313
348
  }),
@@ -535,6 +570,18 @@ const definitions = {
535
570
  `,
536
571
  flatten,
537
572
  }),
573
+ 'dangerously-allow-all-scripts': new Definition('dangerously-allow-all-scripts', {
574
+ default: false,
575
+ type: Boolean,
576
+ description: `
577
+ If \`true\`, bypass the \`allowScripts\` policy entirely and run every
578
+ dependency install script regardless of whether it was approved or
579
+ denied. Intended as a migration escape hatch only; its use is strongly
580
+ discouraged. \`--ignore-scripts\` still takes precedence over this
581
+ setting.
582
+ `,
583
+ flatten,
584
+ }),
538
585
  depth: new Definition('depth', {
539
586
  default: null,
540
587
  defaultDescription: `
@@ -1427,6 +1474,9 @@ const definitions = {
1427
1474
  spawns a sub-process with \`--before\` while preparing a \`git:\` or
1428
1475
  \`github:\` dependency); when both apply, \`before\` wins within a
1429
1476
  single source and across sources the standard precedence rules apply.
1477
+
1478
+ Packages whose names match \`min-release-age-exclude\` are exempt from
1479
+ this filter.
1430
1480
  `,
1431
1481
  flatten: (key, obj, flatOptions) => {
1432
1482
  const age = obj['min-release-age']
@@ -1437,6 +1487,45 @@ const definitions = {
1437
1487
  }
1438
1488
  },
1439
1489
  }),
1490
+ 'min-release-age-exclude': new Definition('min-release-age-exclude', {
1491
+ default: [],
1492
+ hint: '<pkg|glob>',
1493
+ type: [Array, String],
1494
+ envExport: false,
1495
+ description: `
1496
+ A list of package names or \`minimatch\` glob patterns that are exempt
1497
+ from the \`min-release-age\` (and \`before\`) filter. A matching package
1498
+ can always resolve to its newest version, even when a release-age window
1499
+ is set.
1500
+
1501
+ For example, to apply a release-age window to third-party dependencies
1502
+ while letting internally maintained packages update immediately:
1503
+
1504
+ \`\`\`
1505
+ min-release-age=7
1506
+ min-release-age-exclude[]=@myorg/*
1507
+ min-release-age-exclude[]=my-internal-pkg
1508
+ \`\`\`
1509
+
1510
+ Only the named package is exempt; its own dependencies still follow the
1511
+ release-age policy unless they also match a pattern. Patterns match
1512
+ against the package name, so \`@myorg/*\` matches \`@myorg/shared-utils\`.
1513
+
1514
+ Excluding a package does not change which registry it is fetched from. You
1515
+ should own your private scope on the public registry so that nobody else
1516
+ can publish a package with the same name.
1517
+ `,
1518
+ flatten: (key, obj, flatOptions) => {
1519
+ // The config layer always resolves this to an array (nopt and .npmrc both
1520
+ // coerce `[Array, String]` to a list, default `[]`), so treat it as one.
1521
+ // A single value may still pack multiple names as a comma string.
1522
+ const list = obj[key]
1523
+ .flatMap(v => String(v).split(','))
1524
+ .map(v => v.trim())
1525
+ .filter(Boolean)
1526
+ flatOptions.minReleaseAgeExclude = [...new Set(list)]
1527
+ },
1528
+ }),
1440
1529
  'node-gyp': new Definition('node-gyp', {
1441
1530
  default: (() => {
1442
1531
  try {
@@ -1667,6 +1756,27 @@ const definitions = {
1667
1756
  `,
1668
1757
  flatten,
1669
1758
  }),
1759
+ 'allow-scripts-pending': new Definition('allow-scripts-pending', {
1760
+ default: false,
1761
+ type: Boolean,
1762
+ description: `
1763
+ List packages with install scripts that are not yet covered by the
1764
+ \`allowScripts\` policy, without modifying \`package.json\`. Only
1765
+ meaningful for \`npm approve-scripts\`.
1766
+ `,
1767
+ flatten,
1768
+ }),
1769
+ 'allow-scripts-pin': new Definition('allow-scripts-pin', {
1770
+ default: true,
1771
+ type: Boolean,
1772
+ description: `
1773
+ Write pinned (\`pkg@version\`) entries when approving install scripts.
1774
+ Set to \`false\` to write name-only entries that allow any version.
1775
+ Has no effect on \`npm deny-scripts\`, which always writes name-only
1776
+ entries regardless of this setting.
1777
+ `,
1778
+ flatten,
1779
+ }),
1670
1780
  'prefer-dedupe': new Definition('prefer-dedupe', {
1671
1781
  default: false,
1672
1782
  type: Boolean,
@@ -2238,6 +2348,22 @@ const definitions = {
2238
2348
  `,
2239
2349
  flatten,
2240
2350
  }),
2351
+ 'strict-allow-scripts': new Definition('strict-allow-scripts', {
2352
+ default: false,
2353
+ type: Boolean,
2354
+ description: `
2355
+ If \`true\`, turn the install-script policy from a warning into a hard
2356
+ error: any dependency with install scripts not covered by
2357
+ \`allowScripts\` will fail the install instead of running with a
2358
+ notice.
2359
+
2360
+ Dependencies explicitly denied with \`false\` in \`allowScripts\` are
2361
+ always silently skipped; this setting only affects unreviewed entries.
2362
+ \`--ignore-scripts\` and \`--dangerously-allow-all-scripts\` both
2363
+ override this setting.
2364
+ `,
2365
+ flatten,
2366
+ }),
2241
2367
  'strict-ssl': new Definition('strict-ssl', {
2242
2368
  default: true,
2243
2369
  type: Boolean,
@@ -2258,13 +2384,13 @@ const definitions = {
2258
2384
  If you ask npm to install a package and don't tell it a specific version,
2259
2385
  then it will install the specified tag.
2260
2386
 
2261
- It is the tag added to the package@version specified in the
2387
+ It is the tag added to the package@version specified in the
2262
2388
  \`npm dist-tag add\` command, if no explicit tag is given.
2263
2389
 
2264
2390
  When used by the \`npm diff\` command, this is the tag used to fetch the
2265
2391
  tarball that will be compared with the local files by default.
2266
-
2267
- If used in the \`npm publish\` command, this is the tag that will be
2392
+
2393
+ If used in the \`npm publish\` command, this is the tag that will be
2268
2394
  added to the package submitted to the registry.
2269
2395
  `,
2270
2396
  flatten (key, obj, flatOptions) {
@@ -2373,6 +2499,36 @@ const definitions = {
2373
2499
  flatten (key, obj, flatOptions) {
2374
2500
  const value = obj[key]
2375
2501
  const ciName = ciInfo.name?.toLowerCase().split(' ').join('-') || null
2502
+ // A more specific sub-category for the detected CI, appended to the
2503
+ // ci token as `ci/{ci-name}/{sub-ci-name}` when present.
2504
+ let subCiName = null
2505
+ if (ciInfo.GITHUB_ACTIONS) {
2506
+ // Env vars can be absent, empty, or whitespace; normalize before use.
2507
+ const serverUrl = (process.env.GITHUB_SERVER_URL || '').trim()
2508
+ const runnerEnv = (process.env.RUNNER_ENVIRONMENT || '').trim()
2509
+ let serverHost = ''
2510
+ try {
2511
+ serverHost = new URL(serverUrl).hostname.toLowerCase()
2512
+ } catch {
2513
+ serverHost = ''
2514
+ }
2515
+ if (serverHost === 'github.com') {
2516
+ if (runnerEnv === 'github-hosted') {
2517
+ subCiName = 'dotcom-hosted'
2518
+ } else if (runnerEnv === 'self-hosted') {
2519
+ subCiName = 'dotcom-selfhosted'
2520
+ } else {
2521
+ subCiName = 'dotcom'
2522
+ }
2523
+ } else if (serverHost === 'ghe.com' || serverHost.endsWith('.ghe.com')) {
2524
+ subCiName = 'ghecom'
2525
+ } else if (serverHost) {
2526
+ subCiName = 'ghes'
2527
+ }
2528
+ }
2529
+ const ci = ciName
2530
+ ? `ci/${ciName}${subCiName ? `/${subCiName}` : ''}`
2531
+ : ''
2376
2532
  let inWorkspaces = false
2377
2533
  if (obj.workspaces || obj.workspace && obj.workspace.length) {
2378
2534
  inWorkspaces = true
@@ -2383,7 +2539,7 @@ const definitions = {
2383
2539
  .replace(/\{platform\}/gi, process.platform)
2384
2540
  .replace(/\{arch\}/gi, process.arch)
2385
2541
  .replace(/\{workspaces\}/gi, inWorkspaces)
2386
- .replace(/\{ci\}/gi, ciName ? `ci/${ciName}` : '')
2542
+ .replace(/\{ci\}/gi, ci)
2387
2543
  .trim()
2388
2544
 
2389
2545
  // We can't clobber the original or else subsequent flattening will fail
@@ -0,0 +1,23 @@
1
+ // Parse an `allow-scripts` raw config value (string or array of strings)
2
+ // into a flat array of trimmed package-spec entries. Shared between the
3
+ // CLI/env layer (via the `allow-scripts` definition's `flatten`) and the
4
+ // package.json / .npmrc layer (in lib/utils/resolve-allow-scripts.js) so
5
+ // both paths agree on quoting, whitespace, and duplicate handling.
6
+ const parseAllowScriptsList = (raw) => {
7
+ const parts = []
8
+ const entries = Array.isArray(raw) ? raw : (typeof raw === 'string' ? [raw] : [])
9
+ for (const entry of entries) {
10
+ if (typeof entry !== 'string') {
11
+ continue
12
+ }
13
+ for (const part of entry.split(',')) {
14
+ const trimmed = part.trim()
15
+ if (trimmed) {
16
+ parts.push(trimmed)
17
+ }
18
+ }
19
+ }
20
+ return parts
21
+ }
22
+
23
+ module.exports = parseAllowScriptsList
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npmcli/config",
3
- "version": "10.9.1",
3
+ "version": "10.11.0",
4
4
  "files": [
5
5
  "bin/",
6
6
  "lib/"