lilact 0.4.0 → 0.5.0

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 (60) hide show
  1. package/README.md +1 -1
  2. package/bin/transpile-dir.js +2 -2
  3. package/bin/transpile.js +5 -5
  4. package/dist/lilact.development.min.js +1 -1
  5. package/dist/lilact.development.min.js.LICENSE.txt +1 -1
  6. package/dist/lilact.development.min.js.map +1 -1
  7. package/dist/lilact.production.min.js +1 -1
  8. package/dist/lilact.production.min.js.map +1 -1
  9. package/docs/assets/navigation.js +1 -1
  10. package/docs/assets/search.js +1 -1
  11. package/docs/classes/accessories.ErrorBoundary.html +8 -8
  12. package/docs/classes/accessories.Suspense.html +7 -7
  13. package/docs/classes/components.Component.html +10 -10
  14. package/docs/classes/components.HTMLComponent.html +10 -10
  15. package/docs/classes/components.RootComponent.html +10 -10
  16. package/docs/functions/components.createComponent.html +1 -1
  17. package/docs/functions/components.createRoot.html +1 -1
  18. package/docs/functions/components.render.html +1 -1
  19. package/docs/functions/jsx.transpileJSX.html +3 -3
  20. package/docs/functions/misc.classNames.html +1 -1
  21. package/docs/functions/misc.deepEqual.html +1 -1
  22. package/docs/functions/misc.getComponentByPointer.html +1 -1
  23. package/docs/functions/misc.isAsync.html +1 -1
  24. package/docs/functions/misc.isClass.html +1 -1
  25. package/docs/functions/misc.isEmpty.html +1 -1
  26. package/docs/functions/misc.isError.html +1 -1
  27. package/docs/functions/misc.isThenable.html +1 -1
  28. package/docs/functions/misc.shallowEqual.html +1 -1
  29. package/docs/functions/misc.toBool.html +1 -1
  30. package/docs/functions/run.lazy.html +1 -1
  31. package/docs/functions/run.require.html +1 -1
  32. package/docs/functions/run.runScripts.html +1 -1
  33. package/docs/functions/transition.Transition.html +3 -3
  34. package/docs/index.html +1 -1
  35. package/docs/modules/misc.html +1 -1
  36. package/docs/modules/run.html +1 -1
  37. package/docs/static/demos/error-1.jsx +10 -0
  38. package/docs/static/demos/error-2.jsx +7 -0
  39. package/docs/static/demos/error-3.jsx +9 -0
  40. package/docs/static/index.html +7 -4
  41. package/docs/static/lilact.development.min.js +1 -1
  42. package/docs/static/lilact.production.min.js +1 -1
  43. package/docs/variables/misc.required_scripts.html +1 -0
  44. package/package.json +1 -1
  45. package/root/demos/error-1.jsx +10 -0
  46. package/root/demos/error-2.jsx +7 -0
  47. package/root/demos/error-3.jsx +9 -0
  48. package/root/index.html +7 -4
  49. package/root/lilact.development.min.js +1 -1
  50. package/root/lilact.production.min.js +1 -1
  51. package/src/components.jsx +14 -12
  52. package/src/errors.jsx +217 -0
  53. package/src/events.jsx +4 -14
  54. package/src/jsx.js +30 -42
  55. package/src/lilact.jsx +13 -5
  56. package/src/misc.jsx +2 -59
  57. package/src/run.jsx +22 -96
  58. package/docs/functions/run.traceError.html +0 -6
  59. /package/docs/static/demos/{boundary.jsx → error-boundary.jsx} +0 -0
  60. /package/root/demos/{boundary.jsx → error-boundary.jsx} +0 -0
