alchemymvc 1.3.21 → 1.3.23

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 (97) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +0 -0
  3. package/index.js +0 -0
  4. package/lib/app/assets/scripts/.gitkeep +0 -0
  5. package/lib/app/assets/stylesheets/alchemy-info.less +0 -0
  6. package/lib/app/behaviour/publishable_behaviour.js +0 -0
  7. package/lib/app/behaviour/revision_behaviour.js +0 -0
  8. package/lib/app/bootstrap.js +0 -0
  9. package/lib/app/component/.gitkeep +0 -0
  10. package/lib/app/conduit/electron_conduit.js +0 -0
  11. package/lib/app/conduit/http_conduit.js +0 -0
  12. package/lib/app/helper/backed_map.js +0 -0
  13. package/lib/app/helper/breadcrumb.js +0 -0
  14. package/lib/app/helper/client_collection.js +0 -0
  15. package/lib/app/helper/enum_values.js +0 -0
  16. package/lib/app/helper/pagination_helper.js +0 -0
  17. package/lib/app/helper/syncable.js +25 -0
  18. package/lib/app/helper_component/paginate_component.js +0 -0
  19. package/lib/app/helper_controller/component.js +0 -0
  20. package/lib/app/helper_controller/conduit.js +0 -0
  21. package/lib/app/helper_controller/controller.js +0 -0
  22. package/lib/app/helper_datasource/05-fallback_datasource.js +0 -0
  23. package/lib/app/helper_datasource/idb_datasource.js +0 -0
  24. package/lib/app/helper_datasource/indexed_db.js +0 -0
  25. package/lib/app/helper_datasource/remote_datasource.js +0 -0
  26. package/lib/app/helper_error/http_error.js +0 -0
  27. package/lib/app/helper_error/model_error.js +0 -0
  28. package/lib/app/helper_error/validation_error.js +0 -0
  29. package/lib/app/helper_field/00-objectid_field.js +0 -0
  30. package/lib/app/helper_field/05-string_field.js +0 -0
  31. package/lib/app/helper_field/06-text_field.js +0 -0
  32. package/lib/app/helper_field/10-number_field.js +0 -0
  33. package/lib/app/helper_field/belongsto_field.js +0 -0
  34. package/lib/app/helper_field/boolean_field.js +0 -0
  35. package/lib/app/helper_field/datetime_field.js +0 -0
  36. package/lib/app/helper_field/enum_field.js +0 -0
  37. package/lib/app/helper_field/geopoint_field.js +0 -0
  38. package/lib/app/helper_field/habtm_field.js +0 -0
  39. package/lib/app/helper_field/hasoneparent_field.js +0 -0
  40. package/lib/app/helper_field/html_field.js +0 -0
  41. package/lib/app/helper_field/integer_field.js +0 -0
  42. package/lib/app/helper_field/object_field.js +2 -2
  43. package/lib/app/helper_field/password_field.js +0 -0
  44. package/lib/app/helper_field/regexp_field.js +0 -0
  45. package/lib/app/helper_field/time_field.js +0 -0
  46. package/lib/app/helper_field/url_field.js +0 -0
  47. package/lib/app/helper_model/criteria.js +0 -0
  48. package/lib/app/helper_model/db_query.js +0 -0
  49. package/lib/app/helper_model/document_list.js +0 -0
  50. package/lib/app/helper_model/field_config.js +0 -0
  51. package/lib/app/helper_model/model.js +2 -1
  52. package/lib/app/helper_validator/00_validator.js +0 -0
  53. package/lib/app/helper_validator/not_empty_validator.js +0 -0
  54. package/lib/app/model/alchemy_migration_model.js +0 -0
  55. package/lib/app/root/alchemy-logo.png +0 -0
  56. package/lib/app/root/favicon.ico +0 -0
  57. package/lib/app/view/alchemy/info.hwk +0 -0
  58. package/lib/app/view/error/403.ejs +0 -0
  59. package/lib/app/view/error/404.ejs +0 -0
  60. package/lib/app/view/error/unknown.ejs +0 -0
  61. package/lib/app/view/paginate/navlist.ejs +0 -0
  62. package/lib/class/accumulator.js +0 -0
  63. package/lib/class/behaviour.js +0 -0
  64. package/lib/class/component.js +0 -0
  65. package/lib/class/conduit.js +91 -20
  66. package/lib/class/controller.js +0 -0
  67. package/lib/class/document.js +0 -0
  68. package/lib/class/document_list.js +0 -0
  69. package/lib/class/element.js +0 -0
  70. package/lib/class/error.js +0 -0
  71. package/lib/class/field.js +0 -0
  72. package/lib/class/field_value.js +0 -0
  73. package/lib/class/helper.js +0 -0
  74. package/lib/class/inode.js +0 -0
  75. package/lib/class/inode_dir.js +0 -0
  76. package/lib/class/inode_file.js +25 -0
  77. package/lib/class/inode_list.js +0 -0
  78. package/lib/class/migration.js +0 -0
  79. package/lib/class/model.js +33 -9
  80. package/lib/class/path_definition.js +0 -0
  81. package/lib/class/path_evaluator.js +0 -0
  82. package/lib/class/postponement.js +14 -4
  83. package/lib/class/reciprocal.js +0 -0
  84. package/lib/class/schema.js +0 -0
  85. package/lib/class/session_scene.js +0 -0
  86. package/lib/class/sitemap.js +0 -0
  87. package/lib/core/client_base.js +12 -2
  88. package/lib/core/discovery.js +0 -0
  89. package/lib/core/routing.js +0 -0
  90. package/lib/core/socket.js +0 -0
  91. package/lib/init/alchemy.js +3 -2
  92. package/lib/init/devwatch.js +0 -0
  93. package/lib/init/functions.js +60 -19
  94. package/lib/init/languages.js +0 -0
  95. package/lib/init/load_functions.js +9 -3
  96. package/lib/stages.js +9 -7
  97. package/package.json +3 -3
