lilact 0.26.16 → 0.27.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/dist/lilact.development.js +236 -337
- package/dist/lilact.development.js.map +3 -3
- package/dist/lilact.development.min.js +34 -34
- package/dist/lilact.development.min.js.map +3 -3
- package/dist/lilact.production.min.js +34 -34
- 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 +11 -11
- package/docs/classes/components.HTMLComponent.html +11 -11
- package/docs/classes/components.RootComponent.html +11 -11
- package/docs/functions/components.cloneComponent.html +1 -1
- package/docs/functions/components.createComponent.html +1 -1
- package/docs/functions/components.createPortal.html +1 -1
- package/docs/functions/components.createRoot.html +1 -1
- package/docs/functions/components.memo.html +1 -1
- package/docs/functions/components.render.html +1 -1
- package/docs/functions/errors.globalErrorHandler.html +1 -2
- package/docs/functions/errors.scanBlockLabels.html +1 -2
- package/docs/functions/errors.traceError.html +1 -3
- package/docs/functions/hooks.startTransition.html +1 -1
- package/docs/functions/hooks.useActionState.html +1 -1
- package/docs/functions/hooks.useDebugValue.html +1 -1
- package/docs/functions/hooks.useDeferredValue.html +1 -1
- package/docs/functions/hooks.useEffect.html +1 -1
- package/docs/functions/hooks.useImperativeHandle.html +1 -1
- package/docs/functions/hooks.useInsertionEffect.html +1 -1
- package/docs/functions/hooks.useMemo.html +1 -1
- package/docs/functions/hooks.useReducer.html +1 -1
- package/docs/functions/run.lazy.html +1 -2
- package/docs/functions/run.require.html +1 -2
- package/docs/functions/run.run.html +1 -2
- package/docs/functions/run.runScripts.html +1 -1
- package/docs/functions/timers.timeoutPromise.html +3 -3
- package/docs/modules/errors.html +1 -1
- package/docs/modules/run.html +1 -1
- package/docs/static/index.html +1 -1
- package/docs/static/lilact.development.js +236 -337
- package/docs/static/lilact.development.js.map +3 -3
- package/docs/static/lilact.development.min.js +34 -34
- package/docs/static/lilact.development.min.js.map +3 -3
- package/docs/static/lilact.production.min.js +34 -34
- package/docs/variables/components.cloneElement.html +1 -1
- package/docs/variables/errors.blocks_info.html +1 -1
- package/docs/variables/errors.error.html +1 -1
- package/docs/variables/run.required_scripts.html +1 -0
- package/examples/index.html +1 -1
- package/examples/lilact.development.js +236 -337
- package/examples/lilact.development.js.map +3 -3
- package/examples/lilact.development.min.js +34 -34
- package/examples/lilact.development.min.js.map +3 -3
- package/examples/lilact.production.min.js +34 -34
- package/package.json +1 -1
- package/src/components.jsx +10 -4
- package/src/errors.jsx +179 -364
- package/src/expscan.js +1 -1
- package/src/hooks.jsx +8 -5
- package/src/jsx.js +14 -14
- package/src/lilact.jsx +1 -1
- package/src/run.jsx +119 -157
- package/docs/functions/errors.mapLocation.html +0 -1
package/src/errors.jsx
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
*/
|
|
30
30
|
/*
|
|
31
31
|
Lilact
|
|
32
|
-
Copyright (C) 2024-2026 Arash Kazemi
|
|
32
|
+
Copyright (C) 2024-2026 Arash Kazemi <contact.arash.kazemi@gmail.com>
|
|
33
33
|
BSD-2-Clause
|
|
34
34
|
*/
|
|
35
35
|
|
|
@@ -37,398 +37,224 @@ import Lilact from "./lilact.jsx";
|
|
|
37
37
|
import { required_scripts } from "./run.jsx";
|
|
38
38
|
import { css } from "@emotion/css";
|
|
39
39
|
|
|
40
|
-
function
|
|
41
|
-
const
|
|
42
|
-
return Number.isFinite(
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function firstNumber(...values) {
|
|
46
|
-
for (const value of values) {
|
|
47
|
-
const n = numberOrNull(value);
|
|
48
|
-
if (n !== null) return n;
|
|
49
|
-
}
|
|
50
|
-
return null;
|
|
40
|
+
function number(value) {
|
|
41
|
+
const result = Number(value);
|
|
42
|
+
return Number.isFinite(result) ? result : null;
|
|
51
43
|
}
|
|
52
44
|
|
|
53
45
|
function asError(value) {
|
|
54
46
|
if (value instanceof Error) return value;
|
|
47
|
+
if (value?.error instanceof Error) return value.error;
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
);
|
|
49
|
+
const error = new Error(
|
|
50
|
+
value?.message == null
|
|
51
|
+
? String(value)
|
|
52
|
+
: String(value.message)
|
|
53
|
+
);
|
|
62
54
|
|
|
55
|
+
if (value && typeof value === "object") {
|
|
63
56
|
if (value.name) error.name = value.name;
|
|
64
57
|
if (value.stack) error.stack = value.stack;
|
|
65
58
|
|
|
66
59
|
for (const key of Object.keys(value)) {
|
|
67
60
|
if (!(key in error)) error[key] = value[key];
|
|
68
61
|
}
|
|
69
|
-
|
|
70
|
-
return error;
|
|
71
62
|
}
|
|
72
63
|
|
|
73
|
-
return
|
|
64
|
+
return error;
|
|
74
65
|
}
|
|
75
66
|
|
|
76
67
|
function isParserError(error) {
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/*
|
|
81
|
-
Returns zero-based line and column numbers.
|
|
82
|
-
|
|
83
|
-
Parser errors produced by jsx.js already use zero-based positions.
|
|
84
|
-
Browser Error objects and ErrorEvents normally use one-based positions.
|
|
85
|
-
*/
|
|
86
|
-
function getErrorLocation(error, { zeroBased = false } = {}) {
|
|
87
|
-
const line = firstNumber(
|
|
88
|
-
error?.lineNumber,
|
|
89
|
-
error?.lineno,
|
|
90
|
-
error?.line
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
const column = firstNumber(
|
|
94
|
-
error?.columnNumber,
|
|
95
|
-
error?.colno,
|
|
96
|
-
error?.column
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
if (line !== null || column !== null) {
|
|
100
|
-
return {
|
|
101
|
-
line:
|
|
102
|
-
line === null
|
|
103
|
-
? null
|
|
104
|
-
: zeroBased
|
|
105
|
-
? line
|
|
106
|
-
: Math.max(0, line - 1),
|
|
107
|
-
|
|
108
|
-
col:
|
|
109
|
-
column === null
|
|
110
|
-
? null
|
|
111
|
-
: zeroBased
|
|
112
|
-
? column
|
|
113
|
-
: Math.max(0, column - 1),
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return null;
|
|
68
|
+
return error?.name === "JSXParserError";
|
|
118
69
|
}
|
|
119
70
|
|
|
120
|
-
function
|
|
121
|
-
|
|
71
|
+
function stackLocation(stack) {
|
|
72
|
+
if (typeof stack !== "string") return null;
|
|
122
73
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
* The path is intentionally greedy so paths containing ':' still work.
|
|
126
|
-
*
|
|
127
|
-
* Examples:
|
|
128
|
-
*
|
|
129
|
-
* at fn (eval:/components/App.jsx:12:8)
|
|
130
|
-
* fn@eval:/components/App.jsx:12:8
|
|
131
|
-
* eval:/components/App.jsx:12:8
|
|
132
|
-
*/
|
|
133
|
-
const expression = /(?:^|[\s(@])((?:eval:\/)[\s\S]*):(\d+):(\d+)(?:\)?$)/;
|
|
74
|
+
for (const line of stack.split(/\r?\n/)) {
|
|
75
|
+
const match = line.match(/(eval:\/.*):(\d+):(\d+)/);
|
|
134
76
|
|
|
135
|
-
for (const line of text.split(/\r?\n/)) {
|
|
136
|
-
const match = line.trim().match(expression);
|
|
137
77
|
if (!match) continue;
|
|
138
78
|
|
|
139
79
|
return {
|
|
140
|
-
|
|
141
|
-
line: Number(match[2]),
|
|
142
|
-
|
|
80
|
+
path: match[1].replace(/^eval:\/+/, ""),
|
|
81
|
+
line: Number(match[2]) - 1,
|
|
82
|
+
column: Number(match[3]) - 1,
|
|
143
83
|
};
|
|
144
84
|
}
|
|
145
85
|
|
|
146
86
|
return null;
|
|
147
87
|
}
|
|
148
88
|
|
|
149
|
-
function
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
89
|
+
function browserLocation(error) {
|
|
90
|
+
const line = number(
|
|
91
|
+
error?.lineNumber ??
|
|
92
|
+
error?.lineno ??
|
|
93
|
+
error?.line
|
|
94
|
+
);
|
|
155
95
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
96
|
+
const column = number(
|
|
97
|
+
error?.columnNumber ??
|
|
98
|
+
error?.colno ??
|
|
99
|
+
error?.column
|
|
100
|
+
);
|
|
159
101
|
|
|
160
|
-
return
|
|
102
|
+
return {
|
|
103
|
+
line: line == null ? null : Math.max(0, line - 1),
|
|
104
|
+
column: column == null ? null : Math.max(0, column - 1),
|
|
105
|
+
};
|
|
161
106
|
}
|
|
162
107
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
generatedLine,
|
|
168
|
-
generatedColumn,
|
|
169
|
-
sourceLine,
|
|
170
|
-
sourceColumn,
|
|
171
|
-
node
|
|
172
|
-
]
|
|
173
|
-
|
|
174
|
-
All four coordinates are zero-based.
|
|
175
|
-
|
|
176
|
-
The correct mapping is the closest mapping at or before the generated
|
|
177
|
-
location. The old implementation searched in the opposite direction and
|
|
178
|
-
used the final mapping for errors occurring before the first mapping.
|
|
179
|
-
*/
|
|
180
|
-
export function mapLocation(mappings, generatedLine, generatedColumn) {
|
|
181
|
-
if (!Array.isArray(mappings) || mappings.length === 0) {
|
|
182
|
-
return {
|
|
183
|
-
line: generatedLine,
|
|
184
|
-
col: generatedColumn,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
108
|
+
function traceBlock(error) {
|
|
109
|
+
const trace = error?.lilact_trace;
|
|
110
|
+
return Array.isArray(trace) ? trace[0] : trace;
|
|
111
|
+
}
|
|
187
112
|
|
|
188
|
-
|
|
189
|
-
const
|
|
113
|
+
function blockInfo(error) {
|
|
114
|
+
const trace = traceBlock(error);
|
|
115
|
+
return trace == null
|
|
116
|
+
? null
|
|
117
|
+
: Lilact.blocks_info?.labels?.[trace];
|
|
118
|
+
}
|
|
190
119
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
120
|
+
function mapLocation(mappings, line, column) {
|
|
121
|
+
if (
|
|
122
|
+
!Array.isArray(mappings) ||
|
|
123
|
+
!mappings.length ||
|
|
124
|
+
!Number.isFinite(line) ||
|
|
125
|
+
!Number.isFinite(column)
|
|
126
|
+
) {
|
|
127
|
+
return { line, column };
|
|
196
128
|
}
|
|
197
129
|
|
|
198
|
-
const
|
|
199
|
-
.filter(
|
|
200
|
-
(mapping)
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
Number.isFinite(Number(
|
|
205
|
-
Number.isFinite(Number(mapping[2])) &&
|
|
206
|
-
Number.isFinite(Number(mapping[3]))
|
|
130
|
+
const valid = mappings
|
|
131
|
+
.filter(mapping =>
|
|
132
|
+
Array.isArray(mapping) &&
|
|
133
|
+
mapping.length >= 4 &&
|
|
134
|
+
mapping
|
|
135
|
+
.slice(0, 4)
|
|
136
|
+
.every(value => Number.isFinite(Number(value)))
|
|
207
137
|
)
|
|
208
|
-
.
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (lineDifference !== 0) {
|
|
213
|
-
return lineDifference;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return Number(a[1]) - Number(b[1]);
|
|
217
|
-
});
|
|
138
|
+
.sort((a, b) =>
|
|
139
|
+
Number(a[0]) - Number(b[0]) ||
|
|
140
|
+
Number(a[1]) - Number(b[1])
|
|
141
|
+
);
|
|
218
142
|
|
|
219
|
-
if (
|
|
220
|
-
return {
|
|
221
|
-
line,
|
|
222
|
-
col,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
143
|
+
if (!valid.length) return { line, column };
|
|
225
144
|
|
|
226
|
-
|
|
227
|
-
* Find the last mapping whose generated position is before or equal
|
|
228
|
-
* to the runtime position.
|
|
229
|
-
*/
|
|
230
|
-
let mapping = validMappings[0];
|
|
145
|
+
let selected = valid[0];
|
|
231
146
|
|
|
232
|
-
for (const
|
|
233
|
-
const
|
|
234
|
-
const
|
|
147
|
+
for (const mapping of valid) {
|
|
148
|
+
const generatedLine = Number(mapping[0]);
|
|
149
|
+
const generatedColumn = Number(mapping[1]);
|
|
235
150
|
|
|
236
151
|
if (
|
|
237
|
-
|
|
152
|
+
generatedLine < line ||
|
|
238
153
|
(
|
|
239
|
-
|
|
240
|
-
|
|
154
|
+
generatedLine === line &&
|
|
155
|
+
generatedColumn <= column
|
|
241
156
|
)
|
|
242
157
|
) {
|
|
243
|
-
|
|
244
|
-
|
|
158
|
+
selected = mapping;
|
|
159
|
+
} else {
|
|
160
|
+
break;
|
|
245
161
|
}
|
|
246
|
-
|
|
247
|
-
break;
|
|
248
162
|
}
|
|
249
163
|
|
|
250
|
-
const
|
|
251
|
-
const
|
|
252
|
-
const
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
/*
|
|
256
|
-
* A mapping points to the beginning of a generated region. Preserve
|
|
257
|
-
* the relative line offset inside that region.
|
|
258
|
-
*
|
|
259
|
-
* This is the important part. Returning mappingSourceLine directly
|
|
260
|
-
* causes errors inside a generated multi-line block to point to the
|
|
261
|
-
* first line of the block.
|
|
262
|
-
*/
|
|
263
|
-
const sourceLine =
|
|
264
|
-
mappingSourceLine + (line - mappingGeneratedLine);
|
|
265
|
-
|
|
266
|
-
/*
|
|
267
|
-
* Columns are only safely relative when the generated error is on the
|
|
268
|
-
* same generated line as the mapping. On later lines, use the source
|
|
269
|
-
* anchor column instead of carrying the generated column across lines.
|
|
270
|
-
*/
|
|
271
|
-
const sourceColumn =
|
|
272
|
-
line === mappingGeneratedLine
|
|
273
|
-
? Math.max(
|
|
274
|
-
0,
|
|
275
|
-
mappingSourceColumn +
|
|
276
|
-
(col - mappingGeneratedColumn)
|
|
277
|
-
)
|
|
278
|
-
: mappingSourceColumn;
|
|
164
|
+
const generatedLine = Number(selected[0]);
|
|
165
|
+
const generatedColumn = Number(selected[1]);
|
|
166
|
+
const sourceLine = Number(selected[2]);
|
|
167
|
+
const sourceColumn = Number(selected[3]);
|
|
279
168
|
|
|
280
169
|
return {
|
|
281
|
-
line:
|
|
282
|
-
|
|
170
|
+
line:
|
|
171
|
+
sourceLine +
|
|
172
|
+
(line === generatedLine ? 0 : line - generatedLine),
|
|
173
|
+
column:
|
|
174
|
+
line === generatedLine
|
|
175
|
+
? Math.max(0, sourceColumn + column - generatedColumn)
|
|
176
|
+
: sourceColumn,
|
|
283
177
|
};
|
|
284
178
|
}
|
|
285
179
|
|
|
286
|
-
function getBlockTrace(error) {
|
|
287
|
-
const trace = error?.lilact_trace;
|
|
288
|
-
|
|
289
|
-
if (Array.isArray(trace)) {
|
|
290
|
-
return trace[0];
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return trace;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function getBlockInfo(error) {
|
|
297
|
-
const trace = getBlockTrace(error);
|
|
298
|
-
|
|
299
|
-
if (trace === undefined || trace === null) {
|
|
300
|
-
return null;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return Lilact.blocks_info?.labels?.[trace] ?? null;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
function applyBlockFallback(error, result, currentPath) {
|
|
307
|
-
const block = getBlockInfo(error);
|
|
308
|
-
if (!block) return result;
|
|
309
|
-
|
|
310
|
-
if (block.path) {
|
|
311
|
-
result.fileName = block.path;
|
|
312
|
-
} else if (!result.fileName) {
|
|
313
|
-
result.fileName = currentPath;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/*
|
|
317
|
-
* scanBlockLabels() stores the original source position of the block.
|
|
318
|
-
* This is more reliable than using the location of the generated catch
|
|
319
|
-
* wrapper.
|
|
320
|
-
*/
|
|
321
|
-
if (
|
|
322
|
-
Number.isFinite(block.line) &&
|
|
323
|
-
Number.isFinite(block.col)
|
|
324
|
-
) {
|
|
325
|
-
result.lineNumber = block.line;
|
|
326
|
-
result.columnNumber = block.col;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if (block.desc) {
|
|
330
|
-
result.label = block.desc;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return result;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
function copyErrorMetadata(source, target) {
|
|
337
|
-
if (!source || typeof source !== "object") return;
|
|
338
|
-
|
|
339
|
-
for (const key of [
|
|
340
|
-
"fileName",
|
|
341
|
-
"lineNumber",
|
|
342
|
-
"columnNumber",
|
|
343
|
-
"lineno",
|
|
344
|
-
"colno",
|
|
345
|
-
"line",
|
|
346
|
-
"column",
|
|
347
|
-
"componentStackLog",
|
|
348
|
-
"lilact_trace",
|
|
349
|
-
]) {
|
|
350
|
-
if (source[key] !== undefined && target[key] === undefined) {
|
|
351
|
-
target[key] = source[key];
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Converts parser errors, runtime errors, ErrorEvents, and rejected
|
|
358
|
-
* promises into one consistent zero-based representation.
|
|
359
|
-
*/
|
|
360
180
|
export function traceError(value, runPath) {
|
|
361
181
|
if (value?.isTraced) return value;
|
|
362
182
|
|
|
363
|
-
const
|
|
364
|
-
|
|
183
|
+
const error = asError(value);
|
|
184
|
+
const source = error.lilact_source;
|
|
185
|
+
const stack = isParserError(error)
|
|
186
|
+
? null
|
|
187
|
+
: stackLocation(error.stack);
|
|
188
|
+
const browser = isParserError(error)
|
|
189
|
+
? {
|
|
190
|
+
line: number(error.lineNumber),
|
|
191
|
+
column: number(error.columnNumber),
|
|
192
|
+
}
|
|
193
|
+
: browserLocation(error);
|
|
365
194
|
|
|
366
|
-
|
|
195
|
+
/*
|
|
196
|
+
* lilact_source is authoritative. In particular, it prevents a syntax
|
|
197
|
+
* error from a nested eval from inheriting the caller's eval filename.
|
|
198
|
+
*/
|
|
199
|
+
const fileName =
|
|
200
|
+
source?.path ||
|
|
201
|
+
stack?.path ||
|
|
202
|
+
error.fileName ||
|
|
203
|
+
runPath ||
|
|
204
|
+
null;
|
|
367
205
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
206
|
+
let line =
|
|
207
|
+
stack?.line ??
|
|
208
|
+
browser.line ??
|
|
209
|
+
null;
|
|
371
210
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
211
|
+
let column =
|
|
212
|
+
stack?.column ??
|
|
213
|
+
browser.column ??
|
|
214
|
+
null;
|
|
375
215
|
|
|
376
216
|
const result = {
|
|
377
|
-
fileName
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
runPath ||
|
|
381
|
-
null,
|
|
382
|
-
|
|
383
|
-
lineNumber:
|
|
384
|
-
stackLocation?.line != null
|
|
385
|
-
? Math.max(0, stackLocation.line - 1)
|
|
386
|
-
: eventLocation?.line ?? null,
|
|
387
|
-
|
|
388
|
-
columnNumber:
|
|
389
|
-
stackLocation?.col != null
|
|
390
|
-
? Math.max(0, stackLocation.col - 1)
|
|
391
|
-
: eventLocation?.col ?? null,
|
|
392
|
-
|
|
217
|
+
fileName,
|
|
218
|
+
lineNumber: line,
|
|
219
|
+
columnNumber: column,
|
|
393
220
|
message:
|
|
394
|
-
|
|
395
|
-
? String(
|
|
396
|
-
: String(
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
_error:
|
|
221
|
+
error.message == null
|
|
222
|
+
? String(error)
|
|
223
|
+
: String(error.message),
|
|
224
|
+
name: error.name || "Error",
|
|
225
|
+
stack: error.stack || null,
|
|
226
|
+
lilact_source: source || null,
|
|
227
|
+
_error: error,
|
|
401
228
|
isTraced: true,
|
|
402
229
|
};
|
|
403
230
|
|
|
404
|
-
|
|
405
|
-
copyErrorMetadata(original, result);
|
|
231
|
+
const module = fileName && required_scripts[fileName];
|
|
406
232
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
module.mappings,
|
|
417
|
-
result.lineNumber,
|
|
418
|
-
result.columnNumber
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
result.lineNumber = mapped.line;
|
|
422
|
-
result.columnNumber = mapped.col;
|
|
423
|
-
}
|
|
233
|
+
if (module) {
|
|
234
|
+
const mapped = mapLocation(
|
|
235
|
+
module.mappings,
|
|
236
|
+
result.lineNumber,
|
|
237
|
+
result.columnNumber
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
result.lineNumber = mapped.line;
|
|
241
|
+
result.columnNumber = mapped.column;
|
|
424
242
|
}
|
|
425
243
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
244
|
+
const block = blockInfo(error);
|
|
245
|
+
|
|
246
|
+
if (
|
|
247
|
+
block &&
|
|
248
|
+
(
|
|
249
|
+
result.lineNumber == null ||
|
|
250
|
+
result.columnNumber == null ||
|
|
251
|
+
!result.fileName
|
|
252
|
+
)
|
|
253
|
+
) {
|
|
254
|
+
result.fileName ||= block.path || runPath || null;
|
|
255
|
+
result.lineNumber ??= block.line;
|
|
256
|
+
result.columnNumber ??= block.col;
|
|
257
|
+
result.label = block.desc;
|
|
432
258
|
}
|
|
433
259
|
|
|
434
260
|
Lilact.error = result;
|
|
@@ -444,37 +270,35 @@ function escapeHtml(value) {
|
|
|
444
270
|
.replaceAll("'", "'");
|
|
445
271
|
}
|
|
446
272
|
|
|
447
|
-
function sourceExcerpt(module,
|
|
448
|
-
if (!module || !Number.isFinite(
|
|
449
|
-
return null;
|
|
450
|
-
}
|
|
273
|
+
function sourceExcerpt(module, line) {
|
|
274
|
+
if (!module || !Number.isFinite(line)) return null;
|
|
451
275
|
|
|
452
276
|
const lines = String(module.code ?? "").split(/\r?\n/);
|
|
453
|
-
const before = lines[zeroBasedLine - 1] ?? "";
|
|
454
|
-
const current = lines[zeroBasedLine] ?? "";
|
|
455
|
-
const after = lines[zeroBasedLine + 1] ?? "";
|
|
456
277
|
|
|
457
|
-
return {
|
|
278
|
+
return {
|
|
279
|
+
before: lines[line - 1] ?? "",
|
|
280
|
+
current: lines[line] ?? "",
|
|
281
|
+
after: lines[line + 1] ?? "",
|
|
282
|
+
};
|
|
458
283
|
}
|
|
459
284
|
|
|
460
|
-
/**
|
|
461
|
-
* Displays an unhandled error.
|
|
462
|
-
*/
|
|
463
285
|
export function globalErrorHandler(eventOrError) {
|
|
464
|
-
const
|
|
286
|
+
const value =
|
|
465
287
|
eventOrError?.error instanceof Error
|
|
466
288
|
? eventOrError.error
|
|
467
289
|
: eventOrError?.reason !== undefined
|
|
468
290
|
? eventOrError.reason
|
|
469
291
|
: eventOrError;
|
|
470
292
|
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
null
|
|
293
|
+
const error = traceError(
|
|
294
|
+
value,
|
|
295
|
+
eventOrError?.fileName || null
|
|
296
|
+
);
|
|
474
297
|
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
298
|
+
const excerpt = sourceExcerpt(
|
|
299
|
+
required_scripts[error.fileName],
|
|
300
|
+
error.lineNumber
|
|
301
|
+
);
|
|
478
302
|
|
|
479
303
|
const className = css(`
|
|
480
304
|
background: linear-gradient(135deg, #fff2f2d4, #ffffffd4);
|
|
@@ -501,26 +325,24 @@ export function globalErrorHandler(eventOrError) {
|
|
|
501
325
|
const dialog = document.createElement("dialog");
|
|
502
326
|
dialog.className = className;
|
|
503
327
|
|
|
504
|
-
const location =
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
: "";
|
|
328
|
+
const location = error.fileName
|
|
329
|
+
? `At ${escapeHtml(error.fileName)}`
|
|
330
|
+
: "";
|
|
508
331
|
|
|
509
|
-
const line =
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
: "";
|
|
332
|
+
const line = Number.isFinite(error.lineNumber)
|
|
333
|
+
? `: Line ${error.lineNumber + 1}`
|
|
334
|
+
: "";
|
|
513
335
|
|
|
514
336
|
const componentStack =
|
|
515
|
-
|
|
516
|
-
|
|
337
|
+
error._error?.componentStackLog ||
|
|
338
|
+
error._error?.componentStack ||
|
|
517
339
|
"";
|
|
518
340
|
|
|
519
341
|
dialog.innerHTML = `
|
|
520
342
|
<h3><red>Error!</red></h3>
|
|
521
343
|
<b>${location}${line}</b><br><br>
|
|
522
|
-
<b>${escapeHtml(
|
|
523
|
-
<span>${escapeHtml(
|
|
344
|
+
<b>${escapeHtml(error.name)}</b>:
|
|
345
|
+
<span>${escapeHtml(error.message)}</span>
|
|
524
346
|
<br><br>
|
|
525
347
|
|
|
526
348
|
${
|
|
@@ -556,21 +378,14 @@ export function globalErrorHandler(eventOrError) {
|
|
|
556
378
|
dialog.setAttribute("open", "");
|
|
557
379
|
}
|
|
558
380
|
|
|
559
|
-
return
|
|
381
|
+
return error;
|
|
560
382
|
}
|
|
561
383
|
|
|
562
|
-
/**
|
|
563
|
-
* Registers the source location of an injected Lilact block.
|
|
564
|
-
*/
|
|
565
384
|
export function scanBlockLabels(code, path) {
|
|
566
|
-
const
|
|
385
|
+
for (const match of String(code).matchAll(
|
|
567
386
|
/LILACTBLOCK(\d+):(\d+),(\d+):([^*]+)\*\//gm
|
|
568
|
-
)
|
|
569
|
-
|
|
570
|
-
for (const match of labels) {
|
|
571
|
-
const id = match[1];
|
|
572
|
-
|
|
573
|
-
Lilact.blocks_info.labels[id] = {
|
|
387
|
+
)) {
|
|
388
|
+
Lilact.blocks_info.labels[match[1]] = {
|
|
574
389
|
path,
|
|
575
390
|
line: Number(match[2]),
|
|
576
391
|
col: Number(match[3]),
|
package/src/expscan.js
CHANGED
|
@@ -91,7 +91,7 @@ export function labeler(custom_words, x)
|
|
|
91
91
|
if(x.type==='comment') return 'C';
|
|
92
92
|
if(x.type==='regexp') return 'R';
|
|
93
93
|
if(x.type==='js') return 'J';
|
|
94
|
-
if(x.type==='
|
|
94
|
+
if(x.type==='parenthesis') return 'P';
|
|
95
95
|
if(x.type==='string') return 'S';
|
|
96
96
|
if(x.type==='xml') return 'X';
|
|
97
97
|
}
|