@npmcli/config 1.2.6 → 2.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/lib/index.js +78 -67
- package/lib/set-envs.js +7 -7
- package/package.json +2 -2
- package/lib/get-user-agent.js +0 -13
package/lib/index.js
CHANGED
|
@@ -47,7 +47,6 @@ const envReplace = require('./env-replace.js')
|
|
|
47
47
|
const parseField = require('./parse-field.js')
|
|
48
48
|
const typeDescription = require('./type-description.js')
|
|
49
49
|
const setEnvs = require('./set-envs.js')
|
|
50
|
-
const getUserAgent = require('./get-user-agent.js')
|
|
51
50
|
|
|
52
51
|
// types that can be saved back to
|
|
53
52
|
const confFileTypes = new Set([
|
|
@@ -69,6 +68,9 @@ const _get = Symbol('get')
|
|
|
69
68
|
const _find = Symbol('find')
|
|
70
69
|
const _loadObject = Symbol('loadObject')
|
|
71
70
|
const _loadFile = Symbol('loadFile')
|
|
71
|
+
const _checkDeprecated = Symbol('checkDeprecated')
|
|
72
|
+
const _flatten = Symbol('flatten')
|
|
73
|
+
const _flatOptions = Symbol('flatOptions')
|
|
72
74
|
|
|
73
75
|
class Config {
|
|
74
76
|
static get typeDefs () {
|
|
@@ -76,9 +78,9 @@ class Config {
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
constructor ({
|
|
79
|
-
|
|
81
|
+
definitions,
|
|
80
82
|
shorthands,
|
|
81
|
-
|
|
83
|
+
flatten,
|
|
82
84
|
npmPath,
|
|
83
85
|
|
|
84
86
|
// options just to override in tests, mostly
|
|
@@ -89,10 +91,27 @@ class Config {
|
|
|
89
91
|
execPath = process.execPath,
|
|
90
92
|
cwd = process.cwd(),
|
|
91
93
|
}) {
|
|
92
|
-
|
|
94
|
+
|
|
95
|
+
// turn the definitions into nopt's weirdo syntax
|
|
96
|
+
this.definitions = definitions
|
|
97
|
+
const types = {}
|
|
98
|
+
const defaults = {}
|
|
99
|
+
this.deprecated = {}
|
|
100
|
+
for (const [key, def] of Object.entries(definitions)) {
|
|
101
|
+
defaults[key] = def.default
|
|
102
|
+
types[key] = def.type
|
|
103
|
+
if (def.deprecated)
|
|
104
|
+
this.deprecated[key] = def.deprecated.trim().replace(/\n +/, '\n')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// populated the first time we flatten the object
|
|
108
|
+
this[_flatOptions] = null
|
|
109
|
+
this[_flatten] = flatten
|
|
93
110
|
this.types = types
|
|
94
111
|
this.shorthands = shorthands
|
|
95
112
|
this.defaults = defaults
|
|
113
|
+
|
|
114
|
+
this.npmPath = npmPath
|
|
96
115
|
this.log = log
|
|
97
116
|
this.argv = argv
|
|
98
117
|
this.env = env
|
|
@@ -178,10 +197,36 @@ class Config {
|
|
|
178
197
|
throw new Error('call config.load() before setting values')
|
|
179
198
|
if (!confTypes.has(where))
|
|
180
199
|
throw new Error('invalid config location param: ' + where)
|
|
181
|
-
|
|
200
|
+
if (key === '_auth') {
|
|
201
|
+
const { email } = this.getCredentialsByURI(this.get('registry'))
|
|
202
|
+
if (!email)
|
|
203
|
+
throw new Error('Cannot set _auth without first setting email')
|
|
204
|
+
}
|
|
205
|
+
this[_checkDeprecated](key)
|
|
206
|
+
const { data } = this.data.get(where)
|
|
207
|
+
data[key] = val
|
|
182
208
|
|
|
183
209
|
// this is now dirty, the next call to this.valid will have to check it
|
|
184
210
|
this.data.get(where)[_valid] = null
|
|
211
|
+
|
|
212
|
+
// the flat options are invalidated, regenerate next time they're needed
|
|
213
|
+
this[_flatOptions] = null
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
get flat () {
|
|
217
|
+
if (this[_flatOptions])
|
|
218
|
+
return this[_flatOptions]
|
|
219
|
+
|
|
220
|
+
// create the object for flat options passed to deps
|
|
221
|
+
process.emit('time', 'config:load:flatten')
|
|
222
|
+
this[_flatOptions] = {}
|
|
223
|
+
// walk from least priority to highest
|
|
224
|
+
for (const { data } of this.data.values()) {
|
|
225
|
+
this[_flatten](data, this[_flatOptions])
|
|
226
|
+
}
|
|
227
|
+
process.emit('timeEnd', 'config:load:flatten')
|
|
228
|
+
|
|
229
|
+
return this[_flatOptions]
|
|
185
230
|
}
|
|
186
231
|
|
|
187
232
|
delete (key, where = 'cli') {
|
|
@@ -228,11 +273,6 @@ class Config {
|
|
|
228
273
|
await this.loadGlobalConfig()
|
|
229
274
|
process.emit('timeEnd', 'config:load:global')
|
|
230
275
|
|
|
231
|
-
// now the extras
|
|
232
|
-
process.emit('time', 'config:load:cafile')
|
|
233
|
-
await this.loadCAFile()
|
|
234
|
-
process.emit('timeEnd', 'config:load:cafile')
|
|
235
|
-
|
|
236
276
|
// warn if anything is not valid
|
|
237
277
|
process.emit('time', 'config:load:validate')
|
|
238
278
|
this.validate()
|
|
@@ -245,10 +285,6 @@ class Config {
|
|
|
245
285
|
// set proper globalPrefix now that everything is loaded
|
|
246
286
|
this.globalPrefix = this.get('prefix')
|
|
247
287
|
|
|
248
|
-
process.emit('time', 'config:load:setUserAgent')
|
|
249
|
-
this.setUserAgent()
|
|
250
|
-
process.emit('timeEnd', 'config:load:setUserAgent')
|
|
251
|
-
|
|
252
288
|
process.emit('time', 'config:load:setEnvs')
|
|
253
289
|
this.setEnvs()
|
|
254
290
|
process.emit('timeEnd', 'config:load:setEnvs')
|
|
@@ -371,13 +407,13 @@ class Config {
|
|
|
371
407
|
this.data.get(where)[_valid] = false
|
|
372
408
|
|
|
373
409
|
if (Array.isArray(type)) {
|
|
374
|
-
if (type.
|
|
410
|
+
if (type.includes(typeDefs.url.type))
|
|
375
411
|
type = typeDefs.url.type
|
|
376
412
|
else {
|
|
377
413
|
/* istanbul ignore if - no actual configs matching this, but
|
|
378
414
|
* path types SHOULD be handled this way, like URLs, for the
|
|
379
415
|
* same reason */
|
|
380
|
-
if (type.
|
|
416
|
+
if (type.includes(typeDefs.path.type))
|
|
381
417
|
type = typeDefs.path.type
|
|
382
418
|
}
|
|
383
419
|
}
|
|
@@ -423,11 +459,21 @@ class Config {
|
|
|
423
459
|
for (const [key, value] of Object.entries(obj)) {
|
|
424
460
|
const k = envReplace(key, this.env)
|
|
425
461
|
const v = this.parseField(value, k)
|
|
462
|
+
if (where !== 'default')
|
|
463
|
+
this[_checkDeprecated](k, where, obj, [key, value])
|
|
426
464
|
conf.data[k] = v
|
|
427
465
|
}
|
|
428
466
|
}
|
|
429
467
|
}
|
|
430
468
|
|
|
469
|
+
[_checkDeprecated] (key, where, obj, kv) {
|
|
470
|
+
// XXX a future npm version will make this a warning.
|
|
471
|
+
// An even more future npm version will make this an error.
|
|
472
|
+
if (this.deprecated[key]) {
|
|
473
|
+
this.log.verbose('config', key, this.deprecated[key])
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
431
477
|
// Parse a field, coercing it to the best type available.
|
|
432
478
|
parseField (f, key, listElement = false) {
|
|
433
479
|
return parseField(f, key, this, listElement)
|
|
@@ -512,6 +558,9 @@ class Config {
|
|
|
512
558
|
if (where === 'user') {
|
|
513
559
|
const reg = this.get('registry')
|
|
514
560
|
const creds = this.getCredentialsByURI(reg)
|
|
561
|
+
// we ignore this error because the failed set already removed
|
|
562
|
+
// anything that might be a security hazard, and it won't be
|
|
563
|
+
// saved back to the .npmrc file, so we're good.
|
|
515
564
|
try { this.setCredentialsByURI(reg, creds) } catch (_) {}
|
|
516
565
|
}
|
|
517
566
|
|
|
@@ -576,18 +625,22 @@ class Config {
|
|
|
576
625
|
this.delete(`${nerfed}:email`, 'user')
|
|
577
626
|
this.delete(`${nerfed}:always-auth`, 'user')
|
|
578
627
|
} else if (username || password || email) {
|
|
579
|
-
if (
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
628
|
+
if (username || password) {
|
|
629
|
+
if (!username)
|
|
630
|
+
throw new Error('must include username')
|
|
631
|
+
if (!password)
|
|
632
|
+
throw new Error('must include password')
|
|
633
|
+
}
|
|
583
634
|
if (!email)
|
|
584
635
|
throw new Error('must include email')
|
|
585
636
|
this.delete(`${nerfed}:_authToken`, 'user')
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
637
|
+
if (username || password) {
|
|
638
|
+
this.set(`${nerfed}:username`, username, 'user')
|
|
639
|
+
// note: not encrypted, no idea why we bothered to do this, but oh well
|
|
640
|
+
// protects against shoulder-hacks if password is memorable, I guess?
|
|
641
|
+
const encoded = Buffer.from(password, 'utf8').toString('base64')
|
|
642
|
+
this.set(`${nerfed}:_password`, encoded, 'user')
|
|
643
|
+
}
|
|
591
644
|
this.set(`${nerfed}:email`, email, 'user')
|
|
592
645
|
if (alwaysAuth !== undefined)
|
|
593
646
|
this.set(`${nerfed}:always-auth`, alwaysAuth, 'user')
|
|
@@ -663,48 +716,6 @@ class Config {
|
|
|
663
716
|
return creds
|
|
664
717
|
}
|
|
665
718
|
|
|
666
|
-
async loadCAFile () {
|
|
667
|
-
const where = this[_find]('cafile')
|
|
668
|
-
|
|
669
|
-
/* istanbul ignore if - it'll always be set in the defaults */
|
|
670
|
-
if (!where)
|
|
671
|
-
return
|
|
672
|
-
|
|
673
|
-
const cafile = this[_get]('cafile', where)
|
|
674
|
-
const ca = this[_get]('ca', where)
|
|
675
|
-
|
|
676
|
-
// if you have a ca, or cafile is set to null, then nothing to do here.
|
|
677
|
-
if (ca || !cafile)
|
|
678
|
-
return
|
|
679
|
-
|
|
680
|
-
const raw = await readFile(cafile, 'utf8').catch(er => {
|
|
681
|
-
if (er.code !== 'ENOENT')
|
|
682
|
-
throw er
|
|
683
|
-
})
|
|
684
|
-
if (!raw)
|
|
685
|
-
return
|
|
686
|
-
|
|
687
|
-
const delim = '-----END CERTIFICATE-----'
|
|
688
|
-
const output = raw.replace(/\r\n/g, '\n').split(delim)
|
|
689
|
-
.filter(section => section.trim())
|
|
690
|
-
.map(section => section.trimLeft() + delim)
|
|
691
|
-
|
|
692
|
-
// make it non-enumerable so we don't save it back by accident
|
|
693
|
-
const { data } = this.data.get(where)
|
|
694
|
-
Object.defineProperty(data, 'ca', {
|
|
695
|
-
value: output,
|
|
696
|
-
enumerable: false,
|
|
697
|
-
configurable: true,
|
|
698
|
-
writable: true,
|
|
699
|
-
})
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
// the user-agent configuration is a template that gets populated
|
|
703
|
-
// with some variables, that takes place here
|
|
704
|
-
setUserAgent () {
|
|
705
|
-
this.set('user-agent', getUserAgent(this))
|
|
706
|
-
}
|
|
707
|
-
|
|
708
719
|
// set up the environment object we have with npm_config_* environs
|
|
709
720
|
// for all configs that are different from their default values, and
|
|
710
721
|
// set EDITOR and HOME.
|
package/lib/set-envs.js
CHANGED
|
@@ -50,17 +50,13 @@ const setEnvs = (config) => {
|
|
|
50
50
|
platform,
|
|
51
51
|
env,
|
|
52
52
|
defaults,
|
|
53
|
+
definitions,
|
|
53
54
|
list: [cliConf, envConf],
|
|
54
55
|
} = config
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
if (platform !== 'win32' && DESTDIR && globalPrefix.indexOf(DESTDIR) === 0)
|
|
58
|
-
env.PREFIX = globalPrefix.substr(DESTDIR.length)
|
|
59
|
-
else
|
|
60
|
-
env.PREFIX = globalPrefix
|
|
61
|
-
|
|
62
|
-
env.INIT_CWD = env.INIT_CWD || process.cwd()
|
|
57
|
+
env.INIT_CWD = process.cwd()
|
|
63
58
|
|
|
59
|
+
// if the key is deprecated, skip it always.
|
|
64
60
|
// if the key is the default value,
|
|
65
61
|
// if the environ is NOT the default value,
|
|
66
62
|
// set the environ
|
|
@@ -71,6 +67,10 @@ const setEnvs = (config) => {
|
|
|
71
67
|
const cliSet = new Set(Object.keys(cliConf))
|
|
72
68
|
const envSet = new Set(Object.keys(envConf))
|
|
73
69
|
for (const key in cliConf) {
|
|
70
|
+
const { deprecated } = definitions[key] || {}
|
|
71
|
+
if (deprecated)
|
|
72
|
+
continue
|
|
73
|
+
|
|
74
74
|
if (sameConfigValue(defaults[key], cliConf[key])) {
|
|
75
75
|
// config is the default, if the env thought different, then we
|
|
76
76
|
// have to set it BACK to the default in the environment.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/config",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"files": [
|
|
5
5
|
"lib"
|
|
6
6
|
],
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"tap": "^14.10.8"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"ini": "^
|
|
30
|
+
"ini": "^2.0.0",
|
|
31
31
|
"mkdirp-infer-owner": "^2.0.0",
|
|
32
32
|
"nopt": "^5.0.0",
|
|
33
33
|
"semver": "^7.3.4",
|
package/lib/get-user-agent.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Accepts a config object, returns a user-agent string
|
|
2
|
-
const getUserAgent = (config) => {
|
|
3
|
-
const ciName = config.get('ci-name')
|
|
4
|
-
return (config.get('user-agent') || '')
|
|
5
|
-
.replace(/\{node-version\}/gi, config.get('node-version'))
|
|
6
|
-
.replace(/\{npm-version\}/gi, config.get('npm-version'))
|
|
7
|
-
.replace(/\{platform\}/gi, process.platform)
|
|
8
|
-
.replace(/\{arch\}/gi, process.arch)
|
|
9
|
-
.replace(/\{ci\}/gi, ciName ? `ci/${ciName}` : '')
|
|
10
|
-
.trim()
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
module.exports = getUserAgent
|