package/src/errors.jsx ADDED
@@ -0,0 +1,217 @@
1
+ /*
2
+
3
+ Lilact
4
+ Copyright (C) 2024-2026 Arash Kazemi <contact.arash.kazemi@gmail.com>
5
+ All rights reserved.
6
+
7
+ BSD-2-Clause
8
+
9
+ Redistribution and use in source and binary forms, with or without
10
+ modification, are permitted provided that the following conditions are met:
11
+
12
+ * Redistributions of source code must retain the above copyright
13
+ notice, this list of conditions and the following disclaimer.
14
+ * Redistributions in binary form must reproduce the above copyright
15
+ notice, this list of conditions and the following disclaimer in the
16
+ documentation and/or other materials provided with the distribution.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ */
30
+
31
+
32
+
33
+ // Lilact API
34
+ /** @ignore */
35
+ export function getErrorLocation(err) // works for both error and error-event, and also in node env
36
+ {
37
+ if(err.lineno!==undefined || err.line!==undefined || err.lineNumber!==undefined) {
38
+ const l = err.lineno || err.line || err.lineNumber;
39
+ const c = err.colno || err.column || err.columnNumber;
40
+
41
+ return [l, c];
42
+ }
43
+
44
+ let match = /:(\d+):(\d+)[\n].*/m.exec(err.stack);
45
+ if(match===null) {
46
+ match = /:(\d+):(\d+)\)\s+at .*/m.exec(err.stack);
47
+ }
48
+
49
+ if(match) {
50
+ return [parseInt(match[1]), parseInt(match[2])]
51
+ }
52
+
53
+ return null;
54
+ }
55
+
56
+ /** @ignore */
57
+ export function mapLocation(mps, r,c)
58
+ {
59
+ let map = [0,0,0,0];
60
+
61
+ for(const i in mps) {
62
+ if(mps[i][0]<r) continue;
63
+ if(mps[i][0]>r || mps[i][1]>=c) {
64
+ map = mps[i-1];
65
+ break;
66
+ }
67
+ }
68
+
69
+ return [r-map[0]+map[2], ((r-map[0]===0)?map[3]:0)];
70
+ }
71
+
72
+
73
+ /** @ignore */
74
+ export function scanBlockLabels(code, path)
75
+ {
76
+ const ls = Array.from( code.matchAll(/LILACTBLOCK(\d+):(\d+),(\d+):([^*]+)\*\//mg) );
77
+
78
+ ls.forEach(
79
+ (x) => {
80
+ Lilact.blocks_info.labels[x[1]] = {
81
+ path,
82
+ row: parseInt(x[2]),
83
+ col: parseInt(x[3]),
84
+ desc: x[4]
85
+ }
86
+ //console.log(Lilact.blocks_info.labels[x[1]]);
87
+ } );
88
+ }
89
+
90
+
91
+ /**
92
+ * Debug tool to get the Lilact traced location of an error. It can also produce some block based stack trace
93
+ * if `Lilact.transpilerConfig.enableLabelStack` is set to `true` before loading the script. This is `false`
94
+ * by default for efficiency.
95
+ *
96
+ * @returns A new object that includes `path`, `row`, `col`, `msg`, `name`, and optional `stack`.
97
+ * The exception itself is stored as `err`.
98
+ */
99
+ export function traceError(err)
100
+ {
101
+ const loc = Lilact.getErrorLocation(err);
102
+
103
+ const obj = {
104
+ fileName: err.fileName,
105
+ label: null,
106
+
107
+ lineNumber: loc[0],
108
+ columnNumber: loc[1],
109
+
110
+ message: err.message,
111
+ name: err.name,
112
+
113
+ stack: null,
114
+ error: err,
115
+
116
+ is_traced: true
117
+ };
118
+
119
+ if(err.lilact_trace!==undefined) {
120
+
121
+ // to be able to trace, we assume that all of the scripts are running inside lilact.
122
+ // if not, the error is returned unchanged and stack and label would remain null.
123
+
124
+ let mps;
125
+ let blk;
126
+
127
+ if(typeof(err.lilact_trace)==='object') {
128
+ blk = Lilact.blocks_info.labels[err.lilact_trace[0]];
129
+ }
130
+ else {
131
+ blk = Lilact.blocks_info.labels[err.lilact_trace];
132
+ }
133
+
134
+ if(blk) {
135
+ obj.fileName = blk.path;
136
+ obj.label = blk.label;
137
+
138
+ mps = Lilact.required_scripts[blk.path].mappings;
139
+
140
+ [obj.lineNumber, obj.columnNumber] = Lilact.mapLocation(mps, obj.lineNumber,obj.columnNumber);
141
+
142
+ //const rm = Lilact.block_labels[block_num].required;
143
+
144
+ // Lilact.onError( err.message,
145
+ // rm.path,
146
+ // Lilact.block_labels[block_num].label,
147
+ // ...Lilact.mapLocation(...loc,mps),
148
+ // Lilact.call_stack.map(
149
+ // (x)=>({ path: Lilact.block_labels[x].path,
150
+ // label: Lilact.block_labels[x].label,
151
+ // lineNumber: Lilact.block_labels[x].lineNumber
152
+ // })
153
+ // ), err );
154
+ }
155
+
156
+ }
157
+ Lilact.error = obj;
158
+ return obj;
159
+
160
+ }
161
+
162
+ export function globalErrorHandler(err)
163
+ {
164
+ //console.log(err);
165
+ if(err.error) err = err.error;
166
+
167
+ if(!err?.is_traced && err.name!=='JSXParseError') err = Lilact.traceError(err);
168
+ const cls = Lilact.emotion.css(`
169
+ background: linear-gradient(135deg, #fff2f2d4, #ffffffd4);
170
+ backdrop-filter: blur(10px);
171
+ border: 1px solid rgba(255,255,255,.25);
172
+ border-radius: 5px;
173
+ box-shadow: 0 10px 30px rgba(0,0,0,.35);
174
+ overflow:hidden;
175
+ min-width: 400px;
176
+ width: 66%;
177
+ red {
178
+ color:#d00;
179
+ }
180
+ code {
181
+ border: 1px solid #0003;
182
+ overflow: auto;
183
+ }
184
+ `);
185
+
186
+ const el = document.createElement('dialog');
187
+
188
+
189
+ el.className=cls;
190
+ el.innerHTML =
191
+ `<h3 style=""><red>Error!</red></h3>
192
+ At <b>${err.fileName}: Line ${err.lineNumber+1}, Column ${err.columnNumber+1}</b><br><br>
193
+ <b>${err.name}</b>:&nbsp;<span>${err.message}</span><br><br>
194
+ <code><pre></pre><pre><red></red></pre><pre></pre></code>
195
+ `;
196
+ document.body.appendChild(el);
197
+
198
+
199
+ if(Lilact.required_scripts[err.fileName]) {
200
+ const lines = Lilact.required_scripts[err.fileName].code.split("\n");
201
+ if(err.lineNumber>0)
202
+ el.querySelectorAll('pre')[0].innerText = lines[err.lineNumber-1];
203
+
204
+ el.querySelector('pre red').innerText = lines[err.lineNumber];
205
+
206
+ if(err.lineNumber<lines.length-1)
207
+ el.querySelectorAll('pre')[2].innerText = lines[err.lineNumber+1];
208
+ }
209
+
210
+ el.showModal();
211
+ }
212
+
213
+ /** @ignore */
214
+ export const blocks_info = { counter: 0, labels: {} };
215
+
216
+ /** @ignore */
217
+ export let error = null; // this is only to ease debuggin,
package/src/events.jsx CHANGED
@@ -58,7 +58,7 @@ if (typeof Event !== 'undefined' && !Event.prototype.composedPath) {
58
58
  const _pool = [];
59
59
  const MAX_POOL_SIZE = 10;
60
60
 
61
- function createSyntheticEvent(nativeEvent, currentTarget) {
61
+ export function createSyntheticEvent(nativeEvent, currentTarget) {
62
62
  // Reuse object from pool if available
63
63
  const e = _pool.length ? _pool.pop() : {};
64
64
 
@@ -104,7 +104,7 @@ function createSyntheticEvent(nativeEvent, currentTarget) {
104
104
  return e;
105
105
  }
106
106
 
107
- function releaseSyntheticEvent(e) {
107
+ export function releaseSyntheticEvent(e) {
108
108
  if (e && !e.isPersistent) {
109
109
  // Clean up references to avoid leaks
110
110
  e.nativeEvent = null;
@@ -133,7 +133,7 @@ function releaseSyntheticEvent(e) {
133
133
  // Main wrapper factory
134
134
  // fn: function(syntheticEvent) { ... }
135
135
  // opts: { capture: bool, passive: bool, once: bool, stopPropagationOnTrueReturn: bool }
136
- function wrapListener(fn, opts = {}) {
136
+ export function wrapListener(fn, opts = {}) {
137
137
  const { stopPropagationOnTrueReturn = false } = opts;
138
138
 
139
139
  return function handler(nativeEvent) {
@@ -156,20 +156,10 @@ function wrapListener(fn, opts = {}) {
156
156
  }
157
157
 
158
158
  // Convenience: add/remove wrapper-managed listener
159
- function addWrappedEventListener(target, type, fn, options = {}) {
159
+ export function addWrappedEventListener(target, type, fn, options = {}) {
160
160
  const handler = wrapListener(fn, options);
161
161
 
162
162
  target.addEventListener(type, handler, options);
163
163
  // Return a remover
164
164
  return () => target.removeEventListener(type, handler, options);
165
165
  }
166
-
167
- // Export (CommonJS / ES module-friendly)
168
- const EventWrapper = {
169
- wrapListener,
170
- addWrappedEventListener,
171
- createSyntheticEvent, // exported for advanced use
172
- releaseSyntheticEvent
173
- };
174
-
175
- export default EventWrapper;
package/src/jsx.js CHANGED
@@ -54,17 +54,12 @@ import * as jsxAddons from './jsx.addons.js';
54
54
  /** @ignore */
55
55
  export const transpilerConfig = {
56
56
  addons: jsxAddons,
57
- setFunctionLabels: true,
57
+ setBlockLabels: true,
58
58
  enableLabelStack: false,
59
59
  injectLabels: true,
60
60
  // todo: alt+shift+7 on apple abc extended layout is better i think,
61
61
  // but my current editor doesn't support syntax highlighting with it.
62
62
  preprocessorDelimiter: 'ʔ', // alt+shift+. on apple abc extended layout
63
-
64
-
65
- required: {},
66
- func_labels: {},
67
- func_num: Math.floor(Math.random()*10000)
68
63
  }
69
64
 
70
65
 
@@ -163,7 +158,7 @@ function parseComment(code, index, container)
163
158
  index++;
164
159
  }
165
160
 
166
- raiseError(`unterminated comment`, index);
161
+ raiseError(`Unterminated comment`, b.begin);
167
162
  }
168
163
 
169
164
 
@@ -215,7 +210,7 @@ function parseDirective(code, index, container)
215
210
  }
216
211
  }
217
212
 
218
- raiseError('error in preprocessor statement.')
213
+ raiseError('Error in preprocessor statement', index);
219
214
  }
220
215
 
221
216
 
@@ -336,7 +331,7 @@ function parseString(code, index, q, container)
336
331
  return b;
337
332
 
338
333
  case '\n':
339
- if(q!=='\`') raiseError(`unterminated string`, index);
334
+ if(q!=='\`') raiseError(`Unterminated string`, b.begin);
340
335
  break;
341
336
 
342
337
  case '$':
@@ -357,7 +352,7 @@ function parseString(code, index, q, container)
357
352
  index++;
358
353
  }
359
354
 
360
- raiseError(`unterminated string`, index);
355
+ raiseError(`Unterminated string`, b.begin);
361
356
  }
362
357
 
363
358
 
@@ -387,7 +382,7 @@ function parseXMLContent(code, index, container, eols)
387
382
  const tag = code.substring(i,j).trim();
388
383
 
389
384
  if(container.tag!==tag) {
390
- throw `ill-formed xml (close tag) [${container.tag},${tag}] ${j}`;
385
+ raiseError(`Ill-formed xml (not closed properly)`, index);
391
386
  }
392
387
 
393
388
  container.end = j+1;
@@ -623,7 +618,7 @@ function parseParanthesis(code, index, container)
623
618
  break;
624
619
 
625
620
  case '}':
626
- raiseError(`unmatched curly bracket`, index);
621
+ raiseError(`Unmatched curly bracket`, b.begin);
627
622
  break;
628
623
 
629
624
  case ')':
@@ -646,7 +641,7 @@ function parseParanthesis(code, index, container)
646
641
  }
647
642
  }
648
643
 
649
- raiseError(`unterminated paranthesis block (started at ${b.begin})`, index);
644
+ raiseError(`Unterminated paranthesis block`, b.begin);
650
645
  }
651
646
 
652
647
 
@@ -689,7 +684,7 @@ function parseJS(code, index=0, is_block=false, container)
689
684
  break;
690
685
 
691
686
  case ')': // this is only for function detection
692
- raiseError(`unmatched paranthesis ${index} [from ${b.begin}]`, index);
687
+ raiseError(`Unmatched paranthesis`, b.begin);
693
688
  break;
694
689
 
695
690
  case '}':
@@ -699,7 +694,7 @@ function parseJS(code, index=0, is_block=false, container)
699
694
  if(container) container.children.push(b);
700
695
  return b;
701
696
  }
702
- raiseError(`unmatched curly bracket`, index);
697
+ raiseError(`Unmatched curly bracket`, b.begin);
703
698
  break;
704
699
 
705
700
  case '/':
@@ -726,7 +721,7 @@ function parseJS(code, index=0, is_block=false, container)
726
721
  }
727
722
  }
