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.
- package/README.md +2 -2
- package/bin/transpile-dir.js +2 -2
- package/bin/transpile.js +5 -5
- package/dist/lilact.development.min.js +1 -1
- package/dist/lilact.development.min.js.LICENSE.txt +1 -1
- package/dist/lilact.development.min.js.map +1 -1
- package/dist/lilact.production.min.js +1 -1
- package/dist/lilact.production.min.js.map +1 -1
- package/docs/assets/highlight.css +42 -0
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/accessories.ErrorBoundary.html +8 -8
- package/docs/classes/accessories.Suspense.html +7 -7
- package/docs/classes/components.Component.html +10 -10
- package/docs/classes/components.HTMLComponent.html +10 -10
- package/docs/classes/components.RootComponent.html +10 -10
- package/docs/functions/components.createComponent.html +1 -1
- package/docs/functions/components.createRoot.html +1 -1
- package/docs/functions/components.render.html +1 -1
- package/docs/functions/errors.globalErrorHandler.html +7 -0
- package/docs/functions/errors.traceError.html +6 -0
- package/docs/functions/jsx.transpileJSX.html +3 -3
- package/docs/functions/misc.classNames.html +1 -1
- package/docs/functions/misc.deepEqual.html +1 -1
- package/docs/functions/misc.getComponentByPointer.html +1 -1
- package/docs/functions/misc.isAsync.html +1 -1
- package/docs/functions/misc.isClass.html +1 -1
- package/docs/functions/misc.isEmpty.html +1 -1
- package/docs/functions/misc.isError.html +1 -1
- package/docs/functions/misc.isThenable.html +1 -1
- package/docs/functions/misc.shallowEqual.html +1 -1
- package/docs/functions/misc.toBool.html +1 -1
- package/docs/functions/run.lazy.html +1 -1
- package/docs/functions/run.require.html +1 -1
- package/docs/functions/run.runScripts.html +1 -1
- package/docs/functions/transition.Transition.html +3 -3
- package/docs/index.html +2 -2
- package/docs/modules/errors.html +1 -0
- package/docs/modules/pane.html +1 -0
- package/docs/modules/run.html +1 -1
- package/docs/modules.html +1 -1
- package/docs/static/demos/error-1.jsx +10 -0
- package/docs/static/demos/error-2.jsx +7 -0
- package/docs/static/demos/error-3.jsx +20 -0
- package/docs/static/demos/error-4.jsx +7 -0
- package/docs/static/index.html +8 -4
- package/docs/static/lilact.development.min.js +1 -1
- package/docs/static/lilact.production.min.js +1 -1
- package/docs/variables/pane.ResizablePane.html +48 -0
- package/package.json +5 -2
- package/root/demos/error-1.jsx +10 -0
- package/root/demos/error-2.jsx +7 -0
- package/root/demos/error-3.jsx +20 -0
- package/root/demos/error-4.jsx +7 -0
- package/root/index.html +8 -4
- package/root/lilact.development.min.js +1 -1
- package/root/lilact.production.min.js +1 -1
- package/src/components.jsx +14 -12
- package/src/errors.jsx +231 -0
- package/src/events.jsx +4 -14
- package/src/jsx.js +35 -47
- package/src/lilact.jsx +15 -5
- package/src/misc.jsx +3 -59
- package/src/pane.jsx +52 -9
- package/src/run.jsx +22 -96
- package/typedoc.json +2 -0
- package/docs/functions/run.traceError.html +0 -6
- /package/docs/static/demos/{boundary.jsx → error-boundary.jsx} +0 -0
- /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>: <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
|
-
|
|
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(`
|
|
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('
|
|
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(`
|
|
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(`
|
|
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
|
-
|
|
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(`
|
|
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(`
|
|
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(`
|
|
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(`
|
|
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(`
|
|
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${++
|
|
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=[${
|
|
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=${
|
|
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${++
|
|
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=[${
|
|
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=${
|
|
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
|
-
|
|
873
|
+
//console.log("SCAN", node, node.begin, node.out_index);
|
|
874
|
+
if(node.out?.length>0) {
|
|
879
875
|
|
|
880
|
-
for(const ch of node.
|
|
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
|
-
|
|
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.
|
|
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${++
|
|
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=[${
|
|
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=${
|
|
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
|
|
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.
|
|
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
|
-
...
|
|
83
|
-
...
|
|
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 */
|