package/LICENSE CHANGED
File without changes
package/README.md CHANGED
File without changes
package/index.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -262,6 +262,31 @@ Syncable.setStatic(function setSyncMethod(types, method) {
262
262
  });
263
263
  });
264
264
 
265
+ /**
266
+ * Add a method that will only be called on the client.
267
+ * No response will be returned, since it is sent to multiple clients.
268
+ *
269
+ * @author Jelle De Loecker <jelle@elevenways.be>
270
+ * @since 1.3.22
271
+ * @version 1.3.22
272
+ *
273
+ * @param {Object} data
274
+ *
275
+ * @return {Syncable}
276
+ */
277
+ Syncable.setStatic(function setClientMethod(types, method) {
278
+ return this.setHandledMethod(types, method, function handler(method, args) {
279
+
280
+ if (this.is_server) {
281
+ this.addLog('call', [method.name, args]);
282
+ return;
283
+ }
284
+
285
+ let result = method.apply(this, args);
286
+ return result;
287
+ });
288
+ });
289
+
265
290
  /**
266
291
  * Add a method that fetches info from the server.
267
292
  * The response is always a promise.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -34,7 +34,7 @@ ObjectField.setSelfContained(true);
34
34
  *
35
35
  * @author Jelle De Loecker <jelle@develry.be>
36
36
  * @since 0.5.0
37
- * @version 0.5.0
37
+ * @version 1.3.22
38
38
  *
39
39
  * @param {Mixed} value
40
40
  *
@@ -42,7 +42,7 @@ ObjectField.setSelfContained(true);
42
42
  */
