alchemymvc 1.3.21 → 1.4.0-alpha.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 (155) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +3 -3
  3. package/lib/app/behaviour/publishable_behaviour.js +5 -5
  4. package/lib/app/behaviour/revision_behaviour.js +10 -10
  5. package/lib/app/behaviour/sluggable_behaviour.js +14 -14
  6. package/lib/app/conduit/electron_conduit.js +9 -9
  7. package/lib/app/conduit/http_conduit.js +13 -13
  8. package/lib/app/conduit/loopback_conduit.js +15 -15
  9. package/lib/app/conduit/socket_conduit.js +43 -43
  10. package/lib/app/config/routes.js +26 -0
  11. package/lib/app/controller/00-default_app_controller.js +21 -0
  12. package/lib/app/controller/alchemy_info_controller.js +12 -12
  13. package/lib/app/datasource/mongo_datasource.js +16 -16
  14. package/lib/app/element/00-default_app_element.js +19 -0
  15. package/lib/app/element/time_ago.js +5 -5
  16. package/lib/app/helper/00-default_app_helper.js +11 -0
  17. package/lib/app/helper/alchemy_helper.js +22 -22
  18. package/lib/app/helper/backed_map.js +1 -1
  19. package/lib/app/helper/breadcrumb.js +10 -10
  20. package/lib/app/helper/client_collection.js +3 -3
  21. package/lib/app/helper/cron.js +29 -29
  22. package/lib/app/helper/enum_values.js +6 -6
  23. package/lib/app/helper/pagination_helper.js +36 -36
  24. package/lib/app/helper/router_helper.js +35 -35
  25. package/lib/app/helper/socket_helper.js +57 -57
  26. package/lib/app/helper/syncable.js +84 -59
  27. package/lib/app/helper_component/paginate_component.js +9 -9
  28. package/lib/app/helper_controller/component.js +1 -1
  29. package/lib/app/helper_controller/conduit.js +31 -31
  30. package/lib/app/helper_controller/controller.js +54 -39
  31. package/lib/app/helper_datasource/00-nosql_datasource.js +624 -70
  32. package/lib/app/helper_datasource/05-fallback_datasource.js +10 -10
  33. package/lib/app/helper_datasource/idb_datasource.js +6 -6
  34. package/lib/app/helper_datasource/indexed_db.js +22 -22
  35. package/lib/app/helper_datasource/remote_datasource.js +5 -5
  36. package/lib/app/helper_error/http_error.js +4 -4
  37. package/lib/app/helper_error/model_error.js +2 -2
  38. package/lib/app/helper_error/validation_error.js +12 -12
  39. package/lib/app/helper_field/00-objectid_field.js +7 -7
  40. package/lib/app/helper_field/05-string_field.js +16 -12
  41. package/lib/app/helper_field/06-text_field.js +2 -4
  42. package/lib/app/helper_field/10-number_field.js +9 -12
  43. package/lib/app/helper_field/11-date_field.js +15 -15
  44. package/lib/app/helper_field/15-local_temporal_field.js +10 -10
  45. package/lib/app/helper_field/20-decimal_field.js +8 -9
  46. package/lib/app/helper_field/belongsto_field.js +1 -1
  47. package/lib/app/helper_field/big_int_field.js +8 -8
  48. package/lib/app/helper_field/boolean_field.js +9 -11
  49. package/lib/app/helper_field/datetime_field.js +3 -3
  50. package/lib/app/helper_field/enum_field.js +13 -8
  51. package/lib/app/helper_field/fixed_decimal_field.js +6 -7
  52. package/lib/app/helper_field/geopoint_field.js +9 -10
  53. package/lib/app/helper_field/habtm_field.js +3 -3
  54. package/lib/app/helper_field/hasoneparent_field.js +1 -1
  55. package/lib/app/helper_field/html_field.js +2 -4
  56. package/lib/app/helper_field/integer_field.js +8 -11
  57. package/lib/app/helper_field/local_date_field.js +5 -5
  58. package/lib/app/helper_field/local_date_time_field.js +5 -5
  59. package/lib/app/helper_field/local_time_field.js +5 -5
  60. package/lib/app/helper_field/mixed_field.js +5 -5
  61. package/lib/app/helper_field/object_field.js +8 -8
  62. package/lib/app/helper_field/password_field.js +3 -3
  63. package/lib/app/helper_field/regexp_field.js +7 -9
  64. package/lib/app/helper_field/schema_field.js +91 -88
  65. package/lib/app/helper_field/settings_field.js +92 -0
  66. package/lib/app/helper_field/time_field.js +6 -6
  67. package/lib/app/helper_field/url_field.js +2 -4
  68. package/lib/app/helper_model/00-base_criteria.js +662 -0
  69. package/lib/app/helper_model/05-criteria_expressions.js +605 -0
  70. package/lib/app/helper_model/10-model_criteria.js +1182 -0
  71. package/lib/app/helper_model/data_provider.js +2 -2
  72. package/lib/app/helper_model/document.js +103 -92
  73. package/lib/app/helper_model/document_list.js +14 -14
  74. package/lib/app/helper_model/field_config.js +11 -11
  75. package/lib/app/helper_model/field_set.js +17 -17
  76. package/lib/app/helper_model/model.js +203 -124
  77. package/lib/app/helper_model/remote_data_provider.js +2 -2
  78. package/lib/app/helper_validator/00_validator.js +16 -16
  79. package/lib/app/helper_validator/not_empty_validator.js +9 -9
  80. package/lib/app/model/00-default_app_model.js +18 -0
  81. package/lib/app/model/05-system_model.js +27 -0
  82. package/lib/app/model/{alchemy_migration_model.js → system_migration_model.js} +4 -4
  83. package/lib/app/model/system_setting_model.js +154 -0
  84. package/lib/app/model/{alchemy_task_history_model.js → system_task_history_model.js} +7 -7
  85. package/lib/app/model/{alchemy_task_model.js → system_task_model.js} +11 -11
  86. package/lib/bootstrap.js +22 -312
  87. package/lib/class/accumulator.js +5 -5
  88. package/lib/class/behaviour.js +5 -5
  89. package/lib/class/component.js +3 -3
  90. package/lib/class/conduit.js +203 -163
  91. package/lib/class/controller.js +42 -42
  92. package/lib/class/datasource.js +74 -79
  93. package/lib/class/document.js +74 -95
  94. package/lib/class/document_list.js +5 -5
  95. package/lib/class/element.js +17 -17
  96. package/lib/class/error.js +3 -3
  97. package/lib/class/field.js +169 -91
  98. package/lib/class/field_value.js +6 -6
  99. package/lib/class/helper.js +3 -3
  100. package/lib/class/inode.js +17 -17
  101. package/lib/class/inode_dir.js +12 -12
  102. package/lib/class/inode_file.js +50 -25
  103. package/lib/class/inode_list.js +4 -4
  104. package/lib/class/migration.js +4 -4
  105. package/lib/class/model.js +182 -168
  106. package/lib/class/path_definition.js +22 -22
  107. package/lib/class/path_evaluator.js +5 -5
  108. package/lib/class/path_param_definition.js +7 -7
  109. package/lib/class/plugin.js +312 -0
  110. package/lib/class/postponement.js +29 -29
  111. package/lib/class/reciprocal.js +8 -8
  112. package/lib/class/route.js +33 -33
  113. package/lib/class/router.js +73 -73
  114. package/lib/class/schema.js +21 -21
  115. package/lib/class/schema_client.js +73 -67
  116. package/lib/class/session.js +63 -29
  117. package/lib/class/session_scene.js +4 -4
  118. package/lib/class/sitemap.js +16 -16
  119. package/lib/class/task.js +39 -39
  120. package/lib/class/task_service.js +43 -47
  121. package/lib/{init → core}/alchemy.js +413 -374
  122. package/lib/{init/functions.js → core/alchemy_functions.js} +171 -108
  123. package/lib/core/alchemy_load_functions.js +715 -0
  124. package/lib/core/base.js +50 -62
  125. package/lib/core/client_alchemy.js +144 -152
  126. package/lib/core/client_base.js +39 -52
  127. package/lib/core/discovery.js +16 -18
  128. package/lib/core/middleware.js +54 -43
  129. package/lib/core/{routing.js → prefix.js} +14 -16
  130. package/lib/core/setting.js +1684 -0
  131. package/lib/core/stage.js +758 -0
  132. package/lib/scripts/create_constants.js +119 -0
  133. package/lib/{init/languages.js → scripts/create_languages.js} +5 -5
  134. package/lib/scripts/create_settings.js +449 -0
  135. package/lib/scripts/create_shared_constants.js +95 -0
  136. package/lib/scripts/create_stages.js +55 -0
  137. package/lib/scripts/init_alchemy.js +51 -0
  138. package/lib/{init/requirements.js → scripts/preload_modules.js} +15 -2
  139. package/lib/scripts/setup_devwatch.js +238 -0
  140. package/lib/stages/00-load_core.js +342 -0
  141. package/lib/stages/05-load_app.js +57 -0
  142. package/lib/stages/10-datasource.js +61 -0
  143. package/lib/stages/15-tasks.js +27 -0
  144. package/lib/stages/20-settings.js +68 -0
  145. package/lib/stages/50-routes.js +218 -0
  146. package/lib/stages/90-server.js +347 -0
  147. package/package.json +5 -7
  148. package/lib/app/helper_model/criteria.js +0 -2294
  149. package/lib/app/helper_model/db_query.js +0 -1488
  150. package/lib/app/routes.js +0 -11
  151. package/lib/core/socket.js +0 -171
  152. package/lib/init/constants.js +0 -158
  153. package/lib/init/devwatch.js +0 -238
  154. package/lib/init/load_functions.js +0 -973
  155. package/lib/stages.js +0 -513
