-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconfig.js
116 lines (95 loc) · 3.42 KB
/
config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
'use strict';
/*
This configuration utility is designed to allow the definition of important constants in a
way that is compatible with VSCode Intellisense.
Secret (ignored) configurations can be set in a `.conf.js` file, and will overwrite default
configurations. Environment variables can also be used to define string values, using the
following format for the key: `NODE_CONF_${categoryKey}_${valueKey}`
This utility expects there to be a `.conf.default.js` file in the same directory. The secret
config file is optional
See the default config for details on file formatting
The config object will only get values from the related conf files the first time it is
imported. Use the `config.loadConfig` method to force a read from file
*/
const config = require('./.conf.default.js');
let secretConfig = {};
try {
secretConfig = require('./.conf.js');
} catch(e) {
// Allow error
}
/**
* Array containing falsy values that are explicitly permitted
*/
const allowedFalsyValues = [
'',
0,
null
];
/**
* Simple helper determines if a value exists in a config object
*
* @param {object} obj Object to check
* @param {string} categoryKey Category to check
* @param {string} valueKey Name of the value to check
*/
const checkExists = (obj, categoryKey, valueKey) => {
return obj[categoryKey] && (obj[categoryKey][valueKey] || allowedFalsyValues.includes(obj[categoryKey][valueKey]));
};
/**
* Helper function recursively travels a provided object and returns "false" if any values are undefined. A log
* will also be automatically made to stderr detailing the nature of the failure
*
* @param {object} obj The object to check
* @param {string} originalKey The key related to the object being checked
*/
const checkForUndefinedRecursive = (obj, originalKey = 'this') => {
if (typeof obj === 'undefined') {
console.error(`Item with key ${originalKey} is undefined`);
return false;
}
// Don't check strings
if (typeof obj === 'string') return true;
// For-in statements don't run on non-indexed datatypes
for (const key in obj) {
const item = obj[key];
if (!checkForUndefinedRecursive(item, key)) return false;
}
return true;
};
/**
* Method will load config values into the config object. Can be used to re-initialize the config
* object, if needed
*
* @param {object} configOpts Overrides for any currently set config options
*/
const loadConfig = (configOpts = null) => {
for (const categoryKey in config) {
const category = config[categoryKey];
for (const valueKey in category) {
// Check for the value in the configuration options provided as an argument
if (configOpts && checkExists(configOpts, categoryKey, valueKey)) {
category[valueKey] = configOpts[categoryKey][valueKey];
continue;
}
// Check for the value in the secret config
if (checkExists(secretConfig, categoryKey, valueKey)) {
category[valueKey] = secretConfig[categoryKey][valueKey];
continue;
}
// Check for the value in environment vars
const varName = `NODE_CONF_${categoryKey}_${valueKey}`;
if (process.env[varName]) {
category[valueKey] = process.env[varName];
continue;
}
}
}
if (!config.config.errorOnUndefined) return;
if (!checkForUndefinedRecursive(this)) {
throw new Error('Undefined configurations detected');
}
};
loadConfig();
config.loadConfig = loadConfig;
module.exports = config;