@npmcli/config 6.1.4 → 6.1.6
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 +68 -69
- package/package.json +5 -5
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// TODO: set the scope config from package.json or explicit cli config
|
|
2
|
-
const walkUp = require('walk-up-path')
|
|
2
|
+
const { walkUp } = require('walk-up-path')
|
|
3
3
|
const ini = require('ini')
|
|
4
4
|
const nopt = require('nopt')
|
|
5
5
|
const mapWorkspaces = require('@npmcli/map-workspaces')
|
|
@@ -72,16 +72,12 @@ const confTypes = new Set([
|
|
|
72
72
|
'cli',
|
|
73
73
|
])
|
|
74
74
|
|
|
75
|
-
const _loaded = Symbol('loaded')
|
|
76
|
-
const _get = Symbol('get')
|
|
77
|
-
const _find = Symbol('find')
|
|
78
|
-
const _loadObject = Symbol('loadObject')
|
|
79
|
-
const _loadFile = Symbol('loadFile')
|
|
80
|
-
const _checkDeprecated = Symbol('checkDeprecated')
|
|
81
|
-
const _flatten = Symbol('flatten')
|
|
82
|
-
const _flatOptions = Symbol('flatOptions')
|
|
83
|
-
|
|
84
75
|
class Config {
|
|
76
|
+
#loaded = false
|
|
77
|
+
#flatten
|
|
78
|
+
// populated the first time we flatten the object
|
|
79
|
+
#flatOptions = null
|
|
80
|
+
|
|
85
81
|
static get typeDefs () {
|
|
86
82
|
return typeDefs
|
|
87
83
|
}
|
|
@@ -113,9 +109,7 @@ class Config {
|
|
|
113
109
|
}
|
|
114
110
|
}
|
|
115
111
|
|
|
116
|
-
|
|
117
|
-
this[_flatOptions] = null
|
|
118
|
-
this[_flatten] = flatten
|
|
112
|
+
this.#flatten = flatten
|
|
119
113
|
this.types = types
|
|
120
114
|
this.shorthands = shorthands
|
|
121
115
|
this.defaults = defaults
|
|
@@ -159,15 +153,15 @@ class Config {
|
|
|
159
153
|
}
|
|
160
154
|
Object.freeze(this.list)
|
|
161
155
|
|
|
162
|
-
this
|
|
156
|
+
this.#loaded = false
|
|
163
157
|
}
|
|
164
158
|
|
|
165
159
|
get loaded () {
|
|
166
|
-
return this
|
|
160
|
+
return this.#loaded
|
|
167
161
|
}
|
|
168
162
|
|
|
169
163
|
get prefix () {
|
|
170
|
-
return this
|
|
164
|
+
return this.#get('global') ? this.globalPrefix : this.localPrefix
|
|
171
165
|
}
|
|
172
166
|
|
|
173
167
|
// return the location where key is found.
|
|
@@ -175,10 +169,7 @@ class Config {
|
|
|
175
169
|
if (!this.loaded) {
|
|
176
170
|
throw new Error('call config.load() before reading values')
|
|
177
171
|
}
|
|
178
|
-
return this[_find](key)
|
|
179
|
-
}
|
|
180
172
|
|
|
181
|
-
[_find] (key) {
|
|
182
173
|
// have to look in reverse order
|
|
183
174
|
const entries = [...this.data.entries()]
|
|
184
175
|
for (let i = entries.length - 1; i > -1; i--) {
|
|
@@ -194,12 +185,12 @@ class Config {
|
|
|
194
185
|
if (!this.loaded) {
|
|
195
186
|
throw new Error('call config.load() before reading values')
|
|
196
187
|
}
|
|
197
|
-
return this
|
|
188
|
+
return this.#get(key, where)
|
|
198
189
|
}
|
|
199
190
|
|
|
200
191
|
// we need to get values sometimes, so use this internal one to do so
|
|
201
192
|
// while in the process of loading.
|
|
202
|
-
|
|
193
|
+
#get (key, where = null) {
|
|
203
194
|
if (where !== null && !confTypes.has(where)) {
|
|
204
195
|
throw new Error('invalid config location param: ' + where)
|
|
205
196
|
}
|
|
@@ -214,32 +205,35 @@ class Config {
|
|
|
214
205
|
if (!confTypes.has(where)) {
|
|
215
206
|
throw new Error('invalid config location param: ' + where)
|
|
216
207
|
}
|
|
217
|
-
this
|
|
218
|
-
const { data } = this.data.get(where)
|
|
208
|
+
this.#checkDeprecated(key)
|
|
209
|
+
const { data, raw } = this.data.get(where)
|
|
219
210
|
data[key] = val
|
|
211
|
+
if (['global', 'user', 'project'].includes(where)) {
|
|
212
|
+
raw[key] = val
|
|
213
|
+
}
|
|
220
214
|
|
|
221
215
|
// this is now dirty, the next call to this.valid will have to check it
|
|
222
216
|
this.data.get(where)[_valid] = null
|
|
223
217
|
|
|
224
218
|
// the flat options are invalidated, regenerate next time they're needed
|
|
225
|
-
this
|
|
219
|
+
this.#flatOptions = null
|
|
226
220
|
}
|
|
227
221
|
|
|
228
222
|
get flat () {
|
|
229
|
-
if (this
|
|
230
|
-
return this
|
|
223
|
+
if (this.#flatOptions) {
|
|
224
|
+
return this.#flatOptions
|
|
231
225
|
}
|
|
232
226
|
|
|
233
227
|
// create the object for flat options passed to deps
|
|
234
228
|
process.emit('time', 'config:load:flatten')
|
|
235
|
-
this
|
|
229
|
+
this.#flatOptions = {}
|
|
236
230
|
// walk from least priority to highest
|
|
237
231
|
for (const { data } of this.data.values()) {
|
|
238
|
-
this
|
|
232
|
+
this.#flatten(data, this.#flatOptions)
|
|
239
233
|
}
|
|
240
234
|
process.emit('timeEnd', 'config:load:flatten')
|
|
241
235
|
|
|
242
|
-
return this
|
|
236
|
+
return this.#flatOptions
|
|
243
237
|
}
|
|
244
238
|
|
|
245
239
|
delete (key, where = 'cli') {
|
|
@@ -249,7 +243,11 @@ class Config {
|
|
|
249
243
|
if (!confTypes.has(where)) {
|
|
250
244
|
throw new Error('invalid config location param: ' + where)
|
|
251
245
|
}
|
|
252
|
-
|
|
246
|
+
const { data, raw } = this.data.get(where)
|
|
247
|
+
delete data[key]
|
|
248
|
+
if (['global', 'user', 'project'].includes(where)) {
|
|
249
|
+
delete raw[key]
|
|
250
|
+
}
|
|
253
251
|
}
|
|
254
252
|
|
|
255
253
|
async load () {
|
|
@@ -290,8 +288,8 @@ class Config {
|
|
|
290
288
|
process.emit('timeEnd', 'config:load:global')
|
|
291
289
|
|
|
292
290
|
// set this before calling setEnvs, so that we don't have to share
|
|
293
|
-
//
|
|
294
|
-
this
|
|
291
|
+
// private attributes, as that module also does a bunch of get operations
|
|
292
|
+
this.#loaded = true
|
|
295
293
|
|
|
296
294
|
// set proper globalPrefix now that everything is loaded
|
|
297
295
|
this.globalPrefix = this.get('prefix')
|
|
@@ -307,7 +305,7 @@ class Config {
|
|
|
307
305
|
this.loadGlobalPrefix()
|
|
308
306
|
this.loadHome()
|
|
309
307
|
|
|
310
|
-
this
|
|
308
|
+
this.#loadObject({
|
|
311
309
|
...this.defaults,
|
|
312
310
|
prefix: this.globalPrefix,
|
|
313
311
|
}, 'default', 'default values')
|
|
@@ -316,13 +314,13 @@ class Config {
|
|
|
316
314
|
|
|
317
315
|
// the metrics-registry defaults to the current resolved value of
|
|
318
316
|
// the registry, unless overridden somewhere else.
|
|
319
|
-
settableGetter(data, 'metrics-registry', () => this
|
|
317
|
+
settableGetter(data, 'metrics-registry', () => this.#get('registry'))
|
|
320
318
|
|
|
321
319
|
// if the prefix is set on cli, env, or userconfig, then we need to
|
|
322
320
|
// default the globalconfig file to that location, instead of the default
|
|
323
321
|
// global prefix. It's weird that `npm get globalconfig --prefix=/foo`
|
|
324
322
|
// returns `/foo/etc/npmrc`, but better to not change it at this point.
|
|
325
|
-
settableGetter(data, 'globalconfig', () => resolve(this
|
|
323
|
+
settableGetter(data, 'globalconfig', () => resolve(this.#get('prefix'), 'etc/npmrc'))
|
|
326
324
|
}
|
|
327
325
|
|
|
328
326
|
loadHome () {
|
|
@@ -363,7 +361,7 @@ class Config {
|
|
|
363
361
|
}
|
|
364
362
|
conf[key] = envVal
|
|
365
363
|
}
|
|
366
|
-
this
|
|
364
|
+
this.#loadObject(conf, 'env', 'environment')
|
|
367
365
|
}
|
|
368
366
|
|
|
369
367
|
loadCLI () {
|
|
@@ -373,7 +371,7 @@ class Config {
|
|
|
373
371
|
nopt.invalidHandler = null
|
|
374
372
|
this.parsedArgv = conf.argv
|
|
375
373
|
delete conf.argv
|
|
376
|
-
this
|
|
374
|
+
this.#loadObject(conf, 'cli', 'command line options')
|
|
377
375
|
}
|
|
378
376
|
|
|
379
377
|
get valid () {
|
|
@@ -541,7 +539,8 @@ class Config {
|
|
|
541
539
|
log.warn('invalid config', msg, desc)
|
|
542
540
|
}
|
|
543
541
|
|
|
544
|
-
|
|
542
|
+
#loadObject (obj, where, source, er = null) {
|
|
543
|
+
// obj is the raw data read from the file
|
|
545
544
|
const conf = this.data.get(where)
|
|
546
545
|
if (conf.source) {
|
|
547
546
|
const m = `double-loading "${where}" configs from ${source}, ` +
|
|
@@ -568,14 +567,14 @@ class Config {
|
|
|
568
567
|
const k = envReplace(key, this.env)
|
|
569
568
|
const v = this.parseField(value, k)
|
|
570
569
|
if (where !== 'default') {
|
|
571
|
-
this
|
|
570
|
+
this.#checkDeprecated(k, where, obj, [key, value])
|
|
572
571
|
}
|
|
573
572
|
conf.data[k] = v
|
|
574
573
|
}
|
|
575
574
|
}
|
|
576
575
|
}
|
|
577
576
|
|
|
578
|
-
|
|
577
|
+
#checkDeprecated (key, where, obj, kv) {
|
|
579
578
|
// XXX(npm9+) make this throw an error
|
|
580
579
|
if (this.deprecated[key]) {
|
|
581
580
|
log.warn('config', key, this.deprecated[key])
|
|
@@ -587,18 +586,18 @@ class Config {
|
|
|
587
586
|
return parseField(f, key, this, listElement)
|
|
588
587
|
}
|
|
589
588
|
|
|
590
|
-
async
|
|
589
|
+
async #loadFile (file, type) {
|
|
591
590
|
process.emit('time', 'config:load:file:' + file)
|
|
592
591
|
// only catch the error from readFile, not from the loadObject call
|
|
593
592
|
await readFile(file, 'utf8').then(
|
|
594
|
-
data => this
|
|
595
|
-
er => this
|
|
593
|
+
data => this.#loadObject(ini.parse(data), type, file),
|
|
594
|
+
er => this.#loadObject(null, type, file, er)
|
|
596
595
|
)
|
|
597
596
|
process.emit('timeEnd', 'config:load:file:' + file)
|
|
598
597
|
}
|
|
599
598
|
|
|
600
599
|
loadBuiltinConfig () {
|
|
601
|
-
return this
|
|
600
|
+
return this.#loadFile(resolve(this.npmPath, 'npmrc'), 'builtin')
|
|
602
601
|
}
|
|
603
602
|
|
|
604
603
|
async loadProjectConfig () {
|
|
@@ -613,7 +612,7 @@ class Config {
|
|
|
613
612
|
this.localPackage = await fileExists(this.localPrefix, 'package.json')
|
|
614
613
|
}
|
|
615
614
|
|
|
616
|
-
if (this
|
|
615
|
+
if (this.#get('global') === true || this.#get('location') === 'global') {
|
|
617
616
|
this.data.get('project').source = '(global mode enabled, ignored)'
|
|
618
617
|
this.sources.set(this.data.get('project').source, 'project')
|
|
619
618
|
return
|
|
@@ -625,8 +624,8 @@ class Config {
|
|
|
625
624
|
// up loading the "project" config where the "userconfig" will be,
|
|
626
625
|
// which causes some calamaties. So, we only load project config if
|
|
627
626
|
// it doesn't match what the userconfig will be.
|
|
628
|
-
if (projectFile !== this
|
|
629
|
-
return this
|
|
627
|
+
if (projectFile !== this.#get('userconfig')) {
|
|
628
|
+
return this.#loadFile(projectFile, 'project')
|
|
630
629
|
} else {
|
|
631
630
|
this.data.get('project').source = '(same as "user" config, ignored)'
|
|
632
631
|
this.sources.set(this.data.get('project').source, 'project')
|
|
@@ -634,14 +633,14 @@ class Config {
|
|
|
634
633
|
}
|
|
635
634
|
|
|
636
635
|
async loadLocalPrefix () {
|
|
637
|
-
const cliPrefix = this
|
|
636
|
+
const cliPrefix = this.#get('prefix', 'cli')
|
|
638
637
|
if (cliPrefix) {
|
|
639
638
|
this.localPrefix = cliPrefix
|
|
640
639
|
return
|
|
641
640
|
}
|
|
642
641
|
|
|
643
|
-
const cliWorkspaces = this
|
|
644
|
-
const isGlobal = this
|
|
642
|
+
const cliWorkspaces = this.#get('workspaces', 'cli')
|
|
643
|
+
const isGlobal = this.#get('global') || this.#get('location') === 'global'
|
|
645
644
|
|
|
646
645
|
for (const p of walkUp(this.cwd)) {
|
|
647
646
|
// HACK: this is an option set in tests to stop the local prefix from being set
|
|
@@ -701,11 +700,11 @@ class Config {
|
|
|
701
700
|
}
|
|
702
701
|
|
|
703
702
|
loadUserConfig () {
|
|
704
|
-
return this
|
|
703
|
+
return this.#loadFile(this.#get('userconfig'), 'user')
|
|
705
704
|
}
|
|
706
705
|
|
|
707
706
|
loadGlobalConfig () {
|
|
708
|
-
return this
|
|
707
|
+
return this.#loadFile(this.#get('globalconfig'), 'global')
|
|
709
708
|
}
|
|
710
709
|
|
|
711
710
|
async save (where) {
|
|
@@ -717,7 +716,6 @@ class Config {
|
|
|
717
716
|
}
|
|
718
717
|
|
|
719
718
|
const conf = this.data.get(where)
|
|
720
|
-
conf[_raw] = { ...conf.data }
|
|
721
719
|
conf[_loadError] = null
|
|
722
720
|
|
|
723
721
|
if (where === 'user') {
|
|
@@ -730,7 +728,9 @@ class Config {
|
|
|
730
728
|
}
|
|
731
729
|
}
|
|
732
730
|
|
|
733
|
-
|
|
731
|
+
// We need the actual raw data before we called parseField so that we are
|
|
732
|
+
// saving the same content back to the file
|
|
733
|
+
const iniData = ini.stringify(conf.raw).trim() + '\n'
|
|
734
734
|
if (!iniData.trim()) {
|
|
735
735
|
// ignore the unlink error (eg, if file doesn't exist)
|
|
736
736
|
await unlink(conf.source).catch(er => {})
|
|
@@ -870,22 +870,21 @@ class Config {
|
|
|
870
870
|
}
|
|
871
871
|
}
|
|
872
872
|
|
|
873
|
-
const _data = Symbol('data')
|
|
874
|
-
const _raw = Symbol('raw')
|
|
875
873
|
const _loadError = Symbol('loadError')
|
|
876
|
-
const _source = Symbol('source')
|
|
877
874
|
const _valid = Symbol('valid')
|
|
875
|
+
|
|
878
876
|
class ConfigData {
|
|
877
|
+
#data
|
|
878
|
+
#source = null
|
|
879
|
+
#raw = null
|
|
879
880
|
constructor (parent) {
|
|
880
|
-
this
|
|
881
|
-
this
|
|
882
|
-
this[_loadError] = null
|
|
883
|
-
this[_raw] = null
|
|
881
|
+
this.#data = Object.create(parent && parent.data)
|
|
882
|
+
this.#raw = {}
|
|
884
883
|
this[_valid] = true
|
|
885
884
|
}
|
|
886
885
|
|
|
887
886
|
get data () {
|
|
888
|
-
return this
|
|
887
|
+
return this.#data
|
|
889
888
|
}
|
|
890
889
|
|
|
891
890
|
get valid () {
|
|
@@ -893,18 +892,18 @@ class ConfigData {
|
|
|
893
892
|
}
|
|
894
893
|
|
|
895
894
|
set source (s) {
|
|
896
|
-
if (this
|
|
895
|
+
if (this.#source) {
|
|
897
896
|
throw new Error('cannot set ConfigData source more than once')
|
|
898
897
|
}
|
|
899
|
-
this
|
|
898
|
+
this.#source = s
|
|
900
899
|
}
|
|
901
900
|
|
|
902
901
|
get source () {
|
|
903
|
-
return this
|
|
902
|
+
return this.#source
|
|
904
903
|
}
|
|
905
904
|
|
|
906
905
|
set loadError (e) {
|
|
907
|
-
if (this[_loadError] || this
|
|
906
|
+
if (this[_loadError] || (Object.keys(this.#raw).length)) {
|
|
908
907
|
throw new Error('cannot set ConfigData loadError after load')
|
|
909
908
|
}
|
|
910
909
|
this[_loadError] = e
|
|
@@ -915,14 +914,14 @@ class ConfigData {
|
|
|
915
914
|
}
|
|
916
915
|
|
|
917
916
|
set raw (r) {
|
|
918
|
-
if (this
|
|
917
|
+
if (Object.keys(this.#raw).length || this[_loadError]) {
|
|
919
918
|
throw new Error('cannot set ConfigData raw after load')
|
|
920
919
|
}
|
|
921
|
-
this
|
|
920
|
+
this.#raw = r
|
|
922
921
|
}
|
|
923
922
|
|
|
924
923
|
get raw () {
|
|
925
|
-
return this
|
|
924
|
+
return this.#raw
|
|
926
925
|
}
|
|
927
926
|
}
|
|
928
927
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/config",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.6",
|
|
4
4
|
"files": [
|
|
5
5
|
"bin/",
|
|
6
6
|
"lib/"
|
|
@@ -33,23 +33,23 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@npmcli/eslint-config": "^4.0.0",
|
|
36
|
-
"@npmcli/template-oss": "4.12.
|
|
36
|
+
"@npmcli/template-oss": "4.12.1",
|
|
37
37
|
"tap": "^16.3.4"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@npmcli/map-workspaces": "^3.0.2",
|
|
41
|
-
"ini": "^
|
|
41
|
+
"ini": "^4.1.0",
|
|
42
42
|
"nopt": "^7.0.0",
|
|
43
43
|
"proc-log": "^3.0.0",
|
|
44
44
|
"read-package-json-fast": "^3.0.2",
|
|
45
45
|
"semver": "^7.3.5",
|
|
46
|
-
"walk-up-path": "^
|
|
46
|
+
"walk-up-path": "^3.0.1"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
|
49
49
|
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
|
50
50
|
},
|
|
51
51
|
"templateOSS": {
|
|
52
52
|
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
|
|
53
|
-
"version": "4.12.
|
|
53
|
+
"version": "4.12.1"
|
|
54
54
|
}
|
|
55
55
|
}
|