728
723
 
729
- if(is_block) raiseError(`unterminated js block at ${index} (started at ${b.begin})`);
724
+ if(is_block) raiseError(`Unterminated JS block`, b.begin);
730
725
 
731
726
  b.end = index;
732
727
  b.cend = index;
@@ -738,7 +733,7 @@ function parseJS(code, index=0, is_block=false, container)
738
733
  // this is for lilact internal use, it is a workaround for approximating error location
739
734
  // in eval when transpiling and running jsx directly in browser.
740
735
 
741
- function labelFunctions(node, eols)
736
+ function labelFunctions(node, eols, blocks_info)
742
737
  {
743
738
 
744
739
  node.already_labeled = true;
@@ -781,12 +776,12 @@ function labelFunctions(node, eols)
781
776
 
782
777
  if(transpilerConfig.injectTraceLabels && typeof(nxt)==='object' && nxt.type==='js') {
783
778
  const begin = getRowCol(eols, chi); // begin is always the location of function args paranthesis
784
- nxt.children.splice(1,0, `/*LILACTBLOCK${++transpilerConfig.func_num}:${begin}:${label}*/try{`);
779
+ nxt.children.splice(1,0, `/*LILACTBLOCK${++blocks_info.counter}:${begin}:${label}*/try{`);
785
780
  if(transpilerConfig.enableLabelStack) {
786
- nxt.children.splice(nxt.children.length-1, 0, `} catch(e){ if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=[${transpilerConfig.func_num},e.lilact_trace];throw e}`);
781
+ nxt.children.splice(nxt.children.length-1, 0, `} catch(e){ if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=[${blocks_info.counter},e.lilact_trace];throw e}`);
787
782
  }
788
783
  else {
789
- nxt.children.splice(nxt.children.length-1, 0, `} catch(e){ if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=${transpilerConfig.func_num};throw e}`);
784
+ nxt.children.splice(nxt.children.length-1, 0, `} catch(e){ if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=${blocks_info.counter};throw e}`);
790
785
  }
791
786
  chi += 2;
792
787
  }
@@ -806,15 +801,15 @@ function labelFunctions(node, eols)
806
801
  if(transpilerConfig.injectTraceLabels) {
807
802
 
808
803
  nxt.children.splice(1,0,
809
- `/*LILACTBLOCK${++transpilerConfig.func_num}:${begin}:<ARROW>*/try {`);
804
+ `/*LILACTBLOCK${++blocks_info.counter}:${begin}:<ARROW>*/try {`);
810
805
 
811
806
  if(transpilerConfig.enableLabelStack) {
812
807
  nxt.children.splice(nxt.children.length-1, 0,
813
- `} catch(e){if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=[${transpilerConfig.func_num},e.lilact_trace];throw e}`);
808
+ `} catch(e){if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=[${blocks_info.counter},e.lilact_trace];throw e}`);
814
809
  }
