config 3.3.9 → 3.3.10
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/config.js +138 -133
- package/package.json +1 -1
- package/parser.js +11 -16
package/lib/config.js
CHANGED
|
@@ -4,22 +4,25 @@
|
|
|
4
4
|
// http://lorenwest.github.com/node-config
|
|
5
5
|
|
|
6
6
|
// Dependencies
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
const DeferredConfig = require('../defer').DeferredConfig;
|
|
8
|
+
const RawConfig = require('../raw').RawConfig;
|
|
9
|
+
let Parser = require('../parser');
|
|
10
|
+
const Utils = require('util');
|
|
11
|
+
const Path = require('path');
|
|
12
|
+
const FileSystem = require('fs');
|
|
13
13
|
|
|
14
14
|
// Static members
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
const DEFAULT_CLONE_DEPTH = 20;
|
|
16
|
+
let CONFIG_DIR;
|
|
17
|
+
let NODE_ENV;
|
|
18
|
+
let APP_INSTANCE;
|
|
19
|
+
let CONFIG_SKIP_GITCRYPT;
|
|
20
|
+
let NODE_ENV_VAR_NAME;
|
|
21
|
+
let NODE_CONFIG_PARSER;
|
|
22
|
+
const env = {};
|
|
23
|
+
const configSources = []; // Configuration sources - array of {name, original, parsed}
|
|
24
|
+
let checkMutability = true; // Check for mutability/immutability on first get
|
|
25
|
+
const gitCryptTestRegex = /^.GITCRYPT/; // regular expression to test for gitcrypt files.
|
|
23
26
|
|
|
24
27
|
/**
|
|
25
28
|
* <p>Application Configurations</p>
|
|
@@ -55,7 +58,7 @@ var DEFAULT_CLONE_DEPTH = 20,
|
|
|
55
58
|
* <p>
|
|
56
59
|
*
|
|
57
60
|
* <pre>
|
|
58
|
-
*
|
|
61
|
+
* const CONFIG = require('config').customer;
|
|
59
62
|
* ...
|
|
60
63
|
* newCustomer.creditLimit = CONFIG.initialCredit;
|
|
61
64
|
* database.open(CONFIG.db.name, CONFIG.db.port);
|
|
@@ -79,7 +82,7 @@ var DEFAULT_CLONE_DEPTH = 20,
|
|
|
79
82
|
* for file/module scope. If you want the root of the object, you can do this:
|
|
80
83
|
* </p>
|
|
81
84
|
* <pre>
|
|
82
|
-
*
|
|
85
|
+
* const CONFIG = require('config');
|
|
83
86
|
* </pre>
|
|
84
87
|
*
|
|
85
88
|
* <p>
|
|
@@ -87,9 +90,9 @@ var DEFAULT_CLONE_DEPTH = 20,
|
|
|
87
90
|
* object. In that case you could do this at the top of your file:
|
|
88
91
|
* </p>
|
|
89
92
|
* <pre>
|
|
90
|
-
*
|
|
93
|
+
* const CONFIG = require('config').customer;
|
|
91
94
|
* or
|
|
92
|
-
*
|
|
95
|
+
* const CUSTOMER_CONFIG = require('config').customer;
|
|
93
96
|
* </pre>
|
|
94
97
|
*
|
|
95
98
|
* <script type="text/javascript">
|
|
@@ -99,11 +102,11 @@ var DEFAULT_CLONE_DEPTH = 20,
|
|
|
99
102
|
* @method constructor
|
|
100
103
|
* @return CONFIG {object} - The top level configuration object
|
|
101
104
|
*/
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
const Config = function() {
|
|
106
|
+
const t = this;
|
|
104
107
|
|
|
105
108
|
// Bind all utility functions to this
|
|
106
|
-
for (
|
|
109
|
+
for (const fnName in util) {
|
|
107
110
|
if (typeof util[fnName] === 'function') {
|
|
108
111
|
util[fnName] = util[fnName].bind(t);
|
|
109
112
|
}
|
|
@@ -120,7 +123,7 @@ var Config = function() {
|
|
|
120
123
|
/**
|
|
121
124
|
* Utilities are under the util namespace vs. at the top level
|
|
122
125
|
*/
|
|
123
|
-
|
|
126
|
+
const util = Config.prototype.util = {};
|
|
124
127
|
|
|
125
128
|
/**
|
|
126
129
|
* Underlying get mechanism
|
|
@@ -131,11 +134,11 @@ var util = Config.prototype.util = {};
|
|
|
131
134
|
* @param property {string|string[]} - The property name to get (as an array or '.' delimited string)
|
|
132
135
|
* @return value {*} - Property value, including undefined if not defined.
|
|
133
136
|
*/
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
const getImpl= function(object, property) {
|
|
138
|
+
const t = this;
|
|
139
|
+
const elems = Array.isArray(property) ? property : property.split('.');
|
|
140
|
+
const name = elems[0];
|
|
141
|
+
const value = object[name];
|
|
139
142
|
if (elems.length <= 1) {
|
|
140
143
|
return value;
|
|
141
144
|
}
|
|
@@ -160,7 +163,7 @@ var getImpl= function(object, property) {
|
|
|
160
163
|
* @return value {*} - The property value
|
|
161
164
|
*/
|
|
162
165
|
Config.prototype.get = function(property) {
|
|
163
|
-
if(property === null || property === undefined){
|
|
166
|
+
if(property === null || typeof property === "undefined"){
|
|
164
167
|
throw new Error("Calling config.get with null or undefined argument");
|
|
165
168
|
}
|
|
166
169
|
|
|
@@ -171,11 +174,11 @@ Config.prototype.get = function(property) {
|
|
|
171
174
|
}
|
|
172
175
|
checkMutability = false;
|
|
173
176
|
}
|
|
174
|
-
|
|
175
|
-
|
|
177
|
+
const t = this;
|
|
178
|
+
const value = getImpl(t, property);
|
|
176
179
|
|
|
177
180
|
// Produce an exception if the property doesn't exist
|
|
178
|
-
if (value === undefined) {
|
|
181
|
+
if (typeof value === "undefined") {
|
|
179
182
|
throw new Error('Configuration property "' + property + '" is not defined');
|
|
180
183
|
}
|
|
181
184
|
|
|
@@ -187,7 +190,7 @@ Config.prototype.get = function(property) {
|
|
|
187
190
|
* Test that a configuration parameter exists
|
|
188
191
|
*
|
|
189
192
|
* <pre>
|
|
190
|
-
*
|
|
193
|
+
* const config = require('config');
|
|
191
194
|
* if (config.has('customer.dbName')) {
|
|
192
195
|
* console.log('Customer database name: ' + config.customer.dbName);
|
|
193
196
|
* }
|
|
@@ -199,11 +202,11 @@ Config.prototype.get = function(property) {
|
|
|
199
202
|
*/
|
|
200
203
|
Config.prototype.has = function(property) {
|
|
201
204
|
// While get() throws an exception for undefined input, has() is designed to test validity, so false is appropriate
|
|
202
|
-
if(property === null || property === undefined){
|
|
205
|
+
if(property === null || typeof property === "undefined"){
|
|
203
206
|
return false;
|
|
204
207
|
}
|
|
205
|
-
|
|
206
|
-
return
|
|
208
|
+
const t = this;
|
|
209
|
+
return typeof getImpl(t, property) !== "undefined";
|
|
207
210
|
};
|
|
208
211
|
|
|
209
212
|
/**
|
|
@@ -219,7 +222,7 @@ Config.prototype.has = function(property) {
|
|
|
219
222
|
*
|
|
220
223
|
* <p>Using the function within your module:</p>
|
|
221
224
|
* <pre>
|
|
222
|
-
*
|
|
225
|
+
* const CONFIG = require("config");
|
|
223
226
|
* CONFIG.util.setModuleDefaults("MyModule", {
|
|
224
227
|
* templateName: "t-50",
|
|
225
228
|
* colorScheme: "green"
|
|
@@ -242,8 +245,8 @@ Config.prototype.has = function(property) {
|
|
|
242
245
|
util.setModuleDefaults = function (moduleName, defaultProperties) {
|
|
243
246
|
|
|
244
247
|
// Copy the properties into a new object
|
|
245
|
-
|
|
246
|
-
|
|
248
|
+
const t = this;
|
|
249
|
+
const moduleConfig = util.cloneDeep(defaultProperties);
|
|
247
250
|
|
|
248
251
|
// Set module defaults into the first sources element
|
|
249
252
|
if (configSources.length === 0 || configSources[0].name !== 'Module Defaults') {
|
|
@@ -296,7 +299,7 @@ util.setModuleDefaults = function (moduleName, defaultProperties) {
|
|
|
296
299
|
*
|
|
297
300
|
* <p>Example:</p>
|
|
298
301
|
* <pre>
|
|
299
|
-
*
|
|
302
|
+
* const CONFIG = require('config');
|
|
300
303
|
* ...
|
|
301
304
|
*
|
|
302
305
|
* // Hide the Amazon S3 credentials
|
|
@@ -351,8 +354,8 @@ util.makeHidden = function(object, property, value) {
|
|
|
351
354
|
*
|
|
352
355
|
* <p>Example:</p>
|
|
353
356
|
* <pre>
|
|
354
|
-
*
|
|
355
|
-
*
|
|
357
|
+
* const config = require('config');
|
|
358
|
+
* const myObject = {hello:'world'};
|
|
356
359
|
* config.util.makeImmutable(myObject);
|
|
357
360
|
* </pre>
|
|
358
361
|
*
|
|
@@ -369,7 +372,7 @@ util.makeImmutable = function(object, property, value) {
|
|
|
369
372
|
if (Buffer.isBuffer(object)) {
|
|
370
373
|
return object;
|
|
371
374
|
}
|
|
372
|
-
|
|
375
|
+
let properties = null;
|
|
373
376
|
|
|
374
377
|
// Backwards compatibility mode where property/value can be specified
|
|
375
378
|
if (typeof property === 'string') {
|
|
@@ -389,9 +392,9 @@ util.makeImmutable = function(object, property, value) {
|
|
|
389
392
|
}
|
|
390
393
|
|
|
391
394
|
// Process each property
|
|
392
|
-
for (
|
|
393
|
-
|
|
394
|
-
|
|
395
|
+
for (let i = 0; i < properties.length; i++) {
|
|
396
|
+
const propertyName = properties[i];
|
|
397
|
+
let value = object[propertyName];
|
|
395
398
|
|
|
396
399
|
if (value instanceof RawConfig) {
|
|
397
400
|
Object.defineProperty(object, propertyName, {
|
|
@@ -449,7 +452,7 @@ util.makeImmutable = function(object, property, value) {
|
|
|
449
452
|
* name, original, and parsed elements
|
|
450
453
|
*/
|
|
451
454
|
util.getConfigSources = function() {
|
|
452
|
-
|
|
455
|
+
const t = this;
|
|
453
456
|
return configSources.slice(0);
|
|
454
457
|
};
|
|
455
458
|
|
|
@@ -468,7 +471,7 @@ util.getConfigSources = function() {
|
|
|
468
471
|
* @return options[optionName] if defined, defaultValue if not.
|
|
469
472
|
*/
|
|
470
473
|
util.getOption = function(options, optionName, defaultValue) {
|
|
471
|
-
if (options !== undefined && options[optionName] !== undefined){
|
|
474
|
+
if (options !== undefined && typeof options[optionName] !== 'undefined'){
|
|
472
475
|
return options[optionName];
|
|
473
476
|
} else {
|
|
474
477
|
return defaultValue;
|
|
@@ -541,11 +544,11 @@ util.getOption = function(options, optionName, defaultValue) {
|
|
|
541
544
|
util.loadFileConfigs = function(configDir, options) {
|
|
542
545
|
|
|
543
546
|
// Initialize
|
|
544
|
-
|
|
545
|
-
|
|
547
|
+
const t = this;
|
|
548
|
+
const config = {};
|
|
546
549
|
|
|
547
550
|
// Specify variables that can be used to define the environment
|
|
548
|
-
|
|
551
|
+
const node_env_var_names = ['NODE_CONFIG_ENV', 'NODE_ENV'];
|
|
549
552
|
|
|
550
553
|
// Loop through the variables to try and set environment
|
|
551
554
|
for (const node_env_var_name of node_env_var_names) {
|
|
@@ -568,19 +571,19 @@ util.loadFileConfigs = function(configDir, options) {
|
|
|
568
571
|
// Split files name, for loading multiple files.
|
|
569
572
|
NODE_ENV = NODE_ENV.split(',');
|
|
570
573
|
|
|
571
|
-
|
|
574
|
+
let dir = configDir || util.initParam('NODE_CONFIG_DIR', Path.join( process.cwd(), 'config') );
|
|
572
575
|
dir = _toAbsolutePath(dir);
|
|
573
576
|
|
|
574
577
|
APP_INSTANCE = util.initParam('NODE_APP_INSTANCE');
|
|
575
578
|
CONFIG_SKIP_GITCRYPT = util.initParam('CONFIG_SKIP_GITCRYPT');
|
|
576
579
|
|
|
577
580
|
// This is for backward compatibility
|
|
578
|
-
|
|
581
|
+
const runtimeFilename = util.initParam('NODE_CONFIG_RUNTIME_JSON', Path.join(dir , 'runtime.json') );
|
|
579
582
|
|
|
580
583
|
NODE_CONFIG_PARSER = util.initParam('NODE_CONFIG_PARSER');
|
|
581
584
|
if (NODE_CONFIG_PARSER) {
|
|
582
585
|
try {
|
|
583
|
-
|
|
586
|
+
const parserModule = Path.isAbsolute(NODE_CONFIG_PARSER)
|
|
584
587
|
? NODE_CONFIG_PARSER
|
|
585
588
|
: Path.join(dir, NODE_CONFIG_PARSER);
|
|
586
589
|
Parser = require(parserModule);
|
|
@@ -591,16 +594,15 @@ util.loadFileConfigs = function(configDir, options) {
|
|
|
591
594
|
}
|
|
592
595
|
}
|
|
593
596
|
|
|
594
|
-
|
|
595
|
-
|
|
597
|
+
const HOST = util.initParam('HOST');
|
|
598
|
+
const HOSTNAME = util.initParam('HOSTNAME');
|
|
596
599
|
|
|
597
600
|
// Determine the host name from the OS module, $HOST, or $HOSTNAME
|
|
598
601
|
// Remove any . appendages, and default to null if not set
|
|
602
|
+
let hostName = HOST || HOSTNAME;
|
|
599
603
|
try {
|
|
600
|
-
var hostName = HOST || HOSTNAME;
|
|
601
|
-
|
|
602
604
|
if (!hostName) {
|
|
603
|
-
|
|
605
|
+
const OS = require('os');
|
|
604
606
|
hostName = OS.hostname();
|
|
605
607
|
}
|
|
606
608
|
} catch (e) {
|
|
@@ -611,11 +613,11 @@ util.loadFileConfigs = function(configDir, options) {
|
|
|
611
613
|
env.HOSTNAME = hostName;
|
|
612
614
|
|
|
613
615
|
// Read each file in turn
|
|
614
|
-
|
|
616
|
+
const baseNames = ['default'].concat(NODE_ENV);
|
|
615
617
|
|
|
616
618
|
// #236: Also add full hostname when they are different.
|
|
617
619
|
if (hostName) {
|
|
618
|
-
|
|
620
|
+
const firstDomain = hostName.split('.')[0];
|
|
619
621
|
|
|
620
622
|
NODE_ENV.forEach(function(env) {
|
|
621
623
|
// Backward compatibility
|
|
@@ -632,9 +634,9 @@ util.loadFileConfigs = function(configDir, options) {
|
|
|
632
634
|
baseNames.push('local', 'local-' + env);
|
|
633
635
|
});
|
|
634
636
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
637
|
+
const allowedFiles = {};
|
|
638
|
+
let resolutionIndex = 1;
|
|
639
|
+
const extNames = Parser.getFilesOrder();
|
|
638
640
|
baseNames.forEach(function(baseName) {
|
|
639
641
|
extNames.forEach(function(extName) {
|
|
640
642
|
allowedFiles[baseName + '.' + extName] = resolutionIndex++;
|
|
@@ -644,9 +646,9 @@ util.loadFileConfigs = function(configDir, options) {
|
|
|
644
646
|
});
|
|
645
647
|
});
|
|
646
648
|
|
|
647
|
-
|
|
649
|
+
const locatedFiles = util.locateMatchingFiles(dir, allowedFiles);
|
|
648
650
|
locatedFiles.forEach(function(fullFilename) {
|
|
649
|
-
|
|
651
|
+
const configObj = util.parseFile(fullFilename, options);
|
|
650
652
|
if (configObj) {
|
|
651
653
|
util.extendDeep(config, configObj);
|
|
652
654
|
}
|
|
@@ -655,7 +657,7 @@ util.loadFileConfigs = function(configDir, options) {
|
|
|
655
657
|
// Override configurations from the $NODE_CONFIG environment variable
|
|
656
658
|
// NODE_CONFIG only applies to the base config
|
|
657
659
|
if (!configDir) {
|
|
658
|
-
|
|
660
|
+
let envConfig = {};
|
|
659
661
|
|
|
660
662
|
CONFIG_DIR = dir;
|
|
661
663
|
|
|
@@ -666,7 +668,7 @@ util.loadFileConfigs = function(configDir, options) {
|
|
|
666
668
|
console.error('The $NODE_CONFIG environment variable is malformed JSON');
|
|
667
669
|
}
|
|
668
670
|
util.extendDeep(config, envConfig);
|
|
669
|
-
|
|
671
|
+
const skipConfigSources = util.getOption(options,'skipConfigSources', false);
|
|
670
672
|
if (!skipConfigSources){
|
|
671
673
|
configSources.push({
|
|
672
674
|
name: "$NODE_CONFIG",
|
|
@@ -676,7 +678,7 @@ util.loadFileConfigs = function(configDir, options) {
|
|
|
676
678
|
}
|
|
677
679
|
|
|
678
680
|
// Override configurations from the --NODE_CONFIG command line
|
|
679
|
-
|
|
681
|
+
let cmdLineConfig = util.getCmdLineArg('NODE_CONFIG');
|
|
680
682
|
if (cmdLineConfig) {
|
|
681
683
|
try {
|
|
682
684
|
cmdLineConfig = JSON.parse(cmdLineConfig);
|
|
@@ -684,7 +686,7 @@ util.loadFileConfigs = function(configDir, options) {
|
|
|
684
686
|
console.error('The --NODE_CONFIG={json} command line argument is malformed JSON');
|
|
685
687
|
}
|
|
686
688
|
util.extendDeep(config, cmdLineConfig);
|
|
687
|
-
|
|
689
|
+
const skipConfigSources = util.getOption(options,'skipConfigSources', false);
|
|
688
690
|
if (!skipConfigSources){
|
|
689
691
|
configSources.push({
|
|
690
692
|
name: "--NODE_CONFIG argument",
|
|
@@ -698,11 +700,11 @@ util.loadFileConfigs = function(configDir, options) {
|
|
|
698
700
|
}
|
|
699
701
|
|
|
700
702
|
// Override with environment variables if there is a custom-environment-variables.EXT mapping file
|
|
701
|
-
|
|
703
|
+
const customEnvVars = util.getCustomEnvVars(dir, extNames);
|
|
702
704
|
util.extendDeep(config, customEnvVars);
|
|
703
705
|
|
|
704
706
|
// Extend the original config with the contents of runtime.json (backwards compatibility)
|
|
705
|
-
|
|
707
|
+
const runtimeJson = util.parseFile(runtimeFilename) || {};
|
|
706
708
|
util.extendDeep(config, runtimeJson);
|
|
707
709
|
|
|
708
710
|
util.resolveDeferredConfigs(config);
|
|
@@ -744,15 +746,15 @@ util.locateMatchingFiles = function(configDirs, allowedFiles) {
|
|
|
744
746
|
|
|
745
747
|
// Using basic recursion pattern, find all the deferred values and resolve them.
|
|
746
748
|
util.resolveDeferredConfigs = function (config) {
|
|
747
|
-
|
|
749
|
+
const deferred = [];
|
|
748
750
|
|
|
749
751
|
function _iterate (prop) {
|
|
750
752
|
|
|
751
753
|
// We put the properties we are going to look it in an array to keep the order predictable
|
|
752
|
-
|
|
754
|
+
const propsToSort = [];
|
|
753
755
|
|
|
754
756
|
// First step is to put the properties of interest in an array
|
|
755
|
-
for (
|
|
757
|
+
for (const property in prop) {
|
|
756
758
|
if (Object.hasOwnProperty.call(prop, property) && prop[property] != null) {
|
|
757
759
|
propsToSort.push(property);
|
|
758
760
|
}
|
|
@@ -763,7 +765,7 @@ util.resolveDeferredConfigs = function (config) {
|
|
|
763
765
|
if (prop[property].constructor === Object) {
|
|
764
766
|
_iterate(prop[property]);
|
|
765
767
|
} else if (prop[property].constructor === Array) {
|
|
766
|
-
for (
|
|
768
|
+
for (let i = 0; i < prop[property].length; i++) {
|
|
767
769
|
if (prop[property][i] instanceof DeferredConfig) {
|
|
768
770
|
deferred.push(prop[property][i].prepare(config, prop[property], i));
|
|
769
771
|
}
|
|
@@ -812,10 +814,10 @@ util.resolveDeferredConfigs = function (config) {
|
|
|
812
814
|
* @return configObject {object|null} The configuration object parsed from the file
|
|
813
815
|
*/
|
|
814
816
|
util.parseFile = function(fullFilename, options) {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
817
|
+
const t = this; // Initialize
|
|
818
|
+
let configObject = null;
|
|
819
|
+
let fileContent = null;
|
|
820
|
+
const stat = null;
|
|
819
821
|
|
|
820
822
|
// Note that all methods here are the Sync versions. This is appropriate during
|
|
821
823
|
// module loading (which is a synchronous operation), but not thereafter.
|
|
@@ -854,7 +856,7 @@ util.parseFile = function(fullFilename, options) {
|
|
|
854
856
|
}
|
|
855
857
|
|
|
856
858
|
// Keep track of this configuration sources, including empty ones, unless the skipConfigSources flag is set to true in the options
|
|
857
|
-
|
|
859
|
+
const skipConfigSources = util.getOption(options,'skipConfigSources', false);
|
|
858
860
|
if (typeof configObject === 'object' && !skipConfigSources) {
|
|
859
861
|
configSources.push({
|
|
860
862
|
name: fullFilename,
|
|
@@ -893,7 +895,7 @@ util.parseFile = function(fullFilename, options) {
|
|
|
893
895
|
* @return {configObject} The configuration object parsed from the string
|
|
894
896
|
*/
|
|
895
897
|
util.parseString = function (content, format) {
|
|
896
|
-
|
|
898
|
+
const parser = Parser.getParser(format);
|
|
897
899
|
if (typeof parser === 'function') {
|
|
898
900
|
return parser(null, content);
|
|
899
901
|
}
|
|
@@ -908,7 +910,7 @@ util.parseString = function (content, format) {
|
|
|
908
910
|
* </p>
|
|
909
911
|
*
|
|
910
912
|
* <pre>
|
|
911
|
-
*
|
|
913
|
+
* const CUST_CONFIG = require('config').Customer;
|
|
912
914
|
* CUST_CONFIG.get(...)
|
|
913
915
|
* </pre>
|
|
914
916
|
*
|
|
@@ -924,7 +926,7 @@ util.attachProtoDeep = function(toObject, depth) {
|
|
|
924
926
|
}
|
|
925
927
|
|
|
926
928
|
// Recursion detection
|
|
927
|
-
|
|
929
|
+
const t = this;
|
|
928
930
|
depth = (depth === null ? DEFAULT_CLONE_DEPTH : depth);
|
|
929
931
|
if (depth < 0) {
|
|
930
932
|
return toObject;
|
|
@@ -932,14 +934,14 @@ util.attachProtoDeep = function(toObject, depth) {
|
|
|
932
934
|
|
|
933
935
|
// Adding Config.prototype methods directly to toObject as hidden properties
|
|
934
936
|
// because adding to toObject.__proto__ exposes the function in toObject
|
|
935
|
-
for (
|
|
937
|
+
for (const fnName in Config.prototype) {
|
|
936
938
|
if (!toObject[fnName]) {
|
|
937
939
|
util.makeHidden(toObject, fnName, Config.prototype[fnName]);
|
|
938
940
|
}
|
|
939
941
|
}
|
|
940
942
|
|
|
941
943
|
// Add prototypes to sub-objects
|
|
942
|
-
for (
|
|
944
|
+
for (const prop in toObject) {
|
|
943
945
|
if (util.isObject(toObject[prop])) {
|
|
944
946
|
util.attachProtoDeep(toObject[prop], depth - 1);
|
|
945
947
|
}
|
|
@@ -976,10 +978,10 @@ util.attachProtoDeep = function(toObject, depth) {
|
|
|
976
978
|
util.cloneDeep = function cloneDeep(parent, depth, circular, prototype) {
|
|
977
979
|
// maintain two arrays for circular references, where corresponding parents
|
|
978
980
|
// and children have the same index
|
|
979
|
-
|
|
980
|
-
|
|
981
|
+
const allParents = [];
|
|
982
|
+
const allChildren = [];
|
|
981
983
|
|
|
982
|
-
|
|
984
|
+
const useBuffer = typeof Buffer !== 'undefined';
|
|
983
985
|
|
|
984
986
|
if (typeof circular === 'undefined')
|
|
985
987
|
circular = true;
|
|
@@ -996,7 +998,7 @@ util.cloneDeep = function cloneDeep(parent, depth, circular, prototype) {
|
|
|
996
998
|
if (depth === 0)
|
|
997
999
|
return parent;
|
|
998
1000
|
|
|
999
|
-
|
|
1001
|
+
let child;
|
|
1000
1002
|
if (typeof parent != 'object') {
|
|
1001
1003
|
return parent;
|
|
1002
1004
|
}
|
|
@@ -1018,7 +1020,7 @@ util.cloneDeep = function cloneDeep(parent, depth, circular, prototype) {
|
|
|
1018
1020
|
}
|
|
1019
1021
|
|
|
1020
1022
|
if (circular) {
|
|
1021
|
-
|
|
1023
|
+
const index = allParents.indexOf(parent);
|
|
1022
1024
|
|
|
1023
1025
|
if (index != -1) {
|
|
1024
1026
|
return allChildren[index];
|
|
@@ -1027,9 +1029,9 @@ util.cloneDeep = function cloneDeep(parent, depth, circular, prototype) {
|
|
|
1027
1029
|
allChildren.push(child);
|
|
1028
1030
|
}
|
|
1029
1031
|
|
|
1030
|
-
for (
|
|
1031
|
-
|
|
1032
|
-
|
|
1032
|
+
for (const i in parent) {
|
|
1033
|
+
const propDescriptor = Object.getOwnPropertyDescriptor(parent,i);
|
|
1034
|
+
const hasGetter = ((typeof propDescriptor !== 'undefined') && (typeof propDescriptor.get !== 'undefined'));
|
|
1033
1035
|
|
|
1034
1036
|
if (hasGetter){
|
|
1035
1037
|
Object.defineProperty(child,i,propDescriptor);
|
|
@@ -1056,7 +1058,7 @@ util.cloneDeep = function cloneDeep(parent, depth, circular, prototype) {
|
|
|
1056
1058
|
* @param value {*} - value to set, ignoring null
|
|
1057
1059
|
*/
|
|
1058
1060
|
util.setPath = function (object, path, value) {
|
|
1059
|
-
|
|
1061
|
+
let nextKey = null;
|
|
1060
1062
|
if (value === null || path.length === 0) {
|
|
1061
1063
|
return;
|
|
1062
1064
|
}
|
|
@@ -1087,20 +1089,22 @@ util.setPath = function (object, path, value) {
|
|
|
1087
1089
|
* corresponded to a key in `variables`
|
|
1088
1090
|
*/
|
|
1089
1091
|
util.substituteDeep = function (substitutionMap, variables) {
|
|
1090
|
-
|
|
1092
|
+
const result = {};
|
|
1091
1093
|
|
|
1092
1094
|
function _substituteVars(map, vars, pathTo) {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
+
let parsedValue;
|
|
1096
|
+
for (const prop in map) {
|
|
1097
|
+
const value = map[prop];
|
|
1095
1098
|
if (typeof(value) === 'string') { // We found a leaf variable name
|
|
1096
|
-
if (vars[value] !== undefined && vars[value] !== '') { // if the vars provide a value set the value in the result map
|
|
1099
|
+
if (typeof vars[value] !== 'undefined' && vars[value] !== '') { // if the vars provide a value set the value in the result map
|
|
1097
1100
|
util.setPath(result, pathTo.concat(prop), vars[value]);
|
|
1098
1101
|
}
|
|
1099
1102
|
}
|
|
1100
1103
|
else if (util.isObject(value)) { // work on the subtree, giving it a clone of the pathTo
|
|
1101
|
-
if ('__name' in value && '__format' in value && vars[value.__name] !== undefined && vars[value.__name] !== '') {
|
|
1104
|
+
if ('__name' in value && '__format' in value && typeof vars[value.__name] !== 'undefined' && vars[value.__name] !== '') {
|
|
1105
|
+
let parsedValue;
|
|
1102
1106
|
try {
|
|
1103
|
-
|
|
1107
|
+
parsedValue = util.parseString(vars[value.__name], value.__format);
|
|
1104
1108
|
} catch(err) {
|
|
1105
1109
|
err.message = '__format parser error in ' + value.__name + ': ' + err.message;
|
|
1106
1110
|
throw err;
|
|
@@ -1132,17 +1136,17 @@ util.substituteDeep = function (substitutionMap, variables) {
|
|
|
1132
1136
|
* @returns {object} - mapped environment variables or {} if there are none
|
|
1133
1137
|
*/
|
|
1134
1138
|
util.getCustomEnvVars = function (configDir, extNames) {
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1139
|
+
const result = {};
|
|
1140
|
+
let resolutionIndex = 1;
|
|
1141
|
+
const allowedFiles = {};
|
|
1138
1142
|
extNames.forEach(function (extName) {
|
|
1139
1143
|
allowedFiles['custom-environment-variables' + '.' + extName] = resolutionIndex++;
|
|
1140
1144
|
});
|
|
1141
|
-
|
|
1145
|
+
const locatedFiles = util.locateMatchingFiles(configDir, allowedFiles);
|
|
1142
1146
|
locatedFiles.forEach(function (fullFilename) {
|
|
1143
|
-
|
|
1147
|
+
const configObj = util.parseFile(fullFilename);
|
|
1144
1148
|
if (configObj) {
|
|
1145
|
-
|
|
1149
|
+
const environmentSubstitutions = util.substituteDeep(configObj, process.env);
|
|
1146
1150
|
util.extendDeep(result, environmentSubstitutions);
|
|
1147
1151
|
}
|
|
1148
1152
|
});
|
|
@@ -1162,7 +1166,7 @@ util.getCustomEnvVars = function (configDir, extNames) {
|
|
|
1162
1166
|
util.equalsDeep = function(object1, object2, depth) {
|
|
1163
1167
|
|
|
1164
1168
|
// Recursion detection
|
|
1165
|
-
|
|
1169
|
+
const t = this;
|
|
1166
1170
|
depth = (depth === null ? DEFAULT_CLONE_DEPTH : depth);
|
|
1167
1171
|
if (depth < 0) {
|
|
1168
1172
|
return {};
|
|
@@ -1187,7 +1191,7 @@ util.equalsDeep = function(object1, object2, depth) {
|
|
|
1187
1191
|
}
|
|
1188
1192
|
|
|
1189
1193
|
// Compare the values
|
|
1190
|
-
for (
|
|
1194
|
+
for (const prop in object1) {
|
|
1191
1195
|
|
|
1192
1196
|
// Call recursively if an object or array
|
|
1193
1197
|
if (object1[prop] && typeof(object1[prop]) === 'object') {
|
|
@@ -1229,7 +1233,8 @@ util.equalsDeep = function(object1, object2, depth) {
|
|
|
1229
1233
|
util.diffDeep = function(object1, object2, depth) {
|
|
1230
1234
|
|
|
1231
1235
|
// Recursion detection
|
|
1232
|
-
|
|
1236
|
+
const t = this;
|
|
1237
|
+
const diff = {};
|
|
1233
1238
|
depth = (depth === null ? DEFAULT_CLONE_DEPTH : depth);
|
|
1234
1239
|
if (depth < 0) {
|
|
1235
1240
|
return {};
|
|
@@ -1237,9 +1242,9 @@ util.diffDeep = function(object1, object2, depth) {
|
|
|
1237
1242
|
|
|
1238
1243
|
// Process each element from object2, adding any element that's different
|
|
1239
1244
|
// from object 1.
|
|
1240
|
-
for (
|
|
1241
|
-
|
|
1242
|
-
|
|
1245
|
+
for (const parm in object2) {
|
|
1246
|
+
const value1 = object1[parm];
|
|
1247
|
+
const value2 = object2[parm];
|
|
1243
1248
|
if (value1 && value2 && util.isObject(value2)) {
|
|
1244
1249
|
if (!(util.equalsDeep(value1, value2))) {
|
|
1245
1250
|
diff[parm] = util.diffDeep(value1, value2, depth - 1);
|
|
@@ -1276,9 +1281,9 @@ util.diffDeep = function(object1, object2, depth) {
|
|
|
1276
1281
|
util.extendDeep = function(mergeInto) {
|
|
1277
1282
|
|
|
1278
1283
|
// Initialize
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1284
|
+
const t = this;
|
|
1285
|
+
const vargs = Array.prototype.slice.call(arguments, 1);
|
|
1286
|
+
let depth = vargs.pop();
|
|
1282
1287
|
if (typeof(depth) != 'number') {
|
|
1283
1288
|
vargs.push(depth);
|
|
1284
1289
|
depth = DEFAULT_CLONE_DEPTH;
|
|
@@ -1293,11 +1298,11 @@ util.extendDeep = function(mergeInto) {
|
|
|
1293
1298
|
vargs.forEach(function(mergeFrom) {
|
|
1294
1299
|
|
|
1295
1300
|
// Cycle through each element of the object to merge from
|
|
1296
|
-
for (
|
|
1301
|
+
for (const prop in mergeFrom) {
|
|
1297
1302
|
|
|
1298
1303
|
// save original value in deferred elements
|
|
1299
|
-
|
|
1300
|
-
|
|
1304
|
+
const fromIsDeferredFunc = mergeFrom[prop] instanceof DeferredConfig;
|
|
1305
|
+
const isDeferredFunc = mergeInto[prop] instanceof DeferredConfig;
|
|
1301
1306
|
|
|
1302
1307
|
if (fromIsDeferredFunc && Object.hasOwnProperty.call(mergeInto, prop)) {
|
|
1303
1308
|
mergeFrom[prop]._original = isDeferredFunc ? mergeInto[prop]._original : mergeInto[prop];
|
|
@@ -1373,10 +1378,10 @@ util.isPromise = function(obj) {
|
|
|
1373
1378
|
* @return {Any} The found value, or default value
|
|
1374
1379
|
*/
|
|
1375
1380
|
util.initParam = function (paramName, defaultValue) {
|
|
1376
|
-
|
|
1381
|
+
const t = this;
|
|
1377
1382
|
|
|
1378
1383
|
// Record and return the value
|
|
1379
|
-
|
|
1384
|
+
const value = util.getCmdLineArg(paramName) || process.env[paramName] || defaultValue;
|
|
1380
1385
|
env[paramName] = value;
|
|
1381
1386
|
return value;
|
|
1382
1387
|
}
|
|
@@ -1397,10 +1402,10 @@ util.initParam = function (paramName, defaultValue) {
|
|
|
1397
1402
|
* @return {*} false if the argument was not found, the argument value if found
|
|
1398
1403
|
*/
|
|
1399
1404
|
util.getCmdLineArg = function (searchFor) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1405
|
+
const cmdLineArgs = process.argv.slice(2, process.argv.length);
|
|
1406
|
+
const argName = '--' + searchFor + '=';
|
|
1402
1407
|
|
|
1403
|
-
for (
|
|
1408
|
+
for (let argvIt = 0; argvIt < cmdLineArgs.length; argvIt++) {
|
|
1404
1409
|
if (cmdLineArgs[argvIt].indexOf(argName) === 0) {
|
|
1405
1410
|
return cmdLineArgs[argvIt].substr(argName.length);
|
|
1406
1411
|
}
|
|
@@ -1434,7 +1439,7 @@ util.getEnv = function (varName) {
|
|
|
1434
1439
|
* @returns {string} Flags
|
|
1435
1440
|
*/
|
|
1436
1441
|
util.getRegExpFlags = function (re) {
|
|
1437
|
-
|
|
1442
|
+
let flags = '';
|
|
1438
1443
|
re.global && (flags += 'g');
|
|
1439
1444
|
re.ignoreCase && (flags += 'i');
|
|
1440
1445
|
re.multiline && (flags += 'm');
|
|
@@ -1453,15 +1458,15 @@ util.toObject = function(config) {
|
|
|
1453
1458
|
|
|
1454
1459
|
// Run strictness checks on NODE_ENV and NODE_APP_INSTANCE and throw an error if there's a problem.
|
|
1455
1460
|
util.runStrictnessChecks = function (config) {
|
|
1456
|
-
|
|
1461
|
+
const sources = config.util.getConfigSources();
|
|
1457
1462
|
|
|
1458
|
-
|
|
1463
|
+
const sourceFilenames = sources.map(function (src) {
|
|
1459
1464
|
return Path.basename(src.name);
|
|
1460
1465
|
});
|
|
1461
1466
|
|
|
1462
1467
|
NODE_ENV.forEach(function(env) {
|
|
1463
1468
|
// Throw an exception if there's no explicit config file for NODE_ENV
|
|
1464
|
-
|
|
1469
|
+
const anyFilesMatchEnv = sourceFilenames.some(function (filename) {
|
|
1465
1470
|
return filename.match(env);
|
|
1466
1471
|
});
|
|
1467
1472
|
// development is special-cased because it's the default value
|
|
@@ -1475,7 +1480,7 @@ util.runStrictnessChecks = function (config) {
|
|
|
1475
1480
|
});
|
|
1476
1481
|
|
|
1477
1482
|
// Throw an exception if there's no explicit config file for NODE_APP_INSTANCE
|
|
1478
|
-
|
|
1483
|
+
const anyFilesMatchInstance = sourceFilenames.some(function (filename) {
|
|
1479
1484
|
return filename.match(APP_INSTANCE);
|
|
1480
1485
|
});
|
|
1481
1486
|
if (APP_INSTANCE && !anyFilesMatchInstance) {
|
|
@@ -1483,9 +1488,9 @@ util.runStrictnessChecks = function (config) {
|
|
|
1483
1488
|
}
|
|
1484
1489
|
|
|
1485
1490
|
function _warnOrThrow (msg) {
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1491
|
+
const beStrict = process.env.NODE_CONFIG_STRICT_MODE;
|
|
1492
|
+
const prefix = beStrict ? 'FATAL: ' : 'WARNING: ';
|
|
1493
|
+
const seeURL = 'See https://github.com/node-config/node-config/wiki/Strict-Mode';
|
|
1489
1494
|
|
|
1490
1495
|
console.error(prefix+msg);
|
|
1491
1496
|
console.error(prefix+seeURL);
|
|
@@ -1507,14 +1512,14 @@ function _toAbsolutePath (configDir) {
|
|
|
1507
1512
|
}
|
|
1508
1513
|
|
|
1509
1514
|
// Instantiate and export the configuration
|
|
1510
|
-
|
|
1515
|
+
const config = module.exports = new Config();
|
|
1511
1516
|
|
|
1512
1517
|
// copy methods to util for backwards compatibility
|
|
1513
1518
|
util.stripComments = Parser.stripComments;
|
|
1514
1519
|
util.stripYamlComments = Parser.stripYamlComments;
|
|
1515
1520
|
|
|
1516
1521
|
// Produce warnings if the configuration is empty
|
|
1517
|
-
|
|
1522
|
+
const showWarnings = !(util.initParam('SUPPRESS_NO_CONFIG_WARNING'));
|
|
1518
1523
|
if (showWarnings && Object.keys(config).length === 0) {
|
|
1519
1524
|
console.error('WARNING: No configurations found in configuration directory:' +CONFIG_DIR);
|
|
1520
1525
|
console.error('WARNING: To disable this warning set SUPPRESS_NO_CONFIG_WARNING in the environment.');
|
package/package.json
CHANGED
package/parser.js
CHANGED
|
@@ -61,6 +61,7 @@ Parser.tsParser = function(filename, content) {
|
|
|
61
61
|
if (!require.extensions['.ts']) {
|
|
62
62
|
require(TS_DEP).register({
|
|
63
63
|
lazy: true,
|
|
64
|
+
ignore: ['(?:^|/)node_modules/', '.*(?<!\.ts)$'],
|
|
64
65
|
transpileOnly: true,
|
|
65
66
|
compilerOptions: {
|
|
66
67
|
allowJs: true,
|
|
@@ -154,20 +155,14 @@ Parser.yamlParser = function(filename, content) {
|
|
|
154
155
|
};
|
|
155
156
|
|
|
156
157
|
Parser.jsonParser = function(filename, content) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
throw e;
|
|
165
|
-
}
|
|
166
|
-
if (!JSON5) {
|
|
167
|
-
JSON5 = require(JSON5_DEP);
|
|
168
|
-
}
|
|
158
|
+
/**
|
|
159
|
+
* Default JSON parsing to JSON5 parser.
|
|
160
|
+
* This is due to issues with removing supported comments.
|
|
161
|
+
* More information can be found here: https://github.com/node-config/node-config/issues/715
|
|
162
|
+
*/
|
|
163
|
+
JSON5 = require(JSON5_DEP);
|
|
164
|
+
|
|
169
165
|
return JSON5.parse(content);
|
|
170
|
-
}
|
|
171
166
|
};
|
|
172
167
|
|
|
173
168
|
Parser.json5Parser = function(filename, content) {
|
|
@@ -197,9 +192,9 @@ Parser.csonParser = function(filename, content) {
|
|
|
197
192
|
}
|
|
198
193
|
// Allow comments in CSON files
|
|
199
194
|
if (typeof CSON.parseSync === 'function') {
|
|
200
|
-
return CSON.parseSync(
|
|
195
|
+
return CSON.parseSync(content);
|
|
201
196
|
}
|
|
202
|
-
return CSON.parse(
|
|
197
|
+
return CSON.parse(content);
|
|
203
198
|
};
|
|
204
199
|
|
|
205
200
|
Parser.propertiesParser = function(filename, content) {
|
|
@@ -226,7 +221,7 @@ Parser.propertiesParser = function(filename, content) {
|
|
|
226
221
|
* @return {string} The string with comments stripped.
|
|
227
222
|
*/
|
|
228
223
|
Parser.stripComments = function(fileStr, stringRegex) {
|
|
229
|
-
stringRegex = stringRegex || /([
|
|
224
|
+
stringRegex = stringRegex || /"((?:[^"\\]|\\.)*)"/g;
|
|
230
225
|
|
|
231
226
|
var uid = '_' + +new Date(),
|
|
232
227
|
primitives = [],
|