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
@@ -0,0 +1,758 @@
1
+ const STATUS = Symbol('status'),
2
+ STATUS_PLEDGE = Symbol('status_pledge'),
3
+ MAIN_PLEDGE = Symbol('main_pledge'),
4
+ PRE_STATUS = 'pre',
5
+ MAIN_STATUS = 'main',
6
+ CHILD_STATUS = 'children',
7
+ POST_STATUS = 'post';
8
+
9
+ /**
10
+ * The Stage class
11
+ *
12
+ * @author Jelle De Loecker <jelle@elevenways.be>
13
+ * @since 1.4.0
14
+ * @version 1.4.0
15
+ *
16
+ * @param {string} name
17
+ * @param {Alchemy.Stages.Stages} parent
18
+ */
19
+ const Stage = Function.inherits('Alchemy.Base', 'Alchemy.Stages', function Stage(name, parent) {
20
+
21
+ // The name of this stage
22
+ this.name = name;
23
+
24
+ // The path
25
+ this.id = parent ? parent.id + '.' + name : name;
26
+
27
+ // The parent Stage (if any)
28
+ this.parent = parent;
29
+
30
+ // The root stage
31
+ this.root_stage = parent ? parent.root_stage : this;
32
+
33
+ // The current status
34
+ this[STATUS] = null;
35
+
36
+ // The main pledge
37
+ this[MAIN_PLEDGE] = new Pledge.Swift();
38
+
39
+ // The dependencies of this stage
40
+ this.depends_on = null;
41
+
42
+ // Pre-tasks
43
+ this.pre_tasks = new Map();
44
+
45
+ // Main tasks
46
+ this.main_tasks = new Map();
47
+
48
+ // Child stages
49
+ this.child_stages = new Map();
50
+
51
+ // Post-tasks
52
+ this.post_tasks = new Map();
53
+
54
+ // When this started
55
+ this.started = null;
56
+
57
+ // When this ended
58
+ this.ended = null;
59
+ });
60
+
61
+ /**
62
+ * Is this the root stage?
63
+ *
64
+ * @author Jelle De Loecker <jelle@elevenways.be>
65
+ * @since 1.4.0
66
+ * @version 1.4.0
67
+ */
68
+ Stage.setProperty(function is_root() {
69
+ return this.root_stage === this;
70
+ });
71
+
72
+ /**
73
+ * Get the main pledge
74
+ *
75
+ * @author Jelle De Loecker <jelle@elevenways.be>
76
+ * @since 1.4.0
77
+ * @version 1.4.0
78
+ */
79
+ Stage.setProperty(function pledge() {
80
+ return this[MAIN_PLEDGE];
81
+ });
82
+
83
+ /**
84
+ * Add a dependency to this stage
85
+ *
86
+ * @author Jelle De Loecker <jelle@elevenways.be>
87
+ * @since 1.4.0
88
+ * @version 1.4.0
89
+ *
90
+ * @param {string[]} stage_ids The id of the stage it depends on.
91
+ *
92
+ * @return {Alchemy.Stages.Stage}
93
+ */
94
+ Stage.setMethod(function dependsOn(stage_ids) {
95
+
96
+ if (!this.depends_on) {
97
+ this.depends_on = [];
98
+ }
99
+
100
+ stage_ids = Array.cast(stage_ids);
101
+
102
+ for (let i = 0; i < stage_ids.length; i++) {
103
+ let id = stage_ids[i];
104
+
105
+ if (typeof id != 'string') {
106
+ throw new Error('Stage id should be a string');
107
+ }
108
+
109
+ if (!this.is_root && !id.startsWith(this.root_stage.name)) {
110
+ id = this.root_stage.name + '.' + id;
111
+ }
112
+
113
+ stage_ids[i] = id;
114
+
115
+ }
116
+
117
+ this.depends_on.push(...stage_ids);
118
+
119
+ // Push these dependencies to the already existing children
120
+ for (let [name, stage] of this.child_stages) {
121
+ stage.dependsOn(stage_ids);
122
+ }
123
+
124
+ return this;
125
+ });
126
+
127
+ /**
128
+ * Add a new child stage
129
+ *
130
+ * @author Jelle De Loecker <jelle@elevenways.be>
131
+ * @since 1.4.0
132
+ * @version 1.4.0
133
+ *
134
+ * @param {string} name Name of the stage
135
+ * @param {Function} fnc The function to execute as a main task
136
+ *
137
+ * @return {Alchemy.Stages.Stage}
138
+ */
139
+ Stage.setMethod(function createStage(name, fnc) {
140
+
141
+ if (this.child_stages.has(name)) {
142
+ throw new Error('Stage "' + name + '" already exists');
143
+ }
144
+
145
+ let stage = new Stage(name, this);
146
+
147
+ if (this.depends_on?.length) {
148
+ stage.dependsOn(this.depends_on);
149
+ }
150
+
151
+ this.child_stages.set(name, stage);
152
+
153
+ if (fnc) {
154
+ stage.addMainTask(fnc);
155
+ }
156
+
157
+ return stage;
158
+ });
159
+
160
+ /**
161
+ * Add a certain task
162
+ *
163
+ * @author Jelle De Loecker <jelle@elevenways.be>
164
+ * @since 1.4.0
165
+ * @version 1.4.0
166
+ *
167
+ * @param {string} type
168
+ * @param {Function} fnc
169
+ */
170
+ Stage.setMethod(function _addTask(type, fnc) {
171
+
172
+ let task_map = this[type];
173
+
174
+ // First see if this type has already been started
175
+ let pledge = task_map[STATUS_PLEDGE];
176
+
177
+ // If it has, we can already start the task,
178
+ // but we have to set a new pledge.
179
+ if (pledge) {
180
+ let new_pledge = new Pledge.Swift();
181
+ task_map[STATUS_PLEDGE] = new_pledge;
182
+
183
+ let task_result;
184
+
185
+ try {
186
+ task_result = fnc();
187
+ } catch (err) {
188
+ new_pledge.reject(err);
189
+ task_map.set(fnc, err);
190
+ return;
191
+ }
192
+
193
+ if (!task_result) {
194
+ task_result = true;
195
+ }
196
+
197
+ task_map.set(fnc, task_result);
198
+ } else {
199
+ task_map.set(fnc, null);
200
+ }
201
+ });
202
+
203
+ /**
204
+ * Do the given type of tasks
205
+ *
206
+ * @author Jelle De Loecker <jelle@elevenways.be>
207
+ * @since 1.4.0
208
+ * @version 1.4.0
209
+ *
210
+ * @param {string} type
211
+ */
212
+ Stage.setMethod(function _doTasks(type) {
213
+
214
+ let task_map = this[type];
215
+
216
+ let pledge = new Pledge.Swift();
217
+ task_map[STATUS_PLEDGE] = pledge;
218
+
219
+ let tasks = [];
220
+ let errors = [];
221
+
222
+ for (let [fnc, value] of task_map) {
223
+
224
+ // It already has a value: it has already been executed
225
+ if (value) {
226
+ if (Pledge.isThenable(value)) {
227
+ tasks.push(value);
228
+ }
229
+
230
+ continue;
231
+ }
232
+
233
+ // If needs to be executed
234
+ try {
235
+ value = fnc();
236
+
237
+ if (!value) {
238
+ value = true;
239
+ } else if (Pledge.isThenable(value)) {
240
+ tasks.push(value);
241
+
242
+ Pledge.cast(value).done((err, result) => {
243
+ task_map.set(fnc, result || err || true);
244
+ });
245
+ }
246
+
247
+ task_map.set(fnc, value);
248
+
249
+ } catch (err) {
250
+ errors.push(err);
251
+ task_map.set(fnc, err);
252
+ }
253
+ }
254
+
255
+ if (!tasks.length && !errors.length) {
256
+ pledge.resolve(true);
257
+ return pledge;
258
+ }
259
+
260
+ if (errors.length) {
261
+ pledge.reject(errors[0]);
262
+ return pledge;
263
+ }
264
+
265
+ Function.parallel(tasks).done((err) => {
266
+ if (err) {
267
+ pledge.reject(err);
268
+ } else {
269
+ pledge.resolve(this._doTasks(type));
270
+ }
271
+ });
272
+
273
+ return pledge;
274
+ });
275
+
276
+ /**
277
+ * Add a pre-task to this stage:
278
+ * This task will be performed before the main tasks of this stage.
279
+ *
280
+ * @author Jelle De Loecker <jelle@elevenways.be>
281
+ * @since 1.4.0
282
+ * @version 1.4.0
283
+ *
284
+ * @param {Function} fnc
285
+ */
286
+ Stage.setMethod(function addPreTask(fnc) {
287
+ this._addTask('pre_tasks', fnc);
288
+ });
289
+
290
+ /**
291
+ * Add a main task to this stage:
292
+ * This task will be performed after the pre-tasks of this stage.
293
+ *
294
+ * @author Jelle De Loecker <jelle@elevenways.be>
295
+ * @since 1.4.0
296
+ * @version 1.4.0
297
+ *
298
+ * @param {Function} fnc
299
+ */
300
+ Stage.setMethod(function addMainTask(fnc) {
301
+ this._addTask('main_tasks', fnc);
302
+ });
303
+
304
+ /**
305
+ * Add a post task to this stage:
306
+ * This task will be performed after the main-tasks
307
+ * and the child stages of this stage.
308
+ *
309
+ * @author Jelle De Loecker <jelle@elevenways.be>
310
+ * @since 1.4.0
311
+ * @version 1.4.0
312
+ *
313
+ * @param {Function} fnc
314
+ */
315
+ Stage.setMethod(function addPostTask(fnc) {
316
+ this._addTask('post_tasks', fnc);
317
+ });
318
+
319
+ /**
320
+ * Have all the child stages finished?
321
+ *
322
+ * @author Jelle De Loecker <jelle@elevenways.be>
323
+ * @since 1.4.0
324
+ * @version 1.4.0
325
+ */
326
+ Stage.setMethod(function hasFinishedAllChildStages() {
327
+
328
+ if (this.child_stages.size == 0) {
329
+ return true;
330
+ }
331
+
332
+ for (let [name, stage] of this.child_stages) {
333
+ if (!stage.ended) {
334
+ return false;
335
+ }
336
+ }
337
+
338
+ return true;
339
+ });
340
+
341
+ /**
342
+ * Get a child stage by its path/id
343
+ *
344
+ * @author Jelle De Loecker <jelle@elevenways.be>
345
+ * @since 1.4.0
346
+ * @version 1.4.0
347
+ *
348
+ * @param {string} id
349
+ */
350
+ Stage.setMethod(function getStage(id) {
351
+
352
+ if (!id) {
353
+ throw new Error('Unable to get stage without id');
354
+ }
355
+
356
+ let parts = id.split('.');
357
+
358
+ if (this.is_root && parts[0] == this.name) {
359
+ parts.shift();
360
+ }
361
+
362
+ let current = this;
363
+
364
+ while (parts.length) {
365
+ let part = parts.shift();
366
+
367
+ current = current.child_stages.get(part);
368
+
369
+ if (!current) {
370
+ return;
371
+ }
372
+ }
373
+
374
+ return current;
375
+ });
376
+
377
+ /**
378
+ * Wait for the given child stages (without starting them)
379
+ *
380
+ * @author Jelle De Loecker <jelle@elevenways.be>
381
+ * @since 1.4.0
382
+ * @version 1.4.0
383
+ *
384
+ * @param {string[]} stages
385
+ * @param {Function} callback
386
+ */
387
+ Stage.setMethod(function afterStages(stages, callback) {
388
+
389
+ stages = Array.cast(stages);
390
+
391
+ let tasks = [];
392
+
393
+ for (let id of stages) {
394
+ let stage = this.getStage(id);
395
+
396
+ if (!stage) {
397
+ throw new Error('Child stage "' + id + '" not found');
398
+ }
399
+
400
+ if (stage.ended) {
401
+ continue;
402
+ }
403
+
404
+ tasks.push(async (next) => {
405
+ await stage.pledge;
406
+ next();
407
+ });
408
+ }
409
+
410
+ return Function.series(tasks, callback);
411
+ });
412
+
413
+ /**
414
+ * Recursively get all the child-stages (including this one)
415
+ *
416
+ * @author Jelle De Loecker <jelle@elevenways.be>
417
+ * @since 1.4.0
418
+ * @version 1.4.0
419
+ *
420
+ * @param {string[]} filter
421
+ *
422
+ * @return {Alchemy.Stage.Stage[]}
423
+ */
424
+ Stage.setMethod(function getFlattenedStages(filter) {
425
+
426
+ let result = [];
427
+
428
+ result.push(this);
429
+
430
+ // If the filter is given, split each entry up into parts
431
+ if (filter) {
432
+ filter = Array.cast(filter);
433
+
434
+ for (let i = 0; i < filter.length; i++) {
435
+ let parts = filter[i].split('.');
436
+
437
+ if (this.is_root && parts[0] == this.name) {
438
+ parts.shift();
439
+ }
440
+
441
+ filter[i] = parts;
442
+ }
443
+ }
444
+
445
+ for (let [name, stage] of this.child_stages) {
446
+
447
+ let sub_filter;
448
+
449
+ if (filter) {
450
+ let matches_filter = false;
451
+
452
+ sub_filter = [];
453
+
454
+ for (let i = 0; i < filter.length; i++) {
455
+ let parts = filter[i];
456
+
457
+ if (parts[0] == name) {
458
+ matches_filter = true;
459
+
460
+ // Create a clone of the parts array
461
+ parts = parts.slice(0);
462
+
463
+ // Remove the first part
464
+ parts.shift();
465
+
466
+ if (parts.length) {
467
+ // And add it to the sub filter
468
+ sub_filter.push(parts);
469
+ }
470
+ }
471
+ }
472
+
473
+ if (!matches_filter) {
474
+ continue;
475
+ }
476
+
477
+ if (!sub_filter.length) {
478
+ sub_filter = null;
479
+ }
480
+ }
481
+
482
+ result.push(...stage.getFlattenedStages(sub_filter));
483
+ }
484
+
485
+ return result;
486
+ });
487
+
488
+ /**
489
+ * Recursively get all the child-stages (including this one)
490
+ * sorted in launch order.
491
+ *
492
+ * @author Jelle De Loecker <jelle@elevenways.be>
493
+ * @since 1.4.0
494
+ * @version 1.4.0
495
+ *
496
+ * @param {string[]} filter
497
+ *
498
+ * @return {Alchemy.Stage.Stage[]}
499
+ */
500
+ Stage.setMethod(function getSortedStages(filter) {
501
+
502
+ let stages = this.getFlattenedStages(filter);
503
+
504
+ stages.sortTopological('id', 'depends_on');
505
+
506
+ return stages;
507
+ });
508
+
509
+ /**
510
+ * Launch this stage and all the given child stages.
511
+ *
512
+ * @author Jelle De Loecker <jelle@elevenways.be>
513
+ * @since 1.4.0
514
+ * @version 1.4.0
515
+ *
516
+ * @param {string[]} child_stages The child stages to launch
517
+ */
518
+ Stage.setMethod(async function launch(child_stages) {
519
+
520
+ if (child_stages == null) {
521
+ throw new Error('Unable to launch a stage without allowed child stages');
522
+ }
523
+
524
+ if (child_stages === true) {
525
+ child_stages = undefined;
526
+ }
527
+
528
+ let stages = this.getSortedStages(child_stages);
529
+
530
+ for (let stage of stages) {
531
+ await stage._launch();
532
+ }
533
+ });
534
+
535
+ /**
536
+ * Actually launch this stage and all the given child stages
537
+ *
538
+ * @author Jelle De Loecker <jelle@elevenways.be>
539
+ * @since 1.4.0
540
+ * @version 1.4.0
541
+ *
542
+ * @param {string[]} child_stages The child stages to launch
543
+ */
544
+ Stage.setMethod(async function _launch(child_stages) {
545
+
546
+ if (!this.started) {
547
+ this.started = Date.now();
548
+
549
+ this.emit('launching', this);
550
+
551
+ if (!this.is_root) {
552
+ this.root_stage.emit('launching', this);
553
+ }
554
+ }
555
+
556
+ if (!this[STATUS]) {
557
+ this[STATUS] = PRE_STATUS;
558
+ }
559
+
560
+ await this._doTasks('pre_tasks');
561
+
562
+ if (this[STATUS] == PRE_STATUS) {
563
+ this[STATUS] = MAIN_STATUS;
564
+ }
565
+
566
+ await this._doTasks('main_tasks');
567
+
568
+ await this.pre_tasks[STATUS_PLEDGE];
569
+ await this.main_tasks[STATUS_PLEDGE];
570
+
571
+ if (this[STATUS] != POST_STATUS) {
572
+ this[STATUS] = CHILD_STATUS;
573
+ }
574
+
575
+ await this.refreshStatus();
576
+ });
577
+
578
+ /**
579
+ * Check if everything is finished
580
+ *
581
+ * @author Jelle De Loecker <jelle@elevenways.be>
582
+ * @since 1.4.0
583
+ * @version 1.4.0
584
+ */
585
+ Stage.setMethod(async function refreshStatus() {
586
+
587
+ if (!this.hasFinishedAllChildStages()) {
588
+ return;
589
+ }
590
+
591
+ await this._doTasks('post_tasks');
592
+
593
+ if (!this.ended) {
594
+ this.ended = Date.now();
595
+ }
596
+
597
+ this[STATUS] = POST_STATUS;
598
+
599
+ this.pledge.resolve();
600
+
601
+ if (this.parent) {
602
+ this.parent.refreshStatus();
603
+ }
604
+ });
605
+
606
+ /**
607
+ * Create a sputnik shim
608
+ *
609
+ * @author Jelle De Loecker <jelle@elevenways.be>
610
+ * @since 1.4.0
611
+ * @version 1.4.0
612
+ *
613
+ * @param {Object} mapping
614
+ *
615
+ * @return {Alchemy.Stages.SputnikShim}
616
+ */
617
+ Stage.setMethod(function createSputnikShim(mapping) {
618
+ return new SputnikShim(this, mapping);
619
+ });
620
+
621
+ /**
622
+ * Custom Janeway representation (left side)
623
+ *
624
+ * @author Jelle De Loecker <jelle@elevenways.be>
625
+ * @since 1.4.0
626
+ * @version 1.4.0
627
+ *
628
+ * @return {string}
629
+ */
630
+ Stage.setMethod(Symbol.for('janeway_arg_left'), function janewayClassIdentifier() {
631
+ return 'A.S.' + this.constructor.name;
632
+ });
633
+
634
+ /**
635
+ * Custom Janeway representation (right side)
636
+ *
637
+ * @author Jelle De Loecker <jelle@elevenways.be>
638
+ * @since 1.4.0
639
+ * @version 1.4.0
640
+ *
641
+ * @return {String}
642
+ */
643
+ Stage.setMethod(Symbol.for('janeway_arg_right'), function janewayInstanceInfo() {
644
+ return this.id;
645
+ });
646
+
647
+ /**
648
+ * The SputnikShim class
649
+ *
650
+ * @author Jelle De Loecker <jelle@elevenways.be>
651
+ * @since 1.4.0
652
+ * @version 1.4.0
653
+ *
654
+ * @param {Alchemy.Stages.Stages} stage
655
+ * @param {Object} mapping
656
+ */
657
+ const SputnikShim = Function.inherits('Alchemy.Base', 'Alchemy.Stages', function SputnikShim(stage, mapping) {
658
+ this.stage = stage;
659
+ this.mapping = mapping;
660
+ });
661
+
662
+ /**
663
+ * Get a stage by its old name
664
+ *
665
+ * @author Jelle De Loecker <jelle@elevenways.be>
666
+ * @since 1.4.0
667
+ * @version 1.4.0
668
+ *
669
+ * @param {string} name
670
+ *
671
+ * @return {Alchemy.Stages.Stage}
672
+ */
673
+ SputnikShim.setMethod(function getStage(name) {
674
+
675
+ if (!name) {
676
+ throw new Error('Unable to get stage without name');
677
+ }
678
+
679
+ let id = this.mapping[name];
680
+
681
+ if (!id) {
682
+ id = name;
683
+ }
684
+
685
+ return this.stage.getStage(id);
686
+ });
687
+
688
+ /**
689
+ * Do something before the given stage
690
+ *
691
+ * @author Jelle De Loecker <jelle@elevenways.be>
692
+ * @since 1.4.0
693
+ * @version 1.4.0
694
+ *
695
+ * @param {string[]} names
696
+ * @param {Function} callback
697
+ */
698
+ SputnikShim.setMethod(function before(names, callback) {
699
+
700
+ let pledges = [],
701
+ stage;
702
+
703
+ names = Array.cast(names);
704
+
705
+ for (let name of names) {
706
+ stage = this.getStage(name);
707
+
708
+ if (!stage) {
709
+ throw new Error('Stage "' + name + '" not found');
710
+ }
711
+
712
+ let pledge = new Pledge.Swift();
713
+
714
+ stage.addPreTask(() => {
715
+ pledge.resolve();
716
+ });
717
+
718
+ pledges.push(pledge);
719
+ }
720
+
721
+ return Function.parallel(pledges).then(callback);
722
+ });
723
+
724
+ /**
725
+ * Do something after the given stage
726
+ *
727
+ * @author Jelle De Loecker <jelle@elevenways.be>
728
+ * @since 1.4.0
729
+ * @version 1.4.0
730
+ *
731
+ * @param {string[]} names
732
+ * @param {Function} callback
733
+ */
734
+ SputnikShim.setMethod(function after(names, callback) {
735
+
736
+ let pledges = [],
737
+ stage;
738
+
739
+ names = Array.cast(names);
740
+
741
+ for (let name of names) {
742
+ stage = this.getStage(name);
743
+
744
+ if (!stage) {
745
+ throw new Error('Stage "' + name + '" not found');
746
+ }
747
+
748
+ let pledge = new Pledge.Swift();
749
+
750
+ stage.addPostTask(() => {
751
+ pledge.resolve();
752
+ });
753
+
754
+ pledges.push(pledge);
755
+ }
756
+
757
+ return Function.parallel(pledges).then(callback);
758
+ });