@reimorg/config 1.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/History.md +710 -0
- package/LICENSE +19 -0
- package/README.md +121 -0
- package/async.d.ts +29 -0
- package/async.js +69 -0
- package/defer.d.ts +30 -0
- package/defer.js +23 -0
- package/index.d.ts +30 -0
- package/index.js +20 -0
- package/lib/config.js +627 -0
- package/lib/get.js +1 -0
- package/lib/util.js +1220 -0
- package/package.json +68 -0
- package/parser.d.ts +134 -0
- package/parser.js +299 -0
- package/raw.d.ts +18 -0
- package/raw.js +15 -0
package/lib/config.js
ADDED
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
// config.js (c) 2010-2022 Loren West and other contributors
|
|
2
|
+
// May be freely distributed under the MIT license.
|
|
3
|
+
// For further details and documentation:
|
|
4
|
+
// http://lorenwest.github.com/node-config
|
|
5
|
+
|
|
6
|
+
// Dependencies
|
|
7
|
+
const RawConfig = require('../raw').RawConfig;
|
|
8
|
+
const { Util, Load } = require('./util.js');
|
|
9
|
+
const Path = require('path');
|
|
10
|
+
|
|
11
|
+
const DEFAULT_CLONE_DEPTH = 20;
|
|
12
|
+
let checkMutability = true; // Check for mutability/immutability on first get
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* <p>Application Configurations</p>
|
|
16
|
+
*
|
|
17
|
+
* <p>
|
|
18
|
+
* The config module exports a singleton object representing all
|
|
19
|
+
* configurations for this application deployment.
|
|
20
|
+
* </p>
|
|
21
|
+
*
|
|
22
|
+
* <p>
|
|
23
|
+
* Application configurations are stored in files within the config directory
|
|
24
|
+
* of your application. The default configuration file is loaded, followed
|
|
25
|
+
* by files specific to the deployment type (development, testing, staging,
|
|
26
|
+
* production, etc.).
|
|
27
|
+
* </p>
|
|
28
|
+
*
|
|
29
|
+
* <p>
|
|
30
|
+
* For example, with the following config/default.yaml file:
|
|
31
|
+
* </p>
|
|
32
|
+
*
|
|
33
|
+
* <pre>
|
|
34
|
+
* ...
|
|
35
|
+
* customer:
|
|
36
|
+
* initialCredit: 500
|
|
37
|
+
* db:
|
|
38
|
+
* name: customer
|
|
39
|
+
* port: 5984
|
|
40
|
+
* ...
|
|
41
|
+
* </pre>
|
|
42
|
+
*
|
|
43
|
+
* <p>
|
|
44
|
+
* The following code loads the customer section into the CONFIG variable:
|
|
45
|
+
* <p>
|
|
46
|
+
*
|
|
47
|
+
* <pre>
|
|
48
|
+
* const CONFIG = require('config').customer;
|
|
49
|
+
* ...
|
|
50
|
+
* newCustomer.creditLimit = CONFIG.initialCredit;
|
|
51
|
+
* database.open(CONFIG.db.name, CONFIG.db.port);
|
|
52
|
+
* ...
|
|
53
|
+
* </pre>
|
|
54
|
+
*
|
|
55
|
+
* @module config
|
|
56
|
+
* @class Config
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* <p>Get the configuration object.</p>
|
|
61
|
+
*
|
|
62
|
+
* <p>
|
|
63
|
+
* The configuration object is a shared singleton object within the application,
|
|
64
|
+
* attained by calling require('config').
|
|
65
|
+
* </p>
|
|
66
|
+
*
|
|
67
|
+
* <p>
|
|
68
|
+
* Usually you'll specify a CONFIG variable at the top of your .js file
|
|
69
|
+
* for file/module scope. If you want the root of the object, you can do this:
|
|
70
|
+
* </p>
|
|
71
|
+
* <pre>
|
|
72
|
+
* const CONFIG = require('config');
|
|
73
|
+
* </pre>
|
|
74
|
+
*
|
|
75
|
+
* <p>
|
|
76
|
+
* Sometimes you only care about a specific sub-object within the CONFIG
|
|
77
|
+
* object. In that case you could do this at the top of your file:
|
|
78
|
+
* </p>
|
|
79
|
+
* <pre>
|
|
80
|
+
* const CONFIG = require('config').customer;
|
|
81
|
+
* or
|
|
82
|
+
* const CUSTOMER_CONFIG = require('config').customer;
|
|
83
|
+
* </pre>
|
|
84
|
+
*
|
|
85
|
+
* <script type="text/javascript">
|
|
86
|
+
* document.getElementById("showProtected").style.display = "block";
|
|
87
|
+
* </script>
|
|
88
|
+
*
|
|
89
|
+
* @method constructor
|
|
90
|
+
* @return CONFIG {Object} - The top level configuration object
|
|
91
|
+
*/
|
|
92
|
+
const Config = function() {
|
|
93
|
+
const t = this;
|
|
94
|
+
|
|
95
|
+
// Bind all utility functions to this
|
|
96
|
+
for (const fnName in util) {
|
|
97
|
+
if (typeof util[fnName] === 'function') {
|
|
98
|
+
util[fnName] = util[fnName].bind(t);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Merge configurations into this
|
|
103
|
+
_init(FIRST_LOAD);
|
|
104
|
+
Util.extendDeep(t, FIRST_LOAD.config);
|
|
105
|
+
util.attachProtoDeep(t);
|
|
106
|
+
|
|
107
|
+
// Perform strictness checks and possibly throw an exception.
|
|
108
|
+
util.runStrictnessChecks(t);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Utilities are under the util namespace vs. at the top level
|
|
113
|
+
*/
|
|
114
|
+
const util = Config.prototype.util = {};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* <p>Get a configuration value</p>
|
|
118
|
+
*
|
|
119
|
+
* <p>
|
|
120
|
+
* This will return the specified property value, throwing an exception if the
|
|
121
|
+
* configuration isn't defined. It is used to assure configurations are defined
|
|
122
|
+
* before being used, and to prevent typos.
|
|
123
|
+
* </p>
|
|
124
|
+
*
|
|
125
|
+
* @method get
|
|
126
|
+
* @param property {string} - The configuration property to get. Can include '.' sub-properties.
|
|
127
|
+
* @return value {*} - The property value
|
|
128
|
+
*/
|
|
129
|
+
Config.prototype.get = function(property) {
|
|
130
|
+
if(property === null || typeof property === "undefined"){
|
|
131
|
+
throw new Error("Calling config.get with null or undefined argument");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Make configurations immutable after first get (unless disabled)
|
|
135
|
+
if (checkMutability) {
|
|
136
|
+
if (!FIRST_LOAD.initParam('ALLOW_CONFIG_MUTATIONS', false)) {
|
|
137
|
+
util.makeImmutable(config);
|
|
138
|
+
}
|
|
139
|
+
checkMutability = false;
|
|
140
|
+
}
|
|
141
|
+
const t = this;
|
|
142
|
+
const value = Util.getPath(t, property);
|
|
143
|
+
|
|
144
|
+
// Produce an exception if the property doesn't exist
|
|
145
|
+
if (typeof value === "undefined") {
|
|
146
|
+
throw new Error('Configuration property "' + property + '" is not defined');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Return the value
|
|
150
|
+
return value;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Test that a configuration parameter exists
|
|
155
|
+
*
|
|
156
|
+
* <pre>
|
|
157
|
+
* const config = require('config');
|
|
158
|
+
* if (config.has('customer.dbName')) {
|
|
159
|
+
* console.log('Customer database name: ' + config.customer.dbName);
|
|
160
|
+
* }
|
|
161
|
+
* </pre>
|
|
162
|
+
*
|
|
163
|
+
* @method has
|
|
164
|
+
* @param property {string} - The configuration property to test. Can include '.' sub-properties.
|
|
165
|
+
* @return {boolean} - True if the property is defined, false if not defined.
|
|
166
|
+
*/
|
|
167
|
+
Config.prototype.has = function(property) {
|
|
168
|
+
// While get() throws an exception for undefined input, has() is designed to test validity, so false is appropriate
|
|
169
|
+
if(property === null || typeof property === "undefined"){
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
const t = this;
|
|
173
|
+
return typeof Util.getPath(t, property) !== "undefined";
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* <p>
|
|
178
|
+
* Set default configurations for a node.js module.
|
|
179
|
+
* </p>
|
|
180
|
+
*
|
|
181
|
+
* <p>
|
|
182
|
+
* This allows module developers to attach their configurations onto the
|
|
183
|
+
* default configuration object so they can be configured by the consumers
|
|
184
|
+
* of the module.
|
|
185
|
+
* </p>
|
|
186
|
+
*
|
|
187
|
+
* <p>Using the function within your module:</p>
|
|
188
|
+
* <pre>
|
|
189
|
+
* const CONFIG = require("config");
|
|
190
|
+
* CONFIG.util.setModuleDefaults("MyModule", {
|
|
191
|
+
* templateName: "t-50",
|
|
192
|
+
* colorScheme: "green"
|
|
193
|
+
* });
|
|
194
|
+
* <br>
|
|
195
|
+
* // Template name may be overridden by application config files
|
|
196
|
+
* console.log("Template: " + CONFIG.MyModule.templateName);
|
|
197
|
+
* </pre>
|
|
198
|
+
*
|
|
199
|
+
* <p>
|
|
200
|
+
* The above example results in a "MyModule" element of the configuration
|
|
201
|
+
* object, containing an object with the specified default values.
|
|
202
|
+
* </p>
|
|
203
|
+
*
|
|
204
|
+
* @method setModuleDefaults
|
|
205
|
+
* @param moduleName {string} - Name of your module.
|
|
206
|
+
* @param defaultProperties {Object} - The default module configuration.
|
|
207
|
+
* @return moduleConfig {Object} - The module level configuration object.
|
|
208
|
+
*/
|
|
209
|
+
util.setModuleDefaults = function (moduleName, defaultProperties) {
|
|
210
|
+
|
|
211
|
+
// Copy the properties into a new object
|
|
212
|
+
const t = this;
|
|
213
|
+
const path = moduleName.split('.');
|
|
214
|
+
const moduleConfig = FIRST_LOAD.setModuleDefaults(moduleName, defaultProperties);
|
|
215
|
+
let existing = Util.getPath(t, path);
|
|
216
|
+
|
|
217
|
+
if (existing === undefined) {
|
|
218
|
+
Util.setPath(t, path, Util.cloneDeep(moduleConfig));
|
|
219
|
+
} else {
|
|
220
|
+
Util.extendDeep(existing, moduleConfig);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// reset the mutability check for "config.get" method.
|
|
224
|
+
// we are not making t[moduleName] immutable immediately,
|
|
225
|
+
// since there might be more modifications before the first config.get
|
|
226
|
+
if (!FIRST_LOAD.initParam('ALLOW_CONFIG_MUTATIONS', false)) {
|
|
227
|
+
checkMutability = true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Attach handlers & watchers onto the module config object
|
|
231
|
+
return util.attachProtoDeep(Util.getPath(t, path));
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* <p>Make a javascript object property immutable (assuring it cannot be changed
|
|
236
|
+
* from the current value).</p>
|
|
237
|
+
* <p>
|
|
238
|
+
* If the specified property is an object, all attributes of that object are
|
|
239
|
+
* made immutable, including properties of contained objects, recursively.
|
|
240
|
+
* If a property name isn't supplied, all properties of the object are made
|
|
241
|
+
* immutable.
|
|
242
|
+
* </p>
|
|
243
|
+
* <p>
|
|
244
|
+
*
|
|
245
|
+
* </p>
|
|
246
|
+
* <p>
|
|
247
|
+
* New properties can be added to the object and those properties will not be
|
|
248
|
+
* immutable unless this method is called on those new properties.
|
|
249
|
+
* </p>
|
|
250
|
+
* <p>
|
|
251
|
+
* This operation cannot be undone.
|
|
252
|
+
* </p>
|
|
253
|
+
*
|
|
254
|
+
* <p>Example:</p>
|
|
255
|
+
* <pre>
|
|
256
|
+
* const config = require('config');
|
|
257
|
+
* const myObject = {hello:'world'};
|
|
258
|
+
* config.util.makeImmutable(myObject);
|
|
259
|
+
* </pre>
|
|
260
|
+
*
|
|
261
|
+
* @method makeImmutable
|
|
262
|
+
* @param object {Object} - The object to specify immutable properties for
|
|
263
|
+
* @param [property] {string | [string]} - The name of the property (or array of names) to make immutable.
|
|
264
|
+
* If not provided, all owned properties of the object are made immutable.
|
|
265
|
+
* @param [value] {* | [*]} - Property value (or array of values) to set
|
|
266
|
+
* the property to before making immutable. Only used when setting a single
|
|
267
|
+
* property. Retained for backward compatibility.
|
|
268
|
+
* @return object {Object} - The original object is returned - for chaining.
|
|
269
|
+
*/
|
|
270
|
+
util.makeImmutable = function(object, property, value) {
|
|
271
|
+
if (Buffer.isBuffer(object)) {
|
|
272
|
+
return object;
|
|
273
|
+
}
|
|
274
|
+
let properties = null;
|
|
275
|
+
|
|
276
|
+
// Backwards compatibility mode where property/value can be specified
|
|
277
|
+
if (typeof property === 'string') {
|
|
278
|
+
return Object.defineProperty(object, property, {
|
|
279
|
+
value : (typeof value === 'undefined') ? object[property] : value,
|
|
280
|
+
writable : false,
|
|
281
|
+
configurable: false
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Get the list of properties to work with
|
|
286
|
+
if (Array.isArray(property)) {
|
|
287
|
+
properties = property;
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
properties = Object.keys(object);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Process each property
|
|
294
|
+
for (let i = 0; i < properties.length; i++) {
|
|
295
|
+
const propertyName = properties[i];
|
|
296
|
+
let value = object[propertyName];
|
|
297
|
+
|
|
298
|
+
if (value instanceof RawConfig) {
|
|
299
|
+
Object.defineProperty(object, propertyName, {
|
|
300
|
+
value: value.resolve(),
|
|
301
|
+
writable: false,
|
|
302
|
+
configurable: false
|
|
303
|
+
});
|
|
304
|
+
} else if (Array.isArray(value)) {
|
|
305
|
+
// Ensure object items of this array are also immutable.
|
|
306
|
+
value.forEach((item, index) => { if (Util.isObject(item) || Array.isArray(item)) util.makeImmutable(item) })
|
|
307
|
+
|
|
308
|
+
Object.defineProperty(object, propertyName, {
|
|
309
|
+
value: Object.freeze(value)
|
|
310
|
+
});
|
|
311
|
+
} else {
|
|
312
|
+
// Call recursively if an object.
|
|
313
|
+
if (Util.isObject(value)) {
|
|
314
|
+
// Create a proxy, to capture user updates of configuration options, and throw an exception for awareness, as per:
|
|
315
|
+
// https://github.com/lorenwest/node-config/issues/514
|
|
316
|
+
value = new Proxy(util.makeImmutable(value), {
|
|
317
|
+
get(target, property, receiver) {
|
|
318
|
+
// Config's own defined prototype properties and methods (e.g., `get`, `has`, etc.)
|
|
319
|
+
const ownProps = [
|
|
320
|
+
...Object.getOwnPropertyNames(Config.prototype), //TODO: This keeps us from moving this function to util.js where it belongs
|
|
321
|
+
...Object.getOwnPropertyNames(target),
|
|
322
|
+
]
|
|
323
|
+
|
|
324
|
+
// Bypass proxy receiver for properties directly on the target (e.g., RegExp.prototype.source)
|
|
325
|
+
// or properties that are not functions to prevent errors related to internal object methods.
|
|
326
|
+
if (ownProps.includes(property) || (property in target && typeof target[property] !== 'function')) {
|
|
327
|
+
return Reflect.get(target, property);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Otherwise, use the proxy receiver to handle the property access
|
|
331
|
+
const ref = Reflect.get(target, property, receiver);
|
|
332
|
+
|
|
333
|
+
// Binds the method's `this` context to the target object (e.g., Date.prototype.toISOString)
|
|
334
|
+
// to ensure it behaves correctly when called on the proxy.
|
|
335
|
+
if (typeof ref === 'function') {
|
|
336
|
+
return ref.bind(target);
|
|
337
|
+
}
|
|
338
|
+
return ref;
|
|
339
|
+
},
|
|
340
|
+
set (target, name) {
|
|
341
|
+
const message = (Reflect.has(target, name) ? 'update' : 'add');
|
|
342
|
+
// Notify the user.
|
|
343
|
+
throw Error(`Can not ${message} runtime configuration property: "${name}". Configuration objects are immutable unless ALLOW_CONFIG_MUTATIONS is set.`)
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Check if property already has writable: false and configurable: false
|
|
349
|
+
const currentDescriptor = Object.getOwnPropertyDescriptor(object, propertyName);
|
|
350
|
+
if (!currentDescriptor || currentDescriptor.writable !== false || currentDescriptor.configurable !== false) {
|
|
351
|
+
Object.defineProperty(object, propertyName, {
|
|
352
|
+
value: value,
|
|
353
|
+
writable : false,
|
|
354
|
+
configurable: false
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Ensure new properties can not be added, as per:
|
|
359
|
+
// https://github.com/lorenwest/node-config/issues/505
|
|
360
|
+
Object.preventExtensions(object[propertyName])
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return object;
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Return the sources for the configurations
|
|
369
|
+
*
|
|
370
|
+
* <p>
|
|
371
|
+
* All sources for configurations are stored in an array of objects containing
|
|
372
|
+
* the source name (usually the filename), the original source (as a string),
|
|
373
|
+
* and the parsed source as an object.
|
|
374
|
+
* </p>
|
|
375
|
+
*
|
|
376
|
+
* @method getConfigSources
|
|
377
|
+
* @return configSources {Array[Object]} - An array of objects containing
|
|
378
|
+
* name, original, and parsed elements
|
|
379
|
+
*/
|
|
380
|
+
util.getConfigSources = function() {
|
|
381
|
+
return FIRST_LOAD.getSources();
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Load the individual file configurations.
|
|
386
|
+
*
|
|
387
|
+
* <p>
|
|
388
|
+
* This method builds a map of filename to the configuration object defined
|
|
389
|
+
* by the file. The search order is:
|
|
390
|
+
* </p>
|
|
391
|
+
*
|
|
392
|
+
* <pre>
|
|
393
|
+
* default.EXT
|
|
394
|
+
* (deployment).EXT
|
|
395
|
+
* (hostname).EXT
|
|
396
|
+
* (hostname)-(deployment).EXT
|
|
397
|
+
* local.EXT
|
|
398
|
+
* local-(deployment).EXT
|
|
399
|
+
* </pre>
|
|
400
|
+
*
|
|
401
|
+
* <p>
|
|
402
|
+
* EXT can be yml, yaml, coffee, iced, json, jsonc, cson or js signifying the file type.
|
|
403
|
+
* yaml (and yml) is in YAML format, coffee is a coffee-script, iced is iced-coffee-script,
|
|
404
|
+
* json is in JSON format, jsonc is in JSONC format, cson is in CSON format, properties is
|
|
405
|
+
* in .properties format (http://en.wikipedia.org/wiki/.properties), and js is a javascript
|
|
406
|
+
* executable file that is require()'d with module.exports being the config object.
|
|
407
|
+
* </p>
|
|
408
|
+
*
|
|
409
|
+
* <p>
|
|
410
|
+
* hostname is the $HOST environment variable (or --HOST command line parameter)
|
|
411
|
+
* if set, otherwise the $HOSTNAME environment variable (or --HOSTNAME command
|
|
412
|
+
* line parameter) if set, otherwise the hostname found from
|
|
413
|
+
* require('os').hostname().
|
|
414
|
+
* </p>
|
|
415
|
+
*
|
|
416
|
+
* <p>
|
|
417
|
+
* Once a hostname is found, everything from the first period ('.') onwards
|
|
418
|
+
* is removed. For example, abc.example.com becomes abc
|
|
419
|
+
* </p>
|
|
420
|
+
*
|
|
421
|
+
* <p>
|
|
422
|
+
* (deployment) is the deployment type, found in the $NODE_ENV environment
|
|
423
|
+
* variable (which can be overridden by using $NODE_CONFIG_ENV
|
|
424
|
+
* environment variable). Defaults to 'development'.
|
|
425
|
+
* </p>
|
|
426
|
+
*
|
|
427
|
+
* <p>
|
|
428
|
+
* If the $NODE_APP_INSTANCE environment variable (or --NODE_APP_INSTANCE
|
|
429
|
+
* command line parameter) is set, then files with this appendage will be loaded.
|
|
430
|
+
* See the Multiple Application Instances section of the main documentation page
|
|
431
|
+
* for more information.
|
|
432
|
+
* </p>
|
|
433
|
+
*
|
|
434
|
+
* @protected
|
|
435
|
+
* @see Util.loadFileConfigs for discrete execution of (most of this functionality
|
|
436
|
+
* @method loadFileConfigs
|
|
437
|
+
* @param configDir { string | null } the path to the directory containing the configurations to load
|
|
438
|
+
* @param options { LoadOptions | undefined } parsing options
|
|
439
|
+
* @return {Object} The configuration object
|
|
440
|
+
*/
|
|
441
|
+
util.loadFileConfigs = function(configDir, options) {
|
|
442
|
+
let newLoad;
|
|
443
|
+
|
|
444
|
+
if (configDir) {
|
|
445
|
+
let opts = {...FIRST_LOAD.options, configDir, ...options};
|
|
446
|
+
newLoad = new Load(opts);
|
|
447
|
+
newLoad.scan();
|
|
448
|
+
} else {
|
|
449
|
+
newLoad = new Load({...FIRST_LOAD.options, ...options});
|
|
450
|
+
_init(newLoad);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return newLoad.config;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Scan with the default config dir (usually only at startup.
|
|
458
|
+
* This adds a bit more data from NODE_CONFIG that _load() skips
|
|
459
|
+
*
|
|
460
|
+
* @param load {Load}
|
|
461
|
+
* @private
|
|
462
|
+
*/
|
|
463
|
+
function _init(load) {
|
|
464
|
+
let options = load.options;
|
|
465
|
+
let additional = [];
|
|
466
|
+
|
|
467
|
+
// Override configurations from the $NODE_CONFIG environment variable
|
|
468
|
+
let envConfig = {};
|
|
469
|
+
|
|
470
|
+
load.setEnv("CONFIG_DIR", options.configDir);
|
|
471
|
+
|
|
472
|
+
if (process.env.NODE_CONFIG) {
|
|
473
|
+
try {
|
|
474
|
+
envConfig = JSON.parse(process.env.NODE_CONFIG);
|
|
475
|
+
} catch(e) {
|
|
476
|
+
console.error('The $NODE_CONFIG environment variable is malformed JSON');
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
additional.push({ name: "$NODE_CONFIG", config: envConfig });
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Override configurations from the --NODE_CONFIG command line
|
|
483
|
+
let cmdLineConfig = load.getCmdLineArg('NODE_CONFIG');
|
|
484
|
+
if (cmdLineConfig) {
|
|
485
|
+
try {
|
|
486
|
+
cmdLineConfig = JSON.parse(cmdLineConfig);
|
|
487
|
+
} catch(e) {
|
|
488
|
+
console.error('The --NODE_CONFIG={json} command line argument is malformed JSON');
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
additional.push({ name: "--NODE_CONFIG argument", config: cmdLineConfig });
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Place the mixed NODE_CONFIG into the environment
|
|
495
|
+
load.setEnv('NODE_CONFIG', JSON.stringify(Util.extendDeep(envConfig, cmdLineConfig, {})));
|
|
496
|
+
|
|
497
|
+
load.scan(additional);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Attach the Config class prototype to all config objects recursively.
|
|
502
|
+
*
|
|
503
|
+
* <p>
|
|
504
|
+
* This allows you to do anything with CONFIG sub-objects as you can do with
|
|
505
|
+
* the top-level CONFIG object. It's so you can do this:
|
|
506
|
+
* </p>
|
|
507
|
+
*
|
|
508
|
+
* <pre>
|
|
509
|
+
* const CUST_CONFIG = require('config').Customer;
|
|
510
|
+
* CUST_CONFIG.get(...)
|
|
511
|
+
* </pre>
|
|
512
|
+
*
|
|
513
|
+
* @protected
|
|
514
|
+
* @method attachProtoDeep
|
|
515
|
+
* @param toObject {Object}
|
|
516
|
+
* @param depth {number=20}
|
|
517
|
+
* @return {Object}
|
|
518
|
+
*/
|
|
519
|
+
util.attachProtoDeep = function(toObject, depth) {
|
|
520
|
+
if (toObject instanceof RawConfig) {
|
|
521
|
+
return toObject;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Recursion detection
|
|
525
|
+
depth = (depth === null ? DEFAULT_CLONE_DEPTH : depth);
|
|
526
|
+
if (depth < 0) {
|
|
527
|
+
return toObject;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Adding Config.prototype methods directly to toObject as hidden properties
|
|
531
|
+
// because adding to toObject.__proto__ exposes the function in toObject
|
|
532
|
+
for (const fnName in Config.prototype) {
|
|
533
|
+
if (!toObject[fnName]) {
|
|
534
|
+
Util.makeHidden(toObject, fnName, Config.prototype[fnName]);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Add prototypes to sub-objects
|
|
539
|
+
for (const prop in toObject) {
|
|
540
|
+
if (Util.isObject(toObject[prop])) {
|
|
541
|
+
util.attachProtoDeep(toObject[prop], depth - 1);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Return the original object
|
|
546
|
+
return toObject;
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Returns a new deep copy of the current config object, or any part of the config if provided.
|
|
551
|
+
*
|
|
552
|
+
* @param {Object} config The part of the config to copy and serialize. Omit this argument to return the entire config.
|
|
553
|
+
* @returns {Object} The cloned config or part of the config
|
|
554
|
+
*/
|
|
555
|
+
util.toObject = function(config) {
|
|
556
|
+
return Util.toObject(config || this);
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
// Run strictness checks on NODE_ENV and NODE_APP_INSTANCE and throw an error if there's a problem.
|
|
560
|
+
util.runStrictnessChecks = function (config) {
|
|
561
|
+
if (FIRST_LOAD.initParam('SUPPRESS_STRICTNESS_CHECK')) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const sources = config.util.getConfigSources();
|
|
566
|
+
const sourceFilenames = sources.map(function (src) {
|
|
567
|
+
return Path.basename(src.name);
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
FIRST_LOAD.options.nodeEnv.forEach(function(env) {
|
|
571
|
+
// Throw an exception if there's no explicit config file for NODE_ENV
|
|
572
|
+
const anyFilesMatchEnv = sourceFilenames.some(function (filename) {
|
|
573
|
+
return filename.match(env);
|
|
574
|
+
});
|
|
575
|
+
// development is special-cased because it's the default value
|
|
576
|
+
if (env && (env !== 'development') && !anyFilesMatchEnv) {
|
|
577
|
+
_warnOrThrow(`${FIRST_LOAD.getEnv("nodeEnv")} value of '${env}' did not match any deployment config file names.`);
|
|
578
|
+
}
|
|
579
|
+
// Throw if NODE_ENV matches' default' or 'local'
|
|
580
|
+
if ((env === 'default') || (env === 'local')) {
|
|
581
|
+
_warnOrThrow(`${FIRST_LOAD.getEnv("nodeEnv")} value of '${env}' is ambiguous.`);
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
let appInstance = FIRST_LOAD.options.appInstance;
|
|
586
|
+
|
|
587
|
+
if (appInstance) {
|
|
588
|
+
// Throw an exception if there's no explicit config file for NODE_APP_INSTANCE
|
|
589
|
+
const anyFilesMatchInstance = sourceFilenames.some(function (filename) {
|
|
590
|
+
return filename.match(appInstance);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
if (!anyFilesMatchInstance) {
|
|
594
|
+
_warnOrThrow(`NODE_APP_INSTANCE value of '${appInstance}' did not match any instance config file names.`);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
function _warnOrThrow (msg) {
|
|
599
|
+
const beStrict = process.env.NODE_CONFIG_STRICT_MODE;
|
|
600
|
+
const prefix = beStrict ? 'FATAL: ' : 'WARNING: ';
|
|
601
|
+
const seeURL = 'See https://github.com/node-config/node-config/wiki/Strict-Mode';
|
|
602
|
+
|
|
603
|
+
console.error(prefix+msg);
|
|
604
|
+
console.error(prefix+seeURL);
|
|
605
|
+
|
|
606
|
+
// Accept 1 and true as truthy values. When set via process.env, Node.js casts them to strings.
|
|
607
|
+
if (["true", "1"].indexOf(beStrict) >= 0) {
|
|
608
|
+
throw new Error(prefix+msg+' '+seeURL);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
/** @type {Load} */
|
|
614
|
+
const FIRST_LOAD = Load.fromEnvironment();
|
|
615
|
+
|
|
616
|
+
// Instantiate and export the configuration
|
|
617
|
+
const config = module.exports = new Config();
|
|
618
|
+
|
|
619
|
+
// copy method to util for backwards compatibility
|
|
620
|
+
util.stripYamlComments = FIRST_LOAD.parser.stripYamlComments;
|
|
621
|
+
|
|
622
|
+
// Produce warnings if the configuration is empty
|
|
623
|
+
const showWarnings = !(FIRST_LOAD.initParam('SUPPRESS_NO_CONFIG_WARNING'));
|
|
624
|
+
if (showWarnings && Object.keys(config).length === 0) {
|
|
625
|
+
console.error('WARNING: No configurations found in configuration directory:' + FIRST_LOAD.options.configDir);
|
|
626
|
+
console.error('WARNING: To disable this warning set SUPPRESS_NO_CONFIG_WARNING in the environment.');
|
|
627
|
+
}
|