config 3.3.12 → 4.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/async.js CHANGED
@@ -41,12 +41,11 @@ function resolveAsyncConfigs(config) {
41
41
  var promises = [];
42
42
  var resolvers = [];
43
43
  (function iterate(prop) {
44
- var propsToSort = [];
45
- for (var property in prop) {
46
- if (Object.hasOwnProperty.call(prop, property) && prop[property] != null) {
47
- propsToSort.push(property);
48
- }
44
+ if (prop.constructor === String) {
45
+ return;
49
46
  }
47
+
48
+ var propsToSort = Object.keys(prop).filter((property) => prop[property] != null);
50
49
  propsToSort.sort().forEach(function(property) {
51
50
  if (prop[property].constructor === Object) {
52
51
  iterate(prop[property]);
@@ -54,7 +53,7 @@ function resolveAsyncConfigs(config) {
54
53
  else if (prop[property].constructor === Array) {
55
54
  prop[property].forEach(iterate);
56
55
  }
57
- else if (prop[property] && prop[property].async === asyncSymbol) {
56
+ else if (prop[property].async === asyncSymbol) {
58
57
  resolvers.push(prop[property].prepare(config, prop, property));
59
58
  promises.push(prop[property]);
60
59
  }
package/lib/config.js CHANGED
@@ -414,6 +414,29 @@ util.makeImmutable = function(object, property, value) {
414
414
  // Create a proxy, to capture user updates of configuration options, and throw an exception for awareness, as per:
415
415
  // https://github.com/lorenwest/node-config/issues/514
416
416
  value = new Proxy(util.makeImmutable(value), {
417
+ get(target, property, receiver) {
418
+ // Config's own defined prototype properties and methods (e.g., `get`, `has`, etc.)
419
+ const ownProps = [
420
+ ...Object.getOwnPropertyNames(Config.prototype),
421
+ ...Object.getOwnPropertyNames(target),
422
+ ]
423
+
424
+ // Bypass proxy receiver for properties directly on the target (e.g., RegExp.prototype.source)
425
+ // or properties that are not functions to prevent errors related to internal object methods.
426
+ if (ownProps.includes(property) || (property in target && typeof target[property] !== 'function')) {
427
+ return Reflect.get(target, property);
428
+ }
429
+
430
+ // Otherwise, use the proxy receiver to handle the property access
431
+ const ref = Reflect.get(target, property, receiver);
432
+
433
+ // Binds the method's `this` context to the target object (e.g., Date.prototype.toISOString)
434
+ // to ensure it behaves correctly when called on the proxy.
435
+ if (typeof ref === 'function') {
436
+ return ref.bind(target);
437
+ }
438
+ return ref;
439
+ },
417
440
  set (target, name) {
418
441
  const message = (Reflect.has(target, name) ? 'update' : 'add');
419
442
  // Notify the user.
@@ -493,15 +516,14 @@ util.getOption = function(options, optionName, defaultValue) {
493
516
  * (hostname)-(deployment).EXT
494
517
  * local.EXT
495
518
  * local-(deployment).EXT
496
- * runtime.json
497
519
  * </pre>
498
520
  *
499
521
  * <p>
500
- * EXT can be yml, yaml, coffee, iced, json, cson or js signifying the file type.
522
+ * EXT can be yml, yaml, coffee, iced, json, jsonc, cson or js signifying the file type.
501
523
  * yaml (and yml) is in YAML format, coffee is a coffee-script, iced is iced-coffee-script,
502
- * json is in JSON format, cson is in CSON format, properties is in .properties format
503
- * (http://en.wikipedia.org/wiki/.properties), and js is a javascript executable file that is
504
- * require()'d with module.exports being the config object.
524
+ * json is in JSON format, jsonc is in JSONC format, cson is in CSON format, properties is
525
+ * in .properties format (http://en.wikipedia.org/wiki/.properties), and js is a javascript
526
+ * executable file that is require()'d with module.exports being the config object.
505
527
  * </p>
506
528
  *
507
529
  * <p>
@@ -523,11 +545,6 @@ util.getOption = function(options, optionName, defaultValue) {
523
545
  * </p>
524
546
  *
525
547
  * <p>
526
- * The runtime.json file contains configuration changes made at runtime either
527
- * manually, or by the application setting a configuration value.
528
- * </p>
529
- *
530
- * <p>
531
548
  * If the $NODE_APP_INSTANCE environment variable (or --NODE_APP_INSTANCE
532
549
  * command line parameter) is set, then files with this appendage will be loaded.
533
550
  * See the Multiple Application Instances section of the main documentation page
@@ -576,9 +593,6 @@ util.loadFileConfigs = function(configDir, options) {
576
593
  APP_INSTANCE = util.initParam('NODE_APP_INSTANCE');
577
594
  CONFIG_SKIP_GITCRYPT = util.initParam('CONFIG_SKIP_GITCRYPT');
578
595
 
579
- // This is for backward compatibility
580
- const runtimeFilename = util.initParam('NODE_CONFIG_RUNTIME_JSON', Path.join(dir , 'runtime.json') );
581
-
582
596
  NODE_CONFIG_PARSER = util.initParam('NODE_CONFIG_PARSER');
583
597
  if (NODE_CONFIG_PARSER) {
584
598
  try {
@@ -637,12 +651,15 @@ util.loadFileConfigs = function(configDir, options) {
637
651
  let resolutionIndex = 1;
638
652
  const extNames = Parser.getFilesOrder();
639
653
  baseNames.forEach(function(baseName) {
640
- extNames.forEach(function(extName) {
641
- allowedFiles[baseName + '.' + extName] = resolutionIndex++;
642
- if (APP_INSTANCE) {
643
- allowedFiles[baseName + '-' + APP_INSTANCE + '.' + extName] = resolutionIndex++;
644
- }
645
- });
654
+ const fileNames = [baseName];
655
+ if (APP_INSTANCE) {
656
+ fileNames.push(baseName + '-' + APP_INSTANCE);
657
+ }
658
+ fileNames.forEach(function(fileName) {
659
+ extNames.forEach(function(extName) {
660
+ allowedFiles[fileName + '.' + extName] = resolutionIndex++;
661
+ });
662
+ })
646
663
  });
647
664
 
648
665
  const locatedFiles = util.locateMatchingFiles(dir, allowedFiles);
@@ -702,10 +719,6 @@ util.loadFileConfigs = function(configDir, options) {
702
719
  const customEnvVars = util.getCustomEnvVars(dir, extNames);
703
720
  util.extendDeep(config, customEnvVars);
704
721
 
705
- // Extend the original config with the contents of runtime.json (backwards compatibility)
706
- const runtimeJson = util.parseFile(runtimeFilename) || {};
707
- util.extendDeep(config, runtimeJson);
708
-
709
722
  util.resolveDeferredConfigs(config);
710
723
 
711
724
  // Return the configuration object
@@ -725,19 +738,18 @@ util.loadFileConfigs = function(configDir, options) {
725
738
  */
726
739
  util.locateMatchingFiles = function(configDirs, allowedFiles) {
727
740
  return configDirs.split(Path.delimiter)
741
+ .filter(Boolean)
728
742
  .reduce(function(files, configDir) {
729
- if (configDir) {
730
- configDir = _toAbsolutePath(configDir);
731
- try {
732
- FileSystem.readdirSync(configDir).forEach(function(file) {
733
- if (allowedFiles[file]) {
734
- files.push([allowedFiles[file], Path.join(configDir, file)]);
735
- }
736
- });
737
- }
738
- catch(e) {}
739
- return files;
743
+ configDir = _toAbsolutePath(configDir);
744
+ try {
745
+ FileSystem.readdirSync(configDir)
746
+ .filter(file => allowedFiles[file])
747
+ .forEach(function(file) {
748
+ files.push([allowedFiles[file], Path.join(configDir, file)]);
749
+ });
740
750
  }
751
+ catch(e) {}
752
+ return files;
741
753
  }, [])
742
754
  .sort(function(a, b) { return a[0] - b[0]; })
743
755
  .map(function(file) { return file[1]; });
@@ -748,16 +760,12 @@ util.resolveDeferredConfigs = function (config) {
748
760
  const deferred = [];
749
761
 
750
762
  function _iterate (prop) {
763
+ if (prop.constructor === String) {
764
+ return;
765
+ }
751
766
 
752
767
  // We put the properties we are going to look it in an array to keep the order predictable
753
- const propsToSort = [];
754
-
755
- // First step is to put the properties of interest in an array
756
- for (const property in prop) {
757
- if (Object.hasOwnProperty.call(prop, property) && prop[property] != null) {
758
- propsToSort.push(property);
759
- }
760
- }
768
+ const propsToSort = Object.keys(prop).filter((property) => prop[property] != null);
761
769
 
762
770
  // Second step is to iterate of the elements in a predictable (sorted) order
763
771
  propsToSort.sort().forEach(function (property) {
@@ -797,7 +805,7 @@ util.resolveDeferredConfigs = function (config) {
797
805
  * .js = File to run that has a module.exports containing the config object
798
806
  * .coffee = File to run that has a module.exports with coffee-script containing the config object
799
807
  * .iced = File to run that has a module.exports with iced-coffee-script containing the config object
800
- * All other supported file types (yaml, toml, json, cson, hjson, json5, properties, xml)
808
+ * All other supported file types (yaml, toml, json, jsonc, cson, hjson, json5, properties, xml)
801
809
  * are parsed with util.parseString.
802
810
  *
803
811
  * If the file doesn't exist, a null will be returned. If the file can't be
@@ -872,7 +880,8 @@ util.parseFile = function(fullFilename, options) {
872
880
  *
873
881
  * The format determines the parser to use.
874
882
  *
875
- * json = File is parsed using JSON.parse()
883
+ * json = Parsed with a JSON5 parser
884
+ * jsonc = Parsed with a JSON5 parser
876
885
  * yaml (or yml) = Parsed with a YAML parser
877
886
  * toml = Parsed with a TOML parser
878
887
  * cson = Parsed with a CSON parser
@@ -1277,11 +1286,9 @@ util.diffDeep = function(object1, object2, depth) {
1277
1286
  * @param depth {integer} An optional depth to prevent recursion. Default: 20.
1278
1287
  * @return {object} The altered mergeInto object is returned
1279
1288
  */
1280
- util.extendDeep = function(mergeInto) {
1289
+ util.extendDeep = function(mergeInto, ...vargs) {
1281
1290
 
1282
1291
  // Initialize
1283
- const t = this;
1284
- const vargs = Array.prototype.slice.call(arguments, 1);
1285
1292
  let depth = vargs.pop();
1286
1293
  if (typeof(depth) != 'number') {
1287
1294
  vargs.push(depth);
@@ -1457,8 +1464,11 @@ util.toObject = function(config) {
1457
1464
 
1458
1465
  // Run strictness checks on NODE_ENV and NODE_APP_INSTANCE and throw an error if there's a problem.
1459
1466
  util.runStrictnessChecks = function (config) {
1460
- const sources = config.util.getConfigSources();
1467
+ if (util.initParam('SUPPRESS_STRICTNESS_CHECK')) {
1468
+ return;
1469
+ }
1461
1470
 
1471
+ const sources = config.util.getConfigSources();
1462
1472
  const sourceFilenames = sources.map(function (src) {
1463
1473
  return Path.basename(src.name);
1464
1474
  });
@@ -1513,8 +1523,7 @@ function _toAbsolutePath (configDir) {
1513
1523
  // Instantiate and export the configuration
1514
1524
  const config = module.exports = new Config();
1515
1525
 
1516
- // copy methods to util for backwards compatibility
1517
- util.stripComments = Parser.stripComments;
1526
+ // copy method to util for backwards compatibility
1518
1527
  util.stripYamlComments = Parser.stripYamlComments;
1519
1528
 
1520
1529
  // Produce warnings if the configuration is empty
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "config",
3
- "version": "3.3.12",
3
+ "version": "4.0.0",
4
4
  "main": "./lib/config.js",
5
5
  "description": "Configuration control for production node deployments",
6
6
  "author": "Loren West <open_source@lorenwest.com>",
@@ -30,6 +30,7 @@
30
30
  "cson": "^3.0.1",
31
31
  "hjson": "^1.2.0",
32
32
  "js-yaml": "^3.2.2",
33
+ "nyc": "^15.1.0",
33
34
  "properties": "~1.2.1",
34
35
  "semver": "5.3.0",
35
36
  "toml": "^2.0.6",
@@ -44,9 +45,21 @@
44
45
  "url": "http://github.com/node-config/node-config.git"
45
46
  },
46
47
  "engines": {
47
- "node": ">= 10.0.0"
48
+ "node": ">= 20.0.0"
49
+ },
50
+ "nyc": {
51
+ "include": [
52
+ "*.js",
53
+ "lib/**/*.js"
54
+ ],
55
+ "extension": [
56
+ ".js"
57
+ ],
58
+ "report-dir": "./coverage",
59
+ "reporter": "lcov"
48
60
  },
49
61
  "scripts": {
50
- "test": "./node_modules/vows/bin/vows test/*.js --spec"
62
+ "test": "nyc vows test/*.js --spec",
63
+ "vows": "nyc vows"
51
64
  }
52
65
  }
package/parser.js CHANGED
@@ -208,72 +208,6 @@ Parser.propertiesParser = function(filename, content) {
208
208
  return PPARSER.parse(content, { namespaces: true, variables: true, sections: true });
209
209
  };
210
210
 
211
- /**
212
- * Strip all Javascript type comments from the string.
213
- *
214
- * The string is usually a file loaded from the O/S, containing
215
- * newlines and javascript type comments.
216
- *
217
- * Thanks to James Padolsey, and all who contributed to this implementation.
218
- * http://james.padolsey.com/javascript/javascript-comment-removal-revisted/
219
- *
220
- * @protected
221
- * @method stripComments
222
- * @param fileStr {string} The string to strip comments from
223
- * @param stringRegex {RegExp} Optional regular expression to match strings that
224
- * make up the config file
225
- * @return {string} The string with comments stripped.
226
- */
227
- Parser.stripComments = function(fileStr, stringRegex) {
228
- stringRegex = stringRegex || /"((?:[^"\\]|\\.)*)"/g;
229
-
230
- var uid = '_' + +new Date(),
231
- primitives = [],
232
- primIndex = 0;
233
-
234
- return (
235
- fileStr
236
-
237
- /* Remove strings */
238
- .replace(stringRegex, function(match){
239
- primitives[primIndex] = match;
240
- return (uid + '') + primIndex++;
241
- })
242
-
243
- /* Remove Regexes */
244
- .replace(/([^\/])(\/(?!\*|\/)(\\\/|.)+?\/[gim]{0,3})/g, function(match, $1, $2){
245
- primitives[primIndex] = $2;
246
- return $1 + (uid + '') + primIndex++;
247
- })
248
-
249
- /*
250
- - Remove single-line comments that contain would-be multi-line delimiters
251
- E.g. // Comment /* <--
252
- - Remove multi-line comments that contain would be single-line delimiters
253
- E.g. /* // <--
254
- */
255
- .replace(/\/\/.*?\/?\*.+?(?=\n|\r|$)|\/\*[\s\S]*?\/\/[\s\S]*?\*\//g, '')
256
-
257
- /*
258
- Remove single and multi-line comments,
259
- no consideration of inner-contents
260
- */
261
- .replace(/\/\/.+?(?=\n|\r|$)|\/\*[\s\S]+?\*\//g, '')
262
-
263
- /*
264
- Remove multi-line comments that have a replaced ending (string/regex)
265
- Greedy, so no inner strings/regexes will stop it.
266
- */
267
- .replace(RegExp('\\/\\*[\\s\\S]+' + uid + '\\d+', 'g'), '')
268
-
269
- /* Bring back strings & regexes */
270
- .replace(RegExp(uid + '(\\d+)', 'g'), function(match, n){
271
- return primitives[n];
272
- })
273
- );
274
-
275
- };
276
-
277
211
  /**
278
212
  * Strip YAML comments from the string
279
213
  *
@@ -313,7 +247,7 @@ Parser.numberParser = function(filename, content) {
313
247
  return Number.isNaN(numberValue) ? undefined : numberValue;
314
248
  };
315
249
 
316
- var order = ['js', 'cjs', 'ts', 'json', 'json5', 'hjson', 'toml', 'coffee', 'iced', 'yaml', 'yml', 'cson', 'properties', 'xml',
250
+ var order = ['js', 'cjs', 'mjs', 'ts', 'json', 'jsonc', 'json5', 'hjson', 'toml', 'coffee', 'iced', 'yaml', 'yml', 'cson', 'properties', 'xml',
317
251
  'boolean', 'number'];
318
252
  var definitions = {
319
253
  cjs: Parser.jsParser,
@@ -323,7 +257,9 @@ var definitions = {
323
257
  iced: Parser.icedParser,
324
258
  js: Parser.jsParser,
325
259
  json: Parser.jsonParser,
260
+ jsonc: Parser.jsonParser,
326
261
  json5: Parser.json5Parser,
262
+ mjs: Parser.jsParser,
327
263
  properties: Parser.propertiesParser,
328
264
  toml: Parser.tomlParser,
329
265
  ts: Parser.tsParser,