@@ -1,973 +0,0 @@
1
- 'use strict';
2
-
3
- // Get some modules from the cache
4
- var fs = alchemy.use('fs'),
5
- path = alchemy.use('path'),
6
- LOADED = Symbol('LOADED'),
7
- module = require('module'),
8
- original_wrap = module.wrap,
9
- original_wrapper = module.wrapper.slice(0),
10
- original_resolve = module._resolveFilename,
11
- strict_wrapper = original_wrapper[0] + '"use strict";',
12
- prive = {},
13
- _duplicateCheck = {},
14
- cwd = process.cwd();
15
-
16
- /**
17
- * Require all files in a certain directory.
18
- * Does not cache the files.
19
- *
20
- * @author Jelle De Loecker <jelle@develry.be>
21
- * @since 0.0.1
22
- * @version 1.1.5
23
- *
24
- * @param {String} dirPath The path to load
25
- * @param {Object} options
26
- * .modular Treat certain kinds of subdirectories different
27
- * .bootstrap Load the bootstrap.js file first
28
- * .app Load an app_ file second
29
- * .weight The weight, including views & less
30
- *
31
- * @returns {Boolean} If we were able to load in the directory
32
- */
33
- Alchemy.setMethod(function usePath(dirPath, options) {
34
-
35
- var modularRegex = [],
36
- useOptions = {};
37
-
38
- if (typeof options === 'undefined') options = {};
39
-
40
- // Use different functions for different directories by default
41
- if (typeof options.modular === 'undefined') options.modular = true;
42
- if (typeof options._level === 'undefined') options._level = -1;
43
- if (typeof options.weight !== 'number') options.weight = 10;
44
-
45
- options._level++;
46
- useOptions._level = options._level;
47
-
48
- // Always ignore .git directories
49
- modularRegex.push(/^.git$/);
50
-
51
- // Ignore bootstrap file if it's a plugin, because it's already loaded
52
- if (options.plugin) {
53
- useOptions.bootstrap = false;
54
- modularRegex.push({regex: /bootstrap.js/, level: 0});
55
-
56
- // Plugins have a higher weight
57
- // They're more important than the core, but less than the root
58
- if (typeof options.weight !== 'number') {
59
- options.weight = 15;
60
- }
61
- }
62
-
63
- if (options.modular && options._level == 0) {
64
-
65
- // Load Hawkejs view helper classes
66
- if (options.helpers !== false) {
67
- prive.loadHelpers(dirPath, 'helper_datasource');
68
- prive.loadHelpers(dirPath, 'helper_field');
69
- prive.loadHelpers(dirPath, 'helper');
70
- }
71
-
72
- // Load the custom element folder as helpers, too
73
- if (options.elements !== false) {
74
- prive.loadHelpers(dirPath, 'element');
75
- }
76
-
77
- // Let Hawkejs now about this view directory
78
- if (options.views !== false) {
79
- alchemy.addViewDirectory(path.resolve(dirPath, 'view'), options.weight);
80
- }
81
-
82
- // Main asset directory
83
- alchemy.addAssetDirectory(path.resolve(dirPath, 'assets'), options.weight);
84
-
85
- // Asset scripts
86
- if (options.scripts !== false) {
87
- alchemy.addScriptDirectory(path.resolve(dirPath, 'assets', 'scripts'), options.weight);
88
- }
89
-
90
- // Asset stylesheets
91
- if (options.less !== false) {
92
- alchemy.addStylesheetDirectory(path.resolve(dirPath, 'assets', 'stylesheets'), options.weight);
93
-
94
- // Also add the public folder, so less files in there can also be compiled
95
- alchemy.addStylesheetDirectory(path.resolve(dirPath, 'public'), options.weight);
96
- }
97
-
98
- // Fonts
99
- if (options.fonts !== false) {
100
- alchemy.addFontDirectory(path.resolve(dirPath, 'assets', 'fonts'), options.weight);
101
- }
102
-
103
- // Images
104
- if (options.images !== false) {
105
- alchemy.addImageDirectory(path.resolve(dirPath, 'assets', 'images'), options.weight);
106
- }
107
-
108
- // public folders (going to /public/)
109
- if (options.public !== false) {
110
- alchemy.addPublicDirectory(path.resolve(dirPath, 'public'), options.weight);
111
- }
112
-
113
- // Root folders (/)
114
- if (options.root !== false) {
115
- alchemy.addRootDirectory(path.resolve(dirPath, 'root'), options.weight);
116
- }
117
-
118
- modularRegex.push(/^view$|^helper$|^helper_datasource$|^helper_error$|^helper_field$|^helper_document$|^helper_model$|^helper_controller$|^helper_component$|^helper_validator$|^element$|^plugins$|^assets$/);
119
-
120
- useOptions.modular = true;
121
- }
122
-
123
- // Do not load /config subdirectories
124
- if (/\/config$/.exec(dirPath)) useOptions.recursive = false;
125
-
126
- useOptions.ignore = modularRegex;
127
-
128
- this._usePath(dirPath, useOptions);
129
-
130
- // Load record-related helpers, but only after loading the models
131
- if (options.modular && options._level == 0) {
132
- if (options.helpers !== false) {
133
- prive.loadHelpers(dirPath, 'helper_error');
134
- prive.loadHelpers(dirPath, 'helper_model');
135
- prive.loadHelpers(dirPath, 'helper_document');
136
- prive.loadHelpers(dirPath, 'helper_controller');
137
- prive.loadHelpers(dirPath, 'helper_component');
138
- prive.loadHelpers(dirPath, 'helper_validator');
139
- }
140
- }
141
- });
142
-
143
- /**
144
- * Default _usePath options
145
- *
146
- * @author Jelle De Loecker <jelle@develry.be>
147
- * @since 0.5.0
148
- * @version 0.5.0
149
- *
150
- * @type {Object}
151
- */
152
- Alchemy.setProperty('default_use_path_options', {
153
- ignore : false,
154
- recursive : -1,
155
- _level : -1,
156
-
157
- // Load the bootstrap.js file first
158
- bootstrap : true,
159
-
160
- // Load the app_ file afterwards
161
- app : true
162
- });
163
-
164
- /**
165
- * Require all files in a certain directory.
166
- *
167
- * @author Jelle De Loecker <jelle@develry.be>
168
- * @since 0.0.1
169
- * @version 1.2.0
170
- *
171
- * @param {String} dir_path
172
- * @param {Object} options
173
- *
174
- * @returns {Boolean} If we were able to load in the directory
175
- */
176
- Alchemy.setMethod(function _usePath(dir_path, options) {
177
-
178
- var files;
179
-
180
- options = Object.assign({}, this.default_use_path_options, options);
181
-
182
- // Load the bootstrap file
183
- if (options.bootstrap) {
184
- prive.loadBootstrap(dir_path);
185
- }
186
-
187
- // Load the app_ file
188
- if (options.app) {
189
- prive.loadRegexFile(dir_path, /^app_/);
190
- }
191
-
192
- if (options.modularParent == null) {
193
- options.modularParent = options.modular;
194
- }
195
-
196
- // Up the recursive level by 1. Starting points are 0.
197
- options._level++;
198
-
199
- // Read in the directory file listing
200
- try {
201
- files = fs.readdirSync(dir_path);
202
- } catch (err) {
203
- return false;
204
- }
205
-
206
- let directories = [],
207
- file_name,
208
- file_path,
209
- file_stat,
210
- entry,
211
- i;
212
-
213
- // Iterate over the directorie entries
214
- for (i = 0; i < files.length; i++) {
215
- file_name = files[i];
216
-
217
- // Skip hidden files or the "empty" file
218
- if (file_name[0] == '.' || file_name == 'empty') {
219
- continue;
220
- }
221
-
222
- // Skip bootstrap & app files if already loaded
223
- if (options.bootstrap && file_name === 'bootstrap.js') {
224
- continue;
225
- }
226
-
227
- if (options.app && file_name.startsWith('app_')) {
228
- continue;
229
- }
230
-
231
- // Always ignore public or node_modules paths
232
- if (file_name == 'node_modules' || file_name == 'public' || file_name == 'test') {
233
- continue;
234
- }
235
-
236
- // Ignore files that contain .manual.
237
- if (file_name.indexOf('.manual.') > -1) {
238
- continue;
239
- }
240
-
241
- // See if this is in the options.ignore property
242
- if (prive.checkRegex(file_name, options.ignore, options._level)) {
243
- continue;
244
- }
245
-
246
- // Resolve the entire path
247
- file_path = path.resolve(dir_path, file_name);
248
-
249
- // Get information on this entry
250
- file_stat = fs.lstatSync(file_path);
251
-
252
- // Save directories for later, files come first
253
- if (file_stat.isDirectory()) {
254
- directories.push({
255
- parent_path : dir_path,
256
- name : file_name,
257
- path : file_path,
258
- stat : file_stat,
259
- local_path : file_path.slice(PATH_APP.length),
260
- });
261
-
262
- continue;
263
- }
264
-
265
- alchemy.useOnce(file_path);
266
- }
267
-
268
- // Exit early if we don't have to recursively add directories
269
- if (!options.recursive) {
270
- return true;
271
- }
272
-
273
- // Now do the directories
274
- for (i = 0; i < directories.length; i++) {
275
- entry = directories[i];
276
-
277
- // Don't load migrations
278
- if (entry.local_path == '/migrations') {
279
- continue;
280
- }
281
-
282
- // Do not include subfolders of the "config" directory
283
- // if it's a modular load
284
- if (options.modularParent && /\/config$/.exec(entry.parent_path)) {
285
- continue;
286
- }
287
-
288
- this._usePath(entry.path, {
289
- ignore : options.ignore,
290
- recursive : options.recursive - 1,
291
- _level : options._level,
292
- modularParent : options.modularParent
293
- });
294
- }
295
-
296
- return true;
297
- });
298
-
299
- /**
300
- * Add an asset directory
301
- *
302
- * @author Jelle De Loecker <jelle@develry.be>
303
- * @since 0.2.0
304
- * @version 0.4.0
305
- *
306
- * @param {String} dirPath The path to load
307
- * @param {Number} weight The weighted importance [10]
308
- */
309
- Alchemy.setMethod(function addAssetDirectory(dirPath, weight) {
310
-
311
- if (typeof weight !== 'number') {
312
- weight = 10;
313
- }
314
-
315
- alchemy.shared('asset.directories').push(dirPath, weight);
316
- });
317
-
318
- /**
319
- * Add a scripts directory
320
- *
321
- * @author Jelle De Loecker <jelle@develry.be>
322
- * @since 0.2.0
323
- * @version 0.4.0
324
- *
325
- * @param {String} dirPath The path to load
326
- * @param {Number} weight The weighted importance [10]
327
- */
328
- Alchemy.setMethod(function addScriptDirectory(dirPath, weight) {
329
-
330
- if (typeof weight !== 'number') {
331
- weight = 10;
332
- }
333
-
334
- alchemy.shared('script.directories').push(dirPath, weight);
335
- });
336
-
337
- /**
338
- * Add a stylesheets directory
339
- *
340
- * @author Jelle De Loecker <jelle@develry.be>
341
- * @since 0.2.0
342
- * @version 0.4.0
343
- *
344
- * @param {String} dirPath The path to load
345
- * @param {Number} weight The weighted importance [10]
346
- */
347
- Alchemy.setMethod(function addStylesheetDirectory(dirPath, weight) {
348
-
349
- if (typeof weight !== 'number') {
350
- weight = 10;
351
- }
352
-
353
- alchemy.shared('stylesheet.directories').push(dirPath, weight);
354
- });
355
-
356
- /**
357
- * Add a font directory
358
- *
359
- * @author Jelle De Loecker <jelle@elevenways.be>
360
- * @since 1.1.3
361
- * @version 1.1.3
362
- *
363
- * @param {String} dirPath The path to load
364
- * @param {Number} weight The weighted importance [10]
365
- */
366
- Alchemy.setMethod(function addFontDirectory(dirPath, weight) {
367
-
368
- if (typeof weight !== 'number') {
369
- weight = 10;
370
- }
371
-
372
- alchemy.shared('font.directories').push(dirPath, weight);
373
- });
374
-
375
- /**
376
- * Add an image directory
377
- *
378
- * @author Jelle De Loecker <jelle@develry.be>
379
- * @since 0.2.0
380
- * @version 0.4.0
381
- *
382
- * @param {String} dirPath The path to load
383
- * @param {Number} weight The weighted importance [10]
384
- */
385
- Alchemy.setMethod(function addImageDirectory(dirPath, weight) {
386
-
387
- if (typeof weight !== 'number') {
388
- weight = 10;
389
- }
390
-
391
- alchemy.shared('images.directories').push(dirPath, weight);
392
- });
393
-
394
- /**
395
- * Add a public directory
396
- *
397
- * @author Jelle De Loecker <jelle@develry.be>
398
- * @since 0.2.0
399
- * @version 0.4.0
400
- *
401
- * @param {String} dirPath The path to load
402
- * @param {Number} weight The weighted importance [10]
403
- */
404
- Alchemy.setMethod(function addPublicDirectory(dirPath, weight) {
405
-
406
- if (typeof weight !== 'number') {
407
- weight = 10;
408
- }
409
-
410
- alchemy.shared('public.directories').push(dirPath, weight);
411
- });
412
-
413
- /**
414
- * Add a root directory
415
- *
416
- * @author Jelle De Loecker <jelle@develry.be>
417
- * @since 0.2.0
418
- * @version 0.4.0
419
- *
420
- * @param {String} dirPath The path to load
421
- * @param {Number} weight The weighted importance [10]
422
- */
423
- Alchemy.setMethod(function addRootDirectory(dirPath, weight) {
424
-
425
- if (typeof weight !== 'number') {
426
- weight = 10;
427
- }
428
-
429
- alchemy.shared('root.directories').push(dirPath, weight);
430
- });
431
-
432
- /**
433
- * Tell hawkejs to use this path to look for views.
434
- *
435
- * @author Jelle De Loecker <jelle@develry.be>
436
- * @since 0.0.1
437
- * @version 0.4.0
438
- *
439
- * @param {String} dirPath The path to load
440
- * @param {Number} weight The weighted importance [10]
441
- */
442
- Alchemy.setMethod(function addViewDirectory(dirPath, weight) {
443
-
444
- if (typeof weight !== 'number') {
445
- weight = 10;
446
- }
447
-
448
- alchemy.hawkejs.addViewDirectory(dirPath, weight);
449
- });
450
-
451
- /**
452
- * Load in the bootstrap file.
453
- *
454
- * @author Jelle De Loecker <jelle@develry.be>
455
- * @since 0.0.1
456
- * @version 0.4.0
457
- *
458
- * @param {String} dirPath The path to load
459
- *
460
- * @returns {Boolean} If we were able to load in the file
461
- */
462
- prive.loadBootstrap = function loadBootstrap(dirPath) {
463
-
464
- // If a bootstrap.js file exists inside the directory, load it first
465
- var bootstrapPath = path.resolve(dirPath, 'bootstrap.js');
466
-
467
- if (typeof _duplicateCheck[bootstrapPath] == 'undefined') {
468
-
469
- if (fs.existsSync(bootstrapPath)) {
470
- alchemy.makeNextRequireStrict();
471
- require(bootstrapPath);
472
- }
473
-
474
- _duplicateCheck[bootstrapPath] = true;
475
- }
476
-
477
- return _duplicateCheck[bootstrapPath];
478
- };
479
-
480
- /**
481
- * Load in a file by regex.
482
- *
483
- * @author Jelle De Loecker <jelle@develry.be>
484
- * @since 0.0.1
485
- * @version 0.0.1
486
- *
487
- * @param {String} dirPath The path to load
488
- * @param {RegExp} pattern The pattern to match
489
- * @param {Boolean} multiple Keep looking after finding one? (false)
490
- *
491
- * @returns {Boolean} If we were able to load in the file
492
- */
493
- prive.loadRegexFile = function loadRegexFile (dirPath, pattern, multiple) {
494
-
495
- var files, fileCount, fileName, filePath, fileStat, result = false;
496
-
497
- if (!(pattern instanceof RegExp)) {
498
- log.error('Tried to load a file by passing invalid regex', {level: 1});
499
- return false;
500
- }
501
-
502
- try {
503
- files = fs.readdirSync(dirPath);
504
- } catch (err) {
505
- return false;
506
- }
507
-
508
- for (fileCount in files) {
509
-
510
- fileName = files[fileCount];
511
-
512
- // Continue to the next file if the patternd ooesn't match
513
- if (!pattern.exec(fileName)) continue;
514
-
515
- filePath = path.resolve(dirPath, fileName);
516
- fileStat = fs.lstatSync(filePath);
517
-
518
- // Skip directories
519
- if (fileStat.isDirectory()) continue;
520
-
521
- alchemy.useOnce(filePath);
522
-
523
- result = true;
524
-
525
- // Stop looking for more matches if multiple is false/undefined
526
- if (!multiple) break;
527
- }
528
-
529
- return result;
530
- }
531
-
532
- /**
533
- * Load in a directory containing helpers.
534
- * These helpers will be added to the main Hawkejs instance.
535
- *
536
- * @author Jelle De Loecker <jelle@develry.be>
537
- * @since 0.0.1
538
- * @version 1.1.0
539
- *
540
- * @param {String} dir_path The path to load
541
- */
542
- prive.loadHelpers = function loadHelpers(...path_pieces) {
543
-
544
- var dir_path,
545
- helperFiles,
546
- fileCount,
547
- filePath,
548
- dirs,
549
- name;
550
-
551
- // Make a path out of all the arguments
552
- dir_path = alchemy.pathResolve.apply(null, path_pieces);
553
-
554
- if (typeof _duplicateCheck[dir_path] != 'undefined') return false;
555
-
556
- if (!fs.existsSync(dir_path)) {
557
- _duplicateCheck[dir_path] = false;
558
- return false;
559
- }
560
-
561
- // Possible sub dirs
562
- dirs = [];
563
-
564
- try {
565
- helperFiles = fs.readdirSync(dir_path);
566
-
567
- for (fileCount in helperFiles) {
568
- name = helperFiles[fileCount];
569
-
570
- // Don't require the "empty" file or any hidden files
571
- if (name == 'empty' || name[0] == '.') {
572
- continue;
573
- }
574
-
575
- try {
576
- filePath = path.resolve(dir_path, name);
577
-
578
- if (fs.lstatSync(filePath).isDirectory()) {
579
- dirs.push(filePath);
580
- } else {
581
- alchemy.hawkejs.load(filePath, {
582
- arguments : 'hawkejs'
583
- });
584
- }
585
- } catch (err) {
586
- alchemy.printLog('warning', ['Unable to add helper file ' + name + '\n' + String(err), err], {err: err, level: -2});
587
- alchemy.printLog('warning', ['File was at', filePath], {err: err, level: -2});
588
- }
589
- }
590
-
591
- _duplicateCheck[dir_path] = true;
592
-
593
- for (let i = 0; i < dirs.length; i++) {
594
- loadHelpers(dirs[i]);
595
- }
596
-
597
- return true;
598
- } catch (err) {
599
-
600
- _duplicateCheck[dir_path] = false;
601
- log.warn('Was unable to read in helper directory ' + dir_path);
602
-
603
- return false;
604
- }
605
- };
606
-
607
- /**
608
- * Check haystack for a regex
609
- *
610
- * @author Jelle De Loecker <jelle@develry.be>
611
- * @since 0.0.1
612
- * @version 0.4.0
613
- *
614
- * @param {String} haystack The string to compare to
615
- * @param {Array} needles An array of regexes
616
- * @param {Number} currentLevel The current level we're on
617
- *
618
- * @returns {boolean} False if no match was found, true if any matched
619
- */
620
- prive.checkRegex = function checkRegex(haystack, needles, currentLevel) {
621
-
622
- var rexCount,
623
- rex;
624
-
625
- if (typeof currentLevel == 'undefined') {
626
- currentLevel = -1;
627
- }
628
-
629
- // See if we need to ignore this file according to the given regex
630
- if (needles instanceof RegExp && needles.exec(haystack)) {
631
- return true;
632
- } else if (needles instanceof Array) {
633
-
634
- for (rexCount = 0; rexCount < needles.length; rexCount++) {
635
-
636
- rex = needles[rexCount];
637
-
638
- if (rex instanceof RegExp) {
639
- if (rex.exec(haystack)) return true;
640
- } else {
641
- if (rex.constructor.name == 'Object' && rex.regex instanceof RegExp) {
642
- if (rex.level < 0 || rex.level == currentLevel) {
643
- if (rex.regex.exec(haystack)) {
644
- return true;
645
- }
646
- }
647
- }
648
- }
649
- }
650
- }
651
-
652
- return false;
653
- };
654
-
655
- /**
656
- * Prepare a plugin for use.
657
- * This immediately executes the plugin's bootstrap.js file,
658
- * but the loading of the app tree happens later.
659
- *
660
- * @author Jelle De Loecker <jelle@develry.be>
661
- * @since 0.0.1
662
- * @version 1.1.0
663
- *
664
- * @param {String} name The name of the plugin (which is its path)
665
- * @param {Object} options Options to pass to the plugin
666
- */
667
- Alchemy.setMethod(function usePlugin(name, options) {
668
-
669
- var possible_paths,
670
- path_to_plugin,
671
- plugin_stat,
672
- full_name,
673
- is_dir = false;
674
-
675
- // Strip of the "alchemy-" from the name, should it be given
676
- if (name.startsWith('alchemy-')) {
677
- name = name.slice(8);
678
- }
679
-
680
- // The "full" name starts with "alchemy-"
681
- full_name = 'alchemy-' + name;
682
-
683
- if (alchemy.plugins[name] != null) {
684
-
685
- if (options) {
686
- log.warn('Tried to load plugin "' + name + '" with options twice!');
687
- }
688
-
689
- return true;
690
- }
691
-
692
- if (options == null) {
693
- options = {};
694
- }
695
-
696
- // Create the possible paths to this plugin
697
- possible_paths = [];
698
-
699
- if (options.path_to_plugin) {
700
- possible_paths.push(options.path_to_plugin);
701
- } else {
702
-
703
- let temp,
704
- key;
705
-
706
- // Look for the "alchemy-" path first
707
- possible_paths.push(alchemy.pathResolve(PATH_ROOT, 'node_modules', full_name));
708
- possible_paths.push(alchemy.pathResolve(PATH_ROOT, 'node_modules', name));
709
-
710
- // It's also allowed to be inside the app/plugins folder
711
- possible_paths.push(alchemy.pathResolve(PATH_APP, 'plugins', full_name));
712
- possible_paths.push(alchemy.pathResolve(PATH_APP, 'plugins', name));
713
-
714
- // And even in other plugins
715
- for (key in alchemy.plugins) {
716
- temp = alchemy.plugins[key];
717
- possible_paths.push(alchemy.pathResolve(temp.__path, 'node_modules', full_name));
718
- possible_paths.push(alchemy.pathResolve(temp.__path, 'node_modules', name));
719
- }
720
- }
721
-
722
- // Look for the plugin in every possible path
723
- possible_paths.some(function eachPath(value) {
724
-
725
- try {
726
- path_to_plugin = value;
727
- plugin_stat = fs.lstatSync(path_to_plugin);
728
- is_dir = plugin_stat.isDirectory() || plugin_stat.isSymbolicLink();
729
-
730
- // Stop the loop, path has been found
731
- return true;
732
- } catch (err) {
733
- // Try the next value
734
- return false;
735
- }
736
- });
737
-
738
- if (is_dir) {
739
-
740
- // Pass along the path the plugin is in
741
- options.__path = path_to_plugin;
742
-
743
- // Set the given options
744
- alchemy.plugins[name] = options;
745
-
746
- try {
747
- // Require the bootstrap.js file now, if it exists
748
- alchemy.useOnce(alchemy.pathResolve(path_to_plugin, 'bootstrap.js'), {throwError: true});
749
- } catch (err) {
750
- // Only throw an error when loading failed
751
- // because bootstrap files are not required
752
- if (err.message.indexOf('Cannot find') === -1) {
753
- throw err;
754
- }
755
- }
756
-
757
- return true;
758
- } else {
759
- log.error('Could not find ' + JSON.stringify(name) + ' plugin directory');
760
- return false;
761
- }
762
- });
763
-
764
- /**
765
- * Start all the loaded plugins
766
- *
767
- * @author Jelle De Loecker <jelle@develry.be>
768
- * @since 0.0.1
769
- * @version 1.1.0
770
- *
771
- * @param {String|Array} names Names of plugins to start
772
- */
773
- Alchemy.setMethod(function startPlugins(names) {
774
-
775
- var plugin,
776
- path,
777
- name,
778
- all;
779
-
780
- if (!names) {
781
- all = true;
782
-
783
- // Make sure all the constitutions of the core classes are loaded
784
- Blast.doLoaded();
785
- }
786
-
787
- if (typeof names == 'string') {
788
- names = [names];
789
- }
790
-
791
- for (name in alchemy.plugins) {
792
-
793
- if (!all && names.indexOf(name) == -1) {
794
- continue;
795
- }
796
-
797
- plugin = alchemy.plugins[name];
798
- path = plugin.__path;
799
-
800
- if (path) {
801
- if (!plugin[LOADED]) {
802
- alchemy.usePath(path, {plugin: true});
803
- plugin[LOADED] = true;
804
- }
805
- } else {
806
- log.error('Plugin path was undefined: ' + name);
807
- }
808
- }
809
- });
810
-
811
- /**
812
- * If a plugin hasn't been loaded yet, but it is required, die
813
- *
814
- * @author Jelle De Loecker <jelle@develry.be>
815
- * @since 0.0.1
816
- * @version 1.2.2
817
- *
818
- * @param {String|Array} names
819
- * @param {Boolean} attempt_require
820
- */
821
- Alchemy.setMethod(function requirePlugin(names, attempt_require) {
822
-
823
- var message,
824
- missing = '',
825
- name,
826
- temp,
827
- i;
828
-
829
- if (attempt_require == null) {
830
- attempt_require = true;
831
- }
832
-
833
- if (!Array.isArray(names)) {
834
- names = [names];
835
- }
836
-
837
- for (i = 0; i < names.length; i++) {
838
-
839
- name = names[i];
840
-
841
- if (typeof alchemy.plugins[name] === 'undefined') {
842
-
843
- if (attempt_require) {
844
- temp = alchemy.usePlugin(name);
845
-
846
- if (temp) {
847
- let plugin_stage = alchemy.sputnik.get('plugins');
848
-
849
- if (!plugin_stage || plugin_stage.started) {
850
- // If the plugin stage has already started,
851
- // manually start this plugin now
852
- alchemy.startPlugins(name);
853
- }
854
- continue;
855
- }
856
- }
857
-
858
- if (missing) {
859
- missing += ', ';
860
- }
861
-
862
- missing += name;
863
- }
864
- }
865
-
866
- if (missing) {
867
- message = 'These required plugin(s) are missing: ' + missing;
868
- die(message, {level: 2});
869
- }
870
- });
871
-
872
- /**
873
- * Load in a file only once
874
- *
875
- * @author Jelle De Loecker <jelle@develry.be>
876
- * @since 0.0.1
877
- * @version 1.1.0
878
- */
879
- Alchemy.setMethod(function useOnce(dirPath, options) {
880
-
881
- if (typeof options == 'undefined') {
882
- options = {};
883
- }
884
-
885
- dirPath = alchemy.pathResolve.apply(null, arguments);
886
-
887
- if (dirPath.indexOf('.js') === -1) {
888
- //log.verbose('Skipped non JS file: ' + dirPath.split('/').pop());
889
- return false;
890
- }
891
-
892
- if (typeof _duplicateCheck[dirPath] === 'undefined') {
893
-
894
- // Mainly used for tidying up the unit tests
895
- if (process.env.NO_ALCHEMY_LOAD_WARNING == 1) {
896
- options.throwError = false;
897
- options.silent = true;
898
- }
899
-
900
- // Make sure the next requirement uses strict
901
- alchemy.makeNextRequireStrict();
902
-
903
- try {
904
- require(dirPath);
905
- _duplicateCheck[dirPath] = true;
906
- //log.verbose('Used file once: ' + dirPath, {level: 1});
907
- } catch (err) {
908
-
909
- // Add the path to the file that failed to load,
910
- // this can be used when it's a syntax error
911
- // (It's hard to find the cause otherwise)
912
- err.file_path = dirPath;
913
-
914
- _duplicateCheck[dirPath] = false;
915
-
916
- if (options.throwError !== false) {
917
-
918
- if (options.throwError !== true) {
919
- let yellow = __Janeway.esc('103;91');
920
- alchemy.printLog('error', [yellow + '========================='], {err: err, level: -2});
921
- alchemy.printLog('error', [yellow + ' Failed to load file: '], {err: err, level: -2});
922
- alchemy.printLog('error', [yellow + ' »', dirPath.split(path.sep).last()], {err: err, level: -2});
923
- alchemy.printLog('error', [yellow + ' In directory: '], {err: err, level: -2});
924
- alchemy.printLog('error', [yellow + ' »', dirPath.split(path.sep).slice(0, -1).join(path.sep)], {err: err, level: -2});
925
- alchemy.printLog('error', [yellow + ' With error: '], {err: err, level: -2});
926
- alchemy.printLog('error', [yellow + ' »', err], {err: err, level: -2});
927
- alchemy.printLog('error', [yellow + '========================='], {err: err, level: -2});
928
- }
929
-
930
- throw err;
931
- }
932
-
933
- if (!options.silent) {
934
- // @todo: "Failed to use file once..." message doesn't get displayed
935
- log.error('Failed to use file once: ' + dirPath, {level: 5, err: err, extra: true});
936
- }
937
- }
938
- } else {
939
- //log.verbose('File not loaded, already used once: ' + dirPath, {level: 1});
940
- }
941
- });
942
-
943
- /**
944
- * Make the next `require` call strict
945
- *
946
- * @author Jelle De Loecker <jelle@develry.be>
947
- * @since 0.4.0
948
- * @version 0.4.0
949
- */
950
- Alchemy.setMethod(function makeNextRequireStrict() {
951
- // Overwrite the original wrap method
952
- module.wrap = function wrap(script) {
953
-
954
- // Restore the original functions
955
- module.wrap = original_wrap;
956
- module._resolveFilename = original_resolve;
957
-
958
- // Add the strict wrapper for this requirement
959
- return strict_wrapper + script + module.wrapper[1];
960
- };
961
-
962
- // Overwrite the original _resolveFilename method
963
- module._resolveFilename = function _resolveFilename(request, parent, isMain) {
964
- try {
965
- return original_resolve(request, parent, isMain);
966
- } catch (err) {
967
- module.wrap = original_wrap;
968
- module._resolveFilename = original_resolve;
969
- throw err;
970
- }
971
- };
972
-
973
- });