ee-core 2.9.2 → 2.10.1

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.
Files changed (103) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +65 -65
  3. package/addon/index.js +34 -34
  4. package/addon/window/index.js +98 -98
  5. package/bin/tools.js +8 -8
  6. package/config/cache.js +41 -38
  7. package/config/config.default.js +331 -330
  8. package/config/index.js +86 -73
  9. package/const/channel.js +17 -17
  10. package/const/index.js +8 -8
  11. package/controller/baseContextClass.js +34 -34
  12. package/controller/index.js +34 -34
  13. package/core/index.js +10 -10
  14. package/core/lib/ee.js +216 -216
  15. package/core/lib/loader/context_loader.js +106 -106
  16. package/core/lib/loader/ee_loader.js +435 -435
  17. package/core/lib/loader/file_loader.js +326 -326
  18. package/core/lib/loader/mixin/addon.js +32 -32
  19. package/core/lib/loader/mixin/config.js +130 -130
  20. package/core/lib/loader/mixin/controller.js +125 -125
  21. package/core/lib/loader/mixin/service.js +28 -28
  22. package/core/lib/utils/base_context_class.js +34 -34
  23. package/core/lib/utils/function.js +30 -30
  24. package/core/lib/utils/index.js +133 -133
  25. package/core/lib/utils/sequencify.js +59 -59
  26. package/core/lib/utils/timing.js +77 -77
  27. package/cross/index.js +183 -183
  28. package/cross/spawnProcess.js +183 -183
  29. package/ee/appLoader.js +48 -48
  30. package/ee/application.js +99 -99
  31. package/ee/baseApp.js +103 -102
  32. package/ee/eeApp.js +408 -408
  33. package/ee/index.js +57 -57
  34. package/electron/app/index.js +64 -58
  35. package/electron/index.js +19 -19
  36. package/electron/window/index.js +73 -73
  37. package/electron/window/winState.js +186 -186
  38. package/exception/index.js +112 -112
  39. package/html/boot.html +98 -98
  40. package/html/cross-failure.html +28 -28
  41. package/html/failure.html +28 -28
  42. package/html/index.js +13 -13
  43. package/httpclient/index.js +161 -161
  44. package/index.js +54 -54
  45. package/jobs/baseJobClass.js +16 -16
  46. package/jobs/child/app.js +58 -65
  47. package/jobs/child/forkProcess.js +145 -145
  48. package/jobs/child/index.js +82 -82
  49. package/jobs/child-pool/index.js +213 -213
  50. package/jobs/index.js +8 -8
  51. package/jobs/load-balancer/algorithm/index.js +11 -11
  52. package/jobs/load-balancer/algorithm/minimumConnection.js +18 -18
  53. package/jobs/load-balancer/algorithm/polling.js +11 -11
  54. package/jobs/load-balancer/algorithm/random.js +9 -9
  55. package/jobs/load-balancer/algorithm/specify.js +14 -14
  56. package/jobs/load-balancer/algorithm/weights.js +21 -21
  57. package/jobs/load-balancer/algorithm/weightsMinimumConnection.js +29 -29
  58. package/jobs/load-balancer/algorithm/weightsPolling.js +22 -22
  59. package/jobs/load-balancer/algorithm/weightsRandom.js +16 -16
  60. package/jobs/load-balancer/consts.js +9 -9
  61. package/jobs/load-balancer/index.js +201 -201
  62. package/jobs/load-balancer/scheduler.js +31 -31
  63. package/jobs/renderer/index.js +141 -141
  64. package/jobs/renderer/loadView.js +40 -40
  65. package/jobs/unification.js +63 -63
  66. package/loader/index.js +172 -172
  67. package/log/index.js +68 -68
  68. package/log/logger.js +86 -80
  69. package/main/index.js +56 -56
  70. package/message/childMessage.js +54 -54
  71. package/message/index.js +18 -18
  72. package/old-utils/index.js +91 -91
  73. package/package.json +38 -38
  74. package/ps/index.js +371 -371
  75. package/services/baseContextClass.js +34 -34
  76. package/services/index.js +40 -40
  77. package/socket/httpServer.js +147 -147
  78. package/socket/index.js +81 -81
  79. package/socket/io.js +27 -27
  80. package/socket/ipcServer.js +112 -112
  81. package/socket/socketServer.js +69 -67
  82. package/storage/index.js +38 -38
  83. package/storage/jsondb/adapters/Base.js +23 -23
  84. package/storage/jsondb/adapters/FileSync.js +64 -52
  85. package/storage/jsondb/main.js +55 -42
  86. package/storage/jsondbStorage.js +195 -195
  87. package/storage/sqliteStorage.js +123 -123
  88. package/utils/co.js +237 -237
  89. package/utils/copyto.js +160 -160
  90. package/utils/depd/index.js +538 -538
  91. package/utils/depd/lib/browser/index.js +77 -77
  92. package/utils/extend.js +73 -73
  93. package/utils/get-port/index.d.ts +64 -64
  94. package/utils/get-port/index.js +148 -148
  95. package/utils/helper.js +220 -220
  96. package/utils/index.js +160 -160
  97. package/utils/ip.js +261 -261
  98. package/utils/is.js +145 -145
  99. package/utils/json.js +72 -72
  100. package/utils/pargv.js +263 -263
  101. package/utils/time/index.js +19 -19
  102. package/utils/time/ms.js +162 -162
  103. package/utils/wrap.js +35 -35
