-
Notifications
You must be signed in to change notification settings - Fork 1
/
build-dictionary.js
181 lines (143 loc) · 5.31 KB
/
build-dictionary.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
const isPlainObject = require('lodash.isplainobject')
const _forEach = require('lodash.foreach')
const _merge = require('lodash.merge')
const includeAll = require('include-all')
/**
* buildDictionary
*
* Go through each object, include the code, and determine its identity.
* Tolerates non-existent files/directories by ignoring them.
@param {Object} options {
dirname :: the path to the source directory
identity :: If disabled, (explicitly set to false) don't inject an identity into the module
also don't try to use the bundled `identity` property in the module to determine
the keyname in the result object
default: true
optional :: if enabled, fail silently and return {} when source directory does not exist
or cannot be read (otherwise, exit w/ an error)
default: false
depth :: the level of recursion where modules will be included
defaults to infinity? (not sure)
filter :: only include modules whose FILENAME matches this regex
default `undefined`
pathFilter :: only include modules whose FULL RELATIVE PATH matches this regex
(relative from the entry point directory)
default `undefined`
replaceExpr :: in identity: use this regex to remove substrings like 'Controller' or 'Service'
and replace them with the value of `replaceVal`
replaceVal :: see above
default value: ''
dontLoad :: if `dontLoad` is set to true, don't run the module w/ V8 or load it into memory--
instead, return a tree representing the directory structure
(all extant file leaves are included as keys, with their value = `true`)
useGlobalIdForKeyName
:: if `useGlobalIdForKeyName` is set to true, don't lowercase the identity to get
the keyname-- just use the globalId.
}
@param {Function} cb
*/
module.exports = buildDictionary
function buildDictionary (options, cb) {
// Defaults
options.replaceVal = options.replaceVal || ''
// Deliberately exclude source control directories
if (!options.excludeDirs) {
options.excludeDirs = /^\.(git|svn)$/
}
var files = includeAll(options)
// Start building the module dictionary
var dictionary = {}
// Iterate through each module in the set
_forEach(files, (module, filename) => {
// Build the result object by merging all of the target modules
// Note: Each module must export an object in order for this to work
// (e.g. for building a configuration object from a set of config files)
if (options.aggregate) {
// Check that source module is a valid object
if (!isPlainObject(module)) {
return cb(new Error('Invalid module:' + module))
}
// Merge module into dictionary
_merge(dictionary, module)
return
}
// Keyname is how the module will be identified in the returned module tree
var keyName = filename
// If a module is found but marked as `undefined`,
// don't actually include it (since it's probably unusable)
if (typeof module === 'undefined') {
return
}
// Unless the `identity` option is explicitly disabled,
// (or `dontLoad` is set)
if (!options.dontLoad && options.identity !== false) {
// If no `identity` property is specified in module, infer it from the filename
if (!module.identity) {
if (options.replaceExpr) {
module.identity = filename.replace(options.replaceExpr, options.replaceVal)
} else module.identity = filename
}
// globalId is the name of the variable for this module
// that will be exposed globally in Sails unless configured otherwise
// Generate `globalId` using the original value of module.identity
if (!module.globalId) {
module.globalId = module.identity
}
// `identity` is the all-lowercase version
module.identity = module.identity.toLowerCase()
// Use the identity for the key name
keyName = options.useGlobalIdForKeyName ? module.globalId : module.identity
}
// Save the module's contents in our dictionary object
// (this will actually just be `true` if the `dontLoad` option is set)
dictionary[keyName] = module
})
// Always return at least an empty object
dictionary = dictionary || {}
return cb(null, dictionary)
}
/**
* Build a dictionary of named modules
* (responds with an error if the container cannot be loaded)
*
* @param {Object} options
* @param {Function} cb
*/
module.exports.required = (options, cb) => {
return buildDictionary(options, cb)
}
/**
* Build a dictionary of named modules
* (fails silently-- returns {} if the container cannot be loaded)
*
* @param {Object} options
* @param {Function} cb
*/
module.exports.optional = (options, cb) => {
options.optional = true
return buildDictionary(options, cb)
}
/**
* Build a dictionary indicating whether the matched modules exist
* (fails silently-- returns {} if the container cannot be loaded)
*
* @param {Object} options
* @param {Function} cb
*/
module.exports.exists = (options, cb) => {
options.optional = true
options.dontLoad = false
return buildDictionary(options, cb)
}
/**
* Build a single module object by extending {} with the contents of each module
* (fail silently-- returns {} if the container cannot be loaded)
*
* @param {Object} options
* @param {Function} cb
*/
module.exports.aggregate = (options, cb) => {
options.aggregate = true
options.optional = true
return buildDictionary(options, cb)
}