lilact 0.4.0 → 0.5.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 (69) hide show
  1. package/README.md +2 -2
  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/highlight.css +42 -0
  10. package/docs/assets/navigation.js +1 -1
  11. package/docs/assets/search.js +1 -1
  12. package/docs/classes/accessories.ErrorBoundary.html +8 -8
  13. package/docs/classes/accessories.Suspense.html +7 -7
  14. package/docs/classes/components.Component.html +10 -10
  15. package/docs/classes/components.HTMLComponent.html +10 -10
  16. package/docs/classes/components.RootComponent.html +10 -10
  17. package/docs/functions/components.createComponent.html +1 -1
  18. package/docs/functions/components.createRoot.html +1 -1
  19. package/docs/functions/components.render.html +1 -1
  20. package/docs/functions/errors.globalErrorHandler.html +7 -0
  21. package/docs/functions/errors.traceError.html +6 -0
  22. package/docs/functions/jsx.transpileJSX.html +3 -3
  23. package/docs/functions/misc.classNames.html +1 -1
  24. package/docs/functions/misc.deepEqual.html +1 -1
  25. package/docs/functions/misc.getComponentByPointer.html +1 -1
  26. package/docs/functions/misc.isAsync.html +1 -1
  27. package/docs/functions/misc.isClass.html +1 -1
  28. package/docs/functions/misc.isEmpty.html +1 -1
  29. package/docs/functions/misc.isError.html +1 -1
  30. package/docs/functions/misc.isThenable.html +1 -1
  31. package/docs/functions/misc.shallowEqual.html +1 -1
  32. package/docs/functions/misc.toBool.html +1 -1
  33. package/docs/functions/run.lazy.html +1 -1
  34. package/docs/functions/run.require.html +1 -1
  35. package/docs/functions/run.runScripts.html +1 -1
  36. package/docs/functions/transition.Transition.html +3 -3
  37. package/docs/index.html +2 -2
  38. package/docs/modules/errors.html +1 -0
  39. package/docs/modules/pane.html +1 -0
  40. package/docs/modules/run.html +1 -1
  41. package/docs/modules.html +1 -1
  42. package/docs/static/demos/error-1.jsx +10 -0
  43. package/docs/static/demos/error-2.jsx +7 -0
  44. package/docs/static/demos/error-3.jsx +20 -0
  45. package/docs/static/demos/error-4.jsx +7 -0
  46. package/docs/static/index.html +8 -4
  47. package/docs/static/lilact.development.min.js +1 -1
  48. package/docs/static/lilact.production.min.js +1 -1
  49. package/docs/variables/pane.ResizablePane.html +48 -0
  50. package/package.json +5 -2
  51. package/root/demos/error-1.jsx +10 -0
  52. package/root/demos/error-2.jsx +7 -0
  53. package/root/demos/error-3.jsx +20 -0
  54. package/root/demos/error-4.jsx +7 -0
  55. package/root/index.html +8 -4
  56. package/root/lilact.development.min.js +1 -1
  57. package/root/lilact.production.min.js +1 -1
  58. package/src/components.jsx +14 -12
  59. package/src/errors.jsx +231 -0
  60. package/src/events.jsx +4 -14
  61. package/src/jsx.js +35 -47
  62. package/src/lilact.jsx +15 -5
  63. package/src/misc.jsx +3 -59
  64. package/src/pane.jsx +52 -9
  65. package/src/run.jsx +22 -96
  66. package/typedoc.json +2 -0
  67. package/docs/functions/run.traceError.html +0 -6
  68. /package/docs/static/demos/{boundary.jsx → error-boundary.jsx} +0 -0
  69. /package/root/demos/{boundary.jsx → error-boundary.jsx} +0 -0