815
810
  else {
816
811
  nxt.children.splice(nxt.children.length-1, 0,
817
- `} catch(e){if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=${transpilerConfig.func_num};throw e}`);
812
+ `} catch(e){if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=${blocks_info.counter};throw e}`);
818
813
  }
819
814
 
820
815
  }
@@ -943,17 +938,18 @@ export function transpileJSX( jsx, {
943
938
  factory = "Lilact.createComponent",
944
939
  path = "anonymous",
945
940
  appendSourcemap = true,
946
- mappings = [],
941
+ blocks_info = {
942
+ labels: {},
943
+ counter: 0
944
+ },
945
+ mappings = [],
947
946
  injectTraceLabels = false,
948
947
  discardComments = false
949
948
  } = {} )
950
949
  {
951
950
 
952
- // func_num is shared so consecutive transpilations create new ids each time.
953
- transpilerConfig.func_num ??= 0;
954
951
  transpilerConfig.preprocessorDelimiter ??= 'ʔ'; // alt+shift+. on apple abc extended layout
955
-
956
- transpilerConfig.injectTraceLabels ??= injectTraceLabels; // alt+shift+. on apple abc extended layout
952
+ transpilerConfig.injectTraceLabels ??= injectTraceLabels;
957
953
 
958
954
  const eols = scanEOLs(jsx);
959
955
 
@@ -961,6 +957,7 @@ export function transpileJSX( jsx, {
961
957
  const er = new Error(msg);
962
958
  er.name = 'JSXParseError';
963
959
  [er.lineNumber, er.columnNumber] = getRowCol(eols, index);
960
+ er.fileName = path;
964
961
  er.lilact_trace = 'parse';
965
962
  throw er;
966
963
  }).bind(null, eols);
@@ -1026,8 +1023,8 @@ export function transpileJSX( jsx, {
1026
1023
 
1027
1024
  node.children = node.children.filter( (x)=>x!=="" );
1028
1025
 
1029
- if(transpilerConfig.setFunctionLabels && !node.already_labeled) {
1030
- labelFunctions(node,eols);
1026
+ if(transpilerConfig.setBlockLabels && !node.already_labeled) {
1027
+ labelFunctions(node,eols, blocks_info);
1031
1028
  }
1032
1029
  }
1033
1030
  }
@@ -1131,25 +1128,16 @@ export function transpileJSX( jsx, {
1131
1128
 
1132
1129
  let out = '';
1133
1130
  if(injectTraceLabels) {
1134
- out=`/*LILACTBLOCK${++transpilerConfig.func_num}:0,0:<EXEC>*/try{`
1135
-
1136
- transpilerConfig.func_labels[transpilerConfig.func_num] = {
1137
- path,
1138
- row: 1,
1139
- col: 1,
1140
- label: transpilerConfig.func_num,
1141
- required: transpilerConfig.required[path]
1142
- };
1143
-
1131
+ out=`/*LILACTBLOCK${++blocks_info.counter}:0,0:<EXEC>*/try{`
1144
1132
  }
1145
1133
  out+=codify(0, json);
1146
1134
 
1147
1135
  if(injectTraceLabels) {
1148
1136
  if(transpilerConfig.enableLabelStack) {
1149
- out += `}catch(e){ if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=[${transpilerConfig.func_num},e.lilact_trace];throw e}`;
1137
+ out += `}catch(e){ if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=[${blocks_info.counter},e.lilact_trace];throw e}`;
1150
1138
  }
1151
1139
  else {
1152
- out += `}catch(e){ if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=${transpilerConfig.func_num};throw e}`;
1140
+ out += `}catch(e){ if(typeof(e)!=='object') e=new Error(e);e.lilact_trace=${blocks_info.counter};throw e}`;
1153
1141
  }
1154
1142
  }
1155
1143
 
package/src/lilact.jsx CHANGED
@@ -39,10 +39,11 @@ import * as components from './components.jsx';
39
39
  import * as hooks from './hooks.jsx';
40
40
  import * as run from './run.jsx';
41
41
  import * as transition from './transition.jsx';
42
- import EventWrapper from './events.jsx';
42
+ import * as events from './events.jsx';
43
43
  import * as redux_wrapper from './redux.jsx';
44
44
  import * as timers from './timers.jsx';
45
45
  import * as misc from './misc.jsx';
46
+ import * as errors from './errors.jsx';
46
47
 
47
48
 
48
49
  import * as router from './router.jsx';
@@ -63,7 +64,7 @@ import {transpileJSX, transpilerConfig} from "./jsx";
63
64
  export const Lilact =
64
65
  {
65
66
 
66
- VERSION: "beta.4",
67
+ VERSION: "beta.5",
67
68
 
68
69
  // Configuration
69
70
 
@@ -73,14 +74,15 @@ export const Lilact =
73
74
 
74
75
  // Units
75
76
 
77
+ ...misc,
78
+ ...run,
76
79
  ...components,
77
80
  ...hooks,
78
- ...run,
79
81
  ...transition,
80
82
  ...redux_wrapper,
81
83
  ...timers,
82
- ...misc,
83
- ...EventWrapper,
84
+ ...events,
85
+ ...errors,
84
86
 
85
87
  ...router,
86
88
  ...accessories,
@@ -97,10 +99,16 @@ export const Lilact =
97
99
 
98
100
  }
99
101
 
102
+ globalThis.Lilact = Lilact;
103
+
100
104
  document.addEventListener('DOMContentLoaded', () => {
101
105
  Lilact.runScripts();
102
106
  });
103
107
 
108
+ window.addEventListener('error', (e) => {
109
+ Lilact.globalErrorHandler(e);
110
+ });
111
+
104
112
  ʔ if(DEBUG) {
105
113
  console.log(`Lilact (Version: ${Lilact.VERSION}) - Debug Mode`);
106
114
  console.log(`Copyright(C) 2024-2026 Arash Kazemi <contact.arash.kazemi@gmail.com>`);
package/src/misc.jsx CHANGED
@@ -146,63 +146,6 @@ export const Children = {
146
146
  };
147
147
 
148
148
 
149
- // Lilact API
150
- /** @ignore */
151
- export function getErrorLocation(err) // works for both error and error-event, and also in node env
152
- {
153
- if(err.lineno!==undefined || err.line!==undefined || err.lineNumber!==undefined) {
154
- const l = err.lineno || err.line || err.lineNumber;
155
- const c = err.colno || err.column || err.columnNumber;
156
-
157
- return [l, c];
158
- }
159
-
160
- let match = /:(\d+):(\d+)[\n].*/m.exec(err.stack);
161
- if(match===null) {
162
- match = /:(\d+):(\d+)\)\s+at .*/m.exec(err.stack);
163
- }
164
-
165
- if(match) {
166
- return [parseInt(match[1]), parseInt(match[2])]
167
- }
168
-
169
- return null;
170
- }
171
-
172
- /** @ignore */
173
- export function mapLocation(mps, r,c)
174
- {
175
- let map = [0,0,0,0];
176
-
177
- for(const i in mps) {
178
- if(mps[i][0]<r) continue;
179
- if(mps[i][0]>r || mps[i][1]>=c) {
180
- map = mps[i-1];
181
- break;
182
- }
183
- }
184
-
185
- return [r-map[0]+map[2], ((r-map[0]===0)?map[3]:0)];
186
- }
187
-
188
-
189
- /** @ignore */
190
- export function scanFunctionLabels(code, path)
191
- {
192
- const ls = Array.from( code.matchAll(/LILACTBLOCK(\d+):(\d+),(\d+):([^*]+)\*\//mg) );
193
-
194
- ls.forEach(
195
- (x) => Lilact.transpilerConfig.func_labels[x[1]] = {
196
- path,
197
- row: parseInt(x[2])+1,
198
- col: parseInt(x[3])+1,
199
- label: x[4],
200
- required: Lilact.transpilerConfig.required[path]
201
- } );
202
-
203
- }
204
-
205
-
206
149
  /**
207
150
  * Debug tool to detect the component visible at a point on screen.
208
151
  *
@@ -393,6 +336,8 @@ export function toBool(x) {
393
336
 
394
337
  // Internals
395
338
 
339
+ export const required_scripts = {};
340
+
396
341
  /** @ignore */
397
342
  export let update_timeout = undefined;
398
343
  /** @ignore */
@@ -413,8 +358,6 @@ export let update_cbs = new Set;
413
358
  /** @ignore */
414
359
  export let roots = new Set;
415
360
  /** @ignore */
416
- export let err = null; // this is only to ease debuggin,
417
- /** @ignore */
418
361
  export let layout_effects = new Set;
419
362
 
420
363
  /** @ignore */