@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.
Files changed (2) hide show
  1. package/lib/index.js +68 -69
  2. 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
- // populated the first time we flatten the object
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[_loaded] = false
156
+ this.#loaded = false
163
157
  }
164
158
 
165
159
  get loaded () {
166
- return this[_loaded]
160
+ return this.#loaded
167
161
  }
168
162
 
169
163
  get prefix () {
170
- return this[_get]('global') ? this.globalPrefix : this.localPrefix
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[_get](key, where)
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
- [_get] (key, where = null) {
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[_checkDeprecated](key)
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[_flatOptions] = null
219
+ this.#flatOptions = null
226
220
  }
227
221
 
228
222
  get flat () {
229
- if (this[_flatOptions]) {
230
- return this[_flatOptions]
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[_flatOptions] = {}
229
+ this.#flatOptions = {}
236
230
  // walk from least priority to highest
237
231
  for (const { data } of this.data.values()) {
238
- this[_flatten](data, this[_flatOptions])
232
+ this.#flatten(data, this.#flatOptions)
239
233
  }
240
234
  process.emit('timeEnd', 'config:load:flatten')
241
235
 
242
- return this[_flatOptions]
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
- delete this.data.get(where).data[key]
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
- // symbols, as that module also does a bunch of get operations
294
- this[_loaded] = true
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[_loadObject]({
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[_get]('registry'))
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[_get]('prefix'), 'etc/npmrc'))
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[_loadObject](conf, 'env', 'environment')
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[_loadObject](conf, 'cli', 'command line options')
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
- [_loadObject] (obj, where, source, er = null) {
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[_checkDeprecated](k, where, obj, [key, value])
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
- [_checkDeprecated] (key, where, obj, kv) {
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 [_loadFile] (file, type) {
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[_loadObject](ini.parse(data), type, file),
595
- er => this[_loadObject](null, type, file, er)
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[_loadFile](resolve(this.npmPath, 'npmrc'), 'builtin')
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[_get]('global') === true || this[_get]('location') === 'global') {
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[_get]('userconfig')) {
629
- return this[_loadFile](projectFile, 'project')
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[_get]('prefix', 'cli')
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[_get]('workspaces', 'cli')
644
- const isGlobal = this[_get]('global') || this[_get]('location') === 'global'
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[_loadFile](this[_get]('userconfig'), 'user')
703
+ return this.#loadFile(this.#get('userconfig'), 'user')
705
704
  }
706
705
 
707
706
  loadGlobalConfig () {
708
- return this[_loadFile](this[_get]('globalconfig'), 'global')
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
- const iniData = ini.stringify(conf.data).trim() + '\n'
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[_data] = Object.create(parent && parent.data)
881
- this[_source] = null
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[_data]
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[_source]) {
895
+ if (this.#source) {
897
896
  throw new Error('cannot set ConfigData source more than once')
898
897
  }
899
- this[_source] = s
898
+ this.#source = s
900
899
  }
901
900
 
902
901
  get source () {
903
- return this[_source]
902
+ return this.#source
904
903
  }
905
904
 
906
905
  set loadError (e) {
907
- if (this[_loadError] || this[_raw]) {
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[_raw] || this[_loadError]) {
917
+ if (Object.keys(this.#raw).length || this[_loadError]) {
919
918
  throw new Error('cannot set ConfigData raw after load')
920
919
  }
921
- this[_raw] = r
920
+ this.#raw = r
922
921
  }
923
922
 
924
923
  get raw () {
925
- return this[_raw]
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.4",
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.0",
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": "^3.0.0",
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": "^1.0.0"
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.0"
53
+ "version": "4.12.1"
54
54
  }
55
55
  }