lilact 0.6.0 → 0.7.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.
- package/README.md +1 -1
- package/dist/lilact.development.min.js +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/functions/components.createRoot.html +1 -1
- package/docs/functions/components.render.html +1 -1
- package/docs/functions/errors.globalErrorHandler.html +1 -1
- package/docs/functions/errors.traceError.html +1 -1
- package/docs/functions/jsx.transpileJSX.html +3 -3
- package/docs/functions/run.lazy.html +1 -1
- package/docs/functions/run.require.html +1 -1
- package/docs/functions/run.run.html +1 -6
- package/docs/functions/run.runScripts.html +1 -1
- package/docs/index.html +1 -1
- package/docs/static/demos/error-callback.jsx +22 -13
- package/docs/static/lilact.development.min.js +1 -1
- package/docs/static/lilact.production.min.js +1 -1
- package/package.json +1 -1
- package/root/demos/error-callback.jsx +22 -13
- package/root/lilact.development.min.js +1 -1
- package/root/lilact.production.min.js +1 -1
- package/src/components.jsx +15 -12
- package/src/errors.jsx +96 -47
- package/src/hooks.jsx +4 -4
- package/src/jsx.js +5 -5
- package/src/lilact.jsx +1 -1
- package/src/loader.cjs +1 -1
- package/src/misc.jsx +3 -3
- package/src/pane.jsx +0 -2
- package/src/run.jsx +13 -14
package/src/errors.jsx
CHANGED
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
// Lilact API
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
|
|
35
|
+
function getErrorLocation(err) // works for both error and error-event, and also in node env
|
|
36
36
|
{
|
|
37
37
|
if(err.lineno!==undefined || err.line!==undefined || err.lineNumber!==undefined) {
|
|
38
38
|
const l = err.lineNumber || err.lineno || err.line;
|
|
39
39
|
const c = err.columnNumber || err.colno || err.column;
|
|
40
40
|
|
|
41
|
-
return
|
|
41
|
+
return {line: l, col: c};
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
let match = /:(\d+):(\d+)[\n].*/m.exec(err.stack);
|
|
@@ -47,26 +47,61 @@ export function getErrorLocation(err) // works for both error and error-event, a
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if(match) {
|
|
50
|
-
return
|
|
50
|
+
return {line: parseInt(match[1]), col: parseInt(match[2])}
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
return null;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
// Extract { url, line, col } from an Error.stack.
|
|
57
|
+
// Works with common formats like:
|
|
58
|
+
// Chrome/Edge: at fn (eval:xxx:LINE:COL)
|
|
59
|
+
// Firefox: fn@eval:xxx:LINE:COL
|
|
60
|
+
// Safari: @eval:xxx:LINE:COL (sometimes)
|
|
61
|
+
function parseEvalLocationFromStack(stack, urlPrefix = "eval:/") {
|
|
62
|
+
const raw = typeof stack === "string" ? stack : String(stack || "");
|
|
63
|
+
const lines = raw.split(/\r?\n/);
|
|
64
|
+
|
|
65
|
+
// Match "... (eval:path:LINE:COL)" or "... eval:path:LINE:COL"
|
|
66
|
+
// Group 1: url, group 2: line, group 3: col (col optional in some formats)
|
|
67
|
+
const re = new RegExp(`\\(?((?:${escapeRegExp(urlPrefix)})[^\\s):]+):(\\d+):(?:(\\d+))?\\)?$`);
|
|
68
|
+
|
|
69
|
+
for (const l of lines) {
|
|
70
|
+
const line = l.trim();
|
|
71
|
+
if (!line.includes(urlPrefix)) continue;
|
|
72
|
+
|
|
73
|
+
const m = line.match(re);
|
|
74
|
+
if (!m) continue;
|
|
75
|
+
|
|
76
|
+
const url = m[1];
|
|
77
|
+
const parsedLine = Number(m[2]);
|
|
78
|
+
const parsedCol = m[3] == null ? null : Number(m[3]);
|
|
79
|
+
|
|
80
|
+
if (Number.isFinite(parsedLine) && (parsedCol === null || Number.isFinite(parsedCol))) {
|
|
81
|
+
return { url, line: parsedLine, col: parsedCol, matched: line };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return { url: null, line: null, col: null, matched: null, stackPreview: lines.slice(0, 6).join("\n") };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function escapeRegExp(s) {
|
|
89
|
+
return String(s).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function mapLocation(mps, r,c)
|
|
58
93
|
{
|
|
59
94
|
let map = null;
|
|
60
95
|
|
|
61
96
|
for(const i in mps) {
|
|
62
97
|
if(mps[i][0]<r) continue;
|
|
63
|
-
if(mps[i][0]>r || mps[i][1]>=c) {
|
|
98
|
+
if(mps[i][0]>r || (mps[i][0]===r && mps[i][1]>=c)) {
|
|
64
99
|
map = mps[i-1];
|
|
65
100
|
break;
|
|
66
101
|
}
|
|
67
102
|
}
|
|
68
103
|
if(!map) map = mps[mps.length-1];
|
|
69
|
-
return
|
|
104
|
+
return {line: r-map[0]+map[2], col: ((r-map[0]===0)?map[3]:0) };
|
|
70
105
|
}
|
|
71
106
|
|
|
72
107
|
|
|
@@ -100,62 +135,70 @@ export function traceError(err)
|
|
|
100
135
|
return err;
|
|
101
136
|
}
|
|
102
137
|
|
|
103
|
-
const loc =
|
|
138
|
+
const loc = parseEvalLocationFromStack(err.stack);
|
|
104
139
|
|
|
105
140
|
const obj = {
|
|
106
|
-
fileName: err.fileName,
|
|
107
|
-
label: null,
|
|
141
|
+
fileName: loc.url?.slice(6) || err.fileName,
|
|
108
142
|
|
|
109
|
-
lineNumber: loc
|
|
110
|
-
columnNumber: loc
|
|
143
|
+
lineNumber: loc.line,
|
|
144
|
+
columnNumber: loc.col,
|
|
111
145
|
|
|
112
146
|
message: err.message,
|
|
113
147
|
name: err.name,
|
|
114
148
|
|
|
115
|
-
stack:
|
|
149
|
+
stack: err.stack,
|
|
116
150
|
_error: err,
|
|
117
151
|
|
|
118
152
|
is_traced: true
|
|
119
153
|
};
|
|
120
154
|
|
|
121
|
-
if( err.name!=='JSXParseError'
|
|
122
|
-
|
|
123
|
-
// to be able to trace, we assume that all of the scripts are running inside lilact.
|
|
124
|
-
// if not, the error is returned unchanged and stack and label would remain null.
|
|
155
|
+
if( err.name!=='JSXParseError' ) {
|
|
125
156
|
|
|
126
157
|
let mps;
|
|
127
|
-
let blk;
|
|
128
158
|
|
|
129
|
-
if(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
159
|
+
if(loc.url) {
|
|
160
|
+
const rm = Lilact.required_scripts[obj.fileName];
|
|
161
|
+
mps = rm.mappings;
|
|
162
|
+
|
|
163
|
+
const mloc = mapLocation(mps, obj.lineNumber-1, obj.columnNumber-1);
|
|
164
|
+
|
|
165
|
+
obj.lineNumber = mloc.line;
|
|
166
|
+
obj.columnNumber = mloc.col;
|
|
134
167
|
}
|
|
168
|
+
else if( err.lilact_trace!==undefined) {
|
|
169
|
+
|
|
170
|
+
let loc = getErrorLocation(err);
|
|
171
|
+
|
|
172
|
+
let mps;
|
|
173
|
+
let blk;
|
|
135
174
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
175
|
+
if(typeof(err.lilact_trace)==='object') {
|
|
176
|
+
blk = Lilact.blocks_info.labels[err.lilact_trace[0]];
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
blk = Lilact.blocks_info.labels[err.lilact_trace];
|
|
180
|
+
}
|
|
139
181
|
|
|
140
|
-
|
|
182
|
+
if(blk) {
|
|
183
|
+
obj.fileName = blk.path;
|
|
184
|
+
obj.label = blk.label;
|
|
141
185
|
|
|
142
|
-
|
|
186
|
+
mps = Lilact.required_scripts[blk.path].mappings;
|
|
143
187
|
|
|
144
|
-
|
|
188
|
+
loc = mapLocation(mps, loc.line-1, loc.col-1);
|
|
145
189
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// ...Lilact.mapLocation(...loc,mps),
|
|
150
|
-
// Lilact.call_stack.map(
|
|
151
|
-
// (x)=>({ path: Lilact.block_labels[x].path,
|
|
152
|
-
// label: Lilact.block_labels[x].label,
|
|
153
|
-
// lineNumber: Lilact.block_labels[x].lineNumber
|
|
154
|
-
// })
|
|
155
|
-
// ), err );
|
|
190
|
+
obj.lineNumber = loc.line;
|
|
191
|
+
obj.columnNumber = loc.col;
|
|
192
|
+
}
|
|
156
193
|
}
|
|
157
194
|
|
|
158
195
|
}
|
|
196
|
+
else {
|
|
197
|
+
const loc = getErrorLocation(err);
|
|
198
|
+
if(err.fileName) obj.fileName = err.fileName;
|
|
199
|
+
obj.lineNumber = loc.line;
|
|
200
|
+
obj.columnNumber = loc.col;
|
|
201
|
+
}
|
|
159
202
|
|
|
160
203
|
Lilact.error = obj;
|
|
161
204
|
return obj;
|
|
@@ -180,9 +223,11 @@ export function traceError(err)
|
|
|
180
223
|
*/
|
|
181
224
|
export function globalErrorHandler(err)
|
|
182
225
|
{
|
|
226
|
+
Lilact.pauseTimers();
|
|
183
227
|
if(err.error) err = err.error;
|
|
184
228
|
|
|
185
229
|
err = Lilact.traceError(err);
|
|
230
|
+
|
|
186
231
|
const cls = Lilact.emotion.css(`
|
|
187
232
|
background: linear-gradient(135deg, #fff2f2d4, #ffffffd4);
|
|
188
233
|
backdrop-filter: blur(10px);
|
|
@@ -199,6 +244,7 @@ export function globalErrorHandler(err)
|
|
|
199
244
|
border: 1px solid #0003;
|
|
200
245
|
overflow: auto;
|
|
201
246
|
padding: 10px;
|
|
247
|
+
display: block;
|
|
202
248
|
}
|
|
203
249
|
`);
|
|
204
250
|
|
|
@@ -208,25 +254,28 @@ export function globalErrorHandler(err)
|
|
|
208
254
|
//<b>⚠</b>
|
|
209
255
|
el.innerHTML =
|
|
210
256
|
`<h3 style=""><red>Error!</red></h3>
|
|
211
|
-
|
|
257
|
+
<b>${err.fileName?'At '+err.fileName:''}
|
|
258
|
+
${Number.isFinite(err.lineNumber)?": Line "+(err.lineNumber+1):""}</b><br><br>
|
|
212
259
|
<b>${err.name}</b>: <span>${err.message}</span><br><br>
|
|
213
|
-
<code><pre></pre><pre><red></red></pre><pre></pre></code>
|
|
260
|
+
${Lilact.required_scripts[err.fileName]?'<code><pre></pre><pre><red></red></pre><pre></pre></code>':''}
|
|
214
261
|
${err._error.componentStackLog?'<br>Component Stack:<br><code><pre>'+err._error.componentStackLog+'</pre></code>':''}
|
|
215
262
|
`;
|
|
216
263
|
|
|
217
264
|
|
|
218
265
|
document.body.appendChild(el);
|
|
219
266
|
|
|
267
|
+
const pres = el.querySelectorAll('pre');
|
|
220
268
|
|
|
221
269
|
if(Lilact.required_scripts[err.fileName]) {
|
|
222
270
|
const lines = Lilact.required_scripts[err.fileName].code.split("\n");
|
|
223
|
-
if(err.lineNumber>0)
|
|
224
|
-
el.querySelectorAll('pre')[0].innerText = lines[err.lineNumber-1];
|
|
225
271
|
|
|
226
|
-
|
|
272
|
+
if(lines?.[err.lineNumber-1])
|
|
273
|
+
pres[0].innerText = lines[err.lineNumber-1];
|
|
274
|
+
|
|
275
|
+
if(lines?.[err.lineNumber]) el.querySelector('pre red').innerText = lines[err.lineNumber];
|
|
227
276
|
|
|
228
|
-
if(err.lineNumber
|
|
229
|
-
|
|
277
|
+
if(lines?.[err.lineNumber+1])
|
|
278
|
+
pres[2].innerText = lines[err.lineNumber+1];
|
|
230
279
|
}
|
|
231
280
|
|
|
232
281
|
el.showModal();
|
package/src/hooks.jsx
CHANGED
|
@@ -85,7 +85,7 @@ export function useState(val)
|
|
|
85
85
|
export function useCallback(callback, deps=undefined)
|
|
86
86
|
{
|
|
87
87
|
if( deps!==undefined && (typeof(deps)!=='object' || deps.constructor.name!=='Array') ) {
|
|
88
|
-
throw "
|
|
88
|
+
throw new Error("Callback dependencies must be an array or omitted.");
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
const hk = Lilact.useHook();
|
|
@@ -272,7 +272,7 @@ export function useRef(initialValue = null)
|
|
|
272
272
|
export function useLayoutEffect(effect, deps=undefined)
|
|
273
273
|
{
|
|
274
274
|
if( deps!==undefined && (typeof(deps)!=='object' || deps.constructor.name!=='Array') ) {
|
|
275
|
-
throw "
|
|
275
|
+
throw new Error("Layout effect dependencies must be an array or omitted.");
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
const hk = Lilact.useHook();
|
|
@@ -300,7 +300,7 @@ export function useLayoutEffect(effect, deps=undefined)
|
|
|
300
300
|
export function useEffect(effect, deps=undefined)
|
|
301
301
|
{
|
|
302
302
|
if( deps!==undefined && (typeof(deps)!=='object' || deps.constructor.name!=='Array') ) {
|
|
303
|
-
throw "
|
|
303
|
+
throw new Error("Effect dependencies must be an array or omitted.");
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
const hk = Lilact.useHook();
|
|
@@ -328,7 +328,7 @@ export function useEffect(effect, deps=undefined)
|
|
|
328
328
|
export function useMemo(factory,deps=undefined)
|
|
329
329
|
{
|
|
330
330
|
if( deps!==undefined && (typeof(deps)!=='object' || deps.constructor.name!=='Array') ) {
|
|
331
|
-
throw "
|
|
331
|
+
throw new Error("Memo dependencies must be an array or omitted.");
|
|
332
332
|
}
|
|
333
333
|
|
|
334
334
|
const hk = Lilact.useHook();
|
package/src/jsx.js
CHANGED
|
@@ -336,9 +336,8 @@ function parseString(code, index, q, container)
|
|
|
336
336
|
|
|
337
337
|
case '$':
|
|
338
338
|
if(q==='`') {
|
|
339
|
-
index
|
|
340
|
-
|
|
341
|
-
[index] = lookAhead( parseJS, code, index, true, container );
|
|
339
|
+
if(code[index+1]==='{') {
|
|
340
|
+
[index] = lookAhead( parseJS, code, index+1, true, container );
|
|
342
341
|
index--;
|
|
343
342
|
}
|
|
344
343
|
}
|
|
@@ -934,7 +933,8 @@ function generateSourceMap(json, path, jsx_eols, out_eols, mappings=[])
|
|
|
934
933
|
*/
|
|
935
934
|
|
|
936
935
|
export function transpileJSX( jsx, {
|
|
937
|
-
factory = "
|
|
936
|
+
factory = "createComponent",
|
|
937
|
+
fragment = "Fragment",
|
|
938
938
|
path = "anonymous",
|
|
939
939
|
appendSourcemap = true,
|
|
940
940
|
blocks_info = {
|
|
@@ -1081,7 +1081,7 @@ export function transpileJSX( jsx, {
|
|
|
1081
1081
|
if(node.type==='xml') {
|
|
1082
1082
|
|
|
1083
1083
|
if(node.tag.length===0) {
|
|
1084
|
-
node.tag =
|
|
1084
|
+
node.tag = fragment;
|
|
1085
1085
|
}
|
|
1086
1086
|
else if(node.tag[0]!==node.tag[0].toUpperCase()) {
|
|
1087
1087
|
node.tag = `"${node.tag}"`;
|
package/src/lilact.jsx
CHANGED
package/src/loader.cjs
CHANGED
package/src/misc.jsx
CHANGED
|
@@ -78,7 +78,7 @@ export const findDOMNode = (comp)=>{
|
|
|
78
78
|
|
|
79
79
|
Unlike React, in Lilact findDOMNode can also be used on function components.
|
|
80
80
|
*/
|
|
81
|
-
if(!comp[CORE]?.element?.parentNode) throw "findDOMNode only works on mounted components.";
|
|
81
|
+
if(!comp[CORE]?.element?.parentNode) throw new Error("findDOMNode only works on mounted components.");
|
|
82
82
|
return comp[CORE].element;
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -119,7 +119,7 @@ export const Children = {
|
|
|
119
119
|
i--;
|
|
120
120
|
}
|
|
121
121
|
if(i>1) {
|
|
122
|
-
throw "
|
|
122
|
+
throw new Error("No child or child is not the only one");
|
|
123
123
|
}
|
|
124
124
|
i++;
|
|
125
125
|
}
|
|
@@ -343,7 +343,7 @@ export let update_interval_margin = 0;
|
|
|
343
343
|
/** @ignore */
|
|
344
344
|
export let id_num = Math.floor(Math.random()*10000);
|
|
345
345
|
/** @ignore */
|
|
346
|
-
export let eval_num = Math.floor(Math.random()*10000);
|
|
346
|
+
export let eval_num = 0;//Math.floor(Math.random()*10000);
|
|
347
347
|
|
|
348
348
|
|
|
349
349
|
// todo =improve these stacks
|
package/src/pane.jsx
CHANGED
package/src/run.jsx
CHANGED
|
@@ -35,12 +35,6 @@ import Lilact from './lilact.jsx';
|
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Runs a jsx script. All scripts can access Lilact namespace as a global object.
|
|
38
|
-
*
|
|
39
|
-
* Notice that `run` uses eval internally. There is no standard way of getting the error location when
|
|
40
|
-
* running it with eval. Lilact has its own experimental workarounds for this.
|
|
41
|
-
* When an inline script raises an exception, the original exception does not report
|
|
42
|
-
* which eval has caused the error, so Lilact should guess it from some labels, and for the sake of
|
|
43
|
-
* efficiency, it is block based and not exact.
|
|
44
38
|
*
|
|
45
39
|
* @param jsx - The code to run.
|
|
46
40
|
* @param path - The optional path to be used in reporting errors.
|
|
@@ -48,10 +42,10 @@ import Lilact from './lilact.jsx';
|
|
|
48
42
|
*
|
|
49
43
|
* @returns An array representation of the children.
|
|
50
44
|
*/
|
|
51
|
-
export function run(jsx, path
|
|
45
|
+
export function run(jsx, path=`InlineJSX-${++Lilact.eval_num}`, is_inline=true)
|
|
52
46
|
{
|
|
53
47
|
const mappings = [];
|
|
54
|
-
const module = {};
|
|
48
|
+
const module = {exports: {}};
|
|
55
49
|
let processed;
|
|
56
50
|
|
|
57
51
|
Lilact.required_scripts[path] = {
|
|
@@ -68,8 +62,8 @@ export function run(jsx, path=`<string input ${++Lilact.eval_num}>`, is_inline=t
|
|
|
68
62
|
{
|
|
69
63
|
path,
|
|
70
64
|
mappings,
|
|
71
|
-
factory: "
|
|
72
|
-
|
|
65
|
+
factory: "createComponent",
|
|
66
|
+
appendSourcemap: false,
|
|
73
67
|
blocks_info: Lilact.blocks_info,
|
|
74
68
|
|
|
75
69
|
injectTraceLabels: true,
|
|
@@ -85,12 +79,18 @@ export function run(jsx, path=`<string input ${++Lilact.eval_num}>`, is_inline=t
|
|
|
85
79
|
Lilact.required_scripts[path].processed = processed;
|
|
86
80
|
ʔ }
|
|
87
81
|
|
|
82
|
+
processed += "\n//# sourceURL=eval:/" + path;
|
|
83
|
+
|
|
84
|
+
// todo: this seems to be only useful in safari, should be assessed latera
|
|
88
85
|
Lilact.scanBlockLabels(processed, path);
|
|
89
86
|
|
|
90
87
|
try {
|
|
91
88
|
globalThis.Lilact = Lilact;
|
|
89
|
+
globalThis.createComponent = Lilact.createComponent;
|
|
90
|
+
globalThis.Fragment = Lilact.Fragment;
|
|
92
91
|
|
|
93
|
-
const res =
|
|
92
|
+
//const res = new Function( "module", processed )(module);
|
|
93
|
+
const res = eval(processed);
|
|
94
94
|
if(module.exports) return module.exports;
|
|
95
95
|
return res;
|
|
96
96
|
}
|
|
@@ -106,7 +106,7 @@ export function run(jsx, path=`<string input ${++Lilact.eval_num}>`, is_inline=t
|
|
|
106
106
|
*
|
|
107
107
|
* `Lilact.require` loads synchronously, as it is expected to be loaded on the next instruction.
|
|
108
108
|
*
|
|
109
|
-
* As running the transpiled scripts rely on `
|
|
109
|
+
* As running the transpiled scripts rely on `new Function`, it is not possible to use module imports
|
|
110
110
|
* and exports. So to import you should use `const {useState} = Lilact` convention. And to
|
|
111
111
|
* export, you should use `module.exports = ...`. `Lilact.require` returns `module.exports` value
|
|
112
112
|
* so you can import different modules using the convention above.
|
|
@@ -160,13 +160,12 @@ export function require(path, force_update)
|
|
|
160
160
|
const request = new XMLHttpRequest();
|
|
161
161
|
request.open("GET", path, false);
|
|
162
162
|
request.send(null);
|
|
163
|
-
|
|
164
163
|
if (request.status === 200) {
|
|
165
164
|
return Lilact.run(request.responseText, path, false);
|
|
166
165
|
}
|
|
167
166
|
}
|
|
168
167
|
|
|
169
|
-
throw `
|
|
168
|
+
throw new Error(`Required resource not found (${path})`);
|
|
170
169
|
}
|
|
171
170
|
|
|
172
171
|
|