package/src/errors.jsx ADDED
@@ -0,0 +1,231 @@
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
+ desc: x[4]
83
+ }
84
+ //console.log(Lilact.blocks_info.labels[x[1]]);
85
+ } );
86
+ }
87
+
88
+
89
+ /**
90
+ * Debug tool to get the Lilact traced location of an error. It can also produce some block based stack trace
91
+ * if `Lilact.transpilerConfig.enableLabelStack` is set to `true` before loading the script. This is `false`
92
+ * by default for efficiency.
93
+ *
94
+ * @returns A new object that includes `path`, `row`, `col`, `msg`, `name`, and optional `stack`.
95
+ * The exception itself is stored as `err`.
96
+ */
97
+ export function traceError(err)
98
+ {
99
+ const loc = Lilact.getErrorLocation(err);
100
+
101
+ const obj = {
102
+ fileName: err.fileName,
103
+ label: null,
104
+
105
+ lineNumber: loc[0],
106
+ columnNumber: loc[1],
107
+
108
+ message: err.message,
109
+ name: err.name,
110
+
111
+ stack: null,
112
+ error: err,
113
+
114
+ is_traced: true
115
+ };
116
+
117
+ if(err.lilact_trace!==undefined) {
118
+
119
+ // to be able to trace, we assume that all of the scripts are running inside lilact.
120
+ // if not, the error is returned unchanged and stack and label would remain null.
121
+
122
+ let mps;
123
+ let blk;
124
+
125
+ if(typeof(err.lilact_trace)==='object') {
126
+ blk = Lilact.blocks_info.labels[err.lilact_trace[0]];
127
+ }
128
+ else {
129
+ blk = Lilact.blocks_info.labels[err.lilact_trace];
130
+ }
131
+
132
+ if(blk) {
133
+ obj.fileName = blk.path;
134
+ obj.label = blk.label;
135
+
136
+ mps = Lilact.required_scripts[blk.path].mappings;
137
+
138
+ [obj.lineNumber, obj.columnNumber] = Lilact.mapLocation(mps, obj.lineNumber,obj.columnNumber);
139
+
140
+ //const rm = Lilact.block_labels[block_num].required;
141
+
142
+ // Lilact.onError( err.message,
143
+ // rm.path,
144
+ // Lilact.block_labels[block_num].label,
145
+ // ...Lilact.mapLocation(...loc,mps),
146
+ // Lilact.call_stack.map(
147
+ // (x)=>({ path: Lilact.block_labels[x].path,
148
+ // label: Lilact.block_labels[x].label,
149
+ // lineNumber: Lilact.block_labels[x].lineNumber
150
+ // })
151
+ // ), err );
152
+ }
153
+
154
+ }
155
+ Lilact.error = obj;
156
+ return obj;
157
+
158
+ }
159
+
160
+ /**
161
+ * The global Lilact error handler that shows a modal containing information
162
+ * when an exception is not handled.
163
+ *
164
+ * It is by default attached to the `window.onerror` when using the development
165
+ * bundle. It is not attached in the production mode, but it is available in the
166
+ * bundle and can be attached.
167
+ *
168
+ *
169
+ * `
170
+ * window.addEventListener('error', (e) => {
171
+ * Lilact.globalErrorHandler(e);
172
+ * });
173
+ * `
174
+ *
175
+ */
176
+ export function globalErrorHandler(err)
177
+ {
178
+ //console.log(err);
179
+ if(err.error) err = err.error;
180
+
181
+ if(!err?.is_traced && err.name!=='JSXParseError') err = Lilact.traceError(err);
182
+ const cls = Lilact.emotion.css(`
183
+ background: linear-gradient(135deg, #fff2f2d4, #ffffffd4);
184
+ backdrop-filter: blur(10px);
185
+ border: 1px solid rgba(255,255,255,.25);
186
+ border-radius: 5px;
187
+ box-shadow: 0 10px 30px rgba(0,0,0,.35);
188
+ overflow:hidden;
189
+ min-width: 400px;
190
+ width: 66%;
191
+ red {
192
+ color:#d00;
193
+ }
194
+ code {
195
+ border: 1px solid #0003;
196
+ overflow: auto;
197
+ }
198
+ `);
199
+
200
+ const el = document.createElement('dialog');
201
+
202
+
203
+ el.className=cls;
204
+ el.innerHTML =
205
+ `<h3 style=""><red>Error!</red></h3>
206
+ At <b>${err.fileName}: Line ${err.lineNumber+1}</b><br><br>
207
+ <b>${err.name}</b>:&nbsp;<span>${err.message}</span><br><br>
208
+ <code><pre></pre><pre><red></red></pre><pre></pre></code>
209
+ `;
210
+ document.body.appendChild(el);
211
+
212
+
213
+ if(Lilact.required_scripts[err.fileName]) {
214
+ const lines = Lilact.required_scripts[err.fileName].code.split("\n");
215
+ if(err.lineNumber>0)
216
+ el.querySelectorAll('pre')[0].innerText = lines[err.lineNumber-1];
217
+
218
+ el.querySelector('pre red').innerText = lines[err.lineNumber];
219
+
220
+ if(err.lineNumber<lines.length-1)
221
+ el.querySelectorAll('pre')[2].innerText = lines[err.lineNumber+1];
222
+ }
223
+
224
+ el.showModal();
225
+ }
226
+
227
+ /** @ignore */
228
+ export const blocks_info = { counter: 0, labels: {} };
229
+
230
+ /** @ignore */
231
+ 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
  }
