/
defaults.js
executable file
·125 lines (109 loc) · 3.56 KB
/
defaults.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
117
118
119
120
121
122
123
124
125
// FIXME: When in a browser, defaults will be different (maybe, no defaults)
"use strict";
const C1 = require('./seed.js');
const process = require('process');
const recipe = C1.recipe;
const R = require('ramda');
const path = require('path');
const log = require('./log.js')({id: 'root'});
log.disable();
// Given a base directory, returns a function that resolves a path relative
// to that base
const resolveFrom = base => R.partial(path.resolve, [base]);
module.exports = function() {
return {
// Add predicate functions here to tell config1 that certain types of
// objects should be treated as atomic.
atomTests: [],
configDirEnv: 'CONFIG1_DIR',
configDir: recipe(X=> {
const env = X.configDirEnv;
const rel = process.env[env] || process.cwd();
return path.resolve(rel);
}),
// The list of config filenames that are searched for first, in order from
// defaults -> overrides
basenames: [ 'config', 'config-local' ],
// List of valid filename suffixes
suffixes: [ '.js', '.json' ],
// List of filenames, which is the every combination of basenames and suffixes
filenames: recipe(X=> {
const mapcat2 = R.lift(R.curry((a, b) => a + b));
return mapcat2(X.basenames, X.suffixes);
}),
// List of absolute pathnames
pathnames: recipe(X=> {
const resolve = resolveFrom(X.configDir);
return R.map(resolve, X.filenames)
}),
// Environent variables. Setting this to the empty string or null will
// disable looking for config info in the environment
envPrefix: 'CONFIG1_',
// The source specification types we understand. The `sources` option is
// a list of source specifications, each of which is a plain object with a
// type property that matches the key here.
sourceTypes: {
file: {
makeSpec: pathname => {
return {
type: 'file',
pathname: pathname
};
},
specs: recipe(X=> {
const self = X.sourceTypes.file;
return X.pathnames ? R.map(self.makeSpec, X.pathnames) : null;
}),
fetch: function(srcspec) {
try {
return require(srcspec.pathname);
}
catch(err) {}
},
},
envPrefix: {
makeSpec: prefix => ({
type: 'envPrefix',
prefix: prefix
}),
specs: recipe(X=> {
const self = X.sourceTypes.envPrefix;
return X.envPrefix ? [self.makeSpec(X.envPrefix)] : null;
}),
fetch: function(srcspec) {
// FIXME: implement!
},
},
envJson: {
makeSpec: name => ({
type: 'envJson',
name: name
}),
specs: recipe(X=> {
const self = X.sourceTypes.envJson;
return X.envJson ? [self.makeSpec(X.envPrefix)] : null;
}),
fetch: function(srcspec) {
// FIXME: implement!
},
},
},
// Put them all together
sources: recipe(X=> {
// FIXME: this needs to concatenate all the specs, rather than just these two
const stypes = X.sourceTypes;
const srcs = stypes.file.specs.concat(stypes.envPrefix.specs);
return srcs;
}),
// Function to take any source specification, and return the config data
// for that source. This closes over the root view -- I'm pretty
// sure that won't be a problem!
fetchSource: recipe(X=>
function(srcspec) {
const type = srcspec.type,
fetch = X.sourceTypes[type].fetch;
return fetch(srcspec);
}
),
};
};