43
43
  ObjectField.setMethod(function cast(value) {
44
44
 
45
- if (typeof value == 'string') {
45
+ if (this.options.store_as_string && typeof value == 'string') {
46
46
  return JSON.undry(value);
47
47
  }
48
48
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -49,7 +49,7 @@ Model.constitute(function setModelName() {
49
49
  *
50
50
  * @author Jelle De Loecker <jelle@elevenways.be>
51
51
  * @since 1.2.5
52
- * @version 1.2.5
52
+ * @version 1.3.22
53
53
  */
54
54
  Model.mapEventToMethod({
55
55
  saved : 'afterSave',
@@ -58,6 +58,7 @@ Model.mapEventToMethod({
58
58
  associated : 'afterAssociated',
59
59
  found : 'afterData',
60
60
  foundDocuments : 'afterFind',
61
+ removed : 'afterRemove',
61
62
  });
62
63
 
63
64
  /**
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,5 +1,6 @@
1
1
  const FILECACHE = alchemy.getCache('served_files'),
2
- RX_TEXT = /svg|xml|javascript|text/i;
2
+ RX_TEXT = /svg|xml|javascript|text/i,
3
+ ENDING = Symbol('ending');
3
4
 
4
5
  var libstream = alchemy.use('stream'),
5
6
  libpath = alchemy.use('path'),
@@ -16,7 +17,7 @@ var libstream = alchemy.use('stream'),
16
17
  *
17
18
  * @author Jelle De Loecker <jelle@develry.be>
18
19
  * @since 0.2.0
19
- * @version 1.2.0
20
+ * @version 1.3.23
20
21
  *
21
22
  * @param {IncomingMessage} req
22
23
  * @param {ServerResponse} res
@@ -54,6 +55,9 @@ var Conduit = Function.inherits('Alchemy.Base', 'Alchemy.Conduit', function Cond
54
55
  // Where the files will go
55
56
  this.files = {};
56
57
 
58
+ // Are we in the process of ending?
59
+ this[ENDING] = false;
60
+
57
61
  this.initValues();
58
62
  this.setReqRes(req, res);
59
63
  });
@@ -1456,13 +1460,18 @@ Conduit.setMethod(function setResponseUrl(new_url) {
1456
1460
  *
1457
1461
  * @author Jelle De Loecker <jelle@elevenways.be>
1458
1462
  * @since 0.2.0
1459
- * @version 1.3.17
1463
+ * @version 1.3.23
1460
1464
  *
1461
1465
  * @param {Number} status 3xx redirection codes. 302 (temporary redirect) by default
1462
1466
  * @param {String|Object} options Options or url
1463
1467
  */
1464
1468
  Conduit.setMethod(function redirect(status, options) {
1465
1469
 
1470
+ if (this.ended) {
1471
+ console.warn('Conduit#redirect() called after response has already ended', this);
1472
+ return;
1473
+ }
1474
+
1466
1475
  let hard_refresh = false,
1467
1476
  url;
1468
1477
 
@@ -1578,7 +1587,7 @@ Conduit.setMethod(function redirect(status, options) {
1578
1587
  *
1579
1588
  * @author Jelle De Loecker <jelle@elevenways.be>
1580
1589
  * @since 0.2.0
1581
- * @version 1.3.21
1590
+ * @version 1.3.23
1582
1591
  *
1583
1592
  * @param {Nulber} status Response statuscode
1584
1593
  * @param {Error} message Optional error to send
@@ -1586,6 +1595,11 @@ Conduit.setMethod(function redirect(status, options) {
1586
1595
  */
1587
1596
  Conduit.setMethod(function error(status, message, print_error) {
1588
1597
 
1598
+ if (this.ended) {
1599
+ console.warn('Conduit#error() called after response has already ended', this);
1600
+ return;
1601
+ }
1602
+
1589
1603
  let print_dev = false;
1590
1604
 
1591
1605
  if (status instanceof Classes.Alchemy.Error.HTTP) {
@@ -1783,7 +1797,7 @@ Conduit.setMethod(function notModified() {
1783
1797
  *
1784
1798
  * @author Jelle De Loecker <jelle@elevenways.be>
1785
1799
  * @since 0.2.0
1786
- * @version 1.3.0
1800
+ * @version 1.3.23
1787
1801
  *
1788
1802
  * @param {String|Object} message
1789
1803
  */
@@ -1796,6 +1810,13 @@ Conduit.setMethod(function end(message) {
1796
1810
  etag,
1797
1811
  temp;
1798
1812
 
1813
+ if (this[ENDING]) {
1814
+ console.warn('Conduit#end() called after conduit has already ended', this);
1815
+ return false;
1816
+ }
1817
+
1818
+ this[ENDING] = true;
1819
+
1799
1820
  if (this.websocket) {
1800
1821
  throw new Error('You can not end a websocket, use the callback instead');
1801
1822
  }
@@ -1806,6 +1827,10 @@ Conduit.setMethod(function end(message) {
1806
1827
 
1807
1828
  if (typeof message !== 'string') {
1808
1829
 
1830
+ if (message && message instanceof Classes.Stream.Stream) {
1831
+ return this._endWithStream(message);
1832
+ }
1833
+
1809
1834
  // Use regular JSON if DRY has been disabled in settings
1810
1835
  if (alchemy.settings.json_dry_response === false || this.json_dry === false) {
1811
1836
  json_type = 'json';
@@ -1878,15 +1903,44 @@ Conduit.setMethod(function end(message) {
1878
1903
  this._end(message, 'utf-8');
1879
1904
  });
1880
1905
 
1906
+ /**
1907
+ * End with a stream
1908
+ *
1909
+ * @author Jelle De Loecker <jelle@elevenways.be>
1910
+ * @since 1.3.22
1911
+ * @version 1.3.23
1912
+ */
1913
+ Conduit.setMethod(function _endWithStream(stream) {
1914
+
1915
+ if (this.ended) {
1916
+ console.warn('Conduit#_endWithStream() called after conduit has already ended', this);
1917
+ return false;
1918
+ }
1919
+
1920
+ this[ENDING] = true;
1921
+ this.ended = new Date();
1922
+ this.emit('ending');
1923
+
1924
+ this.flushHeaders();
1925
+
1926
+ stream.pipe(this.response);
1927
+ });
1928
+
1881
1929
  /**
1882
1930
  * Call the actual end method
1883
1931
  *
1884
1932
  * @author Jelle De Loecker <jelle@elevenways.be>
1885
1933
  * @since 0.2.0
1886
- * @version 1.3.14
1934
+ * @version 1.3.23
1887
1935
  */
1888
1936
  Conduit.setMethod(function _end(message, encoding = 'utf-8') {
1889
1937
 
1938
+ if (this.ended) {
1939
+ console.warn('Conduit#_end() called after conduit has already ended', this);
1940
+ return false;
1941
+ }
1942
+
1943
+ this[ENDING] = true;
1890
1944
  this.ended = new Date();
1891
1945
 
1892
1946
  this.emit('ending');
@@ -1906,18 +1960,42 @@ Conduit.setMethod(function _end(message, encoding = 'utf-8') {
1906
1960
  return;
1907
1961
  }
1908
1962
 
1909
- let headers = [],
1910
- value,
1911
- key;
1963
+ // Set the content-length if it hasn't been set yet
1964
+ if (arguments.length > 0 && !this.response_headers['content-length']) {
1965
+ this.response_headers['content-length'] = Buffer.byteLength(message);
1966
+ }
1967
+
1968
+ this.flushHeaders();
1969
+
1970
+ if (arguments.length === 0) {
1971
+ return this.response.end();
1972
+ }
1973
+
1974
+ // End the response
1975
+ return this.response.end(message, encoding);
1976
+ });
1977
+
1978
+ /**
1979
+ * Flush the headers
1980
+ *
1981
+ * @author Jelle De Loecker <jelle@elevenways.be>
1982
+ * @since 1.3.22
1983
+ * @version 1.3.22
1984
+ */
1985
+ Conduit.setMethod(function flushHeaders() {
1986
+
1987
+ if (this._flushed) {
1988
+ return;
1989
+ }
1990
+
1991
+ this._flushed = true;
1912
1992
 
1913
1993
  if (this.status) {
1914
1994
  this.response.statusCode = this.status;
1915
1995
  }
1916
1996
 
1917
- // Set the content-length if it hasn't been set yet
1918
- if (arguments.length > 0 && !this.response_headers['content-length']) {
1919
- this.response_headers['content-length'] = Buffer.byteLength(message);
1920
- }
1997
+ let value,
1998
+ key;
1921
1999
 
1922
2000
  for (key in this.response_headers) {
1923
2001
  value = this.response_headers[key];
@@ -1935,13 +2013,6 @@ Conduit.setMethod(function _end(message, encoding = 'utf-8') {
1935
2013
 
1936
2014
  // Write the actual headers
1937
2015
  this.response.writeHead(this.status);
1938
-
1939
- if (arguments.length === 0) {
1940
- return this.response.end();
1941
- }
1942
-
1943
- // End the response
1944
- return this.response.end(message, encoding);
1945
2016
  });
1946
2017
 
1947
2018
  /**
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -338,4 +338,29 @@ File.setMethod(function readString(encoding) {
338
338
  }
339
339
 
340
340
  return this.read({encoding: encoding});
341
+ });
342
+
343
+ /**
344
+ * Write the given data to the file
345
+ *
346
+ * @author Jelle De Loecker <jelle@elevenways.be>
347
+ * @since 1.3.22
348
+ * @version 1.3.22
349
+ */
350
+ File.setMethod(function overwrite(contents, options = {}) {
351
+
352
+ let pledge = new Pledge();
353
+
354
+ options.flag = 'w';
355
+
356
+ fs.writeFile(this.path, contents, options, function done(err) {
357
+
358
+ if (err) {
359
+ return pledge.reject(err);
360
+ }
361
+
362
+ pledge.resolve();
363
+ });
364
+
365
+ return pledge;
341
366
  });
File without changes
File without changes
@@ -1287,7 +1287,7 @@ Model.setMethod(async function executeMongoPipeline(pipeline) {
1287
1287
  *
1288
1288
  * @author Jelle De Loecker <jelle@develry.be>
1289
1289
  * @since 0.0.1
1290
- * @version 1.3.21
1290
+ * @version 1.3.22
1291
1291
  *
1292
1292
  * @param {String} id The object id
1293
1293
  * @param {Function} callback
@@ -1313,12 +1313,33 @@ Model.setMethod(function remove(id, callback) {
1313
1313
  id = String(id);
1314
1314
  }
1315
1315
 
1316
- let query = {};
1317
- query[this.primary_key] = id;
1316
+ let query = {
1317
+ [this.primary_key] : id,
1318
+ };
1318
1319
 
1319
- Function.series(function recompute(next) {
1320
- that.callOrNext('beforeRemove', [id], next);
1321
- }, function done(err) {
1320
+ let has_remove_events = typeof this.beforeRemove == 'function' || typeof this.afterRemove == 'function' || this.listeners('removed').length;
1321
+ let doc;
1322
+ let tasks = [];
1323
+
1324
+ if (has_remove_events) {
1325
+
1326
+ // Get the actual document
1327
+ tasks.push(async next => {
1328
+ doc = await this.findByPk(id);
1329
+
1330
+ if (!doc) {
1331
+ return next(new Error('Unable to find document with id ' + id));
1332
+ }
1333
+
1334
+ next();
1335
+ });
1336
+
1337
+ tasks.push(next => {
1338
+ this.callOrNext('beforeRemove', [doc], next);
1339
+ });
1340
+ }
1341
+
1342
+ Function.series(tasks, function done(err) {
1322
1343
 
1323
1344
  if (err) {
1324
1345
  pledge.reject(err);
@@ -1330,10 +1351,13 @@ Model.setMethod(function remove(id, callback) {
1330
1351
  if (err != null) {
1331
1352
  return pledge.reject(err);
1332
1353
  }
1333
-
1334
- that.emit('removed', result, {}, false, function afterRemovedEvent() {
1354
+
1355
+ if (has_remove_events) {
1356
+ that.issueEvent('removed', [doc, result], () => pledge.resolve(result));
1357
+ } else {
1335
1358
  pledge.resolve(result);
1336
- });
1359
+ }
1360
+
1337
1361
  });
1338
1362
  });
1339
1363
 
File without changes
File without changes
@@ -293,9 +293,9 @@ Postponement.setMethod(function handleRequest(conduit) {
293
293
  *
294
294
  * @author Jelle De Loecker <jelle@elevenways.be>
295
295
  * @since 1.3.1
296
- * @version 1.3.2
296
+ * @version 1.3.23
297
297
  *
298
- * @return {Boolean} True if the request is being resumed
298
+ * @return {Boolean} True if the request can be resumed
299
299
  */
300
300
  Postponement.setMethod(function attemptUnlock() {
301
301
 
@@ -307,11 +307,21 @@ Postponement.setMethod(function attemptUnlock() {
307
307
 
308
308
  Postponement.scheduleQueueCheck();
309
309
 
310
- if (this.position_in_queue > 5) {
310
+ let max_position = alchemy.settings.postpone_max_unlock_position ?? 5;
311
+
312
+ if (this.position_in_queue > max_position) {
313
+ return false;
314
+ }
315
+
316
+ let max_event_loop_lag = alchemy.settings.postpone_max_unlock_event_loop_lag ?? 100;
317
+
318
+ if (alchemy.lagInMs() > max_event_loop_lag) {
311
319
  return false;
312
320
  }
313
321
 
314
- if (alchemy.lagInMs() > 100) {
322
+ let max_system_load = alchemy.settings.postpone_max_unlock_system_load ?? 110;
323
+
324
+ if (alchemy.systemLoad() > max_system_load) {
315
325
  return false;
316
326
  }
317
327
 
File without changes
File without changes
File without changes
File without changes
@@ -294,7 +294,7 @@ ClientBase.setMethod(function getModel(name, init, options) {
294
294
  *
295
295
  * @author Jelle De Loecker <jelle@elevenways.be>
296
296
  * @since 1.1.1
297
- * @version 1.3.2
297
+ * @version 1.3.22
298
298
  *
299
299
  * @param {String} name The name of the event to emit
300
300
  * @param {Array} args The parameters to pass to the event
@@ -323,7 +323,17 @@ ClientBase.setMethod(function issueEvent(name, args, next) {
323
323
  }
324
324
 
325
325
  if (method_name && typeof this[method_name] == 'function') {
326
- promise = this[method_name].apply(this, args);
326
+ try {
327
+ promise = this[method_name].apply(this, args);
328
+ } catch (err) {
329
+ pledge.reject(err);
330
+
331
+ if (next) {
332
+ next(err);
333
+ }
334
+
335
+ return pledge;
336
+ }
327
337
  }
328
338
 
329
339
  Pledge.done(promise, function doneEventPromise(err, result) {
File without changes
File without changes
File without changes
@@ -924,7 +924,7 @@ Alchemy.setMethod(function ready(callback) {
924
924
  *
925
925
  * @author Jelle De Loecker <jelle@elevenways.be>
926
926
  * @since 1.1.2
927
- * @version 1.3.3
927
+ * @version 1.3.22
928
928
  */
929
929
  Alchemy.setMethod(async function doPreload() {
930
930
 
@@ -952,7 +952,8 @@ Alchemy.setMethod(async function doPreload() {
952
952
  Blast.getClientPath({
953
953
  modify_prototypes : true,
954
954
  create_source_map : alchemy.settings.source_map,
955
- enable_coverage : !!global.__coverage__
955
+ enable_coverage : !!global.__coverage__,
956
+ debug : alchemy.settings.debug,
956
957
  });
957
958
  }
958
959
  });
File without changes
@@ -441,26 +441,49 @@ Alchemy.setMethod(function createDir(target, callback) {
441
441
  /**
442
442
  * Return the key:items of the first object that are no longer in the second
443
443
  *
444
- * @author Jelle De Loecker <jelle@develry.be>
444
+ * @author Jelle De Loecker <jelle@elevenways.be>
445
445
  * @since 0.0.1
446
- * @version 0.4.0
446
+ * @version 1.3.22
447
447
  *
448
- * @param {Object}
449
- * @param {Object}
448
+ * @param {Object|Map} first
449
+ * @param {Object|Map} second
450
450
  *
451
- * @return {Object} The items in the first item that are not in the second
451
+ * @return {Object} The items in the first item that are not in the second
452
452
  */
453
453
  Alchemy.setMethod(function getDifference(first, second) {
454
454
 
455
- var key,
456
- result = {};
455
+ let first_is_map = first instanceof Map,
456
+ second_is_map = second instanceof Map,
457
+ first_keys,
458
+ result = {},
459
+ first_val,
460
+ key,
461
+ val;
462
+
463
+ if (first_is_map) {
464
+ first_keys = [...first.keys()];
465
+ } else {
466
+ first_keys = Object.keys(first);
467
+ }
468
+
469
+ for (key of first_keys) {
457
470
 
458
- for (key in first) {
471
+ if (second_is_map) {
472
+ val = second.get(key);
473
+ } else {
474
+ val = second[key];
475
+ }
459
476
 
460
477
  // If the key in the first item doesn't show up in the second item,
461
478
  // add it to the result
462
- if (typeof second[key] === 'undefined') {
463
- result[key] = first[key];
479
+ if (typeof val === 'undefined') {
480
+ if (first_is_map) {
481
+ first_val = first.get(key);
482
+ } else {
483
+ first_val = first[key];
484
+ }
485
+
486
+ result[key] = first_val;
464
487
  }
465
488
  }
466
489
 
@@ -470,24 +493,42 @@ Alchemy.setMethod(function getDifference(first, second) {
470
493
  /**
471
494
  * Return the shared items
472
495
  *
473
- * @author Jelle De Loecker <jelle@develry.be>
496
+ * @author Jelle De Loecker <jelle@elevenways.be>
474
497
  * @since 0.0.1
475
- * @version 0.4.0
498
+ * @version 1.3.22
476
499
  *
477
- * @param {Object}
478
- * @param {Object}
500
+ * @param {Object|Map} first
501
+ * @param {Object|Map} second
479
502
  *
480
503
  * @return {Object} The items in the second item that are also in the first
481
504
  */
482
505
  Alchemy.setMethod(function getShared(first, second) {
483
506
 
484
- var key,
485
- result = {};
507
+ let first_is_map = first instanceof Map,
508
+ second_is_map = second instanceof Map,
509
+ first_keys,
510
+ result = {},
511
+ key,
512
+ val;
513
+
514
+ if (first_is_map) {
515
+ first_keys = [...first.keys()];
516
+ } else {
517
+ first_keys = Object.keys(first);
518
+ }
486
519
 
487
- for (key in first) {
520
+ for (key of first_keys) {
488
521
 
489
- if (typeof second[key] !== 'undefined') {
490
- result[key] = second[key];
522
+ if (second_is_map) {
523
+ val = second.get(key);
524
+ } else {
525
+ val = second[key];
526
+ }
527
+
528
+ // If the key in the first item doesn't show up in the second item,
529
+ // add it to the result
530
+ if (typeof val !== 'undefined') {
531
+ result[key] = val;
491
532
  }
492
533
  }
493
534
 
File without changes
@@ -19,7 +19,7 @@ var fs = alchemy.use('fs'),
19
19
  *
20
20
  * @author Jelle De Loecker <jelle@develry.be>
21
21
  * @since 0.0.1
22
- * @version 1.1.5
22
+ * @version 1.3.22
23
23
  *
24
24
  * @param {String} dirPath The path to load
25
25
  * @param {Object} options
@@ -44,6 +44,7 @@ Alchemy.setMethod(function usePath(dirPath, options) {
44
44
 
45
45
  options._level++;
46
46
  useOptions._level = options._level;
47
+ useOptions.skip = options.skip;
47
48
 
48
49
  // Always ignore .git directories
49
50
  modularRegex.push(/^.git$/);
@@ -166,7 +167,7 @@ Alchemy.setProperty('default_use_path_options', {
166
167
  *
167
168
  * @author Jelle De Loecker <jelle@develry.be>
168
169
  * @since 0.0.1
169
- * @version 1.2.0
170
+ * @version 1.3.22
170
171
  *
171
172
  * @param {String} dir_path
172
173
  * @param {Object} options
@@ -214,6 +215,10 @@ Alchemy.setMethod(function _usePath(dir_path, options) {
214
215
  for (i = 0; i < files.length; i++) {
215
216
  file_name = files[i];
216
217
 
218
+ if (file_name == 'routes.js' && options.skip?.length && options.skip.includes('routes')) {
219
+ continue;
220
+ }
221
+
217
222
  // Skip hidden files or the "empty" file
218
223
  if (file_name[0] == '.' || file_name == 'empty') {
219
224
  continue;
@@ -289,7 +294,8 @@ Alchemy.setMethod(function _usePath(dir_path, options) {
289
294
  ignore : options.ignore,
290
295
  recursive : options.recursive - 1,
291
296
  _level : options._level,
292
- modularParent : options.modularParent
297
+ modularParent : options.modularParent,
298
+ skip : options.skip,
293
299
  });
294
300
  }
295
301
 
package/lib/stages.js CHANGED
@@ -156,11 +156,11 @@ alchemy.sputnik.add(function plugins() {
156
156
  *
157
157
  * @author Jelle De Loecker <jelle@develry.be>
158
158
  * @since 0.0.1
159
- * @version 0.0.1
159
+ * @version 1.3.22
160
160
  */
161
161
  alchemy.sputnik.add(function base_app() {
162
162
  // Load in the app
163
- alchemy.usePath(PATH_APP, {weight: 20});
163
+ alchemy.usePath(PATH_APP, {weight: 20, skip: ['routes']});
164
164
  });
165
165
 
166
166
  /**
@@ -185,7 +185,7 @@ alchemy.sputnik.add(function define_debug() {
185
185
  *
186
186
  * @author Jelle De Loecker <jelle@elevenways.be>
187
187
  * @since 0.0.1
188
- * @version 1.3.3
188
+ * @version 1.3.22
189
189
  */
190
190
  alchemy.sputnik.add(function hawkejs_setup() {
191
191
 
@@ -202,7 +202,8 @@ alchemy.sputnik.add(function hawkejs_setup() {
202
202
  modify_prototypes : true,
203
203
  ua : req.conduit.headers.useragent,
204
204
  create_source_map : alchemy.settings.source_map,
205
- enable_coverage : !!global.__coverage__
205
+ enable_coverage : !!global.__coverage__,
206
+ debug : alchemy.settings.debug,
206
207
  }).done(gotClientFile);
207
208
 
208
209
  function gotClientFile(err, path) {
@@ -244,6 +245,7 @@ alchemy.sputnik.add(function hawkejs_setup() {
244
245
  modify_prototypes : true,
245
246
  ua : req.conduit.headers.useragent,
246
247
  create_source_map : alchemy.settings.source_map,
248
+ debug : alchemy.settings.debug,
247
249
  }).done(gotClientFile);
248
250
  }
249
251
  });
@@ -362,15 +364,15 @@ alchemy.sputnik.add(function middleware() {
362
364
  *
363
365
  * @author Jelle De Loecker <jelle@develry.be>
364
366
  * @since 0.0.1
365
- * @version 0.4.0
367
+ * @version 1.3.22
366
368
  */
367
369
  alchemy.sputnik.add(function routes() {
368
370
  try {
369
- alchemy.useOnce(path.resolve(PATH_APP, 'config', 'routes'));
371
+ alchemy.useOnce(path.resolve(PATH_APP, 'config', 'routes.js'));
370
372
  } catch (err) {
371
373
  // Only output warning when not in client mode
372
374
  if (!alchemy.settings.client_mode) {
373
- log.warn('No route config was found');
375
+ log.warn('No app routes were found:', err);
374
376
  }
375
377
  }
376
378
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alchemymvc",
3
3
  "description": "MVC framework for Node.js",
4
- "version": "1.3.21",
4
+ "version": "1.3.23",
5
5
  "author": "Jelle De Loecker <jelle@elevenways.be>",
6
6
  "keywords": [
7
7
  "alchemy",
@@ -22,7 +22,7 @@
22
22
  "chokidar" : "~3.5.3",
23
23
  "formidable" : "~3.5.1",
24
24
  "graceful-fs" : "~4.2.11",
25
- "hawkejs" : "~2.3.15",
25
+ "hawkejs" : "~2.3.19",
26
26
  "jsondiffpatch" : "~0.5.0",
27
27
  "mime" : "~3.0.0",
28
28
  "minimist" : "~1.2.5",
@@ -31,7 +31,7 @@
31
31
  "mongodb" : "~6.1.0",
32
32
  "ncp" : "~2.0.0",
33
33
  "postcss" : "~8.4.31",
34
- "protoblast" : "~0.8.15",
34
+ "protoblast" : "~0.8.19",
35
35
  "semver" : "~7.5.4",
36
36
  "socket.io" : "~4.7.2",
37
37
  "@11ways/socket.io-stream" : "~0.9.2",