@@ -1,326 +1,326 @@
1
- 'use strict';
2
-
3
- const assert = require('assert');
4
- const fs = require('fs');
5
- const debug = require('debug')('ee-core:fileLoader');
6
- const path = require('path');
7
- const globby = require('globby');
8
- const is = require('is-type-of');
9
- const deprecate = require('../../../utils/depd')('ee');
10
- const Utils = require('../utils');
11
- const FULLPATH = Symbol('EE_LOADER_ITEM_FULLPATH');
12
- const EXPORTS = Symbol('EE_LOADER_ITEM_EXPORTS');
13
- //const Addon = require('../../../addon');
14
-
15
- const defaults = {
16
- directory: null,
17
- target: null,
18
- match: undefined,
19
- ignore: undefined,
20
- lowercaseFirst: false,
21
- caseStyle: 'camel',
22
- initializer: null,
23
- call: true,
24
- override: false,
25
- inject: undefined,
26
- filter: null,
27
- loader: undefined,
28
- };
29
-
30
- /**
31
- * Load files from directory to target object.
32
- * @since 1.0.0
33
- */
34
- class FileLoader {
35
-
36
- /**
37
- * @class
38
- * @param {Object} options - options
39
- * @param {String|Array} options.directory - directories to be loaded
40
- * @param {Object} options.target - attach the target object from loaded files
41
- * @param {String} options.match - match the files when load, support glob, default to all js files
42
- * @param {String} options.ignore - ignore the files when load, support glob
43
- * @param {Function} options.initializer - custom file exports, receive two parameters, first is the inject object(if not js file, will be content buffer), second is an `options` object that contain `path`
44
- * @param {Boolean} options.call - determine whether invoke when exports is function
45
- * @param {Boolean} options.override - determine whether override the property when get the same name
46
- * @param {Object} options.inject - an object that be the argument when invoke the function
47
- * @param {Function} options.filter - a function that filter the exports which can be loaded
48
- * @param {String|Function} options.caseStyle - set property's case when converting a filepath to property list.
49
- * @param {Object} options.loader - an object that be the argument when invoke the function
50
- */
51
- constructor(options) {
52
- assert(options.directory, 'options.directory is required');
53
- assert(options.target, 'options.target is required');
54
- this.options = Object.assign({}, defaults, options);
55
-
56
- // compatible old options _lowercaseFirst_
57
- if (this.options.lowercaseFirst === true) {
58
- deprecate('lowercaseFirst is deprecated, use caseStyle instead');
59
- this.options.caseStyle = 'lower';
60
- }
61
- }
62
-
63
- /**
64
- * attach items to target object. Mapping the directory to properties.
65
- * `app/controller/group/repository.js` => `target.group.repository`
66
- * @return {Object} target
67
- * @since 1.0.0
68
- */
69
- load() {
70
- const items = this.parse();
71
- const target = this.options.target;
72
- for (const item of items) {
73
- // item { properties: [ 'a', 'b', 'c'], exports }
74
- // => target.a.b.c = exports
75
- item.properties.reduce((target, property, index) => {
76
- let obj;
77
- const properties = item.properties.slice(0, index + 1).join('.');
78
- if (index === item.properties.length - 1) {
79
- if (property in target) {
80
- if (!this.options.override) throw new Error(`can't overwrite property '${properties}' from ${target[property][FULLPATH]} by ${item.fullpath}`);
81
- }
82
- obj = item.exports;
83
- if (obj && !is.primitive(obj)) {
84
- obj[FULLPATH] = item.fullpath;
85
- obj[EXPORTS] = true;
86
- }
87
- } else {
88
- obj = target[property] || {};
89
- }
90
-
91
- target[property] = obj;
92
- debug('loaded %s', properties);
93
- return obj;
94
- }, target);
95
- }
96
-
97
- return target;
98
- }
99
-
100
- /**
101
- * Parse files from given directories, then return an items list, each item contains properties and exports.
102
- *
103
- * For example, parse `app/controller/group/repository.js`
104
- *
105
- * ```
106
- * module.exports = app => {
107
- * return class RepositoryController extends app.Controller {};
108
- * }
109
- * ```
110
- *
111
- * It returns a item
112
- *
113
- * ```
114
- * {
115
- * properties: [ 'group', 'repository' ],
116
- * exports: app => { ... },
117
- * }
118
- * ```
119
- *
120
- * `Properties` is an array that contains the directory of a filepath.
121
- *
122
- * `Exports` depends on type, if exports is a function, it will be called. if initializer is specified, it will be called with exports for customizing.
123
- * @return {Array} items
124
- * @since 1.0.0
125
- */
126
- parse() {
127
- let files = this.options.match;
128
- if (!files) {
129
- files = (process.env.EE_TYPESCRIPT === 'true' && Utils.extensions['.ts'])
130
- ? [ '**/*.(js|ts)', '!**/*.d.ts' ]
131
- : [ '**/*.js', '**/*.jsc'];
132
- } else {
133
- files = Array.isArray(files) ? files : [ files ];
134
- }
135
-
136
- let ignore = this.options.ignore;
137
- if (ignore) {
138
- ignore = Array.isArray(ignore) ? ignore : [ ignore ];
139
- ignore = ignore.filter(f => !!f).map(f => '!' + f);
140
- files = files.concat(ignore);
141
- }
142
-
143
- let directories = this.options.directory;
144
- if (!Array.isArray(directories)) {
145
- directories = [ directories ];
146
- }
147
-
148
- const filter = is.function(this.options.filter) ? this.options.filter : null;
149
- const items = [];
150
- debug('parsing %j', directories);
151
-
152
- for (const directory of directories) {
153
- const filepaths = globby.sync(files, { cwd: directory });
154
- for (const filepath of filepaths) {
155
- const fullpath = path.join(directory, filepath);
156
- if (!fs.statSync(fullpath).isFile()) continue;
157
- // get properties
158
- // app/service/foo/bar.js => [ 'foo', 'bar' ]
159
- const properties = getProperties(filepath, this.options);
160
- // app/service/foo/bar.js => service.foo.bar
161
- const pathName = directory.split(/[/\\]/).slice(-1) + '.' + properties.join('.');
162
- // get exports from the file
163
- let exports = getExports(fullpath, this.options, pathName);
164
- // ignore exports when it's null or false returned by filter function
165
- if (exports == null || (filter && filter(exports) === false)) continue;
166
-
167
- // set properties of class
168
- if (is.class(exports) || Utils.isBytecodeClass(exports)) {
169
- exports.prototype.pathName = pathName;
170
- exports.prototype.fullPath = fullpath;
171
- }
172
-
173
- items.push({ fullpath, properties, exports });
174
- debug('parse %s, properties %j, export %O', fullpath, properties, exports);
175
- }
176
- }
177
-
178
- return items;
179
- }
180
-
181
- /**
182
- * attach items to target object for addons.
183
- * `app/addon/group/index.js` => `target.group`
184
- * @return {Object} target
185
- * @since 1.0.0
186
- */
187
- loadAddons() {
188
- const items = [];
189
- const files = '*';
190
- const app = this.options.inject;
191
- const loader = this.options.loader;
192
- const target = this.options.target;
193
- let directories = this.options.directory;
194
-
195
- if (!Array.isArray(directories)) {
196
- directories = [ directories ];
197
- }
198
-
199
- // check addon
200
- const config = app.config.addons;
201
- let filterAddons = [];
202
- for (let key of Object.keys(config)) {
203
- if (!config[key].enable) {
204
- filterAddons.push(key);
205
- }
206
- }
207
-
208
- for (const directory of directories) {
209
- const addonpaths = globby.sync(files, { cwd: directory, deep: 1, onlyDirectories: true});
210
- for (const addonName of addonpaths) {
211
- if (filterAddons.includes(addonName)) continue;
212
-
213
- let fullpath = path.join(directory, addonName, 'index');
214
- fullpath = loader.resolveModule(fullpath);
215
- if (!fs.statSync(fullpath).isFile()) continue;
216
-
217
- let exports = getExports(fullpath, this.options, addonName);
218
- if (exports == null) continue;
219
-
220
- const properties = [addonName];
221
- if (is.class(exports) || Utils.isBytecodeClass(exports)) {
222
- exports.prototype.pathName = addonName;
223
- exports.prototype.fullPath = fullpath;
224
- }
225
-
226
- items.push({ fullpath, properties, exports });
227
- }
228
-
229
- for (const item of items) {
230
- const property = item.properties[0];
231
- let obj = item.exports;
232
- if (obj && !is.primitive(obj)) {
233
- obj[FULLPATH] = item.fullpath;
234
- obj[EXPORTS] = true;
235
- }
236
-
237
- target[property] = obj;
238
- }
239
- }
240
-
241
- return target;
242
- }
243
- }
244
-
245
- module.exports = FileLoader;
246
- module.exports.EXPORTS = EXPORTS;
247
- module.exports.FULLPATH = FULLPATH;
248
-
249
- // convert file path to an array of properties
250
- // a/b/c.js => ['a', 'b', 'c']
251
- function getProperties(filepath, { caseStyle }) {
252
- // if caseStyle is function, return the result of function
253
- if (is.function(caseStyle)) {
254
- const result = caseStyle(filepath);
255
- assert(is.array(result), `caseStyle expect an array, but got ${result}`);
256
- return result;
257
- }
258
- // use default camelize
259
- return defaultCamelize(filepath, caseStyle);
260
- }
261
-
262
- // Get exports from filepath
263
- // If exports is null/undefined, it will be ignored
264
- function getExports(fullpath, { initializer, call, inject }, pathName) {
265
- let exports = Utils.loadFile(fullpath);
266
-
267
- // process exports as you like
268
- if (initializer) {
269
- exports = initializer(exports, { path: fullpath, pathName });
270
- }
271
-
272
- // return exports when it's a class or generator
273
- //
274
- // module.exports = class Service {};
275
- // or
276
- // module.exports = function*() {}
277
- //new exports;
278
-
279
- if (is.class(exports) || is.generatorFunction(exports) || is.asyncFunction(exports) || Utils.isBytecodeClass(exports)) {
280
- return exports;
281
- }
282
-
283
- // return exports after call when it's a function
284
- //
285
- // module.exports = function(app) {
286
- // return {};
287
- // }
288
- if (call && is.function(exports)) {
289
- exports = exports(inject);
290
- if (exports != null) {
291
- return exports;
292
- }
293
- }
294
-
295
- // return exports what is
296
- return exports;
297
- }
298
-
299
- function defaultCamelize(filepath, caseStyle) {
300
- const properties = filepath.substring(0, filepath.lastIndexOf('.')).split('/');
301
- return properties.map(property => {
302
- if (!/^[a-z][a-z0-9_-]*$/i.test(property)) {
303
- throw new Error(`${property} is not match 'a-z0-9_-' in ${filepath}`);
304
- }
305
-
306
- // use default camelize, will capitalize the first letter
307
- // foo_bar.js > FooBar
308
- // fooBar.js > FooBar
309
- // FooBar.js > FooBar
310
- // FooBar.js > FooBar
311
- // FooBar.js > fooBar (if lowercaseFirst is true)
312
- property = property.replace(/[_-][a-z]/ig, s => s.substring(1).toUpperCase());
313
- let first = property[0];
314
- switch (caseStyle) {
315
- case 'lower':
316
- first = first.toLowerCase();
317
- break;
318
- case 'upper':
319
- first = first.toUpperCase();
320
- break;
321
- case 'camel':
322
- default:
323
- }
324
- return first + property.substring(1);
325
- });
326
- }
1
+ 'use strict';
2
+
3
+ const assert = require('assert');
4
+ const fs = require('fs');
5
+ const debug = require('debug')('ee-core:fileLoader');
6
+ const path = require('path');
7
+ const globby = require('globby');
8
+ const is = require('is-type-of');
9
+ const deprecate = require('../../../utils/depd')('ee');
10
+ const Utils = require('../utils');
11
+ const FULLPATH = Symbol('EE_LOADER_ITEM_FULLPATH');
12
+ const EXPORTS = Symbol('EE_LOADER_ITEM_EXPORTS');
13
+ //const Addon = require('../../../addon');
14
+
15
+ const defaults = {
16
+ directory: null,
17
+ target: null,
18
+ match: undefined,
19
+ ignore: undefined,
20
+ lowercaseFirst: false,
21
+ caseStyle: 'camel',
22
+ initializer: null,
23
+ call: true,
24
+ override: false,
25
+ inject: undefined,
26
+ filter: null,
27
+ loader: undefined,
28
+ };
29
+
30
+ /**
31
+ * Load files from directory to target object.
32
+ * @since 1.0.0
33
+ */
34
+ class FileLoader {
35
+
36
+ /**
37
+ * @class
38
+ * @param {Object} options - options
39
+ * @param {String|Array} options.directory - directories to be loaded
40
+ * @param {Object} options.target - attach the target object from loaded files
41
+ * @param {String} options.match - match the files when load, support glob, default to all js files
42
+ * @param {String} options.ignore - ignore the files when load, support glob
43
+ * @param {Function} options.initializer - custom file exports, receive two parameters, first is the inject object(if not js file, will be content buffer), second is an `options` object that contain `path`
44
+ * @param {Boolean} options.call - determine whether invoke when exports is function
45
+ * @param {Boolean} options.override - determine whether override the property when get the same name
46
+ * @param {Object} options.inject - an object that be the argument when invoke the function
47
+ * @param {Function} options.filter - a function that filter the exports which can be loaded
48
+ * @param {String|Function} options.caseStyle - set property's case when converting a filepath to property list.
49
+ * @param {Object} options.loader - an object that be the argument when invoke the function
50
+ */
51
+ constructor(options) {
52
+ assert(options.directory, 'options.directory is required');
53
+ assert(options.target, 'options.target is required');
54
+ this.options = Object.assign({}, defaults, options);
55
+
56
+ // compatible old options _lowercaseFirst_
57
+ if (this.options.lowercaseFirst === true) {
58
+ deprecate('lowercaseFirst is deprecated, use caseStyle instead');
59
+ this.options.caseStyle = 'lower';
60
+ }
61
+ }
62
+
63
+ /**
64
+ * attach items to target object. Mapping the directory to properties.
65
+ * `app/controller/group/repository.js` => `target.group.repository`
66
+ * @return {Object} target
67
+ * @since 1.0.0
68
+ */
69
+ load() {
70
+ const items = this.parse();
71
+ const target = this.options.target;
72
+ for (const item of items) {
73
+ // item { properties: [ 'a', 'b', 'c'], exports }
74
+ // => target.a.b.c = exports
75
+ item.properties.reduce((target, property, index) => {
76
+ let obj;
77
+ const properties = item.properties.slice(0, index + 1).join('.');
78
+ if (index === item.properties.length - 1) {
79
+ if (property in target) {
80
+ if (!this.options.override) throw new Error(`can't overwrite property '${properties}' from ${target[property][FULLPATH]} by ${item.fullpath}`);
81
+ }
82
+ obj = item.exports;
83
+ if (obj && !is.primitive(obj)) {
84
+ obj[FULLPATH] = item.fullpath;
85
+ obj[EXPORTS] = true;
86
+ }
87
+ } else {
88
+ obj = target[property] || {};
89
+ }
90
+
91
+ target[property] = obj;
92
+ debug('loaded %s', properties);
93
+ return obj;
94
+ }, target);
95
+ }
96
+
97
+ return target;
98
+ }
99
+
100
+ /**
101
+ * Parse files from given directories, then return an items list, each item contains properties and exports.
102
+ *
103
+ * For example, parse `app/controller/group/repository.js`
104
+ *
105
+ * ```
106
+ * module.exports = app => {
107
+ * return class RepositoryController extends app.Controller {};
108
+ * }
109
+ * ```
110
+ *
111
+ * It returns a item
112
+ *
113
+ * ```
114
+ * {
115
+ * properties: [ 'group', 'repository' ],
116
+ * exports: app => { ... },
117
+ * }
118
+ * ```
119
+ *
120
+ * `Properties` is an array that contains the directory of a filepath.
121
+ *
122
+ * `Exports` depends on type, if exports is a function, it will be called. if initializer is specified, it will be called with exports for customizing.
123
+ * @return {Array} items
124
+ * @since 1.0.0
125
+ */
126
+ parse() {
127
+ let files = this.options.match;
128
+ if (!files) {
129
+ files = (process.env.EE_TYPESCRIPT === 'true' && Utils.extensions['.ts'])
130
+ ? [ '**/*.(js|ts)', '!**/*.d.ts' ]
131
+ : [ '**/*.js', '**/*.jsc'];
132
+ } else {
133
+ files = Array.isArray(files) ? files : [ files ];
134
+ }
135
+
136
+ let ignore = this.options.ignore;
137
+ if (ignore) {
138
+ ignore = Array.isArray(ignore) ? ignore : [ ignore ];
139
+ ignore = ignore.filter(f => !!f).map(f => '!' + f);
140
+ files = files.concat(ignore);
141
+ }
142
+
143
+ let directories = this.options.directory;
144
+ if (!Array.isArray(directories)) {
145
+ directories = [ directories ];
146
+ }
147
+
148
+ const filter = is.function(this.options.filter) ? this.options.filter : null;
149
+ const items = [];
150
+ debug('parsing %j', directories);
151
+
152
+ for (const directory of directories) {
153
+ const filepaths = globby.sync(files, { cwd: directory });
154
+ for (const filepath of filepaths) {
155
+ const fullpath = path.join(directory, filepath);
156
+ if (!fs.statSync(fullpath).isFile()) continue;
157
+ // get properties
158
+ // app/service/foo/bar.js => [ 'foo', 'bar' ]
159
+ const properties = getProperties(filepath, this.options);
160
+ // app/service/foo/bar.js => service.foo.bar
161
+ const pathName = directory.split(/[/\\]/).slice(-1) + '.' + properties.join('.');
162
+ // get exports from the file
163
+ let exports = getExports(fullpath, this.options, pathName);
164
+ // ignore exports when it's null or false returned by filter function
165
+ if (exports == null || (filter && filter(exports) === false)) continue;
166
+
167
+ // set properties of class
168
+ if (is.class(exports) || Utils.isBytecodeClass(exports)) {
169
+ exports.prototype.pathName = pathName;
170
+ exports.prototype.fullPath = fullpath;
171
+ }
172
+
173
+ items.push({ fullpath, properties, exports });
174
+ debug('parse %s, properties %j, export %O', fullpath, properties, exports);
175
+ }
176
+ }
177
+
178
+ return items;
179
+ }
180
+
181
+ /**
182
+ * attach items to target object for addons.
183
+ * `app/addon/group/index.js` => `target.group`
184
+ * @return {Object} target
185
+ * @since 1.0.0
186
+ */
187
+ loadAddons() {
188
+ const items = [];
189
+ const files = '*';
190
+ const app = this.options.inject;
191
+ const loader = this.options.loader;
192
+ const target = this.options.target;
193
+ let directories = this.options.directory;
194
+
195
+ if (!Array.isArray(directories)) {
196
+ directories = [ directories ];
197
+ }
198
+
199
+ // check addon
200
+ const config = app.config.addons;
201
+ let filterAddons = [];
202
+ for (let key of Object.keys(config)) {
203
+ if (!config[key].enable) {
204
+ filterAddons.push(key);
205
+ }
206
+ }
207
+
208
+ for (const directory of directories) {
209
+ const addonpaths = globby.sync(files, { cwd: directory, deep: 1, onlyDirectories: true});
210
+ for (const addonName of addonpaths) {
211
+ if (filterAddons.includes(addonName)) continue;
212
+
213
+ let fullpath = path.join(directory, addonName, 'index');
214
+ fullpath = loader.resolveModule(fullpath);
215
+ if (!fs.statSync(fullpath).isFile()) continue;
216
+
217
+ let exports = getExports(fullpath, this.options, addonName);
218
+ if (exports == null) continue;
219
+
220
+ const properties = [addonName];
221
+ if (is.class(exports) || Utils.isBytecodeClass(exports)) {
222
+ exports.prototype.pathName = addonName;
223
+ exports.prototype.fullPath = fullpath;
224
+ }
225
+
226
+ items.push({ fullpath, properties, exports });
227
+ }
228
+
229
+ for (const item of items) {
230
+ const property = item.properties[0];
231
+ let obj = item.exports;
232
+ if (obj && !is.primitive(obj)) {
233
+ obj[FULLPATH] = item.fullpath;
234
+ obj[EXPORTS] = true;
235
+ }
236
+
237
+ target[property] = obj;
238
+ }
239
+ }
240
+
241
+ return target;
242
+ }
243
+ }
244
+
245
+ module.exports = FileLoader;
246
+ module.exports.EXPORTS = EXPORTS;
247
+ module.exports.FULLPATH = FULLPATH;
248
+
249
+ // convert file path to an array of properties
250
+ // a/b/c.js => ['a', 'b', 'c']
251
+ function getProperties(filepath, { caseStyle }) {
252
+ // if caseStyle is function, return the result of function
253
+ if (is.function(caseStyle)) {
254
+ const result = caseStyle(filepath);
255
+ assert(is.array(result), `caseStyle expect an array, but got ${result}`);
256
+ return result;
257
+ }
258
+ // use default camelize
259
+ return defaultCamelize(filepath, caseStyle);
260
+ }
261
+
262
+ // Get exports from filepath
263
+ // If exports is null/undefined, it will be ignored
264
+ function getExports(fullpath, { initializer, call, inject }, pathName) {
265
+ let exports = Utils.loadFile(fullpath);
266
+
267
+ // process exports as you like
268
+ if (initializer) {
269
+ exports = initializer(exports, { path: fullpath, pathName });
270
+ }
271
+
272
+ // return exports when it's a class or generator
273
+ //
274
+ // module.exports = class Service {};
275
+ // or
276
+ // module.exports = function*() {}
277
+ //new exports;
278
+
279
+ if (is.class(exports) || is.generatorFunction(exports) || is.asyncFunction(exports) || Utils.isBytecodeClass(exports)) {
280
+ return exports;
281
+ }
282
+
283
+ // return exports after call when it's a function
284
+ //
285
+ // module.exports = function(app) {
286
+ // return {};
287
+ // }
288
+ if (call && is.function(exports)) {
289
+ exports = exports(inject);
290
+ if (exports != null) {
291
+ return exports;
292
+ }
293
+ }
294
+
295
+ // return exports what is
296
+ return exports;
297
+ }
298
+
299
+ function defaultCamelize(filepath, caseStyle) {
300
+ const properties = filepath.substring(0, filepath.lastIndexOf('.')).split('/');
301
+ return properties.map(property => {
302
+ if (!/^[a-z][a-z0-9_-]*$/i.test(property)) {
303
+ throw new Error(`${property} is not match 'a-z0-9_-' in ${filepath}`);
304
+ }
305
+
306
+ // use default camelize, will capitalize the first letter
307
+ // foo_bar.js > FooBar
308
+ // fooBar.js > FooBar
309
+ // FooBar.js > FooBar
310
+ // FooBar.js > FooBar
311
+ // FooBar.js > fooBar (if lowercaseFirst is true)
312
+ property = property.replace(/[_-][a-z]/ig, s => s.substring(1).toUpperCase());
313
+ let first = property[0];
314
+ switch (caseStyle) {
315
+ case 'lower':
316
+ first = first.toLowerCase();
317
+ break;
318
+ case 'upper':
319
+ first = first.toUpperCase();
320
+ break;
321
+ case 'camel':
322
+ default:
323
+ }
324
+ return first + property.substring(1);
325
+ });
326
+ }