@npmcli/config 2.4.0 → 3.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.
@@ -3,11 +3,12 @@
3
3
  const envExpr = /(\\*)\$\{([^}]+)\}/g
4
4
 
5
5
  module.exports = (f, env) => f.replace(envExpr, (orig, esc, name) => {
6
- const val = env[name] !== undefined ? env[name] : `\$\{${name}\}`
6
+ const val = env[name] !== undefined ? env[name] : `$\{${name}}`
7
7
 
8
8
  // consume the escape chars that are relevant.
9
- if (esc.length % 2)
9
+ if (esc.length % 2) {
10
10
  return orig.substr((esc.length + 1) / 2)
11
+ }
11
12
 
12
13
  return (esc.substr(esc.length / 2)) + val
13
14
  })
package/lib/index.js CHANGED
@@ -3,6 +3,8 @@ const walkUp = require('walk-up-path')
3
3
  const ini = require('ini')
4
4
  const nopt = require('nopt')
5
5
  const mkdirp = require('mkdirp-infer-owner')
6
+ const mapWorkspaces = require('@npmcli/map-workspaces')
7
+ const rpj = require('read-package-json-fast')
6
8
 
7
9
  /* istanbul ignore next */
8
10
  const myUid = process.getuid && process.getuid()
@@ -91,7 +93,6 @@ class Config {
91
93
  execPath = process.execPath,
92
94
  cwd = process.cwd(),
93
95
  }) {
94
-
95
96
  // turn the definitions into nopt's weirdo syntax
96
97
  this.definitions = definitions
97
98
  const types = {}
@@ -100,8 +101,9 @@ class Config {
100
101
  for (const [key, def] of Object.entries(definitions)) {
101
102
  defaults[key] = def.default
102
103
  types[key] = def.type
103
- if (def.deprecated)
104
+ if (def.deprecated) {
104
105
  this.deprecated[key] = def.deprecated.trim().replace(/\n +/, '\n')
106
+ }
105
107
  }
106
108
 
107
109
  // populated the first time we flatten the object
@@ -162,41 +164,48 @@ class Config {
162
164
 
163
165
  // return the location where key is found.
164
166
  find (key) {
165
- if (!this.loaded)
167
+ if (!this.loaded) {
166
168
  throw new Error('call config.load() before reading values')
169
+ }
167
170
  return this[_find](key)
168
171
  }
172
+
169
173
  [_find] (key) {
170
174
  // have to look in reverse order
171
175
  const entries = [...this.data.entries()]
172
176
  for (let i = entries.length - 1; i > -1; i--) {
173
177
  const [where, { data }] = entries[i]
174
- if (hasOwnProperty(data, key))
178
+ if (hasOwnProperty(data, key)) {
175
179
  return where
180
+ }
176
181
  }
177
182
  return null
178
183
  }
179
184
 
180
185
  get (key, where) {
181
- if (!this.loaded)
186
+ if (!this.loaded) {
182
187
  throw new Error('call config.load() before reading values')
188
+ }
183
189
  return this[_get](key, where)
184
190
  }
191
+
185
192
  // we need to get values sometimes, so use this internal one to do so
186
193
  // while in the process of loading.
187
194
  [_get] (key, where = null) {
188
195
  if (where !== null && !confTypes.has(where)) {
189
196
  throw new Error('invalid config location param: ' + where)
190
197
  }
191
- const { data, source } = this.data.get(where || 'cli')
198
+ const { data } = this.data.get(where || 'cli')
192
199
  return where === null || hasOwnProperty(data, key) ? data[key] : undefined
193
200
  }
194
201
 
195
202
  set (key, val, where = 'cli') {
196
- if (!this.loaded)
203
+ if (!this.loaded) {
197
204
  throw new Error('call config.load() before setting values')
198
- if (!confTypes.has(where))
205
+ }
206
+ if (!confTypes.has(where)) {
199
207
  throw new Error('invalid config location param: ' + where)
208
+ }
200
209
  this[_checkDeprecated](key)
201
210
  const { data } = this.data.get(where)
202
211
  data[key] = val
@@ -209,8 +218,9 @@ class Config {
209
218
  }
210
219
 
211
220
  get flat () {
212
- if (this[_flatOptions])
221
+ if (this[_flatOptions]) {
213
222
  return this[_flatOptions]
223
+ }
214
224
 
215
225
  // create the object for flat options passed to deps
216
226
  process.emit('time', 'config:load:flatten')
@@ -225,16 +235,19 @@ class Config {
225
235
  }
226
236
 
227
237
  delete (key, where = 'cli') {
228
- if (!this.loaded)
238
+ if (!this.loaded) {
229
239
  throw new Error('call config.load() before deleting values')
230
- if (!confTypes.has(where))
240
+ }
241
+ if (!confTypes.has(where)) {
231
242
  throw new Error('invalid config location param: ' + where)
243
+ }
232
244
  delete this.data.get(where).data[key]
233
245
  }
234
246
 
235
247
  async load () {
236
- if (this.loaded)
248
+ if (this.loaded) {
237
249
  throw new Error('attempting to load npm config multiple times')
250
+ }
238
251
 
239
252
  process.emit('time', 'config:load')
240
253
  // first load the defaults, which sets the global prefix
@@ -282,7 +295,9 @@ class Config {
282
295
  const creds = this.getCredentialsByURI(reg)
283
296
  // ignore this error because a failed set will strip out anything that
284
297
  // might be a security hazard, which was the intention.
285
- try { this.setCredentialsByURI(reg, creds) } catch (_) {}
298
+ try {
299
+ this.setCredentialsByURI(reg, creds)
300
+ } catch (_) {}
286
301
  process.emit('timeEnd', 'config:load:credentials')
287
302
 
288
303
  // set proper globalPrefix now that everything is loaded
@@ -319,14 +334,16 @@ class Config {
319
334
  }
320
335
 
321
336
  loadHome () {
322
- if (this.env.HOME)
337
+ if (this.env.HOME) {
323
338
  return this.home = this.env.HOME
339
+ }
324
340
  this.home = homedir()
325
341
  }
326
342
 
327
343
  loadGlobalPrefix () {
328
- if (this.globalPrefix)
344
+ if (this.globalPrefix) {
329
345
  throw new Error('cannot load default global prefix more than once')
346
+ }
330
347
 
331
348
  if (this.env.PREFIX) {
332
349
  this.globalPrefix = this.env.PREFIX
@@ -338,17 +355,18 @@ class Config {
338
355
  this.globalPrefix = dirname(dirname(this.execPath))
339
356
 
340
357
  // destdir only is respected on Unix
341
- if (this.env.DESTDIR)
358
+ if (this.env.DESTDIR) {
342
359
  this.globalPrefix = join(this.env.DESTDIR, this.globalPrefix)
360
+ }
343
361
  }
344
362
  }
345
363
 
346
364
  loadEnv () {
347
- const prefix = 'npm_config_'
348
365
  const conf = Object.create(null)
349
366
  for (const [envKey, envVal] of Object.entries(this.env)) {
350
- if (!/^npm_config_/i.test(envKey) || envVal === '')
367
+ if (!/^npm_config_/i.test(envKey) || envVal === '') {
351
368
  continue
369
+ }
352
370
  const key = envKey.substr('npm_config_'.length)
353
371
  .replace(/(?!^)_/g, '-') // don't replace _ at the start of the key
354
372
  .toLowerCase()
@@ -368,9 +386,10 @@ class Config {
368
386
  }
369
387
 
370
388
  get valid () {
371
- for (const [where, {valid}] of this.data.entries()) {
372
- if (valid === false || valid === null && !this.validate(where))
389
+ for (const [where, { valid }] of this.data.entries()) {
390
+ if (valid === false || valid === null && !this.validate(where)) {
373
391
  return false
392
+ }
374
393
  }
375
394
  return true
376
395
  }
@@ -378,11 +397,12 @@ class Config {
378
397
  validate (where) {
379
398
  if (!where) {
380
399
  let valid = true
381
- for (const [where, obj] of this.data.entries()) {
400
+ for (const [where] of this.data.entries()) {
382
401
  // no need to validate our defaults, we know they're fine
383
402
  // cli was already validated when parsed the first time
384
- if (where === 'default' || where === 'builtin' || where === 'cli')
403
+ if (where === 'default' || where === 'builtin' || where === 'cli') {
385
404
  continue
405
+ }
386
406
  const ret = this.validate(where)
387
407
  valid = valid && ret
388
408
  }
@@ -424,14 +444,15 @@ class Config {
424
444
  this.data.get(where)[_valid] = false
425
445
 
426
446
  if (Array.isArray(type)) {
427
- if (type.includes(typeDefs.url.type))
447
+ if (type.includes(typeDefs.url.type)) {
428
448
  type = typeDefs.url.type
429
- else {
449
+ } else {
430
450
  /* istanbul ignore if - no actual configs matching this, but
431
451
  * path types SHOULD be handled this way, like URLs, for the
432
452
  * same reason */
433
- if (type.includes(typeDefs.path.type))
453
+ if (type.includes(typeDefs.path.type)) {
434
454
  type = typeDefs.path.type
455
+ }
435
456
  }
436
457
  }
437
458
 
@@ -469,15 +490,17 @@ class Config {
469
490
  this.sources.set(source, where)
470
491
  if (er) {
471
492
  conf.loadError = er
472
- if (er.code !== 'ENOENT')
493
+ if (er.code !== 'ENOENT') {
473
494
  this.log.verbose('config', `error loading ${where} config`, er)
495
+ }
474
496
  } else {
475
497
  conf.raw = obj
476
498
  for (const [key, value] of Object.entries(obj)) {
477
499
  const k = envReplace(key, this.env)
478
500
  const v = this.parseField(value, k)
479
- if (where !== 'default')
501
+ if (where !== 'default') {
480
502
  this[_checkDeprecated](k, where, obj, [key, value])
503
+ }
481
504
  conf.data[k] = v
482
505
  }
483
506
  }
@@ -528,9 +551,9 @@ class Config {
528
551
  // up loading the "project" config where the "userconfig" will be,
529
552
  // which causes some calamaties. So, we only load project config if
530
553
  // it doesn't match what the userconfig will be.
531
- if (projectFile !== this[_get]('userconfig'))
554
+ if (projectFile !== this[_get]('userconfig')) {
532
555
  return this[_loadFile](projectFile, 'project')
533
- else {
556
+ } else {
534
557
  this.data.get('project').source = '(same as "user" config, ignored)'
535
558
  this.sources.set(this.data.get('project').source, 'project')
536
559
  }
@@ -543,23 +566,65 @@ class Config {
543
566
  return
544
567
  }
545
568
 
569
+ const cliWorkspaces = this[_get]('workspaces', 'cli')
570
+
546
571
  for (const p of walkUp(this.cwd)) {
547
- // walk up until we have a nm dir or a pj file
548
- const hasAny = (await Promise.all([
549
- stat(resolve(p, 'node_modules'))
550
- .then(st => st.isDirectory())
551
- .catch(() => false),
552
- stat(resolve(p, 'package.json'))
553
- .then(st => st.isFile())
554
- .catch(() => false),
555
- ])).some(is => is)
556
- if (hasAny) {
572
+ const hasNodeModules = await stat(resolve(p, 'node_modules'))
573
+ .then((st) => st.isDirectory())
574
+ .catch(() => false)
575
+
576
+ const hasPackageJson = await stat(resolve(p, 'package.json'))
577
+ .then((st) => st.isFile())
578
+ .catch(() => false)
579
+
580
+ if (!this.localPrefix && (hasNodeModules || hasPackageJson)) {
557
581
  this.localPrefix = p
558
- return
582
+
583
+ // if workspaces are disabled, return now
584
+ if (cliWorkspaces === false) {
585
+ return
586
+ }
587
+
588
+ // otherwise, continue the loop
589
+ continue
590
+ }
591
+
592
+ if (this.localPrefix && hasPackageJson) {
593
+ // if we already set localPrefix but this dir has a package.json
594
+ // then we need to see if `p` is a workspace root by reading its package.json
595
+ // however, if reading it fails then we should just move on
596
+ const pkg = await rpj(resolve(p, 'package.json')).catch(() => false)
597
+ if (!pkg) {
598
+ continue
599
+ }
600
+
601
+ const workspaces = await mapWorkspaces({ cwd: p, pkg })
602
+ for (const w of workspaces.values()) {
603
+ if (w === this.localPrefix) {
604
+ // see if there's a .npmrc file in the workspace, if so log a warning
605
+ const hasNpmrc = await stat(resolve(this.localPrefix, '.npmrc'))
606
+ .then((st) => st.isFile())
607
+ .catch(() => false)
608
+
609
+ if (hasNpmrc) {
610
+ this.log.warn(`ignoring workspace config at ${this.localPrefix}/.npmrc`)
611
+ }
612
+
613
+ // set the workspace in the default layer, which allows it to be overridden easily
614
+ const { data } = this.data.get('default')
615
+ data.workspace = [this.localPrefix]
616
+ this.localPrefix = p
617
+ this.log.info(`found workspace root at ${this.localPrefix}`)
618
+ // we found a root, so we return now
619
+ return
620
+ }
621
+ }
559
622
  }
560
623
  }
561
624
 
562
- this.localPrefix = this.cwd
625
+ if (!this.localPrefix) {
626
+ this.localPrefix = this.cwd
627
+ }
563
628
  }
564
629
 
565
630
  loadUserConfig () {
@@ -571,10 +636,12 @@ class Config {
571
636
  }
572
637
 
573
638
  async save (where) {
574
- if (!this.loaded)
639
+ if (!this.loaded) {
575
640
  throw new Error('call config.load() before saving')
576
- if (!confFileTypes.has(where))
641
+ }
642
+ if (!confFileTypes.has(where)) {
577
643
  throw new Error('invalid config location param: ' + where)
644
+ }
578
645
  const conf = this.data.get(where)
579
646
  conf[_raw] = { ...conf.data }
580
647
  conf[_loadError] = null
@@ -586,7 +653,9 @@ class Config {
586
653
  // we ignore this error because the failed set already removed
587
654
  // anything that might be a security hazard, and it won't be
588
655
  // saved back to the .npmrc file, so we're good.
589
- try { this.setCredentialsByURI(reg, creds) } catch (_) {}
656
+ try {
657
+ this.setCredentialsByURI(reg, creds)
658
+ } catch (_) {}
590
659
  }
591
660
 
592
661
  const iniData = ini.stringify(conf.data).trim() + '\n'
@@ -602,8 +671,9 @@ class Config {
602
671
  /* istanbul ignore if - this is best-effort and a pita to test */
603
672
  if (myUid === 0) {
604
673
  const st = await stat(dir).catch(() => null)
605
- if (st && (st.uid !== myUid || st.gid !== myGid))
674
+ if (st && (st.uid !== myUid || st.gid !== myGid)) {
606
675
  await chown(conf.source, st.uid, st.gid).catch(() => {})
676
+ }
607
677
  }
608
678
  const mode = where === 'user' ? 0o600 : 0o666
609
679
  await chmod(conf.source, mode)
@@ -651,8 +721,9 @@ class Config {
651
721
  email = email ||
652
722
  this.get('email', 'user') ||
653
723
  this.get(`${nerfed}:email`, 'user')
654
- if (email)
724
+ if (email) {
655
725
  this.set('email', email, 'user')
726
+ }
656
727
  }
657
728
 
658
729
  // field that hasn't been used as documented for a LONG time,
@@ -668,10 +739,12 @@ class Config {
668
739
  this.delete(`${nerfed}:_password`, 'user')
669
740
  this.delete(`${nerfed}:username`, 'user')
670
741
  } else if (username || password) {
671
- if (!username)
742
+ if (!username) {
672
743
  throw new Error('must include username')
673
- if (!password)
744
+ }
745
+ if (!password) {
674
746
  throw new Error('must include password')
747
+ }
675
748
  this.delete(`${nerfed}:_authToken`, 'user')
676
749
  this.set(`${nerfed}:username`, username, 'user')
677
750
  // note: not encrypted, no idea why we bothered to do this, but oh well
@@ -689,8 +762,9 @@ class Config {
689
762
  const creds = {}
690
763
 
691
764
  const email = this.get(`${nerfed}:email`) || this.get('email')
692
- if (email)
765
+ if (email) {
693
766
  creds.email = email
767
+ }
694
768
 
695
769
  const tokenReg = this.get(`${nerfed}:_authToken`) ||
696
770
  this.get(`${nerfed}:_authtoken`) ||
@@ -725,8 +799,9 @@ class Config {
725
799
  // at this point, we can only use the values if the URI is the
726
800
  // default registry.
727
801
  const defaultNerf = nerfDart(this.get('registry'))
728
- if (nerfed !== defaultNerf)
802
+ if (nerfed !== defaultNerf) {
729
803
  return creds
804
+ }
730
805
 
731
806
  const userDef = this.get('username')
732
807
  const passDef = this.get('_password')
@@ -741,8 +816,9 @@ class Config {
741
816
  // Handle the old-style _auth=<base64> style for the default
742
817
  // registry, if set.
743
818
  const auth = this.get('_auth')
744
- if (!auth)
819
+ if (!auth) {
745
820
  return creds
821
+ }
746
822
 
747
823
  const authDecode = Buffer.from(auth, 'base64').toString('utf8')
748
824
  const authSplit = authDecode.split(':')
@@ -755,7 +831,9 @@ class Config {
755
831
  // set up the environment object we have with npm_config_* environs
756
832
  // for all configs that are different from their default values, and
757
833
  // set EDITOR and HOME.
758
- setEnvs () { setEnvs(this) }
834
+ setEnvs () {
835
+ setEnvs(this)
836
+ }
759
837
  }
760
838
 
761
839
  const _data = Symbol('data')
@@ -781,25 +859,37 @@ class ConfigData {
781
859
  }
782
860
 
783
861
  set source (s) {
784
- if (this[_source])
862
+ if (this[_source]) {
785
863
  throw new Error('cannot set ConfigData source more than once')
864
+ }
786
865
  this[_source] = s
787
866
  }
788
- get source () { return this[_source] }
867
+
868
+ get source () {
869
+ return this[_source]
870
+ }
789
871
 
790
872
  set loadError (e) {
791
- if (this[_loadError] || this[_raw])
873
+ if (this[_loadError] || this[_raw]) {
792
874
  throw new Error('cannot set ConfigData loadError after load')
875
+ }
793
876
  this[_loadError] = e
794
877
  }
795
- get loadError () { return this[_loadError] }
878
+
879
+ get loadError () {
880
+ return this[_loadError]
881
+ }
796
882
 
797
883
  set raw (r) {
798
- if (this[_raw] || this[_loadError])
884
+ if (this[_raw] || this[_loadError]) {
799
885
  throw new Error('cannot set ConfigData raw after load')
886
+ }
800
887
  this[_raw] = r
801
888
  }
802
- get raw () { return this[_raw] }
889
+
890
+ get raw () {
891
+ return this[_raw]
892
+ }
803
893
  }
804
894
 
805
895
  module.exports = Config
@@ -6,10 +6,11 @@ const { resolve } = require('path')
6
6
  const { parse: umaskParse } = require('./umask.js')
7
7
 
8
8
  const parseField = (f, key, opts, listElement = false) => {
9
- if (typeof f !== 'string' && !Array.isArray(f))
9
+ if (typeof f !== 'string' && !Array.isArray(f)) {
10
10
  return f
11
+ }
11
12
 
12
- const { platform, types, log, home, env } = opts
13
+ const { platform, types, home, env } = opts
13
14
 
14
15
  // type can be array or a single thing. coerce to array.
15
16
  const typeList = new Set([].concat(types[key]))
@@ -20,8 +21,9 @@ const parseField = (f, key, opts, listElement = false) => {
20
21
  const isNumber = typeList.has(typeDefs.Number.type)
21
22
  const isList = !listElement && typeList.has(Array)
22
23
 
23
- if (Array.isArray(f))
24
+ if (Array.isArray(f)) {
24
25
  return !isList ? f : f.map(field => parseField(field, key, opts, true))
26
+ }
25
27
 
26
28
  // now we know it's a string
27
29
  f = f.trim()
@@ -29,12 +31,14 @@ const parseField = (f, key, opts, listElement = false) => {
29
31
  // list types get put in the environment separated by double-\n
30
32
  // usually a single \n would suffice, but ca/cert configs can contain
31
33
  // line breaks and multiple entries.
32
- if (isList)
34
+ if (isList) {
33
35
  return parseField(f.split('\n\n'), key, opts)
36
+ }
34
37
 
35
38
  // --foo is like --foo=true for boolean types
36
- if (isBool && !isString && f === '')
39
+ if (isBool && !isString && f === '') {
37
40
  return true
41
+ }
38
42
 
39
43
  // string types can be the string 'true', 'false', etc.
40
44
  // otherwise, parse these values out
@@ -51,10 +55,11 @@ const parseField = (f, key, opts, listElement = false) => {
51
55
 
52
56
  if (isPath) {
53
57
  const homePattern = platform === 'win32' ? /^~(\/|\\)/ : /^~\//
54
- if (homePattern.test(f) && home)
58
+ if (homePattern.test(f) && home) {
55
59
  f = resolve(home, f.substr(2))
56
- else
60
+ } else {
57
61
  f = resolve(f)
62
+ }
58
63
  }
59
64
 
60
65
  if (isUmask) {
@@ -66,8 +71,9 @@ const parseField = (f, key, opts, listElement = false) => {
66
71
  }
67
72
  }
68
73
 
69
- if (isNumber && !isNaN(f))
74
+ if (isNumber && !isNaN(f)) {
70
75
  f = +f
76
+ }
71
77
 
72
78
  return f
73
79
  }
package/lib/set-envs.js CHANGED
@@ -22,15 +22,17 @@ const sameConfigValue = (def, val) =>
22
22
  : sameArrayValue(def, val)
23
23
 
24
24
  const sameArrayValue = (def, val) => {
25
- if (def.length !== val.length)
25
+ if (def.length !== val.length) {
26
26
  return false
27
+ }
27
28
 
28
29
  for (let i = 0; i < def.length; i++) {
29
30
  /* istanbul ignore next - there are no array configs where the default
30
31
  * is not an empty array, so this loop is a no-op, but it's the correct
31
32
  * thing to do if we ever DO add a config like that. */
32
- if (def[i] !== val[i])
33
+ if (def[i] !== val[i]) {
33
34
  return false
35
+ }
34
36
  }
35
37
  return true
36
38
  }
@@ -38,16 +40,15 @@ const sameArrayValue = (def, val) => {
38
40
  const setEnv = (env, rawKey, rawVal) => {
39
41
  const val = envVal(rawVal)
40
42
  const key = envKey(rawKey, val)
41
- if (key && val !== null)
43
+ if (key && val !== null) {
42
44
  env[key] = val
45
+ }
43
46
  }
44
47
 
45
48
  const setEnvs = (config) => {
46
49
  // This ensures that all npm config values that are not the defaults are
47
50
  // shared appropriately with child processes, without false positives.
48
51
  const {
49
- globalPrefix,
50
- platform,
51
52
  env,
52
53
  defaults,
53
54
  definitions,
@@ -68,19 +69,22 @@ const setEnvs = (config) => {
68
69
  const envSet = new Set(Object.keys(envConf))
69
70
  for (const key in cliConf) {
70
71
  const { deprecated, envExport = true } = definitions[key] || {}
71
- if (deprecated || envExport === false)
72
+ if (deprecated || envExport === false) {
72
73
  continue
74
+ }
73
75
 
74
76
  if (sameConfigValue(defaults[key], cliConf[key])) {
75
77
  // config is the default, if the env thought different, then we
76
78
  // have to set it BACK to the default in the environment.
77
- if (!sameConfigValue(envConf[key], cliConf[key]))
79
+ if (!sameConfigValue(envConf[key], cliConf[key])) {
78
80
  setEnv(env, key, cliConf[key])
81
+ }
79
82
  } else {
80
83
  // config is not the default. if the env wasn't the one to set
81
84
  // it that way, then we have to put it in the env
82
- if (!(envSet.has(key) && !cliSet.has(key)))
85
+ if (!(envSet.has(key) && !cliSet.has(key))) {
83
86
  setEnv(env, key, cliConf[key])
87
+ }
84
88
  }
85
89
  }
86
90
 
@@ -88,16 +92,19 @@ const setEnvs = (config) => {
88
92
  env.HOME = config.home
89
93
  env.npm_config_global_prefix = config.globalPrefix
90
94
  env.npm_config_local_prefix = config.localPrefix
91
- if (cliConf.editor)
95
+ if (cliConf.editor) {
92
96
  env.EDITOR = cliConf.editor
97
+ }
93
98
 
94
99
  // note: this doesn't afect the *current* node process, of course, since
95
100
  // it's already started, but it does affect the options passed to scripts.
96
- if (cliConf['node-options'])
101
+ if (cliConf['node-options']) {
97
102
  env.NODE_OPTIONS = cliConf['node-options']
103
+ }
98
104
 
99
- if (require.main && require.main.filename)
105
+ if (require.main && require.main.filename) {
100
106
  env.npm_execpath = require.main.filename
107
+ }
101
108
  env.NODE = env.npm_node_execpath = config.execPath
102
109
  }
103
110
 
package/lib/type-defs.js CHANGED
@@ -5,15 +5,17 @@ const { Umask, validate: validateUmask } = require('./umask.js')
5
5
  const semver = require('semver')
6
6
  const validateSemver = (data, k, val) => {
7
7
  const valid = semver.valid(val)
8
- if (!valid)
8
+ if (!valid) {
9
9
  return false
10
+ }
10
11
  data[k] = valid
11
12
  }
12
13
 
13
14
  const noptValidatePath = nopt.typeDefs.path.validate
14
15
  const validatePath = (data, k, val) => {
15
- if (typeof val !== 'string')
16
+ if (typeof val !== 'string') {
16
17
  return false
18
+ }
17
19
  return noptValidatePath(data, k, val)
18
20
  }
19
21
 
@@ -2,15 +2,18 @@
2
2
  // returns a string for one thing, or an array of descriptions
3
3
  const typeDefs = require('./type-defs.js')
4
4
  const typeDescription = t => {
5
- if (!t || typeof t !== 'function' && typeof t !== 'object')
5
+ if (!t || typeof t !== 'function' && typeof t !== 'object') {
6
6
  return t
7
+ }
7
8
 
8
- if (Array.isArray(t))
9
+ if (Array.isArray(t)) {
9
10
  return t.map(t => typeDescription(t))
11
+ }
10
12
 
11
13
  for (const { type, description } of Object.values(typeDefs)) {
12
- if (type === t)
14
+ if (type === t) {
13
15
  return description || type
16
+ }
14
17
  }
15
18
 
16
19
  return t
package/lib/umask.js CHANGED
@@ -1,18 +1,21 @@
1
1
  class Umask {}
2
2
  const parse = val => {
3
3
  if (typeof val === 'string') {
4
- if (/^0o?[0-7]+$/.test(val))
4
+ if (/^0o?[0-7]+$/.test(val)) {
5
5
  return parseInt(val.replace(/^0o?/, ''), 8)
6
- else if (/^[1-9][0-9]*$/.test(val))
6
+ } else if (/^[1-9][0-9]*$/.test(val)) {
7
7
  return parseInt(val, 10)
8
- else
8
+ } else {
9
9
  throw new Error(`invalid umask value: ${val}`)
10
+ }
10
11
  }
11
- if (typeof val !== 'number')
12
+ if (typeof val !== 'number') {
12
13
  throw new Error(`invalid umask value: ${val}`)
14
+ }
13
15
  val = Math.floor(val)
14
- if (val < 0 || val > 511)
16
+ if (val < 0 || val > 511) {
15
17
  throw new Error(`invalid umask value: ${val}`)
18
+ }
16
19
  return val
17
20
  }
18
21
 
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@npmcli/config",
3
- "version": "2.4.0",
3
+ "version": "3.0.0",
4
4
  "files": [
5
+ "bin",
5
6
  "lib"
6
7
  ],
7
8
  "main": "lib/index.js",
@@ -10,30 +11,41 @@
10
11
  "type": "git",
11
12
  "url": "git+https://github.com/npm/config"
12
13
  },
13
- "author": "Isaac Z. Schlueter <i@izs.me> (https://izs.me)",
14
+ "author": "GitHub Inc.",
14
15
  "license": "ISC",
15
16
  "scripts": {
16
17
  "test": "tap",
17
18
  "snap": "tap",
18
19
  "preversion": "npm test",
19
20
  "postversion": "npm publish",
20
- "prepublishOnly": "git push origin --follow-tags"
21
+ "prepublishOnly": "git push origin --follow-tags",
22
+ "lint": "eslint '**/*.js'",
23
+ "postlint": "npm-template-check",
24
+ "lintfix": "npm run lint -- --fix",
25
+ "posttest": "npm run lint",
26
+ "template-copy": "npm-template-copy --force"
21
27
  },
22
28
  "tap": {
23
29
  "check-coverage": true,
24
30
  "coverage-map": "map.js"
25
31
  },
26
32
  "devDependencies": {
33
+ "@npmcli/template-oss": "^2.5.1",
27
34
  "tap": "^15.0.4"
28
35
  },
29
36
  "dependencies": {
37
+ "@npmcli/map-workspaces": "^2.0.0",
30
38
  "ini": "^2.0.0",
31
39
  "mkdirp-infer-owner": "^2.0.0",
32
40
  "nopt": "^5.0.0",
41
+ "read-package-json-fast": "^2.0.3",
33
42
  "semver": "^7.3.4",
34
43
  "walk-up-path": "^1.0.0"
35
44
  },
36
45
  "engines": {
37
- "node": ">=10"
46
+ "node": "^12.13.0 || ^14.15.0 || >=16"
47
+ },
48
+ "templateOSS": {
49
+ "version": "2.6.0"
38
50
  }
39
51
  }