config 4.2.1 → 4.3.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/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- // Copyright 2010-2025, Loren West and other contributors
1
+ // Copyright 2010-2026, Loren West and other contributors
2
2
 
3
3
  // Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  // of this software and associated documentation files (the "Software"), to
package/README.md CHANGED
@@ -171,6 +171,6 @@ License
171
171
 
172
172
  May be freely distributed under the [MIT license](https://raw.githubusercontent.com/node-config/node-config/master/LICENSE).
173
173
 
174
- Copyright (c) 2010-2025 Loren West
174
+ Copyright (c) 2010-2026 Loren West
175
175
  [and other contributors](https://github.com/node-config/node-config/graphs/contributors)
176
176
 
package/async.js CHANGED
@@ -1,12 +1,16 @@
1
- var asyncSymbol = Symbol('asyncSymbol');
2
- var deferConfig = require('./defer').deferConfig;
1
+ const asyncSymbol = Symbol('asyncSymbol');
2
+ const { deferConfig } = require('./defer');
3
3
 
4
4
  /**
5
5
  * @param promiseOrFunc the promise will determine a property's value once resolved
6
6
  * can also be a function to defer which resolves to a promise
7
7
  * @returns {Promise} a marked promise to be resolve later using `resolveAsyncConfigs`
8
+ * @deprecated please use async functions with defer
8
9
  */
9
10
  function asyncConfig(promiseOrFunc) {
11
+ const { Util } = require('./lib/util.js');
12
+ Util.errorOnce("ASYNC_CONFIG", 'config/async.js is deprecated. Please use async functions with the new defer functionality');
13
+
10
14
  if (typeof promiseOrFunc === 'function') { // also acts as deferConfig
11
15
  return deferConfig(function (config, original) {
12
16
  var release;
@@ -36,6 +40,7 @@ function asyncConfig(promiseOrFunc) {
36
40
  * Do not use `config.get` before executing this method, it will freeze the config object
37
41
  * @param config the main config object, returned from require('config')
38
42
  * @returns {Promise<config>} once all promises are resolved, return the original config object
43
+ * @deprecated please use async functions with defer and Util.resolveAsyncConfigs
39
44
  */
40
45
  function resolveAsyncConfigs(config) {
41
46
  var promises = [];
package/defer.js CHANGED
@@ -1,23 +1,17 @@
1
- // Create a deferredConfig prototype so that we can check for it when reviewing the configs later.
2
- function DeferredConfig() {}
3
- DeferredConfig.prototype.prepare = function() {};
4
- DeferredConfig.prototype.resolve = function() {};
1
+ const { deferConfig, DeferredConfig } = require('./lib/defer.js');
5
2
 
6
- // Accept a function that we'll use to resolve this value later and return a 'deferred' configuration value to resolve it later.
7
- function deferConfig(func) {
8
- var obj = Object.create(DeferredConfig.prototype);
9
- obj.prepare = function(config, prop, property) {
10
- var original = prop[property]._original;
11
- obj.resolve = function() {
12
- var value = func.call(config, config, original);
13
- Object.defineProperty(prop, property, {value: value});
14
- return value;
15
- };
16
- Object.defineProperty(prop, property, {get: function() { return obj.resolve(); }});
17
- return obj;
18
- };
19
- return obj;
3
+ /**
4
+ * @deprecated please use the new callback mechanism
5
+ * @see lib/defer.js
6
+ */
7
+ module.exports.deferConfig = (...args) => {
8
+ const { Util } = require('./lib/util.js');
9
+
10
+ Util.errorOnce("DEFER_CONFIG", 'node-config now supports config file callbacks in place of deferConfig(), which is deprecated.');
11
+ return deferConfig(...args);
20
12
  }
21
13
 
22
- module.exports.deferConfig = deferConfig;
14
+ /**
15
+ * @deprecated please use the new callback mechanism
16
+ */
23
17
  module.exports.DeferredConfig = DeferredConfig;
package/lib/config.js CHANGED
@@ -1,4 +1,4 @@
1
- // config.js (c) 2010-2022 Loren West and other contributors
1
+ // config.js (c) 2010-2026 Loren West and other contributors
2
2
  // May be freely distributed under the MIT license.
3
3
  // For further details and documentation:
4
4
  // http://lorenwest.github.com/node-config
package/lib/defer.js ADDED
@@ -0,0 +1,42 @@
1
+ const { isAsyncFunction } = require('node:util/types');
2
+
3
+ // Create a deferredConfig prototype so that we can check for it when reviewing the configs later.
4
+ function DeferredConfig() {}
5
+ DeferredConfig.prototype.prepare = function() {};
6
+ DeferredConfig.prototype.resolve = function() {};
7
+
8
+ // Accept a function that we'll use to resolve this value later and return a 'deferred' configuration value to resolve it later.
9
+ function deferConfig(func) {
10
+ const obj = Object.create(DeferredConfig.prototype);
11
+ obj.prepare = function(config, prop, property) {
12
+ const original = prop[property]._original;
13
+
14
+ if (isAsyncFunction(func)) {
15
+ obj.resolve = async function () {
16
+ const promise = func.call(config, config, original);
17
+
18
+ Object.defineProperty(prop, property, { value: promise });
19
+ Object.defineProperty(prop, property, { value: await promise });
20
+
21
+ return promise;
22
+ }
23
+ } else {
24
+ obj.resolve = function() {
25
+ const value = func.call(config, config, original);
26
+
27
+ Object.defineProperty(prop, property, {value: value});
28
+
29
+ return value;
30
+ };
31
+ }
32
+
33
+ Object.defineProperty(prop, property, { get: function() { return obj.resolve(); } });
34
+
35
+ return obj;
36
+ };
37
+
38
+ return obj;
39
+ }
40
+
41
+ module.exports.deferConfig = deferConfig;
42
+ module.exports.DeferredConfig = DeferredConfig;
package/lib/util.js CHANGED
@@ -1,15 +1,17 @@
1
- // config.js (c) 2010-2022 Loren West and other contributors
1
+ // config.js (c) 2010-2026 Loren West and other contributors
2
2
  // May be freely distributed under the MIT license.
3
3
  // For further details and documentation:
4
4
  // http://lorenwest.github.com/node-config
5
5
 
6
6
  // Dependencies
7
- const DeferredConfig = require('../defer').DeferredConfig;
7
+ const { deferConfig, DeferredConfig } = require('./defer.js');
8
+ const { resolveAsyncConfigs } = require('../async');
8
9
  const Path = require('path');
9
10
  const FileSystem = require('fs');
10
11
  const OS = require("os");
11
12
 
12
13
  const DEFAULT_CONFIG_DIR = Path.join( process.cwd(), 'config');
14
+ const SEEN_ERRORS = {};
13
15
 
14
16
  /**
15
17
  * A source in the configSources list
@@ -301,29 +303,78 @@ class Util {
301
303
  const propsToSort = Object.keys(prop).filter((property) => prop[property] != null);
302
304
 
303
305
  // Second step is to iterate of the elements in a predictable (sorted) order
304
- propsToSort.sort().forEach(function (property) {
305
- if (prop[property].constructor === Object) {
306
- _iterate(prop[property]);
307
- } else if (prop[property].constructor === Array) {
308
- for (let i = 0; i < prop[property].length; i++) {
309
- if (prop[property][i] instanceof DeferredConfig) {
310
- deferred.push(prop[property][i].prepare(config, prop[property], i));
306
+ for (let name of propsToSort.sort()) {
307
+ const property = prop[name];
308
+
309
+ if (property.constructor === Object) {
310
+ _iterate(property);
311
+ } else if (property.constructor === Array) {
312
+ property.forEach(function (entry, i) {
313
+ if (entry instanceof DeferredConfig) {
314
+ deferred.push(entry.prepare(config, property, i));
311
315
  } else {
312
- _iterate(prop[property][i]);
316
+ _iterate(property[i]);
317
+ }
318
+ });
319
+ } else if (property instanceof DeferredConfig) {
320
+ deferred.push(property.prepare(config, prop, name));
321
+ }
322
+ // else: Nothing to do. Keep the property how it is.
323
+ }
324
+ }
325
+
326
+ _iterate(config);
327
+
328
+ deferred.forEach((defer) => { defer.resolve() });
329
+ }
330
+
331
+ /**
332
+ * Used to resolve configs that have async functions.
333
+ *
334
+ * NOTE: Do not use `config.get` before executing this method, it will freeze the config object
335
+ *
336
+ * This replaces ./async.js, which is deprecated.
337
+ *
338
+ * @param config
339
+ * @returns {Promise<void>}
340
+ */
341
+ static async resolveAsyncConfigs(config) {
342
+ const promises = [];
343
+
344
+ await resolveAsyncConfigs(config);
345
+
346
+ function _iterate (prop) {
347
+ if (prop == null || prop.constructor === String) {
348
+ return;
349
+ }
350
+
351
+ // We put the properties we are going to look it in an array to keep the order predictable
352
+ const propsToSort = Object.keys(prop).filter((property) => prop[property] != null);
353
+
354
+ // Second step is to iterate of the elements in a predictable (sorted) order
355
+ for (let name of propsToSort.sort()) {
356
+ const property = prop[name];
357
+
358
+ if (property.constructor === Object) {
359
+ _iterate(property);
360
+ } else if (property.constructor === Array) {
361
+ for (let entry of property) {
362
+ if (entry instanceof Promise) {
363
+ promises.push(entry);
364
+ } else {
365
+ _iterate(entry);
313
366
  }
314
367
  }
315
- } else {
316
- if (prop[property] instanceof DeferredConfig) {
317
- deferred.push(prop[property].prepare(config, prop, property));
318
- }
319
- // else: Nothing to do. Keep the property how it is.
368
+ } else if (property instanceof Promise) {
369
+ promises.push(property);
320
370
  }
321
- });
371
+ // else: Nothing to do. Keep the property how it is.
372
+ }
322
373
  }
323
374
 
324
375
  _iterate(config);
325
376
 
326
- deferred.forEach(function (defer) { defer.resolve(); });
377
+ await Promise.all(promises);
327
378
  }
328
379
 
329
380
  /**
@@ -649,6 +700,21 @@ class Util {
649
700
  static toObject(config) {
650
701
  return JSON.parse(JSON.stringify(config));
651
702
  }
703
+
704
+ /**
705
+ * Send a message to console.error once
706
+ * @param key {string} the subject of the error, used to prevent duplicates
707
+ * @param message {string} helpful message for library users
708
+ * @param [args] {object[]} additional arguments to console.error
709
+ */
710
+ static errorOnce(key, message, ...args) {
711
+ if (SEEN_ERRORS[key] === undefined) {
712
+ SEEN_ERRORS[key] = true;
713
+ let err = new Error;
714
+ Error.captureStackTrace(err, this.errorOnce);
715
+ console.error(message, ...args, err.stack);
716
+ }
717
+ }
652
718
  }
653
719
 
654
720
  /**
@@ -938,6 +1004,12 @@ class Load {
938
1004
  throw new Error("Cannot parse config file: '" + fullFilename + "': " + e3);
939
1005
  }
940
1006
 
1007
+ if (typeof configObject == 'function') {
1008
+ let fn = configObject;
1009
+
1010
+ configObject = fn({ defer: deferConfig, util: Util });
1011
+ }
1012
+
941
1013
  if (convert) {
942
1014
  configObject = convert(configObject);
943
1015
  }
@@ -1158,8 +1230,6 @@ class Load {
1158
1230
  }
1159
1231
 
1160
1232
  let configDir = env.initParam('NODE_CONFIG_DIR');
1161
- configDir = configDir && _toAbsolutePath(configDir);
1162
-
1163
1233
  let appInstance = env.initParam('NODE_APP_INSTANCE');
1164
1234
  let gitCrypt = !env.initParam('CONFIG_SKIP_GITCRYPT');
1165
1235
  let parser = _loadParser(env.initParam('NODE_CONFIG_PARSER'), configDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "config",
3
- "version": "4.2.1",
3
+ "version": "4.3.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>",
@@ -29,6 +29,7 @@
29
29
  "c8": "^10.1.3",
30
30
  "coffeescript": "2.2.4",
31
31
  "cson": "^3.0.1",
32
+ "faceoff": "^1.3.0",
32
33
  "hjson": "^1.2.0",
33
34
  "properties": "~1.2.1",
34
35
  "request": "^2.88.2",
@@ -56,6 +57,8 @@
56
57
  "reporter": "lcov"
57
58
  },
58
59
  "scripts": {
59
- "test": "NODE_OPTIONS='--no-experimental-strip-types' c8 node --test"
60
+ "ci": "npm run test && npm run benchmarks",
61
+ "test": "NODE_OPTIONS='--no-experimental-strip-types' c8 node --test",
62
+ "benchmarks": "node --allow-natives-syntax --expose-gc benchmarks/index.js"
60
63
  }
61
64
  }