@@ -875,9 +870,10 @@ function generateSourceMap(json, path, jsx_eols, out_eols, mappings=[])
875
870
 
876
871
 
877
872
  const scan_leaves = (node)=>{
878
- if(!!node.children) {
873
+ //console.log("SCAN", node, node.begin, node.out_index);
874
+ if(node.out?.length>0) {
879
875
 
880
- for(const ch of node.children) {
876
+ for(const ch of node.out) {
881
877
  scan_leaves(ch);
882
878
  }
883
879
  }
@@ -913,14 +909,12 @@ function generateSourceMap(json, path, jsx_eols, out_eols, mappings=[])
913
909
  }
914
910
 
915
911
  mstr+=',';
916
-
917
912
  mstr+=( vlq.encode(m[1]-oc,0,m[2]-lr,m[3]-lc) );
918
913
 
919
914
  oc = m[1];
920
915
  lr = m[2];
921
916
  lc = m[3];
922
917
  }
923
-
924
918
  sourcemap.mappings = mstr.substring(1).replace(/;,/g, ";");
925
919
 
926
920
  return "\n\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(JSON.stringify(sourcemap));
@@ -943,17 +937,18 @@ export function transpileJSX( jsx, {
943
937
  factory = "Lilact.createComponent",
944
938
  path = "anonymous",
945
939
  appendSourcemap = true,
946
- mappings = [],
940
+ blocks_info = {
941
+ labels: {},
942
+ counter: 0
943
+ },
944
+ mappings = [],
947
945
  injectTraceLabels = false,
948
946
  discardComments = false
949
947
  } = {} )
950
948
  {
951
949
 
952
- // func_num is shared so consecutive transpilations create new ids each time.
953
- transpilerConfig.func_num ??= 0;
954
950
  transpilerConfig.preprocessorDelimiter ??= 'ʔ'; // alt+shift+. on apple abc extended layout
955
-
956
- transpilerConfig.injectTraceLabels ??= injectTraceLabels; // alt+shift+. on apple abc extended layout
951
+ transpilerConfig.injectTraceLabels ??= injectTraceLabels;
957
952
 
958
953
  const eols = scanEOLs(jsx);
959
954
 
@@ -961,6 +956,7 @@ export function transpileJSX( jsx, {
961
956
  const er = new Error(msg);
962
957
  er.name = 'JSXParseError';
963
958
  [er.lineNumber, er.columnNumber] = getRowCol(eols, index);
959
+ er.fileName = path;
964
960
  er.lilact_trace = 'parse';
965
961
  throw er;
966
962
  }).bind(null, eols);
@@ -1026,8 +1022,8 @@ export function transpileJSX( jsx, {
1026
1022
 
1027
1023
  node.children = node.children.filter( (x)=>x!=="" );
1028
1024
 
1029
- if(transpilerConfig.setFunctionLabels && !node.already_labeled) {
1030
- labelFunctions(node,eols);
1025
+ if(transpilerConfig.setBlockLabels && !node.already_labeled) {
1026
+ labelFunctions(node,eols, blocks_info);
1031
1027
  }
1032
1028
  }
1033
1029
  }
@@ -1041,6 +1037,7 @@ export function transpileJSX( jsx, {
1041
1037
  if(typeof(node)!=='object') return node;
1042
1038
 
1043
1039
  node.out_index = outlen;
1040
+ //console.log("CODIFY", node, node.out_index);
1044
1041
 
1045
1042
  if(node.type==='string') return jsx.substring(node.begin, node.end);
1046
1043
  if(node.type==='regex') return jsx.substring(node.begin, node.end);
@@ -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
+ //console.log(json);
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,18 @@ 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
+ ʔ if(DEBUG) {
109
+ window.addEventListener('error', (e) => {
110
+ Lilact.globalErrorHandler(e);
111
+ });
112
+ ʔ }
113
+
104
114
  ʔ if(DEBUG) {
105
115
  console.log(`Lilact (Version: ${Lilact.VERSION}) - Debug Mode`);
106
116
  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,9 @@ export function toBool(x) {
393
336
 
394
337
  // Internals
395
338
 
339
+ /** @ignore */
340
+ export const required_scripts = {};
341
+
396
342
  /** @ignore */
397
343
  export let update_timeout = undefined;
398
344
  /** @ignore */
@@ -413,8 +359,6 @@ export let update_cbs = new Set;
413
359
  /** @ignore */
414
360
  export let roots = new Set;
415
361
  /** @ignore */
416
- export let err = null; // this is only to ease debuggin,
417
- /** @ignore */
418
362
  export let layout_effects = new Set;
419
363
 
420
364
  /** @ignore */