alchemymvc 1.3.22 → 1.4.0-alpha.2

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