-
Notifications
You must be signed in to change notification settings - Fork 2
/
config.js
114 lines (97 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
'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;