total5 0.0.1-9 → 0.0.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 (59) hide show
  1. package/api.js +18 -10
  2. package/bin/flow5 +142 -0
  3. package/bin/total5 +166 -905
  4. package/builders.js +90 -35
  5. package/changelog.txt +3 -1
  6. package/cluster.js +1 -1
  7. package/cms.js +185 -51
  8. package/controller.js +233 -70
  9. package/cron.js +1 -1
  10. package/debug.js +12 -5
  11. package/edit.js +26 -33
  12. package/filestorage.js +38 -17
  13. package/flow-flowstream.js +199 -68
  14. package/flow.js +16 -10
  15. package/flowstream.js +4 -3
  16. package/global.js +84 -1
  17. package/htmlparser.js +41 -29
  18. package/http.js +3 -1
  19. package/image.js +4 -0
  20. package/images.js +1 -1
  21. package/index.js +246 -117
  22. package/jsonschema.js +21 -17
  23. package/macros.js +222 -0
  24. package/mail.js +11 -27
  25. package/markdown.js +21 -11
  26. package/minificators.js +1 -1
  27. package/nosql-querybuilder.js +4 -0
  28. package/nosql.js +8 -0
  29. package/openclient.js +1 -1
  30. package/package.json +4 -3
  31. package/pause.html +1 -1
  32. package/release.js +1 -1
  33. package/routing.js +118 -35
  34. package/sourcemap.js +6 -3
  35. package/test.js +9 -2
  36. package/tms.js +11 -14
  37. package/uibuilder.js +59 -23
  38. package/utils.js +147 -102
  39. package/viewengine.js +19 -8
  40. package/websocket.js +10 -6
  41. package/503.html +0 -65
  42. package/CONTRIBUTING.md +0 -55
  43. package/helpers/index.js +0 -32
  44. package/templates.json +0 -74
  45. package/tests/bundles/index.js +0 -25
  46. package/tests/cron.js +0 -0
  47. package/tests/htmlparser.js +0 -0
  48. package/tests/minifactors.js +0 -17
  49. package/tests/nosql.js +0 -18
  50. package/tests/proxy/index.js +0 -21
  51. package/tests/routing/index.js +0 -27
  52. package/tests/schemas.js +0 -17
  53. package/tests/server/index.js +0 -24
  54. package/tests/staticfiles/index.js +0 -24
  55. package/tests/utils.js +0 -17
  56. package/tmsclient.js +0 -125
  57. package/todo.txt +0 -11
  58. package/tools/beta.sh +0 -6
  59. package/tools/release.sh +0 -6
package/routing.js CHANGED
@@ -19,26 +19,38 @@ function parseSizeTimeout(route, value) {
19
19
 
20
20
  switch (type) {
21
21
  case 's':
22
- route.timeout = number;
22
+ if (route.timeout < number)
23
+ route.timeout = number;
23
24
  break;
24
25
  case 'm':
25
- route.timeout = number * 60;
26
+ number = number * 60;
27
+ if (route.timeout < number)
28
+ route.timeout = number;
26
29
  break;
27
30
  case 'h':
28
- route.timeout = number * 60 * 60;
31
+ number = number * 60 * 60;
32
+ if (route.timeout < number)
33
+ route.timeout = number;
29
34
  break;
30
35
  case 'b':
31
- route.size = number / 1024;
36
+ if (route.size < number)
37
+ route.size = number;
32
38
  break;
33
39
  case 'kb':
34
- route.size = number;
40
+ number = number / 1024;
41
+ if (route.size < number)
42
+ route.size = number;
35
43
  break;
36
44
  case 'gb':
37
- route.size = (number * 1024) * 1000;
45
+ number = (number * 1024 * 1024) * 1000;
46
+ if (route.size < number)
47
+ route.size = number;
38
48
  break;
39
49
  case 'mb':
40
50
  default:
41
- route.size = number * 1024;
51
+ number = number * 1024 * 1024;
52
+ if (route.size < number)
53
+ route.size = number;
42
54
  break;
43
55
  }
44
56
  }
@@ -51,17 +63,24 @@ function Route(url, action, size) {
51
63
  action = null;
52
64
  }
53
65
 
66
+ // Apply a default API endpoint
67
+ url = url.replace(/\?/g, F.config.$api).replace(/\/{2,}/g, '/');
68
+
54
69
  var t = this;
55
70
 
56
71
  if (url[0] === '#') {
57
72
  // internal routing
58
- t.url = [url[0].substring(1)];
73
+ t.url = [url.substring(1)];
59
74
  t.action = action;
60
75
  t.fallback = true;
61
- F.routes.fallback[t.url[0]] = t;
76
+ F.routes.fallback[t.url] = t;
62
77
  return;
63
78
  }
64
79
 
80
+ t.timeout = 0;
81
+ t.size = 0;
82
+ t.flags = {};
83
+
65
84
  var index = url.indexOf(' ');
66
85
 
67
86
  t.method = url.substring(0, index).toUpperCase();
@@ -77,7 +96,7 @@ function Route(url, action, size) {
77
96
  if (t.url2[0] === '@') {
78
97
  // @TODO: missing WAPI implementation
79
98
  t.skip = true;
80
- console.log('This "{0}" kind of routes are not supported yet'.formaT(t.url2));
99
+ console.log('This "{0}" kind of routes are not supported yet'.format(t.url2));
81
100
  return;
82
101
  }
83
102
 
@@ -100,6 +119,7 @@ function Route(url, action, size) {
100
119
  }
101
120
 
102
121
  if (t.method === 'FILE') {
122
+
103
123
  let types = t.url[t.url.length - 1];
104
124
 
105
125
  // fixed filename
@@ -117,6 +137,7 @@ function Route(url, action, size) {
117
137
  for (let type of types)
118
138
  t.ext[type] = 1;
119
139
  }
140
+
120
141
  } else {
121
142
  t.params = [];
122
143
  index = 0;
@@ -130,7 +151,6 @@ function Route(url, action, size) {
130
151
  t.size = size || 0;
131
152
  }
132
153
 
133
- t.flags = {};
134
154
  t.middleware = [];
135
155
 
136
156
  index = t.url.indexOf('*');
@@ -152,13 +172,16 @@ function Route(url, action, size) {
152
172
  t.partial = t.method === 'PATCH';
153
173
 
154
174
  var endpoint = '';
175
+ var isapi = false;
155
176
 
156
177
  if (t.method === 'API') {
157
178
  t.method = 'POST';
179
+ isapi = true;
158
180
  t.id = t.id.replace(/^(\+|-)/, '');
159
181
  url = url.replace(/(\*|\+|-|%)?[a-z0-9-_/{}]+/i, function(text) {
160
182
  let tmp = text.trim();
161
- endpoint = tmp.substring(1);
183
+ let c = tmp[0];
184
+ endpoint = c === '%' || c === '+' || c === '*' || c === '-' ? tmp.substring(1) : tmp;
162
185
  t.partial = tmp[0] === '%';
163
186
  return text;
164
187
  });
@@ -185,8 +208,12 @@ function Route(url, action, size) {
185
208
  t.actions.push(text.trim());
186
209
  return '';
187
210
  }).trim();
188
- } else
189
- t.actions = url.substring(0, index + 3).replace(/\s{2,}/g, ' ').split(/\s|,/);
211
+ } else {
212
+ if (isapi)
213
+ t.actions = [url.replace(/\+|-|%|#/g, '').trim()];
214
+ else
215
+ t.actions = url.substring(0, index + 3).replace(/\s{2,}/g, ' ').split(/\s|,/);
216
+ }
190
217
 
191
218
  var parent = null;
192
219
 
@@ -202,9 +229,10 @@ function Route(url, action, size) {
202
229
 
203
230
  parent = F.routes.routes.findItem('id', t.id);
204
231
 
205
- var apiroute = { auth: t.auth, params: params, actions: t.actions.join(',') };
232
+ var apiroute = { auth: t.auth, params: params, actions: t.actions.join(','), action: action, timeout: t.timeout };
206
233
 
207
234
  t.apiendpoint = arr[0];
235
+
208
236
  if (parent) {
209
237
  parent.api[arr[0]] = apiroute;
210
238
  t.skip = true;
@@ -227,11 +255,11 @@ function Route(url, action, size) {
227
255
  if (!t.size) {
228
256
  switch (t.type) {
229
257
  case 'websocket':
230
- t.size = F.config.$wsmaxsize;
258
+ t.size = F.config.$wsmaxsize * 1024;
231
259
  t.connections = [];
232
260
  break;
233
261
  case 'route':
234
- t.size = F.config.$httpmaxsize;
262
+ t.size = F.config.$httpmaxsize * 1024;
235
263
  break;
236
264
  }
237
265
  }
@@ -244,8 +272,12 @@ function Route(url, action, size) {
244
272
  t.action = null;
245
273
  }
246
274
 
275
+ if (!t.view && !t.action && t.method !== 'FILE' && t.method !== 'SOCKET')
276
+ t.view = t.url[0] && t.url[0] !== '/' ? t.url[0] : 'index';
277
+
247
278
  if (t.wildcard)
248
279
  t.priority -= 50;
280
+
249
281
  }
250
282
 
251
283
  Route.prototype.compare = function(ctrl) {
@@ -270,7 +302,7 @@ Route.prototype.remove = function() {
270
302
  F.routes.websockets.splice(index);
271
303
  for (let conn of self.connections)
272
304
  conn.destroy();
273
- break;
305
+ break;
274
306
  case 'file':
275
307
  index = F.routes.files.indexOf(self);
276
308
  if (index !== -1)
@@ -401,6 +433,10 @@ exports.sort = function() {
401
433
 
402
434
  tmp = cache;
403
435
  let key = route.url.join('/');
436
+
437
+ if (route.wildcard)
438
+ key += '/*';
439
+
404
440
  if (cache[key])
405
441
  cache[key].push(route);
406
442
  else
@@ -482,8 +518,7 @@ exports.lookup = function(ctrl, auth = 0, skip = false) {
482
518
 
483
519
  // Dynamic routes
484
520
  if (tmp.D && !(length === 1 && arr[0] === '/')) {
485
- for (var i = 0; i < tmp.D.length; i++) {
486
- var r = tmp.D[i];
521
+ for (let r of tmp.D) {
487
522
  if (r.url.length === length || r.wildcard) {
488
523
  if (r.compare(ctrl)) {
489
524
  if (!routes)
@@ -575,11 +610,30 @@ exports.lookupcors = function(ctrl) {
575
610
  return false;
576
611
  }
577
612
 
578
- var origin = ctrl.headers.origin;
613
+ let origin = ctrl.headers.origin;
579
614
 
580
- if (!F.config.$cors || (F.config.$cors != '*' && F.config.$cors.indexOf(origin) == -1)) {
581
- ctrl.system(400, 'Invalid origin (CORS)');
582
- return false;
615
+ if (F.config.$cors !== '*' && !origin.endsWith(ctrl.headers.host)) {
616
+
617
+ let resume = false;
618
+ let cors = F.temporary.cors;
619
+
620
+ if (cors) {
621
+ if (cors.strict.length && cors.strict.includes(origin)) {
622
+ resume = true;
623
+ } else if (cors.wildcard.length) {
624
+ for (let m of cors.wildcard) {
625
+ if (origin.includes(m)) {
626
+ resume = true;
627
+ break;
628
+ }
629
+ }
630
+ }
631
+ }
632
+
633
+ if (!resume) {
634
+ ctrl.fallback(400, 'Invalid origin (CORS)');
635
+ return false;
636
+ }
583
637
  }
584
638
 
585
639
  ctrl.response.headers['access-control-allow-origin'] = origin;
@@ -609,10 +663,20 @@ exports.lookupfile = function(ctrl, auth = 0) {
609
663
  let key = '';
610
664
  for (let i = 0; i < ctrl.split2.length - 1; i++)
611
665
  key += (i ? '/' : '') + ctrl.split2[i];
612
-
613
666
  let routes = F.routes.filescache[key];
614
667
  if (routes)
615
668
  return compareflags(ctrl, routes, auth);
669
+
670
+ // Wildcard
671
+ let length = ctrl.split2.length;
672
+ routes = [];
673
+
674
+ for (let i = 0; i < length; i++) {
675
+ let url = ctrl.split2.slice(0, length - i).join('/') + '/*';
676
+ let item = F.routes.filescache[url];
677
+ if (item)
678
+ return item[0];
679
+ }
616
680
  }
617
681
  };
618
682
 
@@ -712,14 +776,31 @@ Proxy.prototype.copy = function(type) {
712
776
 
713
777
  // @type {String} none|replace|extend
714
778
 
779
+ // "none":
780
+ // PROXY('/cl/', 'https://yourdomain.com');
781
+ // GET /cl/?q=search --> https://yourdomain.com/?q=search');
782
+ // GET /cl/something/?q=search --> https://yourdomain.com/?q=search');
783
+
784
+ // "replace":
785
+ // PROXY('/cl/', 'https://yourdomain.com');
786
+ // GET /cl/?q=search --> https://yourdomain.com/');
787
+ // GET /cl/something/?q=search --> https://yourdomain.com/something/');
788
+
789
+ // "extend":
790
+ // PROXY('/cl/', 'https://yourdomain.com');
791
+ // GET /cl/?q=search --> https://yourdomain.com/?q=search');
792
+ // GET /cl/something/?q=search --> https://yourdomain.com/something/?q=search');
793
+
715
794
  var t = this;
716
795
  if (type === 'replace' && t.target.pathname.length > 1)
717
796
  type = 'extend';
797
+
718
798
  t.copypath = type;
719
799
  return t;
720
800
  };
721
801
 
722
802
  Proxy.prototype.after = function(callback) {
803
+ // callback(response)
723
804
  var t = this;
724
805
  t.$after = callback;
725
806
  return t;
@@ -733,11 +814,13 @@ Proxy.prototype.timeout = function(timeout) {
733
814
 
734
815
  Proxy.prototype.check = function(callback) {
735
816
  var t = this;
817
+ // callback(ctrl)
736
818
  t.$check = callback;
737
819
  return t;
738
820
  };
739
821
 
740
822
  Proxy.prototype.before = function(callback) {
823
+ // callback(uri, ctrl)
741
824
  var t = this;
742
825
  t.$before = callback;
743
826
  return t;
@@ -753,7 +836,7 @@ Proxy.prototype.remove = function() {
753
836
  exports.proxy = function(url, target) {
754
837
 
755
838
  if (!target) {
756
- let index = F.routes.proxies.findIndex('url', url.toLowerCase());
839
+ let index = F.routes.proxies.TfindIndex('url', url.toLowerCase());
757
840
  if (index !== -1)
758
841
  F.routes.proxies.splice(index, 1);
759
842
  return;
@@ -769,7 +852,7 @@ exports.lookupproxy = function(ctrl) {
769
852
  var u = ctrl.uri.key.substring(0, proxy.url.length);
770
853
  if (u[u.length - 1] !== '/')
771
854
  u += '/';
772
- if (u === proxy.url && (!proxy.check || proxy.check(ctrl))) {
855
+ if (u === proxy.url && (!proxy.$check || proxy.$check(ctrl))) {
773
856
  F.stats.response.proxy++;
774
857
  proxycreate(proxy, ctrl);
775
858
  return true;
@@ -807,19 +890,19 @@ function proxycreate(proxy, ctrl) {
807
890
 
808
891
  var tmp;
809
892
 
810
- uri.method = ctrl.method;
893
+ uri.method = ctrl.method === 'SOCKET' ? 'GET' : ctrl.method;
811
894
  uri.headers = ctrl.headers;
812
895
  ctrl.$proxy = proxy;
813
896
 
814
897
  if (uri.socketPath) {
815
- uri.path = proxy.copypath == 'none' || proxy.copypath === 'replace' ? ctrl.url.substring(proxy.url.length - 1) : ctrl.uri.pathname;
898
+ uri.path = (proxy.copypath == 'none' || proxy.copypath === 'replace' ? ctrl.url.substring(proxy.url.length - 1) : ctrl.uri.pathname) + (ctrl.uri.search ? ((proxy.uri.search && proxy.uri.search.length > 1 ? '&' : '?') + ctrl.uri.search) : '');
816
899
  } else {
817
900
 
818
901
  if (proxy.copypath === 'none') {
819
- uri.path = proxy.uri.path;
820
- } else if (proxy.copypath === 'replace')
902
+ uri.path = proxy.uri.path + (ctrl.uri.search ? ((proxy.uri.search && proxy.uri.search.length > 1 ? '&' : '?') + ctrl.uri.search) : '');
903
+ } else if (proxy.copypath === 'replace') {
821
904
  uri.path = ctrl.url.substring(proxy.url.length - 1);
822
- else if (proxy.copypath === 'extend') {
905
+ } else if (proxy.copypath === 'extend') {
823
906
  tmp = ctrl.uri.pathname.substring(proxy.url.length) + (ctrl.uri.search ? ('?' + ctrl.uri.search) : '');
824
907
  uri.path = proxy.path + (tmp ? ((tmp[0] === '/' ? '' : '/') + tmp) : '') + (proxy.query ? (ctrl.uri.search ? ('&' + proxy.query) : ('?' + proxy.query)) : '');
825
908
  } else {
@@ -841,7 +924,7 @@ function proxycreate(proxy, ctrl) {
841
924
 
842
925
  delete uri.headers.host;
843
926
 
844
- proxy.before && proxy.before(uri, ctrl);
927
+ proxy.$before && proxy.$before(uri, ctrl);
845
928
  F.stats.performance.external++;
846
929
  F.stats.request.external++;
847
930
 
@@ -849,7 +932,7 @@ function proxycreate(proxy, ctrl) {
849
932
  if (ctrl.res.headersSent || ctrl.destroyed)
850
933
  return;
851
934
 
852
- var get = uri.method === 'GET' || uri.method === 'HEAD' || uri.method === 'OPTIONS';
935
+ var get = (ctrl.method === 'GET' || ctrl.method === 'HEAD' || ctrl.method === 'OPTIONS');
853
936
  var kind = secured ? F.Https : F.Http;
854
937
  var request = get && !ctrl.iswebsocket ? kind.get(uri, proxycreatecallback) : kind.request(uri, proxycreatecallback);
855
938
 
@@ -938,7 +1021,7 @@ function proxycreatecallback(response) {
938
1021
  let ctrl = self.$controller;
939
1022
  ctrl.released = true;
940
1023
  ctrl.destroyed = true;
941
- ctrl.$proxy.after && self.$proxy.after(response);
1024
+ ctrl.$proxy.$after && self.$proxy.$after(response);
942
1025
  ctrl.res.writeHead && ctrl.res.writeHead(response.statusCode, response.headers);
943
1026
  response.pipe(ctrl.res, PROXY_OPTIONS);
944
1027
  }
package/sourcemap.js CHANGED
@@ -64,9 +64,9 @@ exports.create = function() {
64
64
  if (route.timeout)
65
65
  m.timeout = route.timeout;
66
66
 
67
- if (route.flags.upload) {
67
+ if (route.flags && route.flags.upload) {
68
68
  m.upload = true;
69
- m.limit = route.size / 1024;
69
+ m.limit = route.size;
70
70
  }
71
71
 
72
72
  if (route.api) {
@@ -86,6 +86,9 @@ exports.create = function() {
86
86
  let action = F.actions[name];
87
87
  if (action) {
88
88
  tmp.input = action.input;
89
+ tmp.name = action.name;
90
+ tmp.summary = action.summary;
91
+ tmp.public = action.public;
89
92
 
90
93
  if (tmp.input && tmp.input[0] === '@')
91
94
  tmp.input = stringify(F.jsonschemas[tmp.input.substring(1)]);
@@ -152,7 +155,7 @@ exports.create = function() {
152
155
 
153
156
  exports.refresh = function() {
154
157
 
155
- if (!F.isloaded || !F.config.$sourcemap || F.id)
158
+ if (!F.isLoaded || !F.config.$sourcemap || F.id)
156
159
  return;
157
160
 
158
161
  timeout && clearTimeout(timeout);
package/test.js CHANGED
@@ -1,3 +1,7 @@
1
+ // Total.js Tests
2
+ // The MIT License
3
+ // Copyright 2023 (c) Peter Širka <petersirka@gmail.com>
4
+
1
5
  var Test = { items: [], count: 0 };
2
6
 
3
7
  Test.start = function(message) {
@@ -7,7 +11,7 @@ Test.start = function(message) {
7
11
  console.log('');
8
12
 
9
13
  console.log(divider);
10
- console.log('| ' + message.padRight(divider.length - 4) + ' |');
14
+ console.log('> ' + message.padRight(divider.length - 4) + ' <');
11
15
  console.log(divider);
12
16
  };
13
17
 
@@ -37,7 +41,10 @@ Test.run = function(callback) {
37
41
  console.log('Tests:', Test.count);
38
42
  console.timeEnd('Time');
39
43
  console.log('');
40
- callback && callback();
44
+ if (callback)
45
+ callback();
46
+ else
47
+ process.exit(0);
41
48
  });
42
49
  };
43
50
 
package/tms.js CHANGED
@@ -115,7 +115,7 @@ exports.client = function(url, token, callback) {
115
115
  token = undefined;
116
116
  }
117
117
 
118
- var client = new F.TWebSocket.WebSocketClient();
118
+ var client = F.TWebSocket.createclient();
119
119
  var publishers = {};
120
120
  var subscribers = {};
121
121
  var callbacks = {};
@@ -211,7 +211,7 @@ exports.client = function(url, token, callback) {
211
211
 
212
212
  client.subscribe = function(name, callback) {
213
213
  timeout && clearTimeout(timeout);
214
- timeout = setTimeout(sync_subscribers, 50, true);
214
+ timeout = setTimeout(sync_subscribers, 30, true);
215
215
  if (subscribers[name])
216
216
  subscribers[name].push(callback);
217
217
  else
@@ -230,6 +230,7 @@ exports.client = function(url, token, callback) {
230
230
  client.send({ type: 'subscribers', subscribers: keys });
231
231
  };
232
232
 
233
+ return client;
233
234
  };
234
235
 
235
236
  function refresh(client) {
@@ -239,19 +240,15 @@ function refresh(client) {
239
240
  var subscribed = [];
240
241
  var published = [];
241
242
 
242
- for (let key in Cache.pcache) {
243
- let schema = F.jsonschemas[Cache.pcache[key]];
244
- published.push({ id: key, schema: schema });
245
- }
243
+ for (let key in Cache.pcache)
244
+ published.push({ id: key, schema: Cache.pcache[key] });
246
245
 
247
- for (let key in Cache.scache) {
248
- let schema = F.jsonschemas[Cache.scache[key]];
249
- subscribed.push({ id: key, schema: schema });
250
- }
246
+ for (let key in Cache.scache)
247
+ subscribed.push({ id: key, schema: Cache.scache[key] });
251
248
 
252
249
  var calls = [];
253
250
  for (let key in Cache.calls)
254
- calls.push({ id: key, schema: F.jsonschemas[Cache.calls[key].schema] });
251
+ calls.push({ id: key, schema: Cache.calls[key].schema });
255
252
 
256
253
  var msg = { type: 'meta', name: F.config.name, subscribe: subscribed, publish: published, subscribers: Object.keys(Cache.subscribers), call: calls };
257
254
  if (client)
@@ -308,7 +305,7 @@ exports.newsubscribe = function(name, schema, callback) {
308
305
  else
309
306
  delete Cache.scache[name];
310
307
 
311
- exports.subscribe(name, callback);
308
+ callback && exports.subscribe(name, callback);
312
309
  exports.refresh();
313
310
 
314
311
  };
@@ -324,7 +321,7 @@ exports.subscribe = function(name, callback, client) {
324
321
  if (client) {
325
322
  var arr = Cache.swatchers[name];
326
323
  if (arr) {
327
- for (let fn of Cache.arr)
324
+ for (let fn of arr)
328
325
  fn(callback, client);
329
326
  }
330
327
  } else {
@@ -371,7 +368,7 @@ F.on('$tms', function() {
371
368
  }
372
369
 
373
370
  if ((is && endpoint && F.config.$tms) || (endpoint && F.config.$tms && !Cache.route))
374
- Cache.route = F.route('SOCKET ' + endpoint, tmscontroller, F.config.$tmsmaxsize);
371
+ Cache.route = F.route('SOCKET ' + endpoint, tmscontroller, F.config.$tmsmaxsize * 1024);
375
372
 
376
373
  Cache.url = endpoint;
377
374
 
package/uibuilder.js CHANGED
@@ -7,6 +7,13 @@ const REG_STRING = /'|"/g;
7
7
 
8
8
  exports.compile = async function(opt, callback) {
9
9
 
10
+ // opt.schema {String/Object}
11
+ // |--- opt.schema.origin {String}
12
+ // opt.local {Boolean}
13
+ // opt.download {Boolean}
14
+ // opt.origin {String}
15
+ // opt.filesystem {Boolean} enables loading components from HDD (default: false)
16
+
10
17
  if (!callback)
11
18
  return new Promise((resolve, reject) => exports.compile(opt, (err, response) => err ? reject(err) : resolve(response)));
12
19
 
@@ -24,7 +31,7 @@ exports.compile = async function(opt, callback) {
24
31
  if (opt.local) {
25
32
  response.components = used;
26
33
  } else {
27
- let components = await getComponents(schema, used, opt.download);
34
+ let components = await getComponents(opt, used);
28
35
  response.components = components;
29
36
  }
30
37
 
@@ -55,7 +62,7 @@ exports.download = async function(opt, callback) {
55
62
  return new Promise((resolve, reject) => exports.download(opt, (err, response) => err ? reject(err) : resolve(response)));
56
63
 
57
64
  try {
58
- let response = await getComponents2(opt.components, opt.origin);
65
+ let response = await getComponents2(opt);
59
66
  callback(null, response);
60
67
  } catch (e) {
61
68
  callback(e);
@@ -81,22 +88,44 @@ function getInstances(schema) {
81
88
  return response;
82
89
  }
83
90
 
84
- async function Download(url) {
91
+ async function Download(url, local = false) {
85
92
  return new Promise(function(resolve) {
86
- let opt = {};
87
- opt.url = url;
88
- opt.method = 'GET';
89
- opt.keepalive = true;
90
- opt.insecure = true;
91
- opt.callback = function(err, response) {
92
- resolve(response.status === 200 ? (response.body.isJSON() ? response.body.parseJSON(true) : response.body) : '');
93
- };
94
- REQUEST(opt);
93
+
94
+ if (local && url[0] === '~') {
95
+ // File on HDD (potential dangerous)
96
+ F.Fs.readFile(url.substring(1), 'utf8', function(err, response) {
97
+ resolve(err ? '' : (response.isJSON() ? response.parseJSON(true) : response));
98
+ });
99
+ } else {
100
+ let opt = {};
101
+ opt.url = url;
102
+ opt.method = 'GET';
103
+ opt.keepalive = true;
104
+ opt.insecure = true;
105
+ opt.callback = function(err, response) {
106
+ resolve(response.status === 200 ? (response.body.isJSON() ? response.body.parseJSON(true) : response.body) : '');
107
+ };
108
+ REQUEST(opt);
109
+ }
95
110
  });
96
111
  }
97
112
 
98
- async function getComponents(schema, used, download) {
113
+ function parseorigin(url) {
99
114
 
115
+ var origin = '';
116
+
117
+ if (url.charAt(0) !== '/') {
118
+ var index = url.indexOf('/', 9);
119
+ origin = index === -1 ? url : url.substring(0, index);
120
+ }
121
+
122
+ return origin;
123
+ }
124
+
125
+ async function getComponents(opt, used) {
126
+
127
+ var schema = opt.schema;
128
+ var download = opt.download;
100
129
  var components = {};
101
130
  var arr = [];
102
131
 
@@ -105,14 +134,18 @@ async function getComponents(schema, used, download) {
105
134
 
106
135
  for (let com of arr) {
107
136
 
108
- if (com.value.indexOf('.json') === -1 & !used[com.id])
137
+ if (com.value.indexOf('.json') === -1 && !used[com.id])
109
138
  continue;
110
139
 
111
140
  let url = com.value;
112
- if (url[0] === '/')
113
- url = schema.origin + url;
141
+ let origin = opt.origin || schema.origin;
114
142
 
115
- let body = await Download(url.format(com.id));
143
+ if (url[0] === '/') {
144
+ url = origin + url;
145
+ } else
146
+ origin = parseorigin(url);
147
+
148
+ let body = await Download(url.format(com.id), opt.filesystem);
116
149
 
117
150
  if (typeof(body) === 'string') {
118
151
 
@@ -132,13 +165,14 @@ async function getComponents(schema, used, download) {
132
165
 
133
166
  let render = body.substring(body.indexOf('=', index) + 1, index + end.index).trim().replace(REG_STRING, '').format(com.id);
134
167
 
168
+ if (render[0] === '/')
169
+ render = (origin || schema.origin || '') + render;
170
+
135
171
  if (download) {
136
172
  if (render.substring(0, 7) === 'base64 ') {
137
173
  components[com.id] = render;
138
174
  } else {
139
- if (render[0] === '/')
140
- render = schema.origin + render;
141
- let html = await Download(render);
175
+ let html = await Download(render, opt.filesystem);
142
176
  if (html)
143
177
  components[com.id] = 'base64 ' + Buffer.from(encodeURIComponent(html), 'utf8').toString('base64');
144
178
  }
@@ -153,8 +187,10 @@ async function getComponents(schema, used, download) {
153
187
  return components;
154
188
  }
155
189
 
156
- async function getComponents2(list, origin) {
190
+ async function getComponents2(opt) {
157
191
 
192
+ var list = opt.components;
193
+ var origin = opt.origin;
158
194
  var components = {};
159
195
  var arr = [];
160
196
 
@@ -167,7 +203,7 @@ async function getComponents2(list, origin) {
167
203
  if (url[0] === '/')
168
204
  url = origin + url;
169
205
 
170
- let body = await Download(url.format(com.id));
206
+ let body = await Download(url.format(com.id), opt.filesystem);
171
207
 
172
208
  if (typeof(body) === 'string') {
173
209
 
@@ -192,7 +228,7 @@ async function getComponents2(list, origin) {
192
228
  } else {
193
229
  if (render[0] === '/')
194
230
  render = origin + render;
195
- let html = await Download(render);
231
+ let html = await Download(render, opt.filesystem);
196
232
  if (html)
197
233
  components[com.id] = 'base64 ' + Buffer.from(encodeURIComponent(html), 'utf8').toString('base64');
198
234
  }