sibujs 4.6.0 → 4.8.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/browser.cjs +62 -8
- package/dist/browser.d.cts +23 -0
- package/dist/browser.d.ts +23 -0
- package/dist/browser.js +6 -5
- package/dist/build.cjs +2388 -1004
- package/dist/build.d.cts +147 -44
- package/dist/build.d.ts +147 -44
- package/dist/build.js +1410 -564
- package/dist/cdn.dev.global.js +14 -12
- package/dist/cdn.full.dev.global.js +15 -13
- package/dist/cdn.full.global.js +14 -12
- package/dist/cdn.global.js +12 -10
- package/dist/chunk-3ACAAQIN.js +224 -0
- package/dist/{chunk-7NCARGJW.js → chunk-44MTL7ED.js} +6 -6
- package/dist/{chunk-BAAG6ZTI.js → chunk-4WMSTZ7J.js} +8 -5
- package/dist/{chunk-H3SRKIYX.js → chunk-62BDYGAG.js} +8 -0
- package/dist/{chunk-DKGBBKOF.js → chunk-C5PEWEGH.js} +20 -5
- package/dist/{chunk-3ISI6ACU.js → chunk-C7AA2CZX.js} +1 -1
- package/dist/{chunk-UZQ6ALFS.js → chunk-CZPRSWSS.js} +1 -1
- package/dist/{chunk-D33YTSX5.js → chunk-DSID757X.js} +5 -4
- package/dist/{chunk-OXUY2A6L.js → chunk-EGUQLBHE.js} +22 -8
- package/dist/{chunk-2INLLLMZ.js → chunk-EXXSN3BW.js} +202 -26
- package/dist/{chunk-HURREPU2.js → chunk-FC6KCJSA.js} +87 -150
- package/dist/{chunk-HYXDKS4N.js → chunk-GSGNX35Q.js} +5 -5
- package/dist/{chunk-7GQCWFOE.js → chunk-J3YQ457H.js} +171 -85
- package/dist/{chunk-ORMZXBKQ.js → chunk-JUTFX2RM.js} +18 -10
- package/dist/{chunk-QE4TTDU3.js → chunk-KJ3UKABJ.js} +12 -11
- package/dist/{chunk-XRRZKZYX.js → chunk-LI4W3U6C.js} +1 -1
- package/dist/{chunk-47M47FOM.js → chunk-O6TRVMJI.js} +58 -6
- package/dist/{chunk-JSXPZCET.js → chunk-Q5J2LVKH.js} +1 -1
- package/dist/{chunk-5MT6SJ3P.js → chunk-QGMSESDD.js} +10 -5
- package/dist/{chunk-AIF3Z2T7.js → chunk-RGLPEBDE.js} +13 -10
- package/dist/{chunk-5Q4R7HCL.js → chunk-TQQUN4WR.js} +11 -2
- package/dist/{chunk-PK6FK2G2.js → chunk-UCNP3HVM.js} +183 -30
- package/dist/{chunk-XC4MEKGA.js → chunk-V3LHZSU5.js} +8 -2
- package/dist/{chunk-VVWPJ543.js → chunk-VWT3VXPL.js} +55 -20
- package/dist/{chunk-SXXVZMKZ.js → chunk-ZVLHNEEL.js} +17 -35
- package/dist/{contracts-DRIuclVT.d.cts → contracts-CLqzJnOV.d.ts} +28 -17
- package/dist/{contracts-DRIuclVT.d.ts → contracts-CTOJXu-x.d.cts} +28 -17
- package/dist/{customElement-MmInOW1U.d.ts → customElement-pYDKUzWl.d.cts} +11 -3
- package/dist/{customElement-MmInOW1U.d.cts → customElement-pYDKUzWl.d.ts} +11 -3
- package/dist/data.cjs +205 -39
- package/dist/data.d.cts +119 -3
- package/dist/data.d.ts +119 -3
- package/dist/data.js +6 -6
- package/dist/devtools.cjs +18 -5
- package/dist/devtools.js +5 -5
- package/dist/ecosystem.cjs +462 -58
- package/dist/ecosystem.d.cts +2 -1
- package/dist/ecosystem.d.ts +2 -1
- package/dist/ecosystem.js +9 -8
- package/dist/extras.cjs +852 -296
- package/dist/extras.d.cts +5 -4
- package/dist/extras.d.ts +5 -4
- package/dist/extras.js +24 -23
- package/dist/index.cjs +721 -176
- package/dist/index.d.cts +220 -169
- package/dist/index.d.ts +220 -169
- package/dist/index.js +16 -12
- package/dist/motion.cjs +12 -4
- package/dist/motion.js +3 -3
- package/dist/patterns.cjs +37 -21
- package/dist/patterns.d.cts +2 -1
- package/dist/patterns.d.ts +2 -1
- package/dist/patterns.js +6 -6
- package/dist/performance.cjs +48 -6
- package/dist/performance.d.cts +12 -2
- package/dist/performance.d.ts +12 -2
- package/dist/performance.js +8 -6
- package/dist/plugins.cjs +672 -261
- package/dist/plugins.d.cts +131 -13
- package/dist/plugins.d.ts +131 -13
- package/dist/plugins.js +83 -47
- package/dist/{ssr-XOTUASDO.js → ssr-5OWAH3U2.js} +4 -2
- package/dist/{ssr-Bli9XRW5.d.cts → ssr-C8hgIAw7.d.cts} +6 -0
- package/dist/{ssr-Bli9XRW5.d.ts → ssr-C8hgIAw7.d.ts} +6 -0
- package/dist/ssr.cjs +509 -142
- package/dist/ssr.d.cts +55 -5
- package/dist/ssr.d.ts +55 -5
- package/dist/ssr.js +11 -9
- package/dist/{tagFactory-DFstCLQV.d.cts → tagFactory-8qL9LCIx.d.cts} +58 -19
- package/dist/{tagFactory-DkaNVUNV.d.ts → tagFactory-BL2fymez.d.ts} +58 -19
- package/dist/testing.cjs +17 -4
- package/dist/testing.js +4 -4
- package/dist/types-CJFViL6Q.d.cts +26 -0
- package/dist/types-CJFViL6Q.d.ts +26 -0
- package/dist/ui.cjs +635 -254
- package/dist/ui.d.cts +3 -2
- package/dist/ui.d.ts +3 -2
- package/dist/ui.js +9 -8
- package/dist/widgets.cjs +22 -14
- package/dist/widgets.js +7 -7
- package/package.json +8 -5
package/dist/build.cjs
CHANGED
|
@@ -59,8 +59,1310 @@ __export(build_exports, {
|
|
|
59
59
|
});
|
|
60
60
|
module.exports = __toCommonJS(build_exports);
|
|
61
61
|
|
|
62
|
-
// src/build/
|
|
62
|
+
// src/build/sourceEdit.ts
|
|
63
|
+
function isLineBreak(c) {
|
|
64
|
+
return c === 10 || c === 13 || c === 8232 || c === 8233;
|
|
65
|
+
}
|
|
66
|
+
function lineBreaksIn(code2, start, end) {
|
|
67
|
+
let out = "";
|
|
68
|
+
for (let i2 = start; i2 < end; i2++) {
|
|
69
|
+
if (isLineBreak(code2.charCodeAt(i2))) out += code2[i2];
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
var LINE_SEPARATOR = String.fromCharCode(8232);
|
|
74
|
+
var PARAGRAPH_SEPARATOR = String.fromCharCode(8233);
|
|
75
|
+
function jsStringLiteral(value) {
|
|
76
|
+
const json = JSON.stringify(value);
|
|
77
|
+
if (!json.includes(LINE_SEPARATOR) && !json.includes(PARAGRAPH_SEPARATOR)) return json;
|
|
78
|
+
const bs = "\\";
|
|
79
|
+
return json.split(LINE_SEPARATOR).join(`${bs}u2028`).split(PARAGRAPH_SEPARATOR).join(`${bs}u2029`);
|
|
80
|
+
}
|
|
81
|
+
function normalizeEdits(edits) {
|
|
82
|
+
const sorted = edits.map((edit, order) => ({ edit, order })).sort(
|
|
83
|
+
(a2, b2) => a2.edit.start - b2.edit.start || a2.edit.end - a2.edit.start - (b2.edit.end - b2.edit.start) || a2.order - b2.order
|
|
84
|
+
).map((x) => x.edit);
|
|
85
|
+
for (let i2 = 1; i2 < sorted.length; i2++) {
|
|
86
|
+
if (sorted[i2].start < sorted[i2 - 1].end) return null;
|
|
87
|
+
}
|
|
88
|
+
return sorted;
|
|
89
|
+
}
|
|
90
|
+
function applyEdits(code2, edits, append = "") {
|
|
91
|
+
let out = "";
|
|
92
|
+
let pos = 0;
|
|
93
|
+
for (const edit of edits) {
|
|
94
|
+
out += code2.slice(pos, edit.start) + edit.text;
|
|
95
|
+
pos = edit.end;
|
|
96
|
+
}
|
|
97
|
+
return out + code2.slice(pos) + append;
|
|
98
|
+
}
|
|
99
|
+
var BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
100
|
+
function vlq(value) {
|
|
101
|
+
let v = value < 0 ? -value << 1 | 1 : value << 1;
|
|
102
|
+
let out = "";
|
|
103
|
+
do {
|
|
104
|
+
let digit = v & 31;
|
|
105
|
+
v >>>= 5;
|
|
106
|
+
if (v > 0) digit |= 32;
|
|
107
|
+
out += BASE64[digit];
|
|
108
|
+
} while (v > 0);
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
function isWordStart(c) {
|
|
112
|
+
return c >= 97 && c <= 122 || c >= 65 && c <= 90 || c === 95 || c === 36 || c > 127 || c >= 48 && c <= 57;
|
|
113
|
+
}
|
|
114
|
+
function editsSourceMap(code2, edits, append, source2) {
|
|
115
|
+
const lineStarts = [0];
|
|
116
|
+
for (let i2 = 0; i2 < code2.length; i2++) if (code2.charCodeAt(i2) === 10) lineStarts.push(i2 + 1);
|
|
117
|
+
const origLine = (offset) => {
|
|
118
|
+
let lo = 0;
|
|
119
|
+
let hi = lineStarts.length - 1;
|
|
120
|
+
while (lo < hi) {
|
|
121
|
+
const mid = lo + hi + 1 >> 1;
|
|
122
|
+
if (lineStarts[mid] <= offset) lo = mid;
|
|
123
|
+
else hi = mid - 1;
|
|
124
|
+
}
|
|
125
|
+
return lo;
|
|
126
|
+
};
|
|
127
|
+
const lines = [[]];
|
|
128
|
+
let col2 = 0;
|
|
129
|
+
const mark2 = (offset) => {
|
|
130
|
+
const line2 = lines[lines.length - 1];
|
|
131
|
+
const last = line2[line2.length - 1];
|
|
132
|
+
if (last && last[0] === col2) return;
|
|
133
|
+
const ol2 = origLine(offset);
|
|
134
|
+
line2.push([col2, ol2, offset - lineStarts[ol2]]);
|
|
135
|
+
};
|
|
136
|
+
const newline = () => {
|
|
137
|
+
lines.push([]);
|
|
138
|
+
col2 = 0;
|
|
139
|
+
};
|
|
140
|
+
const emitOriginal = (from, to) => {
|
|
141
|
+
for (let i2 = from; i2 < to; i2++) {
|
|
142
|
+
const c = code2.charCodeAt(i2);
|
|
143
|
+
if (c === 10) {
|
|
144
|
+
newline();
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (i2 === from || col2 === 0 || isWordStart(c) && !isWordStart(code2.charCodeAt(i2 - 1))) mark2(i2);
|
|
148
|
+
col2++;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
const emitReplacement = (edit) => {
|
|
152
|
+
let origOffset = edit.start;
|
|
153
|
+
let pending = true;
|
|
154
|
+
for (let i2 = 0; i2 < edit.text.length; i2++) {
|
|
155
|
+
if (edit.text.charCodeAt(i2) === 10) {
|
|
156
|
+
newline();
|
|
157
|
+
const nl = code2.indexOf("\n", origOffset);
|
|
158
|
+
if (nl !== -1 && nl < edit.end) {
|
|
159
|
+
origOffset = nl + 1;
|
|
160
|
+
pending = true;
|
|
161
|
+
} else {
|
|
162
|
+
pending = false;
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (pending) {
|
|
167
|
+
mark2(origOffset);
|
|
168
|
+
pending = false;
|
|
169
|
+
}
|
|
170
|
+
col2++;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
let pos = 0;
|
|
174
|
+
for (const edit of edits) {
|
|
175
|
+
emitOriginal(pos, edit.start);
|
|
176
|
+
emitReplacement(edit);
|
|
177
|
+
pos = edit.end;
|
|
178
|
+
}
|
|
179
|
+
emitOriginal(pos, code2.length);
|
|
180
|
+
for (let i2 = 0; i2 < append.length; i2++) {
|
|
181
|
+
if (append.charCodeAt(i2) === 10) newline();
|
|
182
|
+
}
|
|
183
|
+
let prevLine = 0;
|
|
184
|
+
let prevCol = 0;
|
|
185
|
+
let prevSource = 0;
|
|
186
|
+
const mappings = lines.map((segments) => {
|
|
187
|
+
let prevGen = 0;
|
|
188
|
+
return segments.map(([gen, ol2, oc]) => {
|
|
189
|
+
const s2 = vlq(gen - prevGen) + vlq(0 - prevSource) + vlq(ol2 - prevLine) + vlq(oc - prevCol);
|
|
190
|
+
prevGen = gen;
|
|
191
|
+
prevSource = 0;
|
|
192
|
+
prevLine = ol2;
|
|
193
|
+
prevCol = oc;
|
|
194
|
+
return s2;
|
|
195
|
+
}).join(",");
|
|
196
|
+
}).join(";");
|
|
197
|
+
return { version: 3, sources: [source2], sourcesContent: [code2], names: [], mappings };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/build/sourceScan.ts
|
|
201
|
+
var REGEX_AFTER_KEYWORD = /* @__PURE__ */ new Set([
|
|
202
|
+
"return",
|
|
203
|
+
"typeof",
|
|
204
|
+
"instanceof",
|
|
205
|
+
"in",
|
|
206
|
+
"of",
|
|
207
|
+
"new",
|
|
208
|
+
"delete",
|
|
209
|
+
"void",
|
|
210
|
+
"throw",
|
|
211
|
+
"case",
|
|
212
|
+
"do",
|
|
213
|
+
"else",
|
|
214
|
+
"yield",
|
|
215
|
+
"await"
|
|
216
|
+
]);
|
|
217
|
+
function isIdentStart(c) {
|
|
218
|
+
return c >= 97 && c <= 122 || c >= 65 && c <= 90 || c === 95 || c === 36 || c > 127;
|
|
219
|
+
}
|
|
220
|
+
function isIdentPart(c) {
|
|
221
|
+
return isIdentStart(c) || c >= 48 && c <= 57;
|
|
222
|
+
}
|
|
223
|
+
function isDigit(c) {
|
|
224
|
+
return c >= 48 && c <= 57;
|
|
225
|
+
}
|
|
226
|
+
var ScanError = class extends Error {
|
|
227
|
+
};
|
|
228
|
+
var scanStats = { tokenize: 0 };
|
|
229
|
+
function tokenize(code2) {
|
|
230
|
+
scanStats.tokenize++;
|
|
231
|
+
let pos = 0;
|
|
232
|
+
const len = code2.length;
|
|
233
|
+
if (code2.startsWith("#!")) {
|
|
234
|
+
const nl = code2.indexOf("\n");
|
|
235
|
+
pos = nl === -1 ? len : nl;
|
|
236
|
+
}
|
|
237
|
+
function regexAllowed(prev) {
|
|
238
|
+
if (!prev) return true;
|
|
239
|
+
switch (prev.type) {
|
|
240
|
+
case "number":
|
|
241
|
+
case "string":
|
|
242
|
+
case "regex":
|
|
243
|
+
case "template":
|
|
244
|
+
return false;
|
|
245
|
+
case "ident":
|
|
246
|
+
return REGEX_AFTER_KEYWORD.has(prev.value);
|
|
247
|
+
case "punct":
|
|
248
|
+
return prev.value !== ")" && prev.value !== "]";
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function skipTrivia() {
|
|
252
|
+
while (pos < len) {
|
|
253
|
+
const c = code2.charCodeAt(pos);
|
|
254
|
+
if (c === 32 || c === 9 || c === 10 || c === 13 || c === 11 || c === 12 || c === 160 || c === 65279) {
|
|
255
|
+
pos++;
|
|
256
|
+
} else if (c === 8232 || c === 8233) {
|
|
257
|
+
pos++;
|
|
258
|
+
} else if (c === 47 && code2.charCodeAt(pos + 1) === 47) {
|
|
259
|
+
pos += 2;
|
|
260
|
+
while (pos < len) {
|
|
261
|
+
const d = code2.charCodeAt(pos);
|
|
262
|
+
if (d === 10 || d === 13 || d === 8232 || d === 8233) break;
|
|
263
|
+
pos++;
|
|
264
|
+
}
|
|
265
|
+
} else if (c === 47 && code2.charCodeAt(pos + 1) === 42) {
|
|
266
|
+
const end = code2.indexOf("*/", pos + 2);
|
|
267
|
+
if (end === -1) throw new ScanError("unterminated comment");
|
|
268
|
+
pos = end + 2;
|
|
269
|
+
} else {
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function readString() {
|
|
275
|
+
const start = pos;
|
|
276
|
+
const quote2 = code2[pos];
|
|
277
|
+
pos++;
|
|
278
|
+
while (pos < len) {
|
|
279
|
+
const c = code2[pos];
|
|
280
|
+
if (c === "\\") {
|
|
281
|
+
pos += 2;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (c === quote2) {
|
|
285
|
+
pos++;
|
|
286
|
+
return { type: "string", start, end: pos };
|
|
287
|
+
}
|
|
288
|
+
if (c === "\n" || c === "\r") throw new ScanError("line break in string");
|
|
289
|
+
pos++;
|
|
290
|
+
}
|
|
291
|
+
throw new ScanError("unterminated string");
|
|
292
|
+
}
|
|
293
|
+
function readRegex() {
|
|
294
|
+
const start = pos;
|
|
295
|
+
pos++;
|
|
296
|
+
let inClass = false;
|
|
297
|
+
while (pos < len) {
|
|
298
|
+
const c = code2[pos];
|
|
299
|
+
if (c === "\\") {
|
|
300
|
+
pos += 2;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
if (c === "\n" || c === "\r") throw new ScanError("line break in regex");
|
|
304
|
+
if (inClass) {
|
|
305
|
+
if (c === "]") inClass = false;
|
|
306
|
+
} else if (c === "[") {
|
|
307
|
+
inClass = true;
|
|
308
|
+
} else if (c === "/") {
|
|
309
|
+
pos++;
|
|
310
|
+
while (pos < len && isIdentPart(code2.charCodeAt(pos))) pos++;
|
|
311
|
+
return { type: "regex", start, end: pos };
|
|
312
|
+
}
|
|
313
|
+
pos++;
|
|
314
|
+
}
|
|
315
|
+
throw new ScanError("unterminated regex");
|
|
316
|
+
}
|
|
317
|
+
function readTemplate() {
|
|
318
|
+
const start = pos;
|
|
319
|
+
pos++;
|
|
320
|
+
const quasis = [];
|
|
321
|
+
const exprs = [];
|
|
322
|
+
let quasiStart = pos;
|
|
323
|
+
while (pos < len) {
|
|
324
|
+
const c = code2[pos];
|
|
325
|
+
if (c === "\\") {
|
|
326
|
+
pos += 2;
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (c === "`") {
|
|
330
|
+
quasis.push({ start: quasiStart, end: pos });
|
|
331
|
+
pos++;
|
|
332
|
+
return { type: "template", start, end: pos, quasis, exprs };
|
|
333
|
+
}
|
|
334
|
+
if (c === "$" && code2[pos + 1] === "{") {
|
|
335
|
+
quasis.push({ start: quasiStart, end: pos });
|
|
336
|
+
pos += 2;
|
|
337
|
+
const exprStart = pos;
|
|
338
|
+
const tokens = readList(true);
|
|
339
|
+
exprs.push({ start: exprStart, end: pos, tokens });
|
|
340
|
+
pos++;
|
|
341
|
+
quasiStart = pos;
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
pos++;
|
|
345
|
+
}
|
|
346
|
+
throw new ScanError("unterminated template");
|
|
347
|
+
}
|
|
348
|
+
function readList(inTemplateExpr) {
|
|
349
|
+
const tokens = [];
|
|
350
|
+
let depth = 0;
|
|
351
|
+
for (; ; ) {
|
|
352
|
+
skipTrivia();
|
|
353
|
+
if (pos >= len) {
|
|
354
|
+
if (inTemplateExpr || depth !== 0) throw new ScanError("unexpected end of input");
|
|
355
|
+
return tokens;
|
|
356
|
+
}
|
|
357
|
+
const c = code2.charCodeAt(pos);
|
|
358
|
+
const prev = tokens[tokens.length - 1];
|
|
359
|
+
if (c === 34 || c === 39) {
|
|
360
|
+
tokens.push(readString());
|
|
361
|
+
} else if (c === 96) {
|
|
362
|
+
tokens.push(readTemplate());
|
|
363
|
+
} else if (isIdentStart(c) || c === 92) {
|
|
364
|
+
const start = pos;
|
|
365
|
+
pos++;
|
|
366
|
+
while (pos < len) {
|
|
367
|
+
const d = code2.charCodeAt(pos);
|
|
368
|
+
if (isIdentPart(d)) pos++;
|
|
369
|
+
else if (d === 92) pos += 2;
|
|
370
|
+
else break;
|
|
371
|
+
}
|
|
372
|
+
tokens.push({ type: "ident", start, end: pos, value: code2.slice(start, pos) });
|
|
373
|
+
} else if (isDigit(c) || c === 46 && isDigit(code2.charCodeAt(pos + 1))) {
|
|
374
|
+
const start = pos;
|
|
375
|
+
pos++;
|
|
376
|
+
while (pos < len) {
|
|
377
|
+
const d = code2.charCodeAt(pos);
|
|
378
|
+
if (isIdentPart(d) || d === 46) pos++;
|
|
379
|
+
else break;
|
|
380
|
+
}
|
|
381
|
+
tokens.push({ type: "number", start, end: pos, value: code2.slice(start, pos) });
|
|
382
|
+
} else if (c === 47 && regexAllowed(prev)) {
|
|
383
|
+
tokens.push(readRegex());
|
|
384
|
+
} else {
|
|
385
|
+
const start = pos;
|
|
386
|
+
let value = code2[pos];
|
|
387
|
+
if (code2.startsWith("...", pos)) value = "...";
|
|
388
|
+
else if (code2.startsWith("?.", pos) && !isDigit(code2.charCodeAt(pos + 2))) value = "?.";
|
|
389
|
+
else if (code2.startsWith("=>", pos)) value = "=>";
|
|
390
|
+
pos += value.length;
|
|
391
|
+
if (value === "{") {
|
|
392
|
+
depth++;
|
|
393
|
+
} else if (value === "}") {
|
|
394
|
+
if (depth === 0) {
|
|
395
|
+
if (inTemplateExpr) {
|
|
396
|
+
pos = start;
|
|
397
|
+
return tokens;
|
|
398
|
+
}
|
|
399
|
+
throw new ScanError("unbalanced brace");
|
|
400
|
+
}
|
|
401
|
+
depth--;
|
|
402
|
+
}
|
|
403
|
+
tokens.push({ type: "punct", start, end: pos, value });
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
return readList(false);
|
|
409
|
+
} catch (err) {
|
|
410
|
+
if (err instanceof ScanError) return null;
|
|
411
|
+
throw err;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
function cookEscapes(raw) {
|
|
415
|
+
let out = "";
|
|
416
|
+
let i2 = 0;
|
|
417
|
+
const n = raw.length;
|
|
418
|
+
while (i2 < n) {
|
|
419
|
+
const ch = raw[i2];
|
|
420
|
+
if (ch === "\r") {
|
|
421
|
+
out += "\n";
|
|
422
|
+
i2 += raw[i2 + 1] === "\n" ? 2 : 1;
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (ch !== "\\") {
|
|
426
|
+
out += ch;
|
|
427
|
+
i2++;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
const e = raw[i2 + 1];
|
|
431
|
+
i2 += 2;
|
|
432
|
+
switch (e) {
|
|
433
|
+
case "n":
|
|
434
|
+
out += "\n";
|
|
435
|
+
break;
|
|
436
|
+
case "t":
|
|
437
|
+
out += " ";
|
|
438
|
+
break;
|
|
439
|
+
case "r":
|
|
440
|
+
out += "\r";
|
|
441
|
+
break;
|
|
442
|
+
case "b":
|
|
443
|
+
out += "\b";
|
|
444
|
+
break;
|
|
445
|
+
case "f":
|
|
446
|
+
out += "\f";
|
|
447
|
+
break;
|
|
448
|
+
case "v":
|
|
449
|
+
out += "\v";
|
|
450
|
+
break;
|
|
451
|
+
case "0":
|
|
452
|
+
if (i2 < n && isDigit(raw.charCodeAt(i2))) return null;
|
|
453
|
+
out += "\0";
|
|
454
|
+
break;
|
|
455
|
+
case "x": {
|
|
456
|
+
const hex = raw.slice(i2, i2 + 2);
|
|
457
|
+
if (!/^[0-9a-fA-F]{2}$/.test(hex)) return null;
|
|
458
|
+
out += String.fromCharCode(Number.parseInt(hex, 16));
|
|
459
|
+
i2 += 2;
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
case "u": {
|
|
463
|
+
if (raw[i2] === "{") {
|
|
464
|
+
const close = raw.indexOf("}", i2);
|
|
465
|
+
if (close === -1) return null;
|
|
466
|
+
const hex = raw.slice(i2 + 1, close);
|
|
467
|
+
if (!/^[0-9a-fA-F]+$/.test(hex)) return null;
|
|
468
|
+
const cp = Number.parseInt(hex, 16);
|
|
469
|
+
if (cp > 1114111) return null;
|
|
470
|
+
out += String.fromCodePoint(cp);
|
|
471
|
+
i2 = close + 1;
|
|
472
|
+
} else {
|
|
473
|
+
const hex = raw.slice(i2, i2 + 4);
|
|
474
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
|
|
475
|
+
out += String.fromCharCode(Number.parseInt(hex, 16));
|
|
476
|
+
i2 += 4;
|
|
477
|
+
}
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
case "\r":
|
|
481
|
+
if (raw[i2] === "\n") i2++;
|
|
482
|
+
break;
|
|
483
|
+
case "\n":
|
|
484
|
+
case "\u2028":
|
|
485
|
+
case "\u2029":
|
|
486
|
+
break;
|
|
487
|
+
case void 0:
|
|
488
|
+
return null;
|
|
489
|
+
default:
|
|
490
|
+
if (isDigit(e.charCodeAt(0))) return null;
|
|
491
|
+
out += e;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
return out;
|
|
495
|
+
}
|
|
496
|
+
function stringTokenValue(code2, tok) {
|
|
497
|
+
if (tok.type !== "string") return null;
|
|
498
|
+
return cookEscapes(code2.slice(tok.start + 1, tok.end - 1));
|
|
499
|
+
}
|
|
500
|
+
function collectImports(code2, tokens) {
|
|
501
|
+
const decls = [];
|
|
502
|
+
for (let i2 = 0; i2 < tokens.length; i2++) {
|
|
503
|
+
const tok = tokens[i2];
|
|
504
|
+
if (tok.type !== "ident" || tok.value !== "import") continue;
|
|
505
|
+
const prev = tokens[i2 - 1];
|
|
506
|
+
if (prev && prev.type === "punct" && (prev.value === "." || prev.value === "?.")) continue;
|
|
507
|
+
const next = tokens[i2 + 1];
|
|
508
|
+
if (!next) return null;
|
|
509
|
+
if (next.type === "punct" && (next.value === "(" || next.value === ".")) continue;
|
|
510
|
+
let j = i2 + 1;
|
|
511
|
+
const bindings = [];
|
|
512
|
+
let typeOnly = false;
|
|
513
|
+
if (next.type === "string") {
|
|
514
|
+
const source3 = stringTokenValue(code2, next);
|
|
515
|
+
if (source3 === null) return null;
|
|
516
|
+
let end2 = next.end;
|
|
517
|
+
const semi = tokens[j + 1];
|
|
518
|
+
if (semi && semi.type === "punct" && semi.value === ";") end2 = semi.end;
|
|
519
|
+
decls.push({ source: source3, bindings, start: tok.start, end: end2 });
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
const at = (k) => tokens[k];
|
|
523
|
+
const isPunct = (k, v) => {
|
|
524
|
+
const t = at(k);
|
|
525
|
+
return !!t && t.type === "punct" && t.value === v;
|
|
526
|
+
};
|
|
527
|
+
const isIdent = (k, v) => {
|
|
528
|
+
const t = at(k);
|
|
529
|
+
return !!t && t.type === "ident" && (v === void 0 || t.value === v);
|
|
530
|
+
};
|
|
531
|
+
if (isIdent(j, "type") && !isIdent(j + 1, "from") && !isPunct(j + 1, ",")) {
|
|
532
|
+
typeOnly = true;
|
|
533
|
+
j++;
|
|
534
|
+
}
|
|
535
|
+
if (isIdent(j) && !isIdent(j, "from")) {
|
|
536
|
+
bindings.push({ imported: "default", local: at(j).value });
|
|
537
|
+
j++;
|
|
538
|
+
if (isPunct(j, ",")) j++;
|
|
539
|
+
}
|
|
540
|
+
if (isPunct(j, "*")) {
|
|
541
|
+
if (!isIdent(j + 1, "as") || !isIdent(j + 2)) return null;
|
|
542
|
+
bindings.push({ imported: "*", local: at(j + 2).value });
|
|
543
|
+
j += 3;
|
|
544
|
+
} else if (isPunct(j, "{")) {
|
|
545
|
+
j++;
|
|
546
|
+
while (!isPunct(j, "}")) {
|
|
547
|
+
const t = at(j);
|
|
548
|
+
if (!t) return null;
|
|
549
|
+
let specTypeOnly = false;
|
|
550
|
+
if (isIdent(j, "type") && (isIdent(j + 1) || at(j + 1)?.type === "string") && !isIdent(j + 1, "as")) {
|
|
551
|
+
specTypeOnly = true;
|
|
552
|
+
j++;
|
|
553
|
+
}
|
|
554
|
+
const nameTok = at(j);
|
|
555
|
+
let imported = null;
|
|
556
|
+
if (nameTok?.type === "ident") imported = nameTok.value;
|
|
557
|
+
else if (nameTok?.type === "string") imported = stringTokenValue(code2, nameTok);
|
|
558
|
+
if (imported === null) return null;
|
|
559
|
+
j++;
|
|
560
|
+
let local = imported;
|
|
561
|
+
if (isIdent(j, "as")) {
|
|
562
|
+
if (!isIdent(j + 1)) return null;
|
|
563
|
+
local = at(j + 1).value;
|
|
564
|
+
j += 2;
|
|
565
|
+
}
|
|
566
|
+
if (!specTypeOnly) bindings.push({ imported, local });
|
|
567
|
+
if (isPunct(j, ",")) j++;
|
|
568
|
+
else if (!isPunct(j, "}")) return null;
|
|
569
|
+
}
|
|
570
|
+
j++;
|
|
571
|
+
}
|
|
572
|
+
if (!isIdent(j, "from")) return null;
|
|
573
|
+
const srcTok = at(j + 1);
|
|
574
|
+
if (!srcTok || srcTok.type !== "string") return null;
|
|
575
|
+
const source2 = stringTokenValue(code2, srcTok);
|
|
576
|
+
if (source2 === null) return null;
|
|
577
|
+
let end = srcTok.end;
|
|
578
|
+
j += 2;
|
|
579
|
+
if (isIdent(j, "with") || isIdent(j, "assert")) {
|
|
580
|
+
if (!isPunct(j + 1, "{")) return null;
|
|
581
|
+
let k = j + 2;
|
|
582
|
+
while (at(k) && !isPunct(k, "}")) k++;
|
|
583
|
+
if (!at(k)) return null;
|
|
584
|
+
end = at(k).end;
|
|
585
|
+
j = k + 1;
|
|
586
|
+
}
|
|
587
|
+
if (isPunct(j, ";")) end = at(j).end;
|
|
588
|
+
decls.push({ source: source2, bindings: typeOnly ? [] : bindings, start: tok.start, end });
|
|
589
|
+
i2 = j;
|
|
590
|
+
}
|
|
591
|
+
return decls;
|
|
592
|
+
}
|
|
593
|
+
var SCAN_CACHE_SIZE = 4;
|
|
594
|
+
var scanCache = /* @__PURE__ */ new Map();
|
|
595
|
+
function scanModule(code2) {
|
|
596
|
+
const hit = scanCache.get(code2);
|
|
597
|
+
if (hit !== void 0) return hit;
|
|
598
|
+
const tokens = tokenize(code2);
|
|
599
|
+
const imports = tokens && collectImports(code2, tokens);
|
|
600
|
+
const scan = tokens && imports ? { tokens, imports } : null;
|
|
601
|
+
if (scanCache.size >= SCAN_CACHE_SIZE) scanCache.delete(scanCache.keys().next().value);
|
|
602
|
+
scanCache.set(code2, scan);
|
|
603
|
+
return scan;
|
|
604
|
+
}
|
|
605
|
+
function isSibuSource(source2) {
|
|
606
|
+
return source2 === "sibujs" || source2.startsWith("sibujs/");
|
|
607
|
+
}
|
|
608
|
+
function sibuBindings(imports, mainOnly = false) {
|
|
609
|
+
const out = /* @__PURE__ */ new Map();
|
|
610
|
+
for (const decl of imports) {
|
|
611
|
+
if (mainOnly ? decl.source !== "sibujs" : !isSibuSource(decl.source)) continue;
|
|
612
|
+
for (const b2 of decl.bindings) {
|
|
613
|
+
if (b2.imported === "*" || b2.imported === "default") continue;
|
|
614
|
+
out.set(b2.local, b2.imported);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
return out;
|
|
618
|
+
}
|
|
619
|
+
function forEachBindingRef(tokens, imports, visit) {
|
|
620
|
+
const inImport = (offset) => imports.some((d) => offset >= d.start && offset < d.end);
|
|
621
|
+
const walk = (list) => {
|
|
622
|
+
for (let i2 = 0; i2 < list.length; i2++) {
|
|
623
|
+
const tok = list[i2];
|
|
624
|
+
if (tok.type === "template") {
|
|
625
|
+
for (const e of tok.exprs) walk(e.tokens);
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
if (tok.type !== "ident") continue;
|
|
629
|
+
const prev = list[i2 - 1];
|
|
630
|
+
if (prev && prev.type === "punct" && (prev.value === "." || prev.value === "?." || prev.value === "#")) continue;
|
|
631
|
+
if (inImport(tok.start)) continue;
|
|
632
|
+
visit({ tok, list, index: i2 });
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
walk(tokens);
|
|
636
|
+
}
|
|
637
|
+
var EXPRESSION_KEYWORDS = /* @__PURE__ */ new Set([...REGEX_AFTER_KEYWORD, "default", "extends"]);
|
|
638
|
+
function isLineTerminator(c) {
|
|
639
|
+
return c === 10 || c === 13 || c === 8232 || c === 8233;
|
|
640
|
+
}
|
|
641
|
+
function lineBreakBetween(code2, from, to) {
|
|
642
|
+
for (let i2 = from; i2 < to; i2++) if (isLineTerminator(code2.charCodeAt(i2))) return true;
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
function endsValue(tok) {
|
|
646
|
+
if (!tok) return false;
|
|
647
|
+
switch (tok.type) {
|
|
648
|
+
case "number":
|
|
649
|
+
case "string":
|
|
650
|
+
case "regex":
|
|
651
|
+
case "template":
|
|
652
|
+
return true;
|
|
653
|
+
case "ident":
|
|
654
|
+
return !EXPRESSION_KEYWORDS.has(tok.value);
|
|
655
|
+
case "punct":
|
|
656
|
+
return tok.value === ")" || tok.value === "]";
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
function isDeclarationHead(code2, list, index) {
|
|
660
|
+
const tok = list[index];
|
|
661
|
+
const prev = list[index - 1];
|
|
662
|
+
if (prev?.type === "ident") {
|
|
663
|
+
if (prev.value === "function") return true;
|
|
664
|
+
if (!EXPRESSION_KEYWORDS.has(prev.value) && !lineBreakBetween(code2, prev.end, tok.start)) return true;
|
|
665
|
+
} else if (prev?.type === "punct") {
|
|
666
|
+
const before = list[index - 2];
|
|
667
|
+
if (prev.value === "*" && !endsValue(before) && !(before?.type === "ident" && before.value === "yield"))
|
|
668
|
+
return true;
|
|
669
|
+
if (prev.value === "@") return true;
|
|
670
|
+
}
|
|
671
|
+
let depth = 0;
|
|
672
|
+
let close = -1;
|
|
673
|
+
for (let k = index + 1; k < list.length; k++) {
|
|
674
|
+
const t = list[k];
|
|
675
|
+
if (t.type !== "punct") continue;
|
|
676
|
+
if (t.value === "(") depth++;
|
|
677
|
+
else if (t.value === ")" && --depth === 0) {
|
|
678
|
+
close = k;
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (close === -1) return true;
|
|
683
|
+
const after = list[close + 1];
|
|
684
|
+
if (after?.type !== "punct") return false;
|
|
685
|
+
if (after.value === "{") return true;
|
|
686
|
+
if (after.value === ":") {
|
|
687
|
+
if (!prev) return true;
|
|
688
|
+
if (prev.type === "punct") return ["{", "}", ";", ",", "*"].includes(prev.value);
|
|
689
|
+
return prev.type === "ident" && !EXPRESSION_KEYWORDS.has(prev.value);
|
|
690
|
+
}
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
function bindingUses(code2, scan, names) {
|
|
694
|
+
const shadowed = /* @__PURE__ */ new Set();
|
|
695
|
+
const bound = /* @__PURE__ */ new Map();
|
|
696
|
+
for (const decl of scan.imports) {
|
|
697
|
+
for (const b2 of decl.bindings) bound.set(b2.local, (bound.get(b2.local) ?? 0) + 1);
|
|
698
|
+
}
|
|
699
|
+
for (const name of names) if ((bound.get(name) ?? 0) > 1) shadowed.add(name);
|
|
700
|
+
const calls = [];
|
|
701
|
+
const tagged = [];
|
|
702
|
+
forEachBindingRef(scan.tokens, scan.imports, (ref2) => {
|
|
703
|
+
const { tok, list, index } = ref2;
|
|
704
|
+
if (!names.has(tok.value)) return;
|
|
705
|
+
const next = list[index + 1];
|
|
706
|
+
if (next && next.type === "punct" && next.value === "(") {
|
|
707
|
+
if (isDeclarationHead(code2, list, index)) shadowed.add(tok.value);
|
|
708
|
+
else calls.push(ref2);
|
|
709
|
+
} else if (next && next.type === "template") {
|
|
710
|
+
const prev = list[index - 1];
|
|
711
|
+
if (prev?.type === "punct" && prev.value === "@") shadowed.add(tok.value);
|
|
712
|
+
else tagged.push(ref2);
|
|
713
|
+
} else {
|
|
714
|
+
shadowed.add(tok.value);
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
return {
|
|
718
|
+
calls: calls.filter((r) => !shadowed.has(r.tok.value)),
|
|
719
|
+
tagged: tagged.filter((r) => !shadowed.has(r.tok.value)),
|
|
720
|
+
shadowed
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
function uniquePrefix(code2, base2 = "__sibujs") {
|
|
724
|
+
let prefix = `${base2}$`;
|
|
725
|
+
for (let n = 1; code2.includes(prefix); n++) prefix = `${base2}${n}$`;
|
|
726
|
+
return prefix;
|
|
727
|
+
}
|
|
728
|
+
var PURE_FACTORIES = /* @__PURE__ */ new Set([
|
|
729
|
+
"tagFactory",
|
|
730
|
+
"context",
|
|
731
|
+
"defineComponent",
|
|
732
|
+
"withProps",
|
|
733
|
+
"withDefaults",
|
|
734
|
+
"pure",
|
|
735
|
+
"noSideEffect"
|
|
736
|
+
]);
|
|
737
|
+
var PURE_COMMENT = "/*#__PURE__*/ ";
|
|
738
|
+
function pureAnnotationEdits(code2) {
|
|
739
|
+
if (!code2.includes("sibujs")) return [];
|
|
740
|
+
const scan = scanModule(code2);
|
|
741
|
+
if (!scan) return [];
|
|
742
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
743
|
+
for (const [local, imported] of sibuBindings(scan.imports)) if (PURE_FACTORIES.has(imported)) candidates.add(local);
|
|
744
|
+
if (candidates.size === 0) return [];
|
|
745
|
+
const uses = bindingUses(code2, scan, candidates);
|
|
746
|
+
const unsafe = new Set(uses.shadowed);
|
|
747
|
+
for (const ref2 of uses.tagged) unsafe.add(ref2.tok.value);
|
|
748
|
+
return uses.calls.filter(({ tok }) => {
|
|
749
|
+
if (unsafe.has(tok.value)) return false;
|
|
750
|
+
return !/\/\*\s*[#@]__PURE__\s*\*\/\s*$/.test(code2.slice(Math.max(0, tok.start - 40), tok.start));
|
|
751
|
+
}).map(({ tok }) => ({ start: tok.start, end: tok.start, text: PURE_COMMENT }));
|
|
752
|
+
}
|
|
753
|
+
function injectPureAnnotations(code2) {
|
|
754
|
+
const edits = normalizeEdits(pureAnnotationEdits(code2));
|
|
755
|
+
return edits && edits.length > 0 ? applyEdits(code2, edits) : code2;
|
|
756
|
+
}
|
|
757
|
+
function importsSibu(code2) {
|
|
758
|
+
if (!code2.includes("sibujs")) return false;
|
|
759
|
+
const scan = scanModule(code2);
|
|
760
|
+
return !!scan?.imports.some((d) => isSibuSource(d.source));
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// src/core/dev.ts
|
|
764
|
+
var DEV = typeof __SIBU_DEV__ !== "undefined" ? !!__SIBU_DEV__ : typeof globalThis.__SIBU_DEV__ !== "undefined" ? !!globalThis.__SIBU_DEV__ : (
|
|
765
|
+
// safe default: off in browser, on in test/dev Node
|
|
766
|
+
typeof process !== "undefined" && process.env?.NODE_ENV !== "production"
|
|
767
|
+
);
|
|
768
|
+
function isDev() {
|
|
769
|
+
if (typeof globalThis.__SIBU_DEV__ !== "undefined") return !!globalThis.__SIBU_DEV__;
|
|
770
|
+
if (typeof __SIBU_DEV__ !== "undefined") return !!__SIBU_DEV__;
|
|
771
|
+
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
772
|
+
}
|
|
773
|
+
function devAssert(condition, message) {
|
|
774
|
+
if ((typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) && !condition) {
|
|
775
|
+
throw new Error(`[SibuJS] ${message}`);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
function devWarnLazy(build) {
|
|
779
|
+
if (typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) {
|
|
780
|
+
const message = build();
|
|
781
|
+
if (message) console.warn(`[SibuJS] ${message}`);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
function devWarn(message) {
|
|
785
|
+
if (typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) {
|
|
786
|
+
console.warn(`[SibuJS] ${message}`);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// src/utils/sanitize.ts
|
|
791
|
+
function stripControlChars(value) {
|
|
792
|
+
return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
|
|
793
|
+
}
|
|
794
|
+
var ASCII_UPPER = /[A-Z]/;
|
|
795
|
+
var ASCII_UPPER_G = /[A-Z]/g;
|
|
796
|
+
function canonicalAttrName(name) {
|
|
797
|
+
return ASCII_UPPER.test(name) ? name.replace(ASCII_UPPER_G, (ch) => String.fromCharCode(ch.charCodeAt(0) + 32)) : name;
|
|
798
|
+
}
|
|
799
|
+
function isEventHandlerAttr(name) {
|
|
800
|
+
if (name.length < 3) return false;
|
|
801
|
+
const lower = name.toLowerCase();
|
|
802
|
+
return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
|
|
803
|
+
}
|
|
804
|
+
var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
805
|
+
var OUTER_TRIM = /^[\x00-\x20\x7f-\x9f]+|[\x00-\x20\x7f-\x9f]+$/g;
|
|
806
|
+
function sanitizeUrl(url) {
|
|
807
|
+
const probe = stripControlChars(url).trim();
|
|
808
|
+
if (!probe) return "";
|
|
809
|
+
const output2 = url.replace(OUTER_TRIM, "");
|
|
810
|
+
if (probe.length >= 2 && (probe[0] === "\\" || probe[0] === "/") && (probe[1] === "\\" || probe[1] === "/") && (probe[0] === "\\" || probe[1] === "\\")) {
|
|
811
|
+
return "";
|
|
812
|
+
}
|
|
813
|
+
const lower = probe.toLowerCase();
|
|
814
|
+
let schemeEnd = -1;
|
|
815
|
+
for (let i2 = 0; i2 < lower.length; i2++) {
|
|
816
|
+
const ch = lower.charCodeAt(i2);
|
|
817
|
+
if (ch === 58) {
|
|
818
|
+
schemeEnd = i2;
|
|
819
|
+
break;
|
|
820
|
+
}
|
|
821
|
+
if (ch === 47 || ch === 63 || ch === 35) break;
|
|
822
|
+
}
|
|
823
|
+
if (schemeEnd === -1) return output2;
|
|
824
|
+
const scheme = lower.slice(0, schemeEnd + 1);
|
|
825
|
+
if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return output2;
|
|
826
|
+
if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
|
|
827
|
+
return output2;
|
|
828
|
+
}
|
|
829
|
+
var SRCSET_DESCRIPTOR = /^\d+(\.\d+)?[wx]$/;
|
|
830
|
+
function isSrcsetWhitespace(ch) {
|
|
831
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
832
|
+
}
|
|
833
|
+
function sanitizeSrcset(value) {
|
|
834
|
+
const input2 = String(value);
|
|
835
|
+
const out = [];
|
|
836
|
+
let i2 = 0;
|
|
837
|
+
const n = input2.length;
|
|
838
|
+
while (i2 < n) {
|
|
839
|
+
while (i2 < n && (isSrcsetWhitespace(input2[i2]) || input2[i2] === ",")) i2++;
|
|
840
|
+
if (i2 >= n) break;
|
|
841
|
+
const urlStart = i2;
|
|
842
|
+
while (i2 < n && !isSrcsetWhitespace(input2[i2])) i2++;
|
|
843
|
+
let url = input2.slice(urlStart, i2);
|
|
844
|
+
const descriptors = [];
|
|
845
|
+
if (url.endsWith(",")) {
|
|
846
|
+
url = url.replace(/,+$/, "");
|
|
847
|
+
} else {
|
|
848
|
+
let current = "";
|
|
849
|
+
let inParens = false;
|
|
850
|
+
while (i2 < n) {
|
|
851
|
+
const ch = input2[i2];
|
|
852
|
+
if (inParens) {
|
|
853
|
+
current += ch;
|
|
854
|
+
if (ch === ")") inParens = false;
|
|
855
|
+
i2++;
|
|
856
|
+
continue;
|
|
857
|
+
}
|
|
858
|
+
if (isSrcsetWhitespace(ch)) {
|
|
859
|
+
if (current) descriptors.push(current);
|
|
860
|
+
current = "";
|
|
861
|
+
i2++;
|
|
862
|
+
continue;
|
|
863
|
+
}
|
|
864
|
+
if (ch === ",") {
|
|
865
|
+
i2++;
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
868
|
+
if (ch === "(") inParens = true;
|
|
869
|
+
current += ch;
|
|
870
|
+
i2++;
|
|
871
|
+
}
|
|
872
|
+
if (current) descriptors.push(current);
|
|
873
|
+
}
|
|
874
|
+
if (url === "") continue;
|
|
875
|
+
if (descriptors.length > 1) continue;
|
|
876
|
+
if (descriptors.length === 1 && !SRCSET_DESCRIPTOR.test(descriptors[0])) continue;
|
|
877
|
+
const safe = sanitizeUrl(url);
|
|
878
|
+
if (!safe) continue;
|
|
879
|
+
if (safe.startsWith(",") || safe.endsWith(",")) continue;
|
|
880
|
+
out.push(descriptors.length === 1 ? `${safe} ${descriptors[0]}` : safe);
|
|
881
|
+
}
|
|
882
|
+
return out.join(", ");
|
|
883
|
+
}
|
|
884
|
+
var CSS_DANGER_GATE = /[(:@\\]/;
|
|
885
|
+
function isCssWhitespace(ch) {
|
|
886
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
887
|
+
}
|
|
888
|
+
function isHexDigit(ch) {
|
|
889
|
+
return ch >= "0" && ch <= "9" || ch >= "a" && ch <= "f" || ch >= "A" && ch <= "F";
|
|
890
|
+
}
|
|
891
|
+
function decodeCssEscapes(value) {
|
|
892
|
+
let out = "";
|
|
893
|
+
for (let i2 = 0; i2 < value.length; i2++) {
|
|
894
|
+
const ch = value[i2];
|
|
895
|
+
if (ch !== "\\") {
|
|
896
|
+
out += ch;
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
if (i2 + 1 >= value.length) break;
|
|
900
|
+
const next = value[i2 + 1];
|
|
901
|
+
if (next === "\n" || next === "\f") {
|
|
902
|
+
i2 += 1;
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
if (next === "\r") {
|
|
906
|
+
i2 += value[i2 + 2] === "\n" ? 2 : 1;
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
if (isHexDigit(next)) {
|
|
910
|
+
let hex = "";
|
|
911
|
+
let j = i2 + 1;
|
|
912
|
+
while (j < value.length && hex.length < 6 && isHexDigit(value[j])) {
|
|
913
|
+
hex += value[j];
|
|
914
|
+
j++;
|
|
915
|
+
}
|
|
916
|
+
if (j < value.length && isCssWhitespace(value[j])) {
|
|
917
|
+
j += value[j] === "\r" && value[j + 1] === "\n" ? 2 : 1;
|
|
918
|
+
}
|
|
919
|
+
const code2 = Number.parseInt(hex, 16);
|
|
920
|
+
const invalid = code2 === 0 || code2 > 1114111 || code2 >= 55296 && code2 <= 57343;
|
|
921
|
+
out += invalid ? "\uFFFD" : String.fromCodePoint(code2);
|
|
922
|
+
i2 = j - 1;
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
out += next;
|
|
926
|
+
i2 += 1;
|
|
927
|
+
}
|
|
928
|
+
return out;
|
|
929
|
+
}
|
|
930
|
+
var BLOCKED_CSS_NEEDLES = [
|
|
931
|
+
"url(",
|
|
932
|
+
"expression(",
|
|
933
|
+
"javascript:",
|
|
934
|
+
"vbscript:",
|
|
935
|
+
"-moz-binding",
|
|
936
|
+
"behavior:",
|
|
937
|
+
"@import",
|
|
938
|
+
"image-set(",
|
|
939
|
+
"filter:progid",
|
|
940
|
+
// CSS Images 4 `image("…")` and CSS Values 5 `src("…")` take a URL as a
|
|
941
|
+
// plain STRING, so they fetch without ever spelling `url(`. Support is thin
|
|
942
|
+
// today, which is exactly when a blocklist should get ahead of it.
|
|
943
|
+
"image(",
|
|
944
|
+
"src("
|
|
945
|
+
];
|
|
946
|
+
var CSS_REASON_MOZ_BINDING = 4;
|
|
947
|
+
var CSS_REASON_BEHAVIOR = 5;
|
|
948
|
+
var CSS_REASON_PROGID = 8;
|
|
949
|
+
function describeElement(el) {
|
|
950
|
+
if (!el) return "an element";
|
|
951
|
+
let out = el.tagName.toLowerCase();
|
|
952
|
+
const id = el.getAttribute("id");
|
|
953
|
+
if (id) out += `#${id}`;
|
|
954
|
+
const cls = el.getAttribute("class");
|
|
955
|
+
if (cls) out += `.${cls.trim().split(/\s+/).slice(0, 3).join(".")}`;
|
|
956
|
+
return `<${out}>`;
|
|
957
|
+
}
|
|
958
|
+
var warnedDeclarations = /* @__PURE__ */ new Set();
|
|
959
|
+
var MAX_WARNED_DECLARATIONS = 100;
|
|
960
|
+
var declarationCapAnnounced = false;
|
|
961
|
+
function warnDroppedDeclaration(value, reason, ctx) {
|
|
962
|
+
devWarnLazy(() => {
|
|
963
|
+
const reasons = [
|
|
964
|
+
"url() in an inline style is an exfiltration channel: the browser fetches it immediately and the URL's path or query can carry page data off-origin",
|
|
965
|
+
"expression() executes arbitrary script in legacy engines",
|
|
966
|
+
"the javascript: scheme executes script",
|
|
967
|
+
"the vbscript: scheme executes script",
|
|
968
|
+
"-moz-binding loads and runs remote XBL",
|
|
969
|
+
"behavior: loads and runs a remote HTC script",
|
|
970
|
+
"@import pulls in a remote stylesheet",
|
|
971
|
+
"image-set() fetches remote images, the same exfiltration channel as url()",
|
|
972
|
+
"filter:progid activates legacy scriptable filters",
|
|
973
|
+
"image() fetches its string argument as a URL, the same exfiltration channel as url()",
|
|
974
|
+
"src() fetches its string argument as a URL, the same exfiltration channel as url()"
|
|
975
|
+
];
|
|
976
|
+
const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
|
|
977
|
+
const where = describeElement(ctx?.element);
|
|
978
|
+
const key = `${where}|${declaration}`;
|
|
979
|
+
if (warnedDeclarations.has(key)) return "";
|
|
980
|
+
if (warnedDeclarations.size >= MAX_WARNED_DECLARATIONS) {
|
|
981
|
+
if (declarationCapAnnounced) return "";
|
|
982
|
+
declarationCapAnnounced = true;
|
|
983
|
+
return `${MAX_WARNED_DECLARATIONS} distinct dropped style declarations have been reported; suppressing further ones for the rest of this session so they cannot flood the console. The declarations are still dropped \u2014 only the reporting stops. Fix the reported ones and reload to see any that remain.`;
|
|
984
|
+
}
|
|
985
|
+
warnedDeclarations.add(key);
|
|
986
|
+
return `style declaration "${declaration}" was dropped by the style sanitizer on ${where} \u2014 ${reasons[reason]}. The element renders without it, which usually looks like a missing image rather than an error. Sanctioned alternatives: for a content image use an <img> element (or a <picture>); for decoration, put the rule in a stylesheet and set a class instead \u2014 stylesheet CSS is not sanitized, only inline style attributes are. If this declaration is not yours, it came from untrusted data and the drop just prevented an exfiltration.`;
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
function normalizeCssForScan(value) {
|
|
990
|
+
const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
|
|
991
|
+
return normalized.toLowerCase().replace(/\s+/g, "");
|
|
992
|
+
}
|
|
993
|
+
function blockedCssReason(value) {
|
|
994
|
+
if (!CSS_DANGER_GATE.test(value)) return -1;
|
|
995
|
+
const lower = normalizeCssForScan(value);
|
|
996
|
+
for (let i2 = 0; i2 < BLOCKED_CSS_NEEDLES.length; i2++) {
|
|
997
|
+
if (lower.includes(BLOCKED_CSS_NEEDLES[i2])) return i2;
|
|
998
|
+
}
|
|
999
|
+
return -1;
|
|
1000
|
+
}
|
|
1001
|
+
function sanitizeCSSDeclaration(property, value, context2) {
|
|
1002
|
+
const reason = blockedDeclarationReason(property, value);
|
|
1003
|
+
if (reason === -1) return value;
|
|
1004
|
+
warnDroppedDeclaration(value, reason, { property, element: context2?.element });
|
|
1005
|
+
return "";
|
|
1006
|
+
}
|
|
1007
|
+
function blockedDeclarationReason(property, value) {
|
|
1008
|
+
const reason = blockedCssReason(value);
|
|
1009
|
+
if (reason !== -1) return reason;
|
|
1010
|
+
const name = canonicalAttrName(property);
|
|
1011
|
+
if (name === "behavior") return CSS_REASON_BEHAVIOR;
|
|
1012
|
+
if (name === "-moz-binding") return CSS_REASON_MOZ_BINDING;
|
|
1013
|
+
if ((name === "filter" || name === "-ms-filter") && normalizeCssForScan(value).includes("progid:")) {
|
|
1014
|
+
return CSS_REASON_PROGID;
|
|
1015
|
+
}
|
|
1016
|
+
return -1;
|
|
1017
|
+
}
|
|
1018
|
+
function parseStyleDeclarations(css) {
|
|
1019
|
+
const chunks = [];
|
|
1020
|
+
let buf = "";
|
|
1021
|
+
let depth = 0;
|
|
1022
|
+
let quote2 = "";
|
|
1023
|
+
for (let i2 = 0; i2 < css.length; i2++) {
|
|
1024
|
+
const ch = css[i2];
|
|
1025
|
+
if (quote2) {
|
|
1026
|
+
buf += ch;
|
|
1027
|
+
if (ch === "\\" && i2 + 1 < css.length) buf += css[++i2];
|
|
1028
|
+
else if (ch === quote2) quote2 = "";
|
|
1029
|
+
continue;
|
|
1030
|
+
}
|
|
1031
|
+
if (ch === "\\") {
|
|
1032
|
+
buf += ch;
|
|
1033
|
+
if (i2 + 1 < css.length) buf += css[++i2];
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
1036
|
+
if (ch === "/" && css[i2 + 1] === "*") {
|
|
1037
|
+
const end = css.indexOf("*/", i2 + 2);
|
|
1038
|
+
if (end === -1) return null;
|
|
1039
|
+
i2 = end + 1;
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
if (ch === '"' || ch === "'") quote2 = ch;
|
|
1043
|
+
else if (ch === "(" || ch === "[") depth++;
|
|
1044
|
+
else if (ch === ")" || ch === "]") {
|
|
1045
|
+
if (--depth < 0) return null;
|
|
1046
|
+
} else if (ch === "{" || ch === "}") return null;
|
|
1047
|
+
else if (ch === ";" && depth === 0) {
|
|
1048
|
+
chunks.push(buf);
|
|
1049
|
+
buf = "";
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
buf += ch;
|
|
1053
|
+
}
|
|
1054
|
+
if (quote2 || depth !== 0) return null;
|
|
1055
|
+
chunks.push(buf);
|
|
1056
|
+
const out = [];
|
|
1057
|
+
for (const chunk of chunks) {
|
|
1058
|
+
const colon = chunk.indexOf(":");
|
|
1059
|
+
if (colon === -1) continue;
|
|
1060
|
+
const rawName = chunk.slice(0, colon).trim();
|
|
1061
|
+
if (!/^(--[\w-]+|-?[a-zA-Z_][\w-]*)$/.test(rawName)) continue;
|
|
1062
|
+
let value = chunk.slice(colon + 1).trim();
|
|
1063
|
+
const bang = /!\s*important\s*$/i.exec(value);
|
|
1064
|
+
if (bang) value = value.slice(0, bang.index).trim();
|
|
1065
|
+
if (value === "") continue;
|
|
1066
|
+
const property = rawName.startsWith("--") ? rawName : canonicalAttrName(rawName);
|
|
1067
|
+
out.push([property, value, bang !== null]);
|
|
1068
|
+
}
|
|
1069
|
+
return out;
|
|
1070
|
+
}
|
|
1071
|
+
function sanitizeStyleDeclarationList(cssText, context2) {
|
|
1072
|
+
const input2 = String(cssText);
|
|
1073
|
+
const declarations = parseStyleDeclarations(input2);
|
|
1074
|
+
if (declarations === null) {
|
|
1075
|
+
if (blockedCssReason(input2) !== -1) warnDroppedDeclaration(input2, blockedCssReason(input2), context2);
|
|
1076
|
+
return "";
|
|
1077
|
+
}
|
|
1078
|
+
const kept = [];
|
|
1079
|
+
for (const [property, value, important] of declarations) {
|
|
1080
|
+
const reason = blockedDeclarationReason(property, value);
|
|
1081
|
+
if (reason !== -1) {
|
|
1082
|
+
warnDroppedDeclaration(value, reason, { property, element: context2?.element });
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
kept.push(`${property}: ${value}${important ? " !important" : ""}`);
|
|
1086
|
+
}
|
|
1087
|
+
return kept.join("; ");
|
|
1088
|
+
}
|
|
1089
|
+
function sanitizeStyleAttribute(cssText, context2) {
|
|
1090
|
+
const input2 = String(cssText);
|
|
1091
|
+
if (input2.trim() === "") return "";
|
|
1092
|
+
if (typeof document === "undefined") return sanitizeStyleDeclarationList(input2, context2);
|
|
1093
|
+
const probe = document.createElement("div");
|
|
1094
|
+
try {
|
|
1095
|
+
probe.style.cssText = input2;
|
|
1096
|
+
} catch {
|
|
1097
|
+
return "";
|
|
1098
|
+
}
|
|
1099
|
+
const declarations = [];
|
|
1100
|
+
for (let i2 = 0; i2 < probe.style.length; i2++) {
|
|
1101
|
+
const property = probe.style[i2];
|
|
1102
|
+
const value = probe.style.getPropertyValue(property);
|
|
1103
|
+
const reason = blockedDeclarationReason(property, value);
|
|
1104
|
+
if (reason !== -1) {
|
|
1105
|
+
warnDroppedDeclaration(value, reason, { property, element: context2?.element });
|
|
1106
|
+
continue;
|
|
1107
|
+
}
|
|
1108
|
+
const priority = probe.style.getPropertyPriority(property);
|
|
1109
|
+
declarations.push(`${property}: ${value}${priority ? ` !${priority}` : ""}`);
|
|
1110
|
+
}
|
|
1111
|
+
return declarations.join("; ");
|
|
1112
|
+
}
|
|
1113
|
+
var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
1114
|
+
"href",
|
|
1115
|
+
"xlink:href",
|
|
1116
|
+
"src",
|
|
1117
|
+
"action",
|
|
1118
|
+
"formaction",
|
|
1119
|
+
"formtarget",
|
|
1120
|
+
"cite",
|
|
1121
|
+
"poster",
|
|
1122
|
+
"background",
|
|
1123
|
+
"srcset",
|
|
1124
|
+
"ping",
|
|
1125
|
+
"data",
|
|
1126
|
+
// `<html manifest>` is a URL sink too. It was carried only by the SSR
|
|
1127
|
+
// serializers' private copy of this set; folding that copy into this one would
|
|
1128
|
+
// otherwise have silently dropped its coverage.
|
|
1129
|
+
"manifest"
|
|
1130
|
+
]);
|
|
1131
|
+
var HTML_CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set(["srcdoc"]);
|
|
1132
|
+
function isHtmlContentAttribute(name) {
|
|
1133
|
+
return HTML_CONTENT_ATTRIBUTES.has(name.toLowerCase());
|
|
1134
|
+
}
|
|
1135
|
+
function isUrlAttribute(attr) {
|
|
1136
|
+
return URL_ATTRIBUTES.has(attr.toLowerCase());
|
|
1137
|
+
}
|
|
1138
|
+
function isPolicyAttribute(name) {
|
|
1139
|
+
const lower = name.toLowerCase();
|
|
1140
|
+
return lower === "style" || URL_ATTRIBUTES.has(lower);
|
|
1141
|
+
}
|
|
1142
|
+
function sanitizeAttributeString(attr, value, context2) {
|
|
1143
|
+
const lower = attr.toLowerCase();
|
|
1144
|
+
if (lower === "srcset") return sanitizeSrcset(value);
|
|
1145
|
+
if (URL_ATTRIBUTES.has(lower)) return sanitizeUrl(value);
|
|
1146
|
+
if (lower === "style") return sanitizeStyleAttribute(value, context2);
|
|
1147
|
+
return value;
|
|
1148
|
+
}
|
|
1149
|
+
function resolveAttributeValue(attr, value, context2) {
|
|
1150
|
+
if (!isPolicyAttribute(attr)) return value;
|
|
1151
|
+
const safe = sanitizeAttributeString(attr, value, context2);
|
|
1152
|
+
return safe === "" ? null : safe;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// src/build/staticAnalysis.ts
|
|
1156
|
+
var STATIC_TAGS = /* @__PURE__ */ new Set([
|
|
1157
|
+
"div",
|
|
1158
|
+
"span",
|
|
1159
|
+
"section",
|
|
1160
|
+
"article",
|
|
1161
|
+
"header",
|
|
1162
|
+
"footer",
|
|
1163
|
+
"nav",
|
|
1164
|
+
"main",
|
|
1165
|
+
"aside",
|
|
1166
|
+
"p",
|
|
1167
|
+
"h1",
|
|
1168
|
+
"h2",
|
|
1169
|
+
"h3",
|
|
1170
|
+
"h4",
|
|
1171
|
+
"h5",
|
|
1172
|
+
"h6",
|
|
1173
|
+
"blockquote",
|
|
1174
|
+
"li",
|
|
1175
|
+
"ol",
|
|
1176
|
+
"ul",
|
|
1177
|
+
"a",
|
|
1178
|
+
"b",
|
|
1179
|
+
"em",
|
|
1180
|
+
"i",
|
|
1181
|
+
"strong",
|
|
1182
|
+
"small",
|
|
1183
|
+
"code",
|
|
1184
|
+
"mark",
|
|
1185
|
+
"img",
|
|
1186
|
+
"br",
|
|
1187
|
+
"hr",
|
|
1188
|
+
"input",
|
|
1189
|
+
"button",
|
|
1190
|
+
"form",
|
|
1191
|
+
"label",
|
|
1192
|
+
"details",
|
|
1193
|
+
"summary",
|
|
1194
|
+
"dialog"
|
|
1195
|
+
]);
|
|
63
1196
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
1197
|
+
"br",
|
|
1198
|
+
"hr",
|
|
1199
|
+
"img",
|
|
1200
|
+
"input",
|
|
1201
|
+
"meta",
|
|
1202
|
+
"link",
|
|
1203
|
+
"area",
|
|
1204
|
+
"base",
|
|
1205
|
+
"col",
|
|
1206
|
+
"embed",
|
|
1207
|
+
"param",
|
|
1208
|
+
"source",
|
|
1209
|
+
"track",
|
|
1210
|
+
"wbr"
|
|
1211
|
+
]);
|
|
1212
|
+
var SPECIAL_PROPS = /* @__PURE__ */ new Set(["style", "ref", "on", "onElement"]);
|
|
1213
|
+
var NON_REFLECTING_BOOLEANS = /* @__PURE__ */ new Set(["checked", "selected"]);
|
|
1214
|
+
function readLiteral(code2, tok) {
|
|
1215
|
+
if (!tok) return null;
|
|
1216
|
+
if (tok.type === "string") {
|
|
1217
|
+
const value = stringTokenValue(code2, tok);
|
|
1218
|
+
return value === null ? null : { kind: "string", value };
|
|
1219
|
+
}
|
|
1220
|
+
if (tok.type === "number" && /^(0|[1-9]\d*)(\.\d+)?$/.test(tok.value)) {
|
|
1221
|
+
return { kind: "number", value: String(Number(tok.value)) };
|
|
1222
|
+
}
|
|
1223
|
+
if (tok.type === "ident" && ["true", "false", "null", "undefined"].includes(tok.value)) {
|
|
1224
|
+
return { kind: "keyword", value: tok.value };
|
|
1225
|
+
}
|
|
1226
|
+
return null;
|
|
1227
|
+
}
|
|
1228
|
+
function parserSafeText(s2) {
|
|
1229
|
+
return !s2.includes("\r") && !s2.includes("\0");
|
|
1230
|
+
}
|
|
1231
|
+
function escapeHtml(str) {
|
|
1232
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1233
|
+
}
|
|
1234
|
+
function escapeAttr(str) {
|
|
1235
|
+
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
1236
|
+
}
|
|
1237
|
+
function attributeHtml(name, lit) {
|
|
1238
|
+
if (!/^[a-zA-Z][a-zA-Z0-9-]*$/.test(name)) return null;
|
|
1239
|
+
const lower = name.toLowerCase();
|
|
1240
|
+
if (SPECIAL_PROPS.has(name) || lower === "style" || lower === "srcset") return null;
|
|
1241
|
+
if (isEventHandlerAttr(name) || isUrlAttribute(name) || isHtmlContentAttribute(name)) return null;
|
|
1242
|
+
if (lit.kind === "keyword") {
|
|
1243
|
+
if (lit.value === "null" || lit.value === "undefined") return "";
|
|
1244
|
+
const on2 = lit.value === "true";
|
|
1245
|
+
if (lower.startsWith("aria-")) return `${lower}="${on2}"`;
|
|
1246
|
+
if (NON_REFLECTING_BOOLEANS.has(lower)) return null;
|
|
1247
|
+
return on2 ? `${lower}=""` : "";
|
|
1248
|
+
}
|
|
1249
|
+
if (!parserSafeText(lit.value)) return null;
|
|
1250
|
+
return `${lower}="${escapeAttr(lit.value)}"`;
|
|
1251
|
+
}
|
|
1252
|
+
function parseCall(code2, list, i2) {
|
|
1253
|
+
const at = (k2) => list[k2];
|
|
1254
|
+
const isPunct = (k2, v) => {
|
|
1255
|
+
const t = at(k2);
|
|
1256
|
+
return !!t && t.type === "punct" && t.value === v;
|
|
1257
|
+
};
|
|
1258
|
+
let k = i2 + 1;
|
|
1259
|
+
const result = { end: 0, cls: null, id: null, attrs: [], text: null };
|
|
1260
|
+
let nodesText = null;
|
|
1261
|
+
if (isPunct(k, "{")) {
|
|
1262
|
+
k++;
|
|
1263
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1264
|
+
while (!isPunct(k, "}")) {
|
|
1265
|
+
const keyTok = at(k);
|
|
1266
|
+
let key = null;
|
|
1267
|
+
if (keyTok?.type === "ident") key = keyTok.value;
|
|
1268
|
+
else if (keyTok?.type === "string") key = stringTokenValue(code2, keyTok);
|
|
1269
|
+
if (key === null || !isPunct(k + 1, ":")) return null;
|
|
1270
|
+
if (seen.has(key.toLowerCase())) return null;
|
|
1271
|
+
seen.add(key.toLowerCase());
|
|
1272
|
+
const lit = readLiteral(code2, at(k + 2));
|
|
1273
|
+
if (lit === null) return null;
|
|
1274
|
+
k += 3;
|
|
1275
|
+
if (isPunct(k, ",")) k++;
|
|
1276
|
+
else if (!isPunct(k, "}")) return null;
|
|
1277
|
+
if (key === "class" || key === "id") {
|
|
1278
|
+
if (lit.kind !== "string" || !parserSafeText(lit.value)) return null;
|
|
1279
|
+
if (key === "class") result.cls = lit.value;
|
|
1280
|
+
else result.id = lit.value;
|
|
1281
|
+
} else if (key === "nodes") {
|
|
1282
|
+
if (lit.kind !== "string" || !parserSafeText(lit.value)) return null;
|
|
1283
|
+
nodesText = lit.value;
|
|
1284
|
+
} else {
|
|
1285
|
+
const html3 = attributeHtml(key, lit);
|
|
1286
|
+
if (html3 === null) return null;
|
|
1287
|
+
if (html3) result.attrs.push(html3);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
k++;
|
|
1291
|
+
if (isPunct(k, ",")) {
|
|
1292
|
+
const second = readLiteral(code2, at(k + 1));
|
|
1293
|
+
if (second === null) {
|
|
1294
|
+
if (!isPunct(k + 1, ")")) return null;
|
|
1295
|
+
k++;
|
|
1296
|
+
} else {
|
|
1297
|
+
if (second.kind !== "string" || !parserSafeText(second.value)) return null;
|
|
1298
|
+
result.text = second.value;
|
|
1299
|
+
k += 2;
|
|
1300
|
+
if (isPunct(k, ",")) k++;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
if (result.text === null) result.text = nodesText;
|
|
1304
|
+
} else {
|
|
1305
|
+
const first = readLiteral(code2, at(k));
|
|
1306
|
+
if (first === null || first.kind !== "string" || !parserSafeText(first.value)) return null;
|
|
1307
|
+
k++;
|
|
1308
|
+
if (isPunct(k, ",") && at(k + 1)?.type === "string") {
|
|
1309
|
+
const second = readLiteral(code2, at(k + 1));
|
|
1310
|
+
if (second === null || second.kind !== "string" || !parserSafeText(second.value)) return null;
|
|
1311
|
+
result.cls = first.value;
|
|
1312
|
+
result.text = second.value;
|
|
1313
|
+
k += 2;
|
|
1314
|
+
} else {
|
|
1315
|
+
result.text = first.value;
|
|
1316
|
+
}
|
|
1317
|
+
if (isPunct(k, ",")) k++;
|
|
1318
|
+
}
|
|
1319
|
+
if (!isPunct(k, ")")) return null;
|
|
1320
|
+
result.end = at(k).end;
|
|
1321
|
+
return result;
|
|
1322
|
+
}
|
|
1323
|
+
function toHtml(tag, call) {
|
|
1324
|
+
const attrs = [];
|
|
1325
|
+
if (call.cls !== null) attrs.push(`class="${escapeAttr(call.cls)}"`);
|
|
1326
|
+
if (call.id !== null) attrs.push(`id="${escapeAttr(call.id)}"`);
|
|
1327
|
+
attrs.push(...call.attrs);
|
|
1328
|
+
const attrStr = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
1329
|
+
if (VOID_ELEMENTS.has(tag)) {
|
|
1330
|
+
if (call.text) return null;
|
|
1331
|
+
return `<${tag}${attrStr} />`;
|
|
1332
|
+
}
|
|
1333
|
+
return `<${tag}${attrStr}>${escapeHtml(call.text ?? "")}</${tag}>`;
|
|
1334
|
+
}
|
|
1335
|
+
function analyzeStaticTemplates(code2) {
|
|
1336
|
+
const none = { hasStaticPatterns: false, patterns: [] };
|
|
1337
|
+
if (!code2.includes("sibujs")) return none;
|
|
1338
|
+
const scan = scanModule(code2);
|
|
1339
|
+
if (!scan) return none;
|
|
1340
|
+
const factories = /* @__PURE__ */ new Map();
|
|
1341
|
+
for (const decl of scan.imports) {
|
|
1342
|
+
if (decl.source !== "sibujs") continue;
|
|
1343
|
+
for (const b2 of decl.bindings) if (STATIC_TAGS.has(b2.imported)) factories.set(b2.local, b2.imported);
|
|
1344
|
+
}
|
|
1345
|
+
if (factories.size === 0) return none;
|
|
1346
|
+
const uses = bindingUses(code2, scan, new Set(factories.keys()));
|
|
1347
|
+
const unsafe = new Set(uses.shadowed);
|
|
1348
|
+
for (const ref2 of uses.tagged) unsafe.add(ref2.tok.value);
|
|
1349
|
+
const patterns = [];
|
|
1350
|
+
for (const { tok, list, index } of uses.calls) {
|
|
1351
|
+
if (unsafe.has(tok.value)) continue;
|
|
1352
|
+
const tag = factories.get(tok.value);
|
|
1353
|
+
const call = parseCall(code2, list, index + 1);
|
|
1354
|
+
if (!call) continue;
|
|
1355
|
+
const templateHtml = toHtml(tag, call);
|
|
1356
|
+
if (templateHtml === null) continue;
|
|
1357
|
+
const start = list[index].start;
|
|
1358
|
+
patterns.push({ original: code2.slice(start, call.end), tag, templateHtml, start, end: call.end });
|
|
1359
|
+
}
|
|
1360
|
+
return { hasStaticPatterns: patterns.length > 0, patterns };
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
// src/build/templateCompiler.ts
|
|
1364
|
+
var RAW_TEXT_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
1365
|
+
var VOID_ELEMENTS2 = /* @__PURE__ */ new Set([
|
|
64
1366
|
"area",
|
|
65
1367
|
"base",
|
|
66
1368
|
"br",
|
|
@@ -99,96 +1401,10 @@ var SVG_TAGS = /* @__PURE__ */ new Set([
|
|
|
99
1401
|
"symbol",
|
|
100
1402
|
"marker"
|
|
101
1403
|
]);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
while ((match2 = tagRegex.exec(code2)) !== null) {
|
|
107
|
-
const start = match2.index;
|
|
108
|
-
const backtickStart = code2.indexOf("`", start + 4);
|
|
109
|
-
if (backtickStart === -1) continue;
|
|
110
|
-
const parsed = parseTemplateLiteral(code2, backtickStart);
|
|
111
|
-
if (!parsed) continue;
|
|
112
|
-
results.push({
|
|
113
|
-
start,
|
|
114
|
-
end: parsed.end,
|
|
115
|
-
strings: parsed.strings,
|
|
116
|
-
exprCount: parsed.exprCount
|
|
117
|
-
});
|
|
118
|
-
tagRegex.lastIndex = parsed.end;
|
|
119
|
-
}
|
|
120
|
-
return results;
|
|
121
|
-
}
|
|
122
|
-
function parseTemplateLiteral(code2, openBacktick) {
|
|
123
|
-
const strings = [];
|
|
124
|
-
let exprCount = 0;
|
|
125
|
-
let pos = openBacktick + 1;
|
|
126
|
-
let current = "";
|
|
127
|
-
while (pos < code2.length) {
|
|
128
|
-
const ch = code2[pos];
|
|
129
|
-
if (ch === "`") {
|
|
130
|
-
strings.push(current);
|
|
131
|
-
return { end: pos + 1, strings, exprCount };
|
|
132
|
-
}
|
|
133
|
-
if (ch === "$" && pos + 1 < code2.length && code2[pos + 1] === "{") {
|
|
134
|
-
strings.push(current);
|
|
135
|
-
current = "";
|
|
136
|
-
exprCount++;
|
|
137
|
-
pos += 2;
|
|
138
|
-
let depth = 1;
|
|
139
|
-
while (pos < code2.length && depth > 0) {
|
|
140
|
-
const c = code2[pos];
|
|
141
|
-
if (c === "{") depth++;
|
|
142
|
-
else if (c === "}") depth--;
|
|
143
|
-
else if (c === '"' || c === "'" || c === "`") {
|
|
144
|
-
pos = skipString(code2, pos);
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
if (depth > 0) pos++;
|
|
148
|
-
}
|
|
149
|
-
if (depth !== 0) return null;
|
|
150
|
-
pos++;
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
if (ch === "\\") {
|
|
154
|
-
current += code2[pos] + (code2[pos + 1] || "");
|
|
155
|
-
pos += 2;
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
current += ch;
|
|
159
|
-
pos++;
|
|
160
|
-
}
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
function skipString(code2, start) {
|
|
164
|
-
const quote2 = code2[start];
|
|
165
|
-
let pos = start + 1;
|
|
166
|
-
while (pos < code2.length) {
|
|
167
|
-
if (code2[pos] === "\\") {
|
|
168
|
-
pos += 2;
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
if (code2[pos] === quote2) return pos + 1;
|
|
172
|
-
if (quote2 === "`" && code2[pos] === "$" && code2[pos + 1] === "{") {
|
|
173
|
-
pos += 2;
|
|
174
|
-
let depth = 1;
|
|
175
|
-
while (pos < code2.length && depth > 0) {
|
|
176
|
-
if (code2[pos] === "{") depth++;
|
|
177
|
-
else if (code2[pos] === "}") depth--;
|
|
178
|
-
else if (code2[pos] === '"' || code2[pos] === "'" || code2[pos] === "`") {
|
|
179
|
-
pos = skipString(code2, pos);
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
if (depth > 0) pos++;
|
|
183
|
-
}
|
|
184
|
-
pos++;
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
pos++;
|
|
188
|
-
}
|
|
189
|
-
return pos;
|
|
190
|
-
}
|
|
191
|
-
function parseTemplateToAST(strings) {
|
|
1404
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1405
|
+
var RuntimeParseError = class extends Error {
|
|
1406
|
+
};
|
|
1407
|
+
function parseTemplate(strings) {
|
|
192
1408
|
const exprCount = strings.length - 1;
|
|
193
1409
|
let template2 = strings[0];
|
|
194
1410
|
for (let i2 = 0; i2 < exprCount; i2++) {
|
|
@@ -197,26 +1413,34 @@ function parseTemplateToAST(strings) {
|
|
|
197
1413
|
let pos = 0;
|
|
198
1414
|
const len = template2.length;
|
|
199
1415
|
function skipWs() {
|
|
200
|
-
while (pos < len &&
|
|
1416
|
+
while (pos < len && (template2[pos] === " " || template2[pos] === " " || template2[pos] === "\n" || template2[pos] === "\r"))
|
|
1417
|
+
pos++;
|
|
201
1418
|
}
|
|
202
1419
|
function tryExprIdx() {
|
|
203
|
-
if (template2
|
|
1420
|
+
if (template2.charCodeAt(pos) !== 0) return -1;
|
|
204
1421
|
const start = pos;
|
|
205
1422
|
pos++;
|
|
206
|
-
let
|
|
207
|
-
while (pos < len && template2
|
|
1423
|
+
let idx = 0;
|
|
1424
|
+
while (pos < len && template2.charCodeAt(pos) !== 0) {
|
|
1425
|
+
idx = idx * 10 + (template2.charCodeAt(pos) - 48);
|
|
1426
|
+
pos++;
|
|
1427
|
+
}
|
|
208
1428
|
if (pos < len) pos++;
|
|
209
|
-
|
|
210
|
-
if (Number.isNaN(idx) || idx < 0 || idx >= exprCount) {
|
|
1429
|
+
if (idx < 0 || idx >= exprCount) {
|
|
211
1430
|
pos = start;
|
|
212
1431
|
return -1;
|
|
213
1432
|
}
|
|
214
1433
|
return idx;
|
|
215
1434
|
}
|
|
216
1435
|
function readTagName() {
|
|
217
|
-
|
|
218
|
-
while (pos < len
|
|
219
|
-
|
|
1436
|
+
const start = pos;
|
|
1437
|
+
while (pos < len) {
|
|
1438
|
+
const c = template2.charCodeAt(pos);
|
|
1439
|
+
if (c >= 97 && c <= 122 || c >= 65 && c <= 90 || c >= 48 && c <= 57 || c === 45) {
|
|
1440
|
+
pos++;
|
|
1441
|
+
} else break;
|
|
1442
|
+
}
|
|
1443
|
+
return template2.slice(start, pos);
|
|
220
1444
|
}
|
|
221
1445
|
function parseAttrValue() {
|
|
222
1446
|
skipWs();
|
|
@@ -224,51 +1448,72 @@ function parseTemplateToAST(strings) {
|
|
|
224
1448
|
pos++;
|
|
225
1449
|
skipWs();
|
|
226
1450
|
const exprIdx = tryExprIdx();
|
|
227
|
-
if (exprIdx >= 0) return { kind: "expr",
|
|
1451
|
+
if (exprIdx >= 0) return { kind: "expr", idx: exprIdx };
|
|
228
1452
|
const quote2 = template2[pos];
|
|
229
1453
|
if (quote2 === '"' || quote2 === "'") {
|
|
230
1454
|
pos++;
|
|
231
|
-
const
|
|
232
|
-
|
|
1455
|
+
const statics2 = [];
|
|
1456
|
+
const exprs2 = [];
|
|
1457
|
+
let current2 = "";
|
|
233
1458
|
while (pos < len && template2[pos] !== quote2) {
|
|
234
1459
|
const innerIdx = tryExprIdx();
|
|
235
1460
|
if (innerIdx >= 0) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
1461
|
+
statics2.push(current2);
|
|
1462
|
+
current2 = "";
|
|
1463
|
+
exprs2.push(innerIdx);
|
|
239
1464
|
} else {
|
|
240
|
-
|
|
1465
|
+
current2 += template2[pos++];
|
|
241
1466
|
}
|
|
242
1467
|
}
|
|
243
1468
|
if (pos < len) pos++;
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
1469
|
+
statics2.push(current2);
|
|
1470
|
+
if (exprs2.length === 0) return { kind: "static", value: statics2[0] };
|
|
1471
|
+
return { kind: "mixed", statics: statics2, exprs: exprs2 };
|
|
1472
|
+
}
|
|
1473
|
+
const statics = [];
|
|
1474
|
+
const exprs = [];
|
|
1475
|
+
let current = "";
|
|
1476
|
+
while (pos < len) {
|
|
1477
|
+
const c = template2.charCodeAt(pos);
|
|
1478
|
+
if (c === 32 || c === 9 || c === 10 || c === 13 || c === 62) break;
|
|
1479
|
+
const innerIdx = tryExprIdx();
|
|
1480
|
+
if (innerIdx >= 0) {
|
|
1481
|
+
statics.push(current);
|
|
1482
|
+
current = "";
|
|
1483
|
+
exprs.push(innerIdx);
|
|
1484
|
+
} else {
|
|
1485
|
+
current += template2[pos++];
|
|
250
1486
|
}
|
|
251
|
-
return { kind: "static", value: parts.map((p2) => p2.value).join("") };
|
|
252
1487
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
return { kind: "
|
|
1488
|
+
statics.push(current);
|
|
1489
|
+
if (exprs.length === 0) return { kind: "static", value: statics[0] };
|
|
1490
|
+
return { kind: "mixed", statics, exprs };
|
|
256
1491
|
}
|
|
257
1492
|
function parseAttrs() {
|
|
258
1493
|
const attrs = [];
|
|
259
1494
|
while (pos < len) {
|
|
260
1495
|
skipWs();
|
|
261
1496
|
if (template2[pos] === ">" || template2[pos] === "/") break;
|
|
262
|
-
|
|
263
|
-
while (pos < len
|
|
1497
|
+
const attrStart = pos;
|
|
1498
|
+
while (pos < len) {
|
|
1499
|
+
const c = template2.charCodeAt(pos);
|
|
1500
|
+
if (c >= 97 && c <= 122 || c >= 65 && c <= 90 || c >= 48 && c <= 57 || c === 45 || c === 58 || c === 95 || c === 46) {
|
|
1501
|
+
pos++;
|
|
1502
|
+
} else break;
|
|
1503
|
+
}
|
|
1504
|
+
const attrName = template2.slice(attrStart, pos);
|
|
264
1505
|
if (!attrName) break;
|
|
265
1506
|
const val = parseAttrValue();
|
|
266
1507
|
if (attrName.startsWith("on:")) {
|
|
267
|
-
if (val.kind === "expr") {
|
|
268
|
-
|
|
269
|
-
}
|
|
1508
|
+
if (val.kind === "expr") attrs.push({ t: 3, name: attrName.slice(3), idx: val.idx });
|
|
1509
|
+
} else if (val.kind === "bool") {
|
|
1510
|
+
attrs.push({ t: 4, name: attrName });
|
|
1511
|
+
} else if (val.kind === "static") {
|
|
1512
|
+
attrs.push({ t: 0, name: attrName, value: val.value });
|
|
1513
|
+
} else if (val.kind === "expr") {
|
|
1514
|
+
attrs.push({ t: 1, name: attrName, idx: val.idx });
|
|
270
1515
|
} else {
|
|
271
|
-
attrs.push({ name: attrName,
|
|
1516
|
+
attrs.push({ t: 2, name: attrName, statics: val.statics, exprs: val.exprs });
|
|
272
1517
|
}
|
|
273
1518
|
}
|
|
274
1519
|
return attrs;
|
|
@@ -282,40 +1527,67 @@ function parseTemplateToAST(strings) {
|
|
|
282
1527
|
const idx = tryExprIdx();
|
|
283
1528
|
if (idx >= 0) {
|
|
284
1529
|
const collapsed2 = collapseWs(text2);
|
|
285
|
-
if (collapsed2) children.push({
|
|
1530
|
+
if (collapsed2) children.push({ t: 1, value: collapsed2 });
|
|
286
1531
|
text2 = "";
|
|
287
|
-
children.push({
|
|
1532
|
+
children.push({ t: 2, idx });
|
|
288
1533
|
} else {
|
|
289
1534
|
text2 += template2[pos++];
|
|
290
1535
|
}
|
|
291
1536
|
}
|
|
292
1537
|
const collapsed = collapseWs(text2);
|
|
293
|
-
if (collapsed) children.push({
|
|
1538
|
+
if (collapsed) children.push({ t: 1, value: collapsed });
|
|
294
1539
|
}
|
|
295
1540
|
function parseChildren() {
|
|
296
1541
|
const children = [];
|
|
297
1542
|
while (pos < len) {
|
|
298
1543
|
if (template2[pos] === "<" && pos + 1 < len && template2[pos + 1] === "/") break;
|
|
299
1544
|
if (template2[pos] === "<") {
|
|
1545
|
+
const next = template2[pos + 1];
|
|
1546
|
+
if (next === "!") {
|
|
1547
|
+
if (template2.startsWith("<!--", pos)) {
|
|
1548
|
+
const end = template2.indexOf("-->", pos + 4);
|
|
1549
|
+
pos = end === -1 ? len : end + 3;
|
|
1550
|
+
} else if (template2.startsWith("<![CDATA[", pos)) {
|
|
1551
|
+
const end = template2.indexOf("]]>", pos + 9);
|
|
1552
|
+
pos = end === -1 ? len : end + 3;
|
|
1553
|
+
} else {
|
|
1554
|
+
const end = template2.indexOf(">", pos);
|
|
1555
|
+
pos = end === -1 ? len : end + 1;
|
|
1556
|
+
}
|
|
1557
|
+
continue;
|
|
1558
|
+
}
|
|
1559
|
+
if (next === "?") {
|
|
1560
|
+
const end = template2.indexOf(">", pos);
|
|
1561
|
+
pos = end === -1 ? len : end + 1;
|
|
1562
|
+
continue;
|
|
1563
|
+
}
|
|
1564
|
+
if (!(next >= "a" && next <= "z") && !(next >= "A" && next <= "Z")) {
|
|
1565
|
+
children.push({ t: 1, value: "<" });
|
|
1566
|
+
pos++;
|
|
1567
|
+
continue;
|
|
1568
|
+
}
|
|
300
1569
|
pos++;
|
|
301
1570
|
const tag = readTagName();
|
|
302
1571
|
const attrs = parseAttrs();
|
|
303
1572
|
skipWs();
|
|
304
|
-
const isVoid =
|
|
1573
|
+
const isVoid = VOID_ELEMENTS2.has(tag);
|
|
305
1574
|
const isSelfClosing = template2[pos] === "/";
|
|
306
1575
|
if (isSelfClosing) pos++;
|
|
307
1576
|
if (pos < len) pos++;
|
|
308
1577
|
if (isVoid || isSelfClosing) {
|
|
309
|
-
children.push({
|
|
1578
|
+
children.push({ t: 0, el: { tag, svg: SVG_TAGS.has(tag), attrs, children: [] } });
|
|
310
1579
|
} else {
|
|
311
1580
|
const inner = parseChildren();
|
|
1581
|
+
if (RAW_TEXT_TAGS.has(tag.toLowerCase()) && inner.some((c) => c.t === 2)) {
|
|
1582
|
+
throw new RuntimeParseError(tag);
|
|
1583
|
+
}
|
|
312
1584
|
if (template2[pos] === "<" && pos + 1 < len && template2[pos + 1] === "/") {
|
|
313
1585
|
pos += 2;
|
|
314
1586
|
readTagName();
|
|
315
1587
|
skipWs();
|
|
316
1588
|
if (pos < len && template2[pos] === ">") pos++;
|
|
317
1589
|
}
|
|
318
|
-
children.push({
|
|
1590
|
+
children.push({ t: 0, el: { tag, svg: SVG_TAGS.has(tag), attrs, children: inner } });
|
|
319
1591
|
}
|
|
320
1592
|
} else {
|
|
321
1593
|
parseTextChildren(children);
|
|
@@ -325,303 +1597,270 @@ function parseTemplateToAST(strings) {
|
|
|
325
1597
|
}
|
|
326
1598
|
return parseChildren();
|
|
327
1599
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
1600
|
+
var IDL_SYNCED_ATTRS = /* @__PURE__ */ new Set(["value", "checked"]);
|
|
1601
|
+
function generateBody(roots, h) {
|
|
1602
|
+
const lines = [];
|
|
1603
|
+
let n = 0;
|
|
1604
|
+
const q2 = jsStringLiteral;
|
|
1605
|
+
const P = h.prefix;
|
|
1606
|
+
function genElement(el) {
|
|
1607
|
+
const tag = el.tag.toLowerCase();
|
|
1608
|
+
if (tag === "meta" || tag === "link") return null;
|
|
1609
|
+
for (const attr of el.attrs) {
|
|
1610
|
+
if ((attr.t === 0 || attr.t === 4) && attr.name.toLowerCase() === "srcdoc") return null;
|
|
1611
|
+
}
|
|
1612
|
+
const v = `e${n++}`;
|
|
1613
|
+
h.tags.add(el.tag);
|
|
1614
|
+
if (el.svg) h.svg = true;
|
|
1615
|
+
lines.push(
|
|
1616
|
+
el.svg ? `const ${v} = document.createElementNS(${q2(SVG_NS)}, ${q2(el.tag)});` : `const ${v} = document.createElement(${q2(el.tag)});`
|
|
1617
|
+
);
|
|
1618
|
+
for (const attr of el.attrs) {
|
|
1619
|
+
switch (attr.t) {
|
|
1620
|
+
case 0:
|
|
1621
|
+
lines.push(`${v}.setAttribute(${q2(attr.name)}, ${q2(attr.value)});`);
|
|
1622
|
+
break;
|
|
1623
|
+
case 4:
|
|
1624
|
+
lines.push(`${v}.setAttribute(${q2(attr.name)}, "");`);
|
|
1625
|
+
break;
|
|
1626
|
+
case 1:
|
|
1627
|
+
case 2: {
|
|
1628
|
+
if (IDL_SYNCED_ATTRS.has(attr.name.toLowerCase())) return null;
|
|
1629
|
+
h.used.add("attr");
|
|
1630
|
+
if (attr.t === 1) {
|
|
1631
|
+
lines.push(`${P}attr(${v}, ${q2(attr.name)}, v${attr.idx});`);
|
|
1632
|
+
} else {
|
|
1633
|
+
h.used.add("str");
|
|
1634
|
+
let expr = q2(attr.statics[0]);
|
|
1635
|
+
for (let j = 0; j < attr.exprs.length; j++) {
|
|
1636
|
+
expr += ` + ${P}str(v${attr.exprs[j]}) + ${q2(attr.statics[j + 1])}`;
|
|
1637
|
+
}
|
|
1638
|
+
lines.push(`${P}attr(${v}, ${q2(attr.name)}, ${expr});`);
|
|
1639
|
+
}
|
|
1640
|
+
break;
|
|
1641
|
+
}
|
|
1642
|
+
case 3:
|
|
1643
|
+
h.used.add("on");
|
|
1644
|
+
lines.push(`${P}on(${v}, ${q2(attr.name)}, v${attr.idx});`);
|
|
1645
|
+
break;
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
for (const child of el.children) {
|
|
1649
|
+
if (child.t === 0) {
|
|
1650
|
+
const c = genElement(child.el);
|
|
1651
|
+
if (c === null) return null;
|
|
1652
|
+
lines.push(`${v}.appendChild(${c});`);
|
|
1653
|
+
} else if (child.t === 1) {
|
|
1654
|
+
lines.push(`${v}.appendChild(document.createTextNode(${q2(child.value)}));`);
|
|
1655
|
+
} else {
|
|
1656
|
+
h.used.add("child");
|
|
1657
|
+
lines.push(`${P}child(${v}, v${child.idx});`);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
return v;
|
|
1661
|
+
}
|
|
1662
|
+
if (roots.length === 1 && roots[0].t === 0) {
|
|
1663
|
+
const root = genElement(roots[0].el);
|
|
1664
|
+
if (root === null) return null;
|
|
1665
|
+
lines.push(`return ${root};`);
|
|
1666
|
+
return lines.join("\n ");
|
|
1667
|
+
}
|
|
1668
|
+
lines.push(`const w = document.createElement("div");`);
|
|
1669
|
+
for (const root of roots) {
|
|
1670
|
+
if (root.t === 0) {
|
|
1671
|
+
const c = genElement(root.el);
|
|
1672
|
+
if (c === null) return null;
|
|
1673
|
+
lines.push(`w.appendChild(${c});`);
|
|
1674
|
+
} else if (root.t === 1) {
|
|
1675
|
+
lines.push(`w.appendChild(document.createTextNode(${q2(root.value)}));`);
|
|
1676
|
+
} else {
|
|
1677
|
+
return null;
|
|
351
1678
|
}
|
|
352
1679
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
1680
|
+
lines.push("return w;");
|
|
1681
|
+
return lines.join("\n ");
|
|
1682
|
+
}
|
|
1683
|
+
function helperSource(h) {
|
|
1684
|
+
const P = h.prefix;
|
|
1685
|
+
const out = [];
|
|
1686
|
+
if (h.used.has("attr")) {
|
|
1687
|
+
out.push(
|
|
1688
|
+
`function ${P}attr(el, name, value) {
|
|
1689
|
+
const teardown = ${P}bindAttrs(el, { [name]: value });
|
|
1690
|
+
if (typeof value === "function") ${P}registerDisposer(el, teardown);
|
|
1691
|
+
}`
|
|
1692
|
+
);
|
|
360
1693
|
}
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
} else {
|
|
366
|
-
parts.push(`nodes: [${childExprs.join(", ")}]`);
|
|
367
|
-
}
|
|
1694
|
+
if (h.used.has("str")) {
|
|
1695
|
+
out.push(`function ${P}str(value) {
|
|
1696
|
+
return value == null ? "" : String(value);
|
|
1697
|
+
}`);
|
|
368
1698
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
1699
|
+
if (h.used.has("on")) {
|
|
1700
|
+
out.push(
|
|
1701
|
+
`function ${P}on(el, name, handler) {
|
|
1702
|
+
if (typeof handler === "function") el.addEventListener(name, handler);
|
|
1703
|
+
else if (typeof __SIBU_DEV__ !== "undefined" && __SIBU_DEV__) {
|
|
1704
|
+
console.warn(\`[SibuJS] html: on:\${name} handler is not a function (got \${typeof handler}). Event listener was not attached.\`);
|
|
372
1705
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
function generateChild(child, valuesVar) {
|
|
376
|
-
switch (child.kind) {
|
|
377
|
-
case "element":
|
|
378
|
-
return generateElement(child.el, valuesVar);
|
|
379
|
-
case "text":
|
|
380
|
-
return JSON.stringify(child.value);
|
|
381
|
-
case "expr":
|
|
382
|
-
return `${valuesVar}[${child.index}]`;
|
|
1706
|
+
}`
|
|
1707
|
+
);
|
|
383
1708
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
if (
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
} else {
|
|
406
|
-
const body2 = rootExpr;
|
|
407
|
-
const exprSource = extractExpressions(code2, tmpl.start, tmpl.end, tmpl.exprCount);
|
|
408
|
-
compiled = `((${valuesVar}) => ${body2})([${exprSource.join(", ")}])`;
|
|
409
|
-
}
|
|
410
|
-
result = result.slice(0, tmpl.start) + compiled + result.slice(tmpl.end);
|
|
1709
|
+
if (h.used.has("child")) {
|
|
1710
|
+
out.push(
|
|
1711
|
+
`function ${P}child(el, value) {
|
|
1712
|
+
if (typeof value === "function") {
|
|
1713
|
+
const frag = ${P}Fragment([value]);
|
|
1714
|
+
const ph = frag.firstChild;
|
|
1715
|
+
el.appendChild(frag);
|
|
1716
|
+
${P}registerDisposer(el, () => ${P}dispose(ph));
|
|
1717
|
+
} else if (value instanceof Node) {
|
|
1718
|
+
el.appendChild(value);
|
|
1719
|
+
} else if (Array.isArray(value)) {
|
|
1720
|
+
for (let i = 0; i < value.length; i++) {
|
|
1721
|
+
const item = value[i];
|
|
1722
|
+
if (item instanceof Node) el.appendChild(item);
|
|
1723
|
+
else if (item != null && typeof item !== "boolean") el.appendChild(document.createTextNode(String(item)));
|
|
1724
|
+
}
|
|
1725
|
+
} else if (value != null && typeof value !== "boolean") {
|
|
1726
|
+
el.appendChild(document.createTextNode(String(value)));
|
|
1727
|
+
}
|
|
1728
|
+
}`
|
|
1729
|
+
);
|
|
411
1730
|
}
|
|
412
|
-
return
|
|
1731
|
+
return out.join("\n");
|
|
413
1732
|
}
|
|
414
|
-
function
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
1733
|
+
function importSource(h) {
|
|
1734
|
+
const P = h.prefix;
|
|
1735
|
+
const core = [];
|
|
1736
|
+
if (h.used.has("child")) core.push(`Fragment as ${P}Fragment`, `dispose as ${P}dispose`);
|
|
1737
|
+
if (h.used.has("attr") || h.used.has("child")) core.push(`registerDisposer as ${P}registerDisposer`);
|
|
1738
|
+
if (h.used.has("run")) core.push(`__renderParsedTemplate as ${P}run`);
|
|
1739
|
+
const lines = [];
|
|
1740
|
+
if (core.length > 0) lines.push(`import { ${core.join(", ")} } from "sibujs";`);
|
|
1741
|
+
if (h.used.has("attr")) lines.push(`import { bindAttrs as ${P}bindAttrs } from "sibujs/ui";`);
|
|
1742
|
+
return lines.join("\n");
|
|
421
1743
|
}
|
|
422
|
-
function
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
1744
|
+
function collectTags(children, h) {
|
|
1745
|
+
for (const child of children) {
|
|
1746
|
+
if (child.t !== 0) continue;
|
|
1747
|
+
h.tags.add(child.el.tag);
|
|
1748
|
+
if (child.el.svg) h.svg = true;
|
|
1749
|
+
collectTags(child.el.children, h);
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
function planHtmlTemplates(code2) {
|
|
1753
|
+
const plan = {
|
|
1754
|
+
edits: [],
|
|
1755
|
+
append: "",
|
|
1756
|
+
usedTags: /* @__PURE__ */ new Set(),
|
|
1757
|
+
usesSvg: false,
|
|
1758
|
+
compiledCount: 0,
|
|
1759
|
+
skippedCount: 0
|
|
1760
|
+
};
|
|
1761
|
+
if (!code2.includes("`") || !code2.includes("sibujs")) return plan;
|
|
1762
|
+
const scan = scanModule(code2);
|
|
1763
|
+
if (!scan) return plan;
|
|
1764
|
+
const tagNames = /* @__PURE__ */ new Set();
|
|
1765
|
+
for (const decl of scan.imports) {
|
|
1766
|
+
if (!isSibuSource(decl.source)) continue;
|
|
1767
|
+
for (const b2 of decl.bindings) if (b2.imported === "html") tagNames.add(b2.local);
|
|
1768
|
+
}
|
|
1769
|
+
if (tagNames.size === 0) return plan;
|
|
1770
|
+
const uses = bindingUses(code2, scan, tagNames);
|
|
1771
|
+
if (uses.shadowed.size > 0 || uses.calls.length > 0 || uses.tagged.length === 0) return plan;
|
|
1772
|
+
const sites = new Set(uses.tagged.map((ref2) => ref2.tok));
|
|
1773
|
+
const h = { prefix: uniquePrefix(code2), used: /* @__PURE__ */ new Set(), tags: /* @__PURE__ */ new Set(), svg: false };
|
|
1774
|
+
const functions = [];
|
|
1775
|
+
const compileTemplate = (tmpl) => {
|
|
1776
|
+
const strings = [];
|
|
1777
|
+
for (const qs of tmpl.quasis) {
|
|
1778
|
+
const cooked = cookEscapes(code2.slice(qs.start, qs.end));
|
|
1779
|
+
if (cooked === null) {
|
|
1780
|
+
if (tmpl.quasis.length === 1) return null;
|
|
1781
|
+
strings.push("undefined");
|
|
434
1782
|
continue;
|
|
435
1783
|
}
|
|
436
|
-
|
|
1784
|
+
strings.push(cooked);
|
|
437
1785
|
}
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
1786
|
+
const name = `${h.prefix}t${functions.length}`;
|
|
1787
|
+
const params = tmpl.exprs.map((_, i2) => `v${i2}`).join(", ");
|
|
1788
|
+
let roots;
|
|
1789
|
+
try {
|
|
1790
|
+
roots = parseTemplate(strings);
|
|
1791
|
+
} catch (err) {
|
|
1792
|
+
if (err instanceof RuntimeParseError) {
|
|
1793
|
+
const message = `html: dynamic \${...} expressions are not allowed inside <${err.message}> (raw-text context). Build the content separately and append it as a Node.`;
|
|
1794
|
+
functions.push(`function ${name}(${params}) {
|
|
1795
|
+
throw new Error(${jsStringLiteral(message)});
|
|
1796
|
+
}`);
|
|
1797
|
+
return name;
|
|
1798
|
+
}
|
|
1799
|
+
throw err;
|
|
1800
|
+
}
|
|
1801
|
+
const scratch = { prefix: h.prefix, used: /* @__PURE__ */ new Set(), tags: /* @__PURE__ */ new Set(), svg: false };
|
|
1802
|
+
const body2 = generateBody(roots, scratch);
|
|
1803
|
+
if (body2 === null) {
|
|
1804
|
+
const tree = JSON.stringify(roots).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
1805
|
+
h.used.add("run");
|
|
1806
|
+
collectTags(roots, h);
|
|
1807
|
+
functions.push(
|
|
1808
|
+
`function ${name}(${params}) {
|
|
1809
|
+
return ${h.prefix}run(${name}.tree || (${name}.tree = ${tree}), [${params}]);
|
|
1810
|
+
}`
|
|
1811
|
+
);
|
|
1812
|
+
return name;
|
|
1813
|
+
}
|
|
1814
|
+
for (const u2 of scratch.used) h.used.add(u2);
|
|
1815
|
+
for (const t of scratch.tags) h.tags.add(t);
|
|
1816
|
+
if (scratch.svg) h.svg = true;
|
|
1817
|
+
functions.push(`function ${name}(${params}) {
|
|
1818
|
+
${body2}
|
|
1819
|
+
}`);
|
|
1820
|
+
return name;
|
|
1821
|
+
};
|
|
1822
|
+
const replaceSite = (tag, tmpl, name) => {
|
|
1823
|
+
const edit = (start, end, before, after) => plan.edits.push({ start, end, text: `${before}${lineBreaksIn(code2, start, end)}${after}` });
|
|
1824
|
+
const exprs = tmpl.exprs;
|
|
1825
|
+
if (exprs.length === 0) {
|
|
1826
|
+
edit(tag.start, tmpl.end, `${name}(`, ")");
|
|
1827
|
+
return;
|
|
451
1828
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
"h3",
|
|
473
|
-
"h4",
|
|
474
|
-
"h5",
|
|
475
|
-
"h6",
|
|
476
|
-
"blockquote",
|
|
477
|
-
"li",
|
|
478
|
-
"ol",
|
|
479
|
-
"ul",
|
|
480
|
-
"pre",
|
|
481
|
-
"a",
|
|
482
|
-
"b",
|
|
483
|
-
"em",
|
|
484
|
-
"i",
|
|
485
|
-
"strong",
|
|
486
|
-
"small",
|
|
487
|
-
"code",
|
|
488
|
-
"mark",
|
|
489
|
-
"img",
|
|
490
|
-
"br",
|
|
491
|
-
"hr",
|
|
492
|
-
"input",
|
|
493
|
-
"button",
|
|
494
|
-
"form",
|
|
495
|
-
"label",
|
|
496
|
-
"select",
|
|
497
|
-
"textarea",
|
|
498
|
-
"option",
|
|
499
|
-
"table",
|
|
500
|
-
"tbody",
|
|
501
|
-
"thead",
|
|
502
|
-
"tfoot",
|
|
503
|
-
"tr",
|
|
504
|
-
"td",
|
|
505
|
-
"th",
|
|
506
|
-
"details",
|
|
507
|
-
"summary",
|
|
508
|
-
"dialog"
|
|
509
|
-
]);
|
|
510
|
-
var VOID_ELEMENTS2 = /* @__PURE__ */ new Set([
|
|
511
|
-
"br",
|
|
512
|
-
"hr",
|
|
513
|
-
"img",
|
|
514
|
-
"input",
|
|
515
|
-
"meta",
|
|
516
|
-
"link",
|
|
517
|
-
"area",
|
|
518
|
-
"base",
|
|
519
|
-
"col",
|
|
520
|
-
"embed",
|
|
521
|
-
"param",
|
|
522
|
-
"source",
|
|
523
|
-
"track",
|
|
524
|
-
"wbr"
|
|
525
|
-
]);
|
|
526
|
-
function analyzeStaticTemplates(code2) {
|
|
527
|
-
const patterns = [];
|
|
528
|
-
const tagCallRegex = new RegExp(`\\b(${Array.from(HTML_TAGS).join("|")})\\s*\\(\\s*\\{([^}]*)\\}\\s*\\)`, "g");
|
|
529
|
-
let match2;
|
|
530
|
-
while ((match2 = tagCallRegex.exec(code2)) !== null) {
|
|
531
|
-
const [fullMatch, tag, propsContent] = match2;
|
|
532
|
-
const start = match2.index;
|
|
533
|
-
const end = start + fullMatch.length;
|
|
534
|
-
if (isStaticPropsContent(propsContent)) {
|
|
535
|
-
const templateHtml = propsToHtml(tag, propsContent);
|
|
536
|
-
if (templateHtml) {
|
|
537
|
-
patterns.push({ original: fullMatch, tag, templateHtml, start, end });
|
|
1829
|
+
edit(tag.start, exprs[0].start, `${name}((`, "");
|
|
1830
|
+
for (let i2 = 1; i2 < exprs.length; i2++) edit(exprs[i2 - 1].end, exprs[i2].start, ")", ", (");
|
|
1831
|
+
edit(exprs[exprs.length - 1].end, tmpl.end, "", "))");
|
|
1832
|
+
};
|
|
1833
|
+
const visit = (list) => {
|
|
1834
|
+
for (let i2 = 0; i2 < list.length; i2++) {
|
|
1835
|
+
const tok = list[i2];
|
|
1836
|
+
if (sites.has(tok)) {
|
|
1837
|
+
const tmpl = list[i2 + 1];
|
|
1838
|
+
for (const e of tmpl.exprs) visit(e.tokens);
|
|
1839
|
+
const name = compileTemplate(tmpl);
|
|
1840
|
+
if (name !== null) {
|
|
1841
|
+
plan.compiledCount++;
|
|
1842
|
+
replaceSite(tok, tmpl, name);
|
|
1843
|
+
} else {
|
|
1844
|
+
plan.skippedCount++;
|
|
1845
|
+
}
|
|
1846
|
+
i2++;
|
|
1847
|
+
} else if (tok.type === "template") {
|
|
1848
|
+
for (const e of tok.exprs) visit(e.tokens);
|
|
538
1849
|
}
|
|
539
1850
|
}
|
|
540
|
-
}
|
|
541
|
-
return {
|
|
542
|
-
hasStaticPatterns: patterns.length > 0,
|
|
543
|
-
patterns
|
|
544
1851
|
};
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
const value = prop.substring(colonIndex + 1).trim();
|
|
555
|
-
if (!isStaticValue(value)) {
|
|
556
|
-
return false;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
return true;
|
|
560
|
-
}
|
|
561
|
-
function isStaticValue(value) {
|
|
562
|
-
if (/^["'].*["']$/.test(value)) return true;
|
|
563
|
-
if (/^-?\d+(\.\d+)?$/.test(value)) return true;
|
|
564
|
-
if (value === "true" || value === "false") return true;
|
|
565
|
-
if (value === "null" || value === "undefined") return true;
|
|
566
|
-
return false;
|
|
567
|
-
}
|
|
568
|
-
function propsToHtml(tag, propsContent) {
|
|
569
|
-
const attrs = [];
|
|
570
|
-
let nodesContent = "";
|
|
571
|
-
const props = propsContent.split(",").map((p2) => p2.trim()).filter(Boolean);
|
|
572
|
-
for (const prop of props) {
|
|
573
|
-
const colonIndex = prop.indexOf(":");
|
|
574
|
-
if (colonIndex === -1) continue;
|
|
575
|
-
const key = prop.substring(0, colonIndex).trim();
|
|
576
|
-
let value = prop.substring(colonIndex + 1).trim();
|
|
577
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
578
|
-
value = value.slice(1, -1);
|
|
579
|
-
}
|
|
580
|
-
if (key === "nodes") {
|
|
581
|
-
nodesContent = escapeHtml(value);
|
|
582
|
-
} else if (key === "class" || key === "id") {
|
|
583
|
-
attrs.push(`${key}="${escapeAttr(value)}"`);
|
|
584
|
-
} else if (key !== "on" && key !== "ref" && key !== "style") {
|
|
585
|
-
attrs.push(`${key}="${escapeAttr(String(value))}"`);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
const attrStr = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
589
|
-
if (VOID_ELEMENTS2.has(tag)) {
|
|
590
|
-
return `<${tag}${attrStr} />`;
|
|
591
|
-
}
|
|
592
|
-
return `<${tag}${attrStr}>${nodesContent}</${tag}>`;
|
|
593
|
-
}
|
|
594
|
-
function escapeHtml(str) {
|
|
595
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
596
|
-
}
|
|
597
|
-
function escapeAttr(str) {
|
|
598
|
-
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
1852
|
+
visit(scan.tokens);
|
|
1853
|
+
if (plan.compiledCount === 0) return { ...plan, edits: [] };
|
|
1854
|
+
const trailer = [importSource(h), helperSource(h), ...functions].filter(Boolean).join("\n");
|
|
1855
|
+
plan.append = `
|
|
1856
|
+
${trailer}
|
|
1857
|
+
`;
|
|
1858
|
+
plan.usedTags = h.tags;
|
|
1859
|
+
plan.usesSvg = h.svg;
|
|
1860
|
+
return plan;
|
|
599
1861
|
}
|
|
600
1862
|
|
|
601
1863
|
// src/build/vite.ts
|
|
602
|
-
var SVG_TAGS_SET = /* @__PURE__ */ new Set([
|
|
603
|
-
"svg",
|
|
604
|
-
"circle",
|
|
605
|
-
"ellipse",
|
|
606
|
-
"g",
|
|
607
|
-
"line",
|
|
608
|
-
"path",
|
|
609
|
-
"polygon",
|
|
610
|
-
"polyline",
|
|
611
|
-
"rect",
|
|
612
|
-
"text",
|
|
613
|
-
"tspan",
|
|
614
|
-
"defs",
|
|
615
|
-
"clipPath",
|
|
616
|
-
"mask",
|
|
617
|
-
"pattern",
|
|
618
|
-
"linearGradient",
|
|
619
|
-
"radialGradient",
|
|
620
|
-
"stop",
|
|
621
|
-
"use",
|
|
622
|
-
"symbol",
|
|
623
|
-
"marker"
|
|
624
|
-
]);
|
|
625
1864
|
var DEFAULT_INCLUDE = ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"];
|
|
626
1865
|
var DEFAULT_EXCLUDE = ["node_modules/**", "dist/**", "**/*.test.*", "**/*.spec.*"];
|
|
627
1866
|
function matchesPattern(filePath, patterns) {
|
|
@@ -631,30 +1870,42 @@ function matchesPattern(filePath, patterns) {
|
|
|
631
1870
|
return new RegExp(regexStr).test(normalized);
|
|
632
1871
|
});
|
|
633
1872
|
}
|
|
634
|
-
function
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
"
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
"withDefaults",
|
|
641
|
-
"pure",
|
|
642
|
-
"noSideEffect"
|
|
643
|
-
];
|
|
644
|
-
let result = code2;
|
|
645
|
-
for (const factory of sibuFactories) {
|
|
646
|
-
const pattern2 = new RegExp(`(?<!/\\*#__PURE__\\*/\\s*)\\b(${factory})\\s*\\(`, "g");
|
|
647
|
-
result = result.replace(pattern2, "/*#__PURE__*/ $1(");
|
|
1873
|
+
function devPrologueEdit(code2) {
|
|
1874
|
+
let at = 0;
|
|
1875
|
+
if (code2.startsWith("#!")) {
|
|
1876
|
+
const nl = code2.indexOf("\n");
|
|
1877
|
+
if (nl === -1) return null;
|
|
1878
|
+
at = nl + 1;
|
|
648
1879
|
}
|
|
649
|
-
return
|
|
1880
|
+
return {
|
|
1881
|
+
start: at,
|
|
1882
|
+
end: at,
|
|
1883
|
+
text: '/* SibuJS Dev Mode */ if (typeof globalThis !== "undefined") { globalThis.__SIBU_DEV__ = true; } '
|
|
1884
|
+
};
|
|
650
1885
|
}
|
|
651
|
-
function
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
1886
|
+
function staticOptimizationEdits(code2) {
|
|
1887
|
+
const analysis = analyzeStaticTemplates(code2);
|
|
1888
|
+
if (!analysis.hasStaticPatterns) return null;
|
|
1889
|
+
const P = uniquePrefix(code2);
|
|
1890
|
+
const edits = analysis.patterns.map((pattern2) => ({
|
|
1891
|
+
start: pattern2.start,
|
|
1892
|
+
end: pattern2.end,
|
|
1893
|
+
// A call spanning several lines keeps its line breaks.
|
|
1894
|
+
text: `${P}static(${jsStringLiteral(pattern2.templateHtml)}${lineBreaksIn(code2, pattern2.start, pattern2.end)})`
|
|
1895
|
+
}));
|
|
1896
|
+
const append = `
|
|
1897
|
+
import { staticTemplate as ${P}staticTemplate } from "sibujs/performance";
|
|
1898
|
+
function ${P}static(markup) {
|
|
1899
|
+
return document.adoptNode(${P}staticTemplate(markup));
|
|
1900
|
+
}
|
|
1901
|
+
`;
|
|
1902
|
+
return { edits, append };
|
|
1903
|
+
}
|
|
1904
|
+
function resolveDevMode(explicit, info) {
|
|
1905
|
+
if (explicit !== void 0) return explicit;
|
|
1906
|
+
if (info?.command === "build") return info.mode === "development";
|
|
1907
|
+
if (info?.command === "serve") return true;
|
|
1908
|
+
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
658
1909
|
}
|
|
659
1910
|
function sibuVitePlugin(options = {}) {
|
|
660
1911
|
const {
|
|
@@ -663,22 +1914,23 @@ function sibuVitePlugin(options = {}) {
|
|
|
663
1914
|
include = DEFAULT_INCLUDE,
|
|
664
1915
|
exclude = DEFAULT_EXCLUDE,
|
|
665
1916
|
devMode,
|
|
666
|
-
staticOptimize,
|
|
1917
|
+
staticOptimize = false,
|
|
667
1918
|
compileTemplates
|
|
668
1919
|
} = options;
|
|
669
|
-
|
|
1920
|
+
let isDevMode = resolveDevMode(devMode, void 0);
|
|
670
1921
|
return {
|
|
671
1922
|
name: "sibu-vite-plugin",
|
|
672
1923
|
enforce: "pre",
|
|
673
|
-
config() {
|
|
1924
|
+
config(_userConfig, env) {
|
|
1925
|
+
isDevMode = resolveDevMode(devMode, env);
|
|
674
1926
|
return {
|
|
675
|
-
// Optimize dependency pre-bundling for
|
|
1927
|
+
// Optimize dependency pre-bundling for sibujs
|
|
676
1928
|
optimizeDeps: {
|
|
677
|
-
include: ["
|
|
1929
|
+
include: ["sibujs"]
|
|
678
1930
|
},
|
|
679
|
-
// Ensure
|
|
1931
|
+
// Ensure sibujs is treated correctly for SSR
|
|
680
1932
|
ssr: {
|
|
681
|
-
noExternal: ["
|
|
1933
|
+
noExternal: ["sibujs"]
|
|
682
1934
|
},
|
|
683
1935
|
// Define global constants for dead code elimination
|
|
684
1936
|
define: {
|
|
@@ -691,69 +1943,47 @@ function sibuVitePlugin(options = {}) {
|
|
|
691
1943
|
}
|
|
692
1944
|
};
|
|
693
1945
|
},
|
|
1946
|
+
configResolved(config) {
|
|
1947
|
+
isDevMode = resolveDevMode(devMode, config);
|
|
1948
|
+
},
|
|
694
1949
|
transform(code2, id) {
|
|
695
1950
|
if (!matchesPattern(id, include) || matchesPattern(id, exclude)) {
|
|
696
1951
|
return null;
|
|
697
1952
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
}
|
|
1953
|
+
if (!code2.includes("sibujs")) return null;
|
|
1954
|
+
if (!scanModule(code2)) return null;
|
|
1955
|
+
const edits = [];
|
|
1956
|
+
let append = "";
|
|
1957
|
+
if (isDevMode && importsSibu(code2)) {
|
|
1958
|
+
const prologue = devPrologueEdit(code2);
|
|
1959
|
+
if (prologue) edits.push(prologue);
|
|
706
1960
|
}
|
|
707
|
-
if (
|
|
708
|
-
|
|
709
|
-
if (withDevHelpers !== transformed) {
|
|
710
|
-
transformed = withDevHelpers;
|
|
711
|
-
modified = true;
|
|
712
|
-
}
|
|
1961
|
+
if (pureAnnotations) {
|
|
1962
|
+
edits.push(...pureAnnotationEdits(code2));
|
|
713
1963
|
}
|
|
714
1964
|
const shouldCompile = compileTemplates ?? !isDevMode;
|
|
715
|
-
if (shouldCompile
|
|
716
|
-
const
|
|
717
|
-
if (
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
const imports = [];
|
|
721
|
-
if (tagImports.length > 0) {
|
|
722
|
-
imports.push(`import { ${tagImports.join(", ")} } from "sibu";`);
|
|
723
|
-
}
|
|
724
|
-
if (needsSvg) {
|
|
725
|
-
imports.push(`import { tagFactory as __sbTagFactory, SVG_NS as __sbSVG_NS } from "sibu";`);
|
|
726
|
-
}
|
|
727
|
-
const newImports = imports.filter((imp) => !transformed.includes(imp));
|
|
728
|
-
if (newImports.length > 0) {
|
|
729
|
-
compiled.code = `${newImports.join("\n")}
|
|
730
|
-
${compiled.code}`;
|
|
731
|
-
}
|
|
732
|
-
transformed = compiled.code;
|
|
733
|
-
modified = true;
|
|
1965
|
+
if (shouldCompile) {
|
|
1966
|
+
const plan = planHtmlTemplates(code2);
|
|
1967
|
+
if (plan.compiledCount > 0) {
|
|
1968
|
+
edits.push(...plan.edits);
|
|
1969
|
+
append += plan.append;
|
|
734
1970
|
}
|
|
735
1971
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
for (const pattern2 of sorted) {
|
|
742
|
-
const replacement = `staticTemplate(${JSON.stringify(pattern2.templateHtml)})`;
|
|
743
|
-
transformed = transformed.slice(0, pattern2.start) + replacement + transformed.slice(pattern2.end);
|
|
744
|
-
}
|
|
745
|
-
if (!transformed.includes("import") || !transformed.includes("staticTemplate")) {
|
|
746
|
-
transformed = `import { staticTemplate } from "sibu";
|
|
747
|
-
${transformed}`;
|
|
748
|
-
}
|
|
749
|
-
modified = true;
|
|
1972
|
+
if (staticOptimize) {
|
|
1973
|
+
const optimized = staticOptimizationEdits(code2);
|
|
1974
|
+
if (optimized) {
|
|
1975
|
+
edits.push(...optimized.edits);
|
|
1976
|
+
append += optimized.append;
|
|
750
1977
|
}
|
|
751
1978
|
}
|
|
752
|
-
if (
|
|
1979
|
+
if (edits.length === 0 && append === "") return null;
|
|
1980
|
+
const sorted = normalizeEdits(edits);
|
|
1981
|
+
if (!sorted) return null;
|
|
1982
|
+
const transformed = applyEdits(code2, sorted, append);
|
|
1983
|
+
if (transformed === code2) return null;
|
|
753
1984
|
return {
|
|
754
1985
|
code: transformed,
|
|
755
|
-
map:
|
|
756
|
-
// Let Vite handle source maps
|
|
1986
|
+
map: editsSourceMap(code2, sorted, append, id)
|
|
757
1987
|
};
|
|
758
1988
|
},
|
|
759
1989
|
handleHotUpdate(ctx) {
|
|
@@ -812,7 +2042,7 @@ function createViteConfig(options = {}) {
|
|
|
812
2042
|
// SSR configuration
|
|
813
2043
|
...ssr ? {
|
|
814
2044
|
ssr: {
|
|
815
|
-
noExternal: ["
|
|
2045
|
+
noExternal: ["sibujs"],
|
|
816
2046
|
target: "node"
|
|
817
2047
|
},
|
|
818
2048
|
build: {
|
|
@@ -829,8 +2059,8 @@ function createViteConfig(options = {}) {
|
|
|
829
2059
|
} : {},
|
|
830
2060
|
// Optimize dependency handling
|
|
831
2061
|
optimizeDeps: {
|
|
832
|
-
include: ["
|
|
833
|
-
// Force pre-bundling of
|
|
2062
|
+
include: ["sibujs"],
|
|
2063
|
+
// Force pre-bundling of sibujs for faster dev startup
|
|
834
2064
|
force: false
|
|
835
2065
|
},
|
|
836
2066
|
// Environment variable handling
|
|
@@ -852,30 +2082,20 @@ function deepMerge(target, source2) {
|
|
|
852
2082
|
return result;
|
|
853
2083
|
}
|
|
854
2084
|
|
|
855
|
-
// src/build/webpack.ts
|
|
856
|
-
var PURE_FACTORIES = [
|
|
857
|
-
"tagFactory",
|
|
858
|
-
"context",
|
|
859
|
-
"defineComponent",
|
|
860
|
-
"withProps",
|
|
861
|
-
"withDefaults",
|
|
862
|
-
"pure",
|
|
863
|
-
"noSideEffect"
|
|
864
|
-
];
|
|
2085
|
+
// src/build/webpack.ts
|
|
865
2086
|
function addPureAnnotations(source2) {
|
|
866
|
-
|
|
867
|
-
for (const factory of PURE_FACTORIES) {
|
|
868
|
-
const pattern2 = new RegExp(`(?<!/\\*#__PURE__\\*/\\s*)\\b(${factory})\\s*\\(`, "g");
|
|
869
|
-
result = result.replace(pattern2, "/*#__PURE__*/ $1(");
|
|
870
|
-
}
|
|
871
|
-
return result;
|
|
2087
|
+
return injectPureAnnotations(source2);
|
|
872
2088
|
}
|
|
873
2089
|
function sibuWebpackPlugin(options = {}) {
|
|
874
|
-
const {
|
|
875
|
-
const isDevMode = devMode ?? (typeof process !== "undefined" && process.env?.NODE_ENV !== "production");
|
|
2090
|
+
const { devMode } = options;
|
|
876
2091
|
return {
|
|
877
2092
|
name: "SibuWebpackPlugin",
|
|
878
2093
|
apply(compiler) {
|
|
2094
|
+
if (options.pureAnnotations === true) {
|
|
2095
|
+
console.warn(
|
|
2096
|
+
'[SibuWebpackPlugin] `pureAnnotations` is not applied by the plugin: webpack needs a loader file. Create sibu-pure-loader.cjs containing `module.exports = require("sibujs/build").createPureAnnotationsLoader();` and add a module rule `{ test: /\\.[cm]?[jt]sx?$/, exclude: /node_modules/, use: "./sibu-pure-loader.cjs" }`.'
|
|
2097
|
+
);
|
|
2098
|
+
}
|
|
879
2099
|
compiler.hooks?.compilation?.tap("SibuWebpackPlugin", (compilation) => {
|
|
880
2100
|
const comp = compilation;
|
|
881
2101
|
if (comp.hooks?.optimizeModules) {
|
|
@@ -883,31 +2103,6 @@ function sibuWebpackPlugin(options = {}) {
|
|
|
883
2103
|
});
|
|
884
2104
|
}
|
|
885
2105
|
});
|
|
886
|
-
if (pureAnnotations) {
|
|
887
|
-
compiler.hooks?.afterEnvironment?.tap("SibuWebpackPlugin", () => {
|
|
888
|
-
if (!compiler.options.module) {
|
|
889
|
-
compiler.options.module = { rules: [] };
|
|
890
|
-
}
|
|
891
|
-
if (!compiler.options.module.rules) {
|
|
892
|
-
compiler.options.module.rules = [];
|
|
893
|
-
}
|
|
894
|
-
compiler.options.module.rules.push({
|
|
895
|
-
test: /\.[jt]sx?$/,
|
|
896
|
-
exclude: /node_modules/,
|
|
897
|
-
enforce: "pre",
|
|
898
|
-
use: [
|
|
899
|
-
{
|
|
900
|
-
loader: {
|
|
901
|
-
// Inline loader function
|
|
902
|
-
ident: "sibu-pure-annotations-loader",
|
|
903
|
-
loader: "__sibu_inline_loader__",
|
|
904
|
-
options: {}
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
]
|
|
908
|
-
});
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
2106
|
compiler.hooks?.afterResolvers?.tap("SibuWebpackPlugin", () => {
|
|
912
2107
|
if (!compiler.options.resolve) {
|
|
913
2108
|
compiler.options.resolve = {};
|
|
@@ -919,20 +2114,21 @@ function sibuWebpackPlugin(options = {}) {
|
|
|
919
2114
|
compiler.options.resolve.mainFields.unshift("module");
|
|
920
2115
|
}
|
|
921
2116
|
});
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
console.log(`[SibuWebpackPlugin] ${warnings.length} warning(s)`);
|
|
931
|
-
}
|
|
2117
|
+
const tapDoneLogger = () => compiler.hooks?.done?.tap("SibuWebpackPlugin", (stats) => {
|
|
2118
|
+
const statsObj = stats;
|
|
2119
|
+
const info = statsObj?.toJson?.({ modules: false, chunks: false });
|
|
2120
|
+
if (info) {
|
|
2121
|
+
console.log(`[SibuWebpackPlugin] Build completed in ${info.time || 0}ms`);
|
|
2122
|
+
const warnings = info.warnings;
|
|
2123
|
+
if (warnings?.length) {
|
|
2124
|
+
console.log(`[SibuWebpackPlugin] ${warnings.length} warning(s)`);
|
|
932
2125
|
}
|
|
933
|
-
}
|
|
934
|
-
}
|
|
2126
|
+
}
|
|
2127
|
+
});
|
|
2128
|
+
if (devMode === true) tapDoneLogger();
|
|
935
2129
|
compiler.hooks?.environment?.tap("SibuWebpackPlugin", () => {
|
|
2130
|
+
const isDevMode = devMode ?? resolveWebpackDevMode(compiler.options);
|
|
2131
|
+
if (devMode === void 0 && isDevMode) tapDoneLogger();
|
|
936
2132
|
if (!compiler.options.plugins) {
|
|
937
2133
|
compiler.options.plugins = [];
|
|
938
2134
|
}
|
|
@@ -940,10 +2136,20 @@ function sibuWebpackPlugin(options = {}) {
|
|
|
940
2136
|
__SIBU_DEV__: JSON.stringify(isDevMode)
|
|
941
2137
|
};
|
|
942
2138
|
compiler.__sibuDefines = defines;
|
|
2139
|
+
const DefinePlugin = compiler.webpack?.DefinePlugin;
|
|
2140
|
+
if (DefinePlugin) {
|
|
2141
|
+
new DefinePlugin(defines).apply(compiler);
|
|
2142
|
+
}
|
|
943
2143
|
});
|
|
944
2144
|
}
|
|
945
2145
|
};
|
|
946
2146
|
}
|
|
2147
|
+
function resolveWebpackDevMode(options) {
|
|
2148
|
+
const mode = options.mode;
|
|
2149
|
+
if (mode === "development") return true;
|
|
2150
|
+
if (mode === "production" || mode === void 0) return false;
|
|
2151
|
+
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
2152
|
+
}
|
|
947
2153
|
function createPureAnnotationsLoader() {
|
|
948
2154
|
return function sibuPureAnnotationsLoader(source2) {
|
|
949
2155
|
return addPureAnnotations(source2);
|
|
@@ -1012,9 +2218,10 @@ function createWebpackConfig(options = {}) {
|
|
|
1012
2218
|
splitChunks: isDev2 ? false : {
|
|
1013
2219
|
chunks: "all",
|
|
1014
2220
|
cacheGroups: {
|
|
1015
|
-
// Separate
|
|
2221
|
+
// Separate sibujs framework code into its own chunk (the package
|
|
2222
|
+
// directory is `sibujs`; matching `sibu` never selected anything)
|
|
1016
2223
|
sibu: {
|
|
1017
|
-
test: /[\\/]node_modules[\\/]
|
|
2224
|
+
test: /[\\/]node_modules[\\/]sibujs[\\/]/,
|
|
1018
2225
|
name: "sibu",
|
|
1019
2226
|
chunks: "all",
|
|
1020
2227
|
priority: 20
|
|
@@ -1065,8 +2272,9 @@ __export(index_exports, {
|
|
|
1065
2272
|
Loading: () => Loading,
|
|
1066
2273
|
MAX_DRAIN_TEARDOWNS: () => MAX_DRAIN_TEARDOWNS,
|
|
1067
2274
|
Portal: () => Portal,
|
|
1068
|
-
SVG_NS: () =>
|
|
2275
|
+
SVG_NS: () => SVG_NS4,
|
|
1069
2276
|
Suspense: () => Suspense,
|
|
2277
|
+
__renderParsedTemplate: () => __renderParsedTemplate,
|
|
1070
2278
|
__resetIdCounter: () => __resetIdCounter,
|
|
1071
2279
|
a: () => a,
|
|
1072
2280
|
abbr: () => abbr,
|
|
@@ -1381,33 +2589,6 @@ function reportError(error, context2) {
|
|
|
1381
2589
|
});
|
|
1382
2590
|
}
|
|
1383
2591
|
|
|
1384
|
-
// src/core/dev.ts
|
|
1385
|
-
var DEV = typeof __SIBU_DEV__ !== "undefined" ? !!__SIBU_DEV__ : typeof globalThis.__SIBU_DEV__ !== "undefined" ? !!globalThis.__SIBU_DEV__ : (
|
|
1386
|
-
// safe default: off in browser, on in test/dev Node
|
|
1387
|
-
typeof process !== "undefined" && process.env?.NODE_ENV !== "production"
|
|
1388
|
-
);
|
|
1389
|
-
function isDev() {
|
|
1390
|
-
if (typeof globalThis.__SIBU_DEV__ !== "undefined") return !!globalThis.__SIBU_DEV__;
|
|
1391
|
-
if (typeof __SIBU_DEV__ !== "undefined") return !!__SIBU_DEV__;
|
|
1392
|
-
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
1393
|
-
}
|
|
1394
|
-
function devAssert(condition, message) {
|
|
1395
|
-
if ((typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) && !condition) {
|
|
1396
|
-
throw new Error(`[SibuJS] ${message}`);
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
function devWarnLazy(build) {
|
|
1400
|
-
if (typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) {
|
|
1401
|
-
const message = build();
|
|
1402
|
-
if (message) console.warn(`[SibuJS] ${message}`);
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
function devWarn(message) {
|
|
1406
|
-
if (typeof __SIBU_DEV__ !== "undefined" ? __SIBU_DEV__ : DEV) {
|
|
1407
|
-
console.warn(`[SibuJS] ${message}`);
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
2592
|
// src/core/rendering/dispose.ts
|
|
1412
2593
|
var elementDisposers = /* @__PURE__ */ new WeakMap();
|
|
1413
2594
|
var MAX_DRAIN_TEARDOWNS = 1e4;
|
|
@@ -1447,6 +2628,49 @@ function registerDisposer(node, teardown) {
|
|
|
1447
2628
|
const capture = resolveCapture(registrationCaptures[registrationCaptures.length - 1]);
|
|
1448
2629
|
if (capture) capture.entries.push([node, teardown]);
|
|
1449
2630
|
}
|
|
2631
|
+
function withDisposerRollback(build) {
|
|
2632
|
+
const frame = { entries: [], closed: false };
|
|
2633
|
+
const captured = frame.entries;
|
|
2634
|
+
registrationCaptures.push(frame);
|
|
2635
|
+
let result;
|
|
2636
|
+
try {
|
|
2637
|
+
result = build();
|
|
2638
|
+
} catch (err) {
|
|
2639
|
+
let executed = 0;
|
|
2640
|
+
try {
|
|
2641
|
+
while (captured.length > 0) {
|
|
2642
|
+
if (executed >= MAX_DRAIN_TEARDOWNS) {
|
|
2643
|
+
reportDrainRunaway("rollback", executed, captured.length);
|
|
2644
|
+
break;
|
|
2645
|
+
}
|
|
2646
|
+
const [node, teardown] = captured.pop();
|
|
2647
|
+
if (!unregisterDisposer(node, teardown)) continue;
|
|
2648
|
+
executed++;
|
|
2649
|
+
try {
|
|
2650
|
+
teardown();
|
|
2651
|
+
} catch (cleanupErr) {
|
|
2652
|
+
reportError(cleanupErr, { phase: "cleanup", name: "disposer" });
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
} finally {
|
|
2656
|
+
frame.closed = true;
|
|
2657
|
+
captured.length = 0;
|
|
2658
|
+
registrationCaptures.pop();
|
|
2659
|
+
}
|
|
2660
|
+
throw err;
|
|
2661
|
+
}
|
|
2662
|
+
frame.closed = true;
|
|
2663
|
+
registrationCaptures.pop();
|
|
2664
|
+
const parent = resolveCapture(registrationCaptures[registrationCaptures.length - 1]);
|
|
2665
|
+
if (parent) {
|
|
2666
|
+
for (const entry of captured) {
|
|
2667
|
+
if (elementDisposers.get(entry[0])?.includes(entry[1])) parent.entries.push(entry);
|
|
2668
|
+
}
|
|
2669
|
+
frame.forwardTo = parent;
|
|
2670
|
+
}
|
|
2671
|
+
captured.length = 0;
|
|
2672
|
+
return result;
|
|
2673
|
+
}
|
|
1450
2674
|
function unregisterDisposer(node, teardown) {
|
|
1451
2675
|
const disposers = elementDisposers.get(node);
|
|
1452
2676
|
if (!disposers) return false;
|
|
@@ -1466,296 +2690,283 @@ function dispose(node) {
|
|
|
1466
2690
|
const children = Array.from(current.childNodes);
|
|
1467
2691
|
for (let i2 = 0; i2 < children.length; i2++) {
|
|
1468
2692
|
stack.push(children[i2]);
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
for (let i2 = order.length - 1; i2 >= 0; i2--) {
|
|
1472
|
-
disposeNodeOwn(order[i2]);
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1475
|
-
function disposeNodeOwn(node) {
|
|
1476
|
-
if (!elementDisposers.has(node)) return;
|
|
1477
|
-
let executed = 0;
|
|
1478
|
-
let runaway = false;
|
|
1479
|
-
while (!runaway) {
|
|
1480
|
-
const pending = elementDisposers.get(node);
|
|
1481
|
-
if (!pending || pending.length === 0) break;
|
|
1482
|
-
const snapshot = pending.slice();
|
|
1483
|
-
elementDisposers.delete(node);
|
|
1484
|
-
if (DEV) activeBindingCount -= snapshot.length;
|
|
1485
|
-
for (let i2 = 0; i2 < snapshot.length; i2++) {
|
|
1486
|
-
if (executed >= MAX_DRAIN_TEARDOWNS) {
|
|
1487
|
-
const rest = snapshot.slice(i2);
|
|
1488
|
-
const added = elementDisposers.get(node);
|
|
1489
|
-
elementDisposers.set(node, added ? rest.concat(added) : rest);
|
|
1490
|
-
if (DEV) activeBindingCount += rest.length;
|
|
1491
|
-
reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
|
|
1492
|
-
runaway = true;
|
|
1493
|
-
break;
|
|
1494
|
-
}
|
|
1495
|
-
executed++;
|
|
1496
|
-
try {
|
|
1497
|
-
snapshot[i2]();
|
|
1498
|
-
} catch (err) {
|
|
1499
|
-
reportError(err, { phase: "cleanup", name: "disposer" });
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
function replaceChildrenSafely(parent, ...next) {
|
|
1505
|
-
for (let i2 = 0; i2 < next.length; i2++) {
|
|
1506
|
-
const node = next[i2];
|
|
1507
|
-
node.parentNode?.removeChild(node);
|
|
1508
|
-
}
|
|
1509
|
-
const current = Array.from(parent.childNodes);
|
|
1510
|
-
for (let i2 = 0; i2 < current.length; i2++) {
|
|
1511
|
-
dispose(current[i2]);
|
|
1512
|
-
}
|
|
1513
|
-
parent.replaceChildren(...next);
|
|
1514
|
-
}
|
|
1515
|
-
function checkLeaks(warnThreshold = 0) {
|
|
1516
|
-
if (!DEV) return 0;
|
|
1517
|
-
if (warnThreshold > 0 && activeBindingCount > warnThreshold) {
|
|
1518
|
-
devWarn(
|
|
1519
|
-
`checkLeaks: ${activeBindingCount} active DOM bindings detected. Expected \u2264${warnThreshold}. This may indicate a component was removed from the DOM without calling dispose().`
|
|
1520
|
-
);
|
|
1521
|
-
}
|
|
1522
|
-
return activeBindingCount;
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
// src/utils/sanitize.ts
|
|
1526
|
-
function stripControlChars(value) {
|
|
1527
|
-
return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
|
|
1528
|
-
}
|
|
1529
|
-
function isEventHandlerAttr(name) {
|
|
1530
|
-
if (name.length < 3) return false;
|
|
1531
|
-
const lower = name.toLowerCase();
|
|
1532
|
-
return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
|
|
1533
|
-
}
|
|
1534
|
-
var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
|
|
1535
|
-
var OUTER_TRIM = /^[\x00-\x20\x7f-\x9f]+|[\x00-\x20\x7f-\x9f]+$/g;
|
|
1536
|
-
function sanitizeUrl(url) {
|
|
1537
|
-
const probe = stripControlChars(url).trim();
|
|
1538
|
-
if (!probe) return "";
|
|
1539
|
-
const output2 = url.replace(OUTER_TRIM, "");
|
|
1540
|
-
const lower = probe.toLowerCase();
|
|
1541
|
-
let schemeEnd = -1;
|
|
1542
|
-
for (let i2 = 0; i2 < lower.length; i2++) {
|
|
1543
|
-
const ch = lower.charCodeAt(i2);
|
|
1544
|
-
if (ch === 58) {
|
|
1545
|
-
schemeEnd = i2;
|
|
1546
|
-
break;
|
|
1547
|
-
}
|
|
1548
|
-
if (ch === 47 || ch === 63 || ch === 35) break;
|
|
1549
|
-
}
|
|
1550
|
-
if (schemeEnd === -1) return output2;
|
|
1551
|
-
const scheme = lower.slice(0, schemeEnd + 1);
|
|
1552
|
-
if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return output2;
|
|
1553
|
-
if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
|
|
1554
|
-
return output2;
|
|
1555
|
-
}
|
|
1556
|
-
var SRCSET_DESCRIPTOR = /^\s+\d+(\.\d+)?[wx]$/;
|
|
1557
|
-
function sanitizeSrcset(value) {
|
|
1558
|
-
const parts = value.split(",");
|
|
1559
|
-
const out = [];
|
|
1560
|
-
for (let i2 = 0; i2 < parts.length; i2++) {
|
|
1561
|
-
const part = parts[i2].trim();
|
|
1562
|
-
if (!part) continue;
|
|
1563
|
-
const m = part.match(/^(\S+)(\s+.+)?$/);
|
|
1564
|
-
if (!m) continue;
|
|
1565
|
-
if (m[2] !== void 0 && !SRCSET_DESCRIPTOR.test(m[2])) continue;
|
|
1566
|
-
const safe = sanitizeUrl(m[1]);
|
|
1567
|
-
if (!safe) continue;
|
|
1568
|
-
out.push(m[2] ? `${safe}${m[2]}` : safe);
|
|
1569
|
-
}
|
|
1570
|
-
return out.join(", ");
|
|
1571
|
-
}
|
|
1572
|
-
var CSS_DANGER_GATE = /[(:@\\]/;
|
|
1573
|
-
function isCssWhitespace(ch) {
|
|
1574
|
-
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
1575
|
-
}
|
|
1576
|
-
function isHexDigit(ch) {
|
|
1577
|
-
return ch >= "0" && ch <= "9" || ch >= "a" && ch <= "f" || ch >= "A" && ch <= "F";
|
|
1578
|
-
}
|
|
1579
|
-
function decodeCssEscapes(value) {
|
|
1580
|
-
let out = "";
|
|
1581
|
-
for (let i2 = 0; i2 < value.length; i2++) {
|
|
1582
|
-
const ch = value[i2];
|
|
1583
|
-
if (ch !== "\\") {
|
|
1584
|
-
out += ch;
|
|
1585
|
-
continue;
|
|
1586
|
-
}
|
|
1587
|
-
if (i2 + 1 >= value.length) break;
|
|
1588
|
-
const next = value[i2 + 1];
|
|
1589
|
-
if (next === "\n" || next === "\f") {
|
|
1590
|
-
i2 += 1;
|
|
1591
|
-
continue;
|
|
1592
|
-
}
|
|
1593
|
-
if (next === "\r") {
|
|
1594
|
-
i2 += value[i2 + 2] === "\n" ? 2 : 1;
|
|
1595
|
-
continue;
|
|
1596
|
-
}
|
|
1597
|
-
if (isHexDigit(next)) {
|
|
1598
|
-
let hex = "";
|
|
1599
|
-
let j = i2 + 1;
|
|
1600
|
-
while (j < value.length && hex.length < 6 && isHexDigit(value[j])) {
|
|
1601
|
-
hex += value[j];
|
|
1602
|
-
j++;
|
|
1603
|
-
}
|
|
1604
|
-
if (j < value.length && isCssWhitespace(value[j])) {
|
|
1605
|
-
j += value[j] === "\r" && value[j + 1] === "\n" ? 2 : 1;
|
|
1606
|
-
}
|
|
1607
|
-
const code2 = Number.parseInt(hex, 16);
|
|
1608
|
-
const invalid = code2 === 0 || code2 > 1114111 || code2 >= 55296 && code2 <= 57343;
|
|
1609
|
-
out += invalid ? "\uFFFD" : String.fromCodePoint(code2);
|
|
1610
|
-
i2 = j - 1;
|
|
1611
|
-
continue;
|
|
1612
|
-
}
|
|
1613
|
-
out += next;
|
|
1614
|
-
i2 += 1;
|
|
1615
|
-
}
|
|
1616
|
-
return out;
|
|
1617
|
-
}
|
|
1618
|
-
var BLOCKED_CSS_NEEDLES = [
|
|
1619
|
-
"url(",
|
|
1620
|
-
"expression(",
|
|
1621
|
-
"javascript:",
|
|
1622
|
-
"vbscript:",
|
|
1623
|
-
"-moz-binding",
|
|
1624
|
-
"behavior:",
|
|
1625
|
-
"@import",
|
|
1626
|
-
"image-set(",
|
|
1627
|
-
"filter:progid"
|
|
1628
|
-
];
|
|
1629
|
-
function describeElement(el) {
|
|
1630
|
-
if (!el) return "an element";
|
|
1631
|
-
let out = el.tagName.toLowerCase();
|
|
1632
|
-
const id = el.getAttribute("id");
|
|
1633
|
-
if (id) out += `#${id}`;
|
|
1634
|
-
const cls = el.getAttribute("class");
|
|
1635
|
-
if (cls) out += `.${cls.trim().split(/\s+/).slice(0, 3).join(".")}`;
|
|
1636
|
-
return `<${out}>`;
|
|
1637
|
-
}
|
|
1638
|
-
var warnedDeclarations = /* @__PURE__ */ new Set();
|
|
1639
|
-
var MAX_WARNED_DECLARATIONS = 100;
|
|
1640
|
-
var declarationCapAnnounced = false;
|
|
1641
|
-
function warnDroppedDeclaration(value, reason, ctx) {
|
|
1642
|
-
devWarnLazy(() => {
|
|
1643
|
-
const reasons = [
|
|
1644
|
-
"url() in an inline style is an exfiltration channel: the browser fetches it immediately and the URL's path or query can carry page data off-origin",
|
|
1645
|
-
"expression() executes arbitrary script in legacy engines",
|
|
1646
|
-
"the javascript: scheme executes script",
|
|
1647
|
-
"the vbscript: scheme executes script",
|
|
1648
|
-
"-moz-binding loads and runs remote XBL",
|
|
1649
|
-
"behavior: loads and runs a remote HTC script",
|
|
1650
|
-
"@import pulls in a remote stylesheet",
|
|
1651
|
-
"image-set() fetches remote images, the same exfiltration channel as url()",
|
|
1652
|
-
"filter:progid activates legacy scriptable filters"
|
|
1653
|
-
];
|
|
1654
|
-
const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
|
|
1655
|
-
const where = describeElement(ctx?.element);
|
|
1656
|
-
const key = `${where}|${declaration}`;
|
|
1657
|
-
if (warnedDeclarations.has(key)) return "";
|
|
1658
|
-
if (warnedDeclarations.size >= MAX_WARNED_DECLARATIONS) {
|
|
1659
|
-
if (declarationCapAnnounced) return "";
|
|
1660
|
-
declarationCapAnnounced = true;
|
|
1661
|
-
return `${MAX_WARNED_DECLARATIONS} distinct dropped style declarations have been reported; suppressing further ones for the rest of this session so they cannot flood the console. The declarations are still dropped \u2014 only the reporting stops. Fix the reported ones and reload to see any that remain.`;
|
|
1662
|
-
}
|
|
1663
|
-
warnedDeclarations.add(key);
|
|
1664
|
-
return `style declaration "${declaration}" was dropped by the style sanitizer on ${where} \u2014 ${reasons[reason]}. The element renders without it, which usually looks like a missing image rather than an error. Sanctioned alternatives: for a content image use an <img> element (or a <picture>); for decoration, put the rule in a stylesheet and set a class instead \u2014 stylesheet CSS is not sanitized, only inline style attributes are. If this declaration is not yours, it came from untrusted data and the drop just prevented an exfiltration.`;
|
|
1665
|
-
});
|
|
1666
|
-
}
|
|
1667
|
-
function blockedCssReason(value) {
|
|
1668
|
-
if (!CSS_DANGER_GATE.test(value)) return -1;
|
|
1669
|
-
const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
|
|
1670
|
-
const lower = normalized.toLowerCase().replace(/\s+/g, "");
|
|
1671
|
-
for (let i2 = 0; i2 < BLOCKED_CSS_NEEDLES.length; i2++) {
|
|
1672
|
-
if (lower.includes(BLOCKED_CSS_NEEDLES[i2])) return i2;
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
for (let i2 = order.length - 1; i2 >= 0; i2--) {
|
|
2696
|
+
disposeNodeOwn(order[i2]);
|
|
1673
2697
|
}
|
|
1674
|
-
return -1;
|
|
1675
2698
|
}
|
|
1676
|
-
function
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
2699
|
+
function disposeNodeOwn(node) {
|
|
2700
|
+
if (!elementDisposers.has(node)) return;
|
|
2701
|
+
let executed = 0;
|
|
2702
|
+
let runaway = false;
|
|
2703
|
+
while (!runaway) {
|
|
2704
|
+
const pending = elementDisposers.get(node);
|
|
2705
|
+
if (!pending || pending.length === 0) break;
|
|
2706
|
+
const snapshot = pending.slice();
|
|
2707
|
+
elementDisposers.delete(node);
|
|
2708
|
+
if (DEV) activeBindingCount -= snapshot.length;
|
|
2709
|
+
for (let i2 = 0; i2 < snapshot.length; i2++) {
|
|
2710
|
+
if (executed >= MAX_DRAIN_TEARDOWNS) {
|
|
2711
|
+
const rest = snapshot.slice(i2);
|
|
2712
|
+
const added = elementDisposers.get(node);
|
|
2713
|
+
elementDisposers.set(node, added ? rest.concat(added) : rest);
|
|
2714
|
+
if (DEV) activeBindingCount += rest.length;
|
|
2715
|
+
reportDrainRunaway("dispose", executed, rest.length + (added?.length ?? 0));
|
|
2716
|
+
runaway = true;
|
|
2717
|
+
break;
|
|
2718
|
+
}
|
|
2719
|
+
executed++;
|
|
2720
|
+
try {
|
|
2721
|
+
snapshot[i2]();
|
|
2722
|
+
} catch (err) {
|
|
2723
|
+
reportError(err, { phase: "cleanup", name: "disposer" });
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
1681
2727
|
}
|
|
1682
|
-
function
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
return sanitizeCSSValue(input2, context2) === "" ? "" : input2;
|
|
2728
|
+
function replaceChildrenSafely(parent, ...next) {
|
|
2729
|
+
for (let i2 = 0; i2 < next.length; i2++) {
|
|
2730
|
+
const node = next[i2];
|
|
2731
|
+
node.parentNode?.removeChild(node);
|
|
1687
2732
|
}
|
|
1688
|
-
const
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
} catch {
|
|
1692
|
-
return "";
|
|
2733
|
+
const current = Array.from(parent.childNodes);
|
|
2734
|
+
for (let i2 = 0; i2 < current.length; i2++) {
|
|
2735
|
+
dispose(current[i2]);
|
|
1693
2736
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
continue;
|
|
1703
|
-
}
|
|
1704
|
-
const priority = probe.style.getPropertyPriority(property);
|
|
1705
|
-
declarations.push(`${property}: ${value}${priority ? ` !${priority}` : ""}`);
|
|
2737
|
+
parent.replaceChildren(...next);
|
|
2738
|
+
}
|
|
2739
|
+
function checkLeaks(warnThreshold = 0) {
|
|
2740
|
+
if (!DEV) return 0;
|
|
2741
|
+
if (warnThreshold > 0 && activeBindingCount > warnThreshold) {
|
|
2742
|
+
devWarn(
|
|
2743
|
+
`checkLeaks: ${activeBindingCount} active DOM bindings detected. Expected \u2264${warnThreshold}. This may indicate a component was removed from the DOM without calling dispose().`
|
|
2744
|
+
);
|
|
1706
2745
|
}
|
|
1707
|
-
return
|
|
2746
|
+
return activeBindingCount;
|
|
1708
2747
|
}
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
"
|
|
1713
|
-
"action",
|
|
1714
|
-
"formaction",
|
|
1715
|
-
"formtarget",
|
|
1716
|
-
"cite",
|
|
1717
|
-
"poster",
|
|
1718
|
-
"background",
|
|
1719
|
-
"srcset",
|
|
1720
|
-
"ping",
|
|
1721
|
-
"data",
|
|
1722
|
-
// `<html manifest>` is a URL sink too. It was carried only by the SSR
|
|
1723
|
-
// serializers' private copy of this set; folding that copy into this one would
|
|
1724
|
-
// otherwise have silently dropped its coverage.
|
|
1725
|
-
"manifest"
|
|
1726
|
-
]);
|
|
1727
|
-
var HTML_CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set(["srcdoc"]);
|
|
1728
|
-
function isHtmlContentAttribute(name) {
|
|
1729
|
-
return HTML_CONTENT_ATTRIBUTES.has(name.toLowerCase());
|
|
2748
|
+
|
|
2749
|
+
// src/utils/metaRefresh.ts
|
|
2750
|
+
function isAsciiWhitespace(ch) {
|
|
2751
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
|
|
1730
2752
|
}
|
|
1731
|
-
function
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
return value;
|
|
2753
|
+
function trimAsciiWhitespace(value) {
|
|
2754
|
+
let start = 0;
|
|
2755
|
+
let end = value.length;
|
|
2756
|
+
while (start < end && isAsciiWhitespace(value[start])) start++;
|
|
2757
|
+
while (end > start && isAsciiWhitespace(value[end - 1])) end--;
|
|
2758
|
+
return value.slice(start, end);
|
|
2759
|
+
}
|
|
2760
|
+
var forbidden = (reason) => ({ kind: "forbidden", reason });
|
|
2761
|
+
function parseMetaRefreshContent(content) {
|
|
2762
|
+
const raw = trimAsciiWhitespace(stripControlChars(content));
|
|
2763
|
+
if (raw === "") return forbidden(DEV ? "empty content" : "");
|
|
2764
|
+
let i2 = 0;
|
|
2765
|
+
while (i2 < raw.length && raw[i2] >= "0" && raw[i2] <= "9") i2++;
|
|
2766
|
+
if (i2 === 0) return forbidden(DEV ? "missing or non-numeric delay" : "");
|
|
2767
|
+
const delay = Number.parseInt(raw.slice(0, i2), 10);
|
|
2768
|
+
if (!Number.isFinite(delay)) return forbidden(DEV ? "unparseable delay" : "");
|
|
2769
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
2770
|
+
if (i2 === raw.length) return { kind: "delay-only", delay };
|
|
2771
|
+
if (raw[i2] !== ";" && raw[i2] !== ",") return forbidden(DEV ? "unexpected text after delay" : "");
|
|
2772
|
+
i2++;
|
|
2773
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
2774
|
+
const keyStart = i2;
|
|
2775
|
+
while (i2 < raw.length && !isAsciiWhitespace(raw[i2]) && raw[i2] !== "=") i2++;
|
|
2776
|
+
const key = raw.slice(keyStart, i2).toLowerCase();
|
|
2777
|
+
if (key !== "url") return forbidden(DEV ? `unsupported refresh key ${JSON.stringify(key)}` : "");
|
|
2778
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
2779
|
+
if (raw[i2] !== "=") return forbidden(DEV ? "missing '=' after url" : "");
|
|
2780
|
+
i2++;
|
|
2781
|
+
while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
|
|
2782
|
+
let destination;
|
|
2783
|
+
const quote2 = raw[i2];
|
|
2784
|
+
if (quote2 === '"' || quote2 === "'") {
|
|
2785
|
+
const close = raw.indexOf(quote2, i2 + 1);
|
|
2786
|
+
if (close === -1) return forbidden(DEV ? "unterminated quoted destination" : "");
|
|
2787
|
+
destination = raw.slice(i2 + 1, close);
|
|
2788
|
+
const rest = trimAsciiWhitespace(raw.slice(close + 1));
|
|
2789
|
+
if (rest !== "") return forbidden(DEV ? "trailing text after quoted destination" : "");
|
|
2790
|
+
} else {
|
|
2791
|
+
destination = trimAsciiWhitespace(raw.slice(i2));
|
|
2792
|
+
if (/[;,]/.test(destination)) return forbidden(DEV ? "multiple refresh assignments" : "");
|
|
2793
|
+
}
|
|
2794
|
+
if (destination === "") return forbidden(DEV ? "empty destination" : "");
|
|
2795
|
+
const sanitizedDestination = sanitizeUrl(destination);
|
|
2796
|
+
if (sanitizedDestination === "") return forbidden(DEV ? "destination uses a disallowed protocol" : "");
|
|
2797
|
+
return { kind: "allowed", delay, destination, sanitizedDestination };
|
|
2798
|
+
}
|
|
2799
|
+
function resolveMetaRefreshPolicy(attributes) {
|
|
2800
|
+
let httpEquiv;
|
|
2801
|
+
let content;
|
|
2802
|
+
let duplicateName;
|
|
2803
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2804
|
+
for (const [key, value] of attributes) {
|
|
2805
|
+
const canonical = canonicalAttrName(key);
|
|
2806
|
+
if (seen.has(canonical)) duplicateName = canonical;
|
|
2807
|
+
seen.add(canonical);
|
|
2808
|
+
if (canonical === "http-equiv") httpEquiv = value;
|
|
2809
|
+
else if (canonical === "content") content = value;
|
|
2810
|
+
}
|
|
2811
|
+
if (duplicateName !== void 0) {
|
|
2812
|
+
return forbidden(DEV ? `duplicate case-insensitive attribute ${JSON.stringify(duplicateName)}` : "");
|
|
2813
|
+
}
|
|
2814
|
+
if (typeof httpEquiv !== "string") return { kind: "not-refresh" };
|
|
2815
|
+
if (trimAsciiWhitespace(stripControlChars(httpEquiv)).toLowerCase() !== "refresh") {
|
|
2816
|
+
return { kind: "not-refresh" };
|
|
2817
|
+
}
|
|
2818
|
+
if (typeof content !== "string") return { kind: "not-refresh" };
|
|
2819
|
+
return parseMetaRefreshContent(content);
|
|
1737
2820
|
}
|
|
1738
2821
|
|
|
1739
|
-
// src/utils/
|
|
2822
|
+
// src/utils/elementPolicy.ts
|
|
1740
2823
|
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
1741
|
-
var
|
|
2824
|
+
var SVG_NS2 = "http://www.w3.org/2000/svg";
|
|
2825
|
+
var BLOCKED_ELEMENTS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
2826
|
+
function canonicalTagName(tag) {
|
|
2827
|
+
return canonicalAttrName(tag);
|
|
2828
|
+
}
|
|
2829
|
+
function isBlockedElement(tag) {
|
|
2830
|
+
return BLOCKED_ELEMENTS.has(canonicalTagName(tag));
|
|
2831
|
+
}
|
|
2832
|
+
var CODE_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
2833
|
+
function isCodeTextElement(tag) {
|
|
2834
|
+
return CODE_TEXT_ELEMENTS.has(canonicalTagName(tag));
|
|
2835
|
+
}
|
|
2836
|
+
var ContextualRefusal = {
|
|
2837
|
+
None: 0,
|
|
2838
|
+
/** The element would carry a refresh directive the shared policy forbids. */
|
|
2839
|
+
MetaRefreshForbidden: 1,
|
|
2840
|
+
/** A `<meta>` with a reactive binding may not carry any refresh directive. */
|
|
2841
|
+
MetaRefreshReactive: 2,
|
|
2842
|
+
/** A runtime value may not choose which program a `<script>` runs. */
|
|
2843
|
+
ScriptSource: 3,
|
|
2844
|
+
/** An SVG animation may not target a URL, handler or document attribute. */
|
|
2845
|
+
AnimationTarget: 4,
|
|
2846
|
+
/** A runtime-written `href` may not become an applied stylesheet. */
|
|
2847
|
+
StylesheetSource: 5
|
|
2848
|
+
};
|
|
2849
|
+
var SCRIPT_SOURCE_ATTRIBUTES = /* @__PURE__ */ new Set(["src", "href", "xlink:href", "type", "language"]);
|
|
2850
|
+
var SVG_ANIMATION_ELEMENTS = /* @__PURE__ */ new Set(["animate", "set", "animateMotion", "animateTransform", "animateColor"]);
|
|
2851
|
+
var reactiveMetaElements = /* @__PURE__ */ new WeakSet();
|
|
2852
|
+
function isHtmlNamespace(el) {
|
|
2853
|
+
return el.namespaceURI === HTML_NS || el.namespaceURI === null;
|
|
2854
|
+
}
|
|
2855
|
+
function metaSnapshot(el, canonical, value) {
|
|
2856
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
2857
|
+
const attrs = el.attributes;
|
|
2858
|
+
for (let i2 = 0; i2 < attrs.length; i2++) {
|
|
2859
|
+
const attr = attrs[i2];
|
|
2860
|
+
if (attr.name === canonical) continue;
|
|
2861
|
+
snapshot.set(attr.name, attr.value);
|
|
2862
|
+
}
|
|
2863
|
+
if (canonical !== null && value !== null) snapshot.set(canonical, value);
|
|
2864
|
+
return snapshot;
|
|
2865
|
+
}
|
|
2866
|
+
function claimReactiveMeta(el) {
|
|
2867
|
+
if (reactiveMetaElements.has(el)) return;
|
|
2868
|
+
reactiveMetaElements.add(el);
|
|
2869
|
+
if (el.getAttribute("content") === null) return;
|
|
2870
|
+
if (resolveMetaRefreshPolicy(metaSnapshot(el, null, null)).kind !== "not-refresh") {
|
|
2871
|
+
el.removeAttribute("content");
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
function metaRefusal(el, name, value, origin) {
|
|
2875
|
+
if (!isHtmlNamespace(el)) return ContextualRefusal.None;
|
|
2876
|
+
const canonical = canonicalAttrName(name);
|
|
2877
|
+
if (canonical !== "http-equiv" && canonical !== "content") return ContextualRefusal.None;
|
|
2878
|
+
if (origin === "reactive") claimReactiveMeta(el);
|
|
2879
|
+
if (value === null) return ContextualRefusal.None;
|
|
2880
|
+
if (canonical === "content" && !el.hasAttribute("http-equiv")) return ContextualRefusal.None;
|
|
2881
|
+
const decision = resolveMetaRefreshPolicy(metaSnapshot(el, canonical, value));
|
|
2882
|
+
if (decision.kind === "forbidden") return ContextualRefusal.MetaRefreshForbidden;
|
|
2883
|
+
if (decision.kind !== "not-refresh" && reactiveMetaElements.has(el)) return ContextualRefusal.MetaRefreshReactive;
|
|
2884
|
+
return ContextualRefusal.None;
|
|
2885
|
+
}
|
|
2886
|
+
function animationRefusal(name, value) {
|
|
2887
|
+
if (value === null || canonicalAttrName(name) !== "attributename") return ContextualRefusal.None;
|
|
2888
|
+
const target = stripControlChars(value);
|
|
2889
|
+
return isUrlAttribute(target) || isEventHandlerAttr(target) || isHtmlContentAttribute(target) ? ContextualRefusal.AnimationTarget : ContextualRefusal.None;
|
|
2890
|
+
}
|
|
2891
|
+
var runtimeHrefLinks = /* @__PURE__ */ new WeakSet();
|
|
2892
|
+
function relHasStylesheet(rel) {
|
|
2893
|
+
if (rel === null) return false;
|
|
2894
|
+
const lower = canonicalAttrName(rel);
|
|
2895
|
+
if (!lower.includes("stylesheet")) return false;
|
|
2896
|
+
const tokens = lower.split(/[\t\n\f\r ]+/);
|
|
2897
|
+
for (let i2 = 0; i2 < tokens.length; i2++) if (tokens[i2] === "stylesheet") return true;
|
|
2898
|
+
return false;
|
|
2899
|
+
}
|
|
2900
|
+
function stylesheetRefusal(el, name, value, origin) {
|
|
2901
|
+
if (!isHtmlNamespace(el)) return ContextualRefusal.None;
|
|
2902
|
+
const canonical = canonicalAttrName(name);
|
|
2903
|
+
if (canonical === "href") {
|
|
2904
|
+
if (origin === "static" || value === null) return ContextualRefusal.None;
|
|
2905
|
+
if (relHasStylesheet(el.getAttribute("rel"))) return ContextualRefusal.StylesheetSource;
|
|
2906
|
+
runtimeHrefLinks.add(el);
|
|
2907
|
+
return ContextualRefusal.None;
|
|
2908
|
+
}
|
|
2909
|
+
if (canonical === "rel") {
|
|
2910
|
+
if (!relHasStylesheet(value)) return ContextualRefusal.None;
|
|
2911
|
+
return runtimeHrefLinks.has(el) && el.hasAttribute("href") ? ContextualRefusal.StylesheetSource : ContextualRefusal.None;
|
|
2912
|
+
}
|
|
2913
|
+
return ContextualRefusal.None;
|
|
2914
|
+
}
|
|
2915
|
+
function contextualAttributeRefusal(el, name, value, origin) {
|
|
2916
|
+
const local = el.localName;
|
|
2917
|
+
if (local === "meta") return metaRefusal(el, name, value, origin);
|
|
2918
|
+
if (local === "link") return stylesheetRefusal(el, name, value, origin);
|
|
2919
|
+
if (local === "script") {
|
|
2920
|
+
if (origin === "static" || value === null) return ContextualRefusal.None;
|
|
2921
|
+
return SCRIPT_SOURCE_ATTRIBUTES.has(canonicalAttrName(name)) ? ContextualRefusal.ScriptSource : ContextualRefusal.None;
|
|
2922
|
+
}
|
|
2923
|
+
if (SVG_ANIMATION_ELEMENTS.has(local) && el.namespaceURI === SVG_NS2) return animationRefusal(name, value);
|
|
2924
|
+
return ContextualRefusal.None;
|
|
2925
|
+
}
|
|
2926
|
+
function settleAttributeProvenance(el, name, origin) {
|
|
2927
|
+
if (el.localName !== "link" || canonicalAttrName(name) !== "href") return;
|
|
2928
|
+
if (origin !== "static" && el.hasAttribute("href")) runtimeHrefLinks.add(el);
|
|
2929
|
+
else runtimeHrefLinks.delete(el);
|
|
2930
|
+
}
|
|
2931
|
+
|
|
2932
|
+
// src/utils/setSafeAttribute.ts
|
|
2933
|
+
var HTML_NS2 = "http://www.w3.org/1999/xhtml";
|
|
2934
|
+
var SVG_NS3 = "http://www.w3.org/2000/svg";
|
|
1742
2935
|
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
1743
2936
|
var XML_NS = "http://www.w3.org/XML/1998/namespace";
|
|
1744
2937
|
var BOOLEAN_IDL_ATTRS = /* @__PURE__ */ new Set(["checked", "disabled", "selected"]);
|
|
1745
2938
|
function isHtmlElement(el) {
|
|
1746
|
-
return el.namespaceURI === null || el.namespaceURI ===
|
|
2939
|
+
return el.namespaceURI === null || el.namespaceURI === HTML_NS2;
|
|
2940
|
+
}
|
|
2941
|
+
function warnContextualRefusal(label2, name, refusal) {
|
|
2942
|
+
devWarnLazy(() => {
|
|
2943
|
+
const reasons = [
|
|
2944
|
+
"",
|
|
2945
|
+
'the element would become a <meta http-equiv="refresh"> directive the shared refresh policy forbids (a destination outside the URL allowlist, or a directive too malformed to read unambiguously)',
|
|
2946
|
+
"a <meta> whose http-equiv or content is reactive may never carry a refresh directive: a browser schedules the navigation as soon as the directive is valid, and nothing can withdraw it when the state changes back",
|
|
2947
|
+
"a runtime value may not choose the program a <script> runs; name the script in static template source, or load it through Head({ script }) as an explicit trust decision",
|
|
2948
|
+
"an SVG animation may not target a URL, event-handler or nested-document attribute; its to / values would be written into that attribute without passing the URL policy",
|
|
2949
|
+
'a runtime-chosen href may not become an applied <link rel="stylesheet">: a well-formed URL is not a trusted stylesheet. Name the stylesheet in static template source, or load a runtime-chosen one through Head({ link }) as an explicit trust decision'
|
|
2950
|
+
];
|
|
2951
|
+
return `${label2}: refusing "${name}" in this element's context \u2014 ${reasons[refusal]}. The write was not performed.`;
|
|
2952
|
+
});
|
|
1747
2953
|
}
|
|
1748
2954
|
function setProp(el, key, val) {
|
|
1749
2955
|
el[key] = val;
|
|
1750
2956
|
}
|
|
1751
2957
|
function namespaceFor(el, name) {
|
|
1752
|
-
if (el.namespaceURI !==
|
|
2958
|
+
if (el.namespaceURI !== SVG_NS3) return null;
|
|
1753
2959
|
const lower = name.toLowerCase();
|
|
1754
2960
|
if (lower.startsWith("xlink:")) return XLINK_NS;
|
|
1755
2961
|
if (lower.startsWith("xml:")) return XML_NS;
|
|
1756
2962
|
return null;
|
|
1757
2963
|
}
|
|
1758
2964
|
function setSafeAttribute(el, name, value, options = {}) {
|
|
2965
|
+
const written = commitSafeAttribute(el, name, value, options);
|
|
2966
|
+
if (el.localName === "link") settleAttributeProvenance(el, name, options.reactive ? "reactive" : "runtime");
|
|
2967
|
+
return written;
|
|
2968
|
+
}
|
|
2969
|
+
function commitSafeAttribute(el, name, value, options) {
|
|
1759
2970
|
const ns = namespaceFor(el, name);
|
|
1760
2971
|
const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
|
|
1761
2972
|
if (isEventHandlerAttr(name)) {
|
|
@@ -1768,6 +2979,14 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1768
2979
|
else el.removeAttribute(name);
|
|
1769
2980
|
return false;
|
|
1770
2981
|
}
|
|
2982
|
+
const pending = value == null || value === false ? null : value === true ? "" : String(value);
|
|
2983
|
+
const refusal = contextualAttributeRefusal(el, name, pending, options.reactive ? "reactive" : "runtime");
|
|
2984
|
+
if (refusal !== ContextualRefusal.None) {
|
|
2985
|
+
warnContextualRefusal(options.label ?? "setSafeAttribute", name, refusal);
|
|
2986
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
2987
|
+
else el.removeAttribute(name);
|
|
2988
|
+
return false;
|
|
2989
|
+
}
|
|
1771
2990
|
if (value == null) {
|
|
1772
2991
|
if (ns) el.removeAttributeNS(ns, localName);
|
|
1773
2992
|
else el.removeAttribute(name);
|
|
@@ -1811,13 +3030,32 @@ function setSafeAttribute(el, name, value, options = {}) {
|
|
|
1811
3030
|
setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
|
|
1812
3031
|
return true;
|
|
1813
3032
|
}
|
|
1814
|
-
const safe =
|
|
3033
|
+
const safe = str === "" ? "" : resolveAttributeValue(name, str, { element: el });
|
|
3034
|
+
if (safe === null) {
|
|
3035
|
+
if (ns) el.removeAttributeNS(ns, localName);
|
|
3036
|
+
else el.removeAttribute(name);
|
|
3037
|
+
return true;
|
|
3038
|
+
}
|
|
1815
3039
|
const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
|
|
1816
3040
|
if (current === safe) return true;
|
|
1817
3041
|
if (ns) el.setAttributeNS(ns, name, safe);
|
|
1818
3042
|
else el.setAttribute(name, safe);
|
|
1819
3043
|
return true;
|
|
1820
3044
|
}
|
|
3045
|
+
function setTrustedAttribute(el, name, value) {
|
|
3046
|
+
if (isHtmlContentAttribute(name)) {
|
|
3047
|
+
if (DEV) devWarn(`html: refusing static attribute "${name}" \u2014 the browser parses it as a nested document.`);
|
|
3048
|
+
return false;
|
|
3049
|
+
}
|
|
3050
|
+
const refusal = contextualAttributeRefusal(el, name, value, "static");
|
|
3051
|
+
if (refusal !== ContextualRefusal.None) {
|
|
3052
|
+
warnContextualRefusal("html (static attribute)", name, refusal);
|
|
3053
|
+
return false;
|
|
3054
|
+
}
|
|
3055
|
+
el.setAttribute(name, value);
|
|
3056
|
+
if (el.localName === "link") settleAttributeProvenance(el, name, "static");
|
|
3057
|
+
return true;
|
|
3058
|
+
}
|
|
1821
3059
|
|
|
1822
3060
|
// src/reactivity/track-core.ts
|
|
1823
3061
|
var POOL_MAX = 4096;
|
|
@@ -2310,7 +3548,7 @@ function forEachSubscriber(signal2, visit) {
|
|
|
2310
3548
|
}
|
|
2311
3549
|
|
|
2312
3550
|
// src/reactivity/track.ts
|
|
2313
|
-
var _runtimeVersion = true ? "4.
|
|
3551
|
+
var _runtimeVersion = true ? "4.8.0" : "dev";
|
|
2314
3552
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
2315
3553
|
function resolveReactiveApi() {
|
|
2316
3554
|
const g2 = globalThis;
|
|
@@ -2381,7 +3619,7 @@ function bindAttribute(el, attr, getter) {
|
|
|
2381
3619
|
reportError(err, { phase: "binding", name: `bindAttribute("${attr}")`, node: el });
|
|
2382
3620
|
return;
|
|
2383
3621
|
}
|
|
2384
|
-
setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")
|
|
3622
|
+
setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")`, reactive: true });
|
|
2385
3623
|
}
|
|
2386
3624
|
return reactiveBinding2(commit, el);
|
|
2387
3625
|
}
|
|
@@ -2406,7 +3644,7 @@ function bindDynamic(el, nameGetter, valueGetter) {
|
|
|
2406
3644
|
el.removeAttribute(prevName);
|
|
2407
3645
|
prevName = null;
|
|
2408
3646
|
}
|
|
2409
|
-
if (!setSafeAttribute(el, name, value, { label: "bindDynamic" })) return;
|
|
3647
|
+
if (!setSafeAttribute(el, name, value, { label: "bindDynamic", reactive: true })) return;
|
|
2410
3648
|
prevName = name;
|
|
2411
3649
|
}
|
|
2412
3650
|
const teardown = reactiveBinding2(commit, el);
|
|
@@ -2587,11 +3825,7 @@ function bindChildNode(placeholder, getter) {
|
|
|
2587
3825
|
}
|
|
2588
3826
|
|
|
2589
3827
|
// src/core/rendering/tagFactory.ts
|
|
2590
|
-
var
|
|
2591
|
-
var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
|
|
2592
|
-
function isBlockedTag(tag) {
|
|
2593
|
-
return BLOCKED_TAGS.has(tag.toLowerCase());
|
|
2594
|
-
}
|
|
3828
|
+
var SVG_NS4 = "http://www.w3.org/2000/svg";
|
|
2595
3829
|
var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
|
|
2596
3830
|
"config",
|
|
2597
3831
|
"location",
|
|
@@ -2618,8 +3852,35 @@ function toKebab(prop) {
|
|
|
2618
3852
|
}
|
|
2619
3853
|
function applyStyle(el, style2) {
|
|
2620
3854
|
if (typeof style2 === "function") {
|
|
3855
|
+
const getter = style2;
|
|
3856
|
+
let written = [];
|
|
3857
|
+
let wroteString = false;
|
|
2621
3858
|
const teardown = reactiveBinding2(() => {
|
|
2622
|
-
|
|
3859
|
+
const value = getter();
|
|
3860
|
+
if (value === null || typeof value !== "object") {
|
|
3861
|
+
written = [];
|
|
3862
|
+
wroteString = true;
|
|
3863
|
+
el.setAttribute("style", sanitizeStyleAttribute(String(value), { element: el }));
|
|
3864
|
+
return;
|
|
3865
|
+
}
|
|
3866
|
+
const decl = el.style;
|
|
3867
|
+
if (wroteString) {
|
|
3868
|
+
el.removeAttribute("style");
|
|
3869
|
+
wroteString = false;
|
|
3870
|
+
}
|
|
3871
|
+
const next = [];
|
|
3872
|
+
for (const prop in value) {
|
|
3873
|
+
if (!Object.hasOwn(value, prop)) continue;
|
|
3874
|
+
const val = value[prop];
|
|
3875
|
+
if (val == null) continue;
|
|
3876
|
+
const name = toKebab(prop);
|
|
3877
|
+
next.push(name);
|
|
3878
|
+
decl.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
|
|
3879
|
+
}
|
|
3880
|
+
for (let i2 = 0; i2 < written.length; i2++) {
|
|
3881
|
+
if (next.indexOf(written[i2]) === -1) decl.removeProperty(written[i2]);
|
|
3882
|
+
}
|
|
3883
|
+
written = next;
|
|
2623
3884
|
}, el);
|
|
2624
3885
|
registerDisposer(el, teardown);
|
|
2625
3886
|
return;
|
|
@@ -2630,16 +3891,17 @@ function applyStyle(el, style2) {
|
|
|
2630
3891
|
}
|
|
2631
3892
|
const htmlEl = el;
|
|
2632
3893
|
for (const prop in style2) {
|
|
3894
|
+
if (!Object.hasOwn(style2, prop)) continue;
|
|
2633
3895
|
const val = style2[prop];
|
|
2634
3896
|
const name = toKebab(prop);
|
|
2635
3897
|
if (typeof val === "function") {
|
|
2636
3898
|
const getter = val;
|
|
2637
3899
|
const teardown = reactiveBinding2(() => {
|
|
2638
|
-
htmlEl.style.setProperty(name,
|
|
3900
|
+
htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(getter()), { element: el }));
|
|
2639
3901
|
}, el);
|
|
2640
3902
|
registerDisposer(el, teardown);
|
|
2641
3903
|
} else {
|
|
2642
|
-
htmlEl.style.setProperty(name,
|
|
3904
|
+
htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
|
|
2643
3905
|
}
|
|
2644
3906
|
}
|
|
2645
3907
|
}
|
|
@@ -2650,7 +3912,9 @@ function applyClass(el, cls) {
|
|
|
2650
3912
|
}
|
|
2651
3913
|
if (typeof cls === "function") {
|
|
2652
3914
|
const teardown = reactiveBinding2(() => {
|
|
2653
|
-
|
|
3915
|
+
const value = cls();
|
|
3916
|
+
if (value == null || value === false) el.removeAttribute("class");
|
|
3917
|
+
else el.setAttribute("class", value);
|
|
2654
3918
|
}, el);
|
|
2655
3919
|
registerDisposer(el, teardown);
|
|
2656
3920
|
return;
|
|
@@ -2659,6 +3923,7 @@ function applyClass(el, cls) {
|
|
|
2659
3923
|
let hasReactive = false;
|
|
2660
3924
|
let result = "";
|
|
2661
3925
|
for (const name in obj) {
|
|
3926
|
+
if (!Object.hasOwn(obj, name)) continue;
|
|
2662
3927
|
const val = obj[name];
|
|
2663
3928
|
if (typeof val === "function") {
|
|
2664
3929
|
hasReactive = true;
|
|
@@ -2670,6 +3935,7 @@ function applyClass(el, cls) {
|
|
|
2670
3935
|
const update = () => {
|
|
2671
3936
|
let r = "";
|
|
2672
3937
|
for (const name in obj) {
|
|
3938
|
+
if (!Object.hasOwn(obj, name)) continue;
|
|
2673
3939
|
const val = obj[name];
|
|
2674
3940
|
const active = typeof val === "function" ? val() : val;
|
|
2675
3941
|
if (active) r = r ? `${r} ${name}` : name;
|
|
@@ -2732,8 +3998,8 @@ function appendChildren(el, nodes) {
|
|
|
2732
3998
|
}
|
|
2733
3999
|
}
|
|
2734
4000
|
}
|
|
2735
|
-
|
|
2736
|
-
const blocked =
|
|
4001
|
+
function tagFactory(tag, ns) {
|
|
4002
|
+
const blocked = isBlockedElement(tag);
|
|
2737
4003
|
return (first, second) => {
|
|
2738
4004
|
if (blocked) {
|
|
2739
4005
|
throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
@@ -2781,7 +4047,9 @@ var tagFactory = (tag, ns) => {
|
|
|
2781
4047
|
const pClass = props.class;
|
|
2782
4048
|
if (pClass != null) applyClass(el, pClass);
|
|
2783
4049
|
const pId = props.id;
|
|
2784
|
-
if (pId
|
|
4050
|
+
if (typeof pId === "function") {
|
|
4051
|
+
registerDisposer(el, bindAttribute(el, "id", pId));
|
|
4052
|
+
} else if (pId != null) {
|
|
2785
4053
|
if (DEV && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
|
|
2786
4054
|
devWarn(
|
|
2787
4055
|
`tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
|
|
@@ -2794,6 +4062,7 @@ var tagFactory = (tag, ns) => {
|
|
|
2794
4062
|
const pOn = props.on;
|
|
2795
4063
|
if (pOn) {
|
|
2796
4064
|
for (const ev in pOn) {
|
|
4065
|
+
if (!Object.hasOwn(pOn, ev)) continue;
|
|
2797
4066
|
const handler = pOn[ev];
|
|
2798
4067
|
if (typeof handler === "function") {
|
|
2799
4068
|
el.addEventListener(ev, handler);
|
|
@@ -2820,6 +4089,7 @@ var tagFactory = (tag, ns) => {
|
|
|
2820
4089
|
continue;
|
|
2821
4090
|
// already handled above / below
|
|
2822
4091
|
default: {
|
|
4092
|
+
if (!Object.hasOwn(props, key)) continue;
|
|
2823
4093
|
const value = props[key];
|
|
2824
4094
|
if (value == null) continue;
|
|
2825
4095
|
if (isEventHandlerAttr(key)) continue;
|
|
@@ -2831,12 +4101,10 @@ var tagFactory = (tag, ns) => {
|
|
|
2831
4101
|
}
|
|
2832
4102
|
}
|
|
2833
4103
|
}
|
|
2834
|
-
if (
|
|
2835
|
-
props.onElement(el);
|
|
2836
|
-
}
|
|
4104
|
+
if (typeof props.onElement === "function") props.onElement(el);
|
|
2837
4105
|
return el;
|
|
2838
4106
|
};
|
|
2839
|
-
}
|
|
4107
|
+
}
|
|
2840
4108
|
|
|
2841
4109
|
// src/core/rendering/html.ts
|
|
2842
4110
|
var html = tagFactory("html");
|
|
@@ -2911,7 +4179,7 @@ var param = tagFactory("param");
|
|
|
2911
4179
|
var picture = tagFactory("picture");
|
|
2912
4180
|
var portal = tagFactory("portal");
|
|
2913
4181
|
var source = tagFactory("source");
|
|
2914
|
-
var svg = tagFactory("svg",
|
|
4182
|
+
var svg = tagFactory("svg", SVG_NS4);
|
|
2915
4183
|
var math = tagFactory("math");
|
|
2916
4184
|
var canvas = tagFactory("canvas");
|
|
2917
4185
|
var noscript = tagFactory("noscript");
|
|
@@ -2952,26 +4220,26 @@ var base = tagFactory("base");
|
|
|
2952
4220
|
var link = tagFactory("link");
|
|
2953
4221
|
var meta = tagFactory("meta");
|
|
2954
4222
|
var style = tagFactory("style");
|
|
2955
|
-
var circle = tagFactory("circle",
|
|
2956
|
-
var ellipse = tagFactory("ellipse",
|
|
2957
|
-
var g = tagFactory("g",
|
|
2958
|
-
var line = tagFactory("line",
|
|
2959
|
-
var path = tagFactory("path",
|
|
2960
|
-
var polygon = tagFactory("polygon",
|
|
2961
|
-
var polyline = tagFactory("polyline",
|
|
2962
|
-
var rect = tagFactory("rect",
|
|
2963
|
-
var text = tagFactory("text",
|
|
2964
|
-
var tspan = tagFactory("tspan",
|
|
2965
|
-
var defs = tagFactory("defs",
|
|
2966
|
-
var clipPath = tagFactory("clipPath",
|
|
2967
|
-
var mask = tagFactory("mask",
|
|
2968
|
-
var pattern = tagFactory("pattern",
|
|
2969
|
-
var linearGradient = tagFactory("linearGradient",
|
|
2970
|
-
var radialGradient = tagFactory("radialGradient",
|
|
2971
|
-
var stop = tagFactory("stop",
|
|
2972
|
-
var use = tagFactory("use",
|
|
2973
|
-
var symbol = tagFactory("symbol",
|
|
2974
|
-
var marker = tagFactory("marker",
|
|
4223
|
+
var circle = tagFactory("circle", SVG_NS4);
|
|
4224
|
+
var ellipse = tagFactory("ellipse", SVG_NS4);
|
|
4225
|
+
var g = tagFactory("g", SVG_NS4);
|
|
4226
|
+
var line = tagFactory("line", SVG_NS4);
|
|
4227
|
+
var path = tagFactory("path", SVG_NS4);
|
|
4228
|
+
var polygon = tagFactory("polygon", SVG_NS4);
|
|
4229
|
+
var polyline = tagFactory("polyline", SVG_NS4);
|
|
4230
|
+
var rect = tagFactory("rect", SVG_NS4);
|
|
4231
|
+
var text = tagFactory("text", SVG_NS4);
|
|
4232
|
+
var tspan = tagFactory("tspan", SVG_NS4);
|
|
4233
|
+
var defs = tagFactory("defs", SVG_NS4);
|
|
4234
|
+
var clipPath = tagFactory("clipPath", SVG_NS4);
|
|
4235
|
+
var mask = tagFactory("mask", SVG_NS4);
|
|
4236
|
+
var pattern = tagFactory("pattern", SVG_NS4);
|
|
4237
|
+
var linearGradient = tagFactory("linearGradient", SVG_NS4);
|
|
4238
|
+
var radialGradient = tagFactory("radialGradient", SVG_NS4);
|
|
4239
|
+
var stop = tagFactory("stop", SVG_NS4);
|
|
4240
|
+
var use = tagFactory("use", SVG_NS4);
|
|
4241
|
+
var symbol = tagFactory("symbol", SVG_NS4);
|
|
4242
|
+
var marker = tagFactory("marker", SVG_NS4);
|
|
2975
4243
|
var center = tagFactory("center");
|
|
2976
4244
|
var font = tagFactory("font");
|
|
2977
4245
|
var marquee = tagFactory("marquee");
|
|
@@ -3085,10 +4353,13 @@ function safeCall(cb, hookName) {
|
|
|
3085
4353
|
return void 0;
|
|
3086
4354
|
}
|
|
3087
4355
|
}
|
|
3088
|
-
function runMountCallback(callback, hookName, element) {
|
|
4356
|
+
function runMountCallback(callback, hookName, element, isDisposed) {
|
|
3089
4357
|
const cleanup3 = safeCall(callback, hookName);
|
|
3090
|
-
if (typeof cleanup3
|
|
3091
|
-
|
|
4358
|
+
if (typeof cleanup3 !== "function") return;
|
|
4359
|
+
if (isDisposed() || !element.isConnected) {
|
|
4360
|
+
safeCall(cleanup3, "onUnmount");
|
|
4361
|
+
} else {
|
|
4362
|
+
onUnmount(cleanup3, element);
|
|
3092
4363
|
}
|
|
3093
4364
|
}
|
|
3094
4365
|
var mountWatchers = /* @__PURE__ */ new WeakMap();
|
|
@@ -3250,25 +4521,26 @@ function onMount(callback, element) {
|
|
|
3250
4521
|
if (typeof document === "undefined") return;
|
|
3251
4522
|
if (element) {
|
|
3252
4523
|
let disposed = false;
|
|
4524
|
+
const isDisposed = () => disposed;
|
|
3253
4525
|
registerDisposer(element, () => {
|
|
3254
4526
|
disposed = true;
|
|
3255
4527
|
});
|
|
3256
4528
|
if (element.isConnected) {
|
|
3257
4529
|
queueMicrotask(() => {
|
|
3258
4530
|
if (disposed) return;
|
|
3259
|
-
runMountCallback(callback, "onMount", element);
|
|
4531
|
+
runMountCallback(callback, "onMount", element, isDisposed);
|
|
3260
4532
|
});
|
|
3261
4533
|
return;
|
|
3262
4534
|
}
|
|
3263
4535
|
queueMicrotask(() => {
|
|
3264
4536
|
if (disposed) return;
|
|
3265
4537
|
if (element.isConnected) {
|
|
3266
|
-
runMountCallback(callback, "onMount", element);
|
|
4538
|
+
runMountCallback(callback, "onMount", element, isDisposed);
|
|
3267
4539
|
return;
|
|
3268
4540
|
}
|
|
3269
4541
|
const unregister = registerMountWatcher(element, () => {
|
|
3270
4542
|
if (disposed) return;
|
|
3271
|
-
runMountCallback(callback, "onMount", element);
|
|
4543
|
+
runMountCallback(callback, "onMount", element, isDisposed);
|
|
3272
4544
|
});
|
|
3273
4545
|
registerDisposer(element, unregister);
|
|
3274
4546
|
});
|
|
@@ -3305,6 +4577,14 @@ function onCleanup(callback, element) {
|
|
|
3305
4577
|
registerDisposer(element, callback);
|
|
3306
4578
|
}
|
|
3307
4579
|
|
|
4580
|
+
// src/core/devtoolsHook.ts
|
|
4581
|
+
function emitDevtools(hook, event, payload) {
|
|
4582
|
+
try {
|
|
4583
|
+
hook.emit(event, payload);
|
|
4584
|
+
} catch {
|
|
4585
|
+
}
|
|
4586
|
+
}
|
|
4587
|
+
|
|
3308
4588
|
// src/core/ssr-context.ts
|
|
3309
4589
|
var SSR_KEY = /* @__PURE__ */ Symbol.for("sibujs.ssr.v1");
|
|
3310
4590
|
function detectSSRShared() {
|
|
@@ -3542,12 +4822,17 @@ function effect(effectFn, options) {
|
|
|
3542
4822
|
try {
|
|
3543
4823
|
retrack2(ctx.bodyFn, ctx.subscriber);
|
|
3544
4824
|
if (ctx.rerunPending) drainReruns(ctx);
|
|
4825
|
+
} catch (err) {
|
|
4826
|
+
ctx.disposed = true;
|
|
4827
|
+
if (ctx.userCleanups.length > 0) flushUserCleanups(ctx);
|
|
4828
|
+
cleanup2(ctx.subscriber);
|
|
4829
|
+
throw err;
|
|
3545
4830
|
} finally {
|
|
3546
4831
|
ctx.running = false;
|
|
3547
4832
|
ctx.rerunPending = false;
|
|
3548
4833
|
}
|
|
3549
4834
|
const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
3550
|
-
if (hook) hook
|
|
4835
|
+
if (hook) emitDevtools(hook, "effect:create", { effectFn });
|
|
3551
4836
|
return () => disposeEffect(ctx);
|
|
3552
4837
|
}
|
|
3553
4838
|
|
|
@@ -3634,7 +4919,7 @@ function signal(initial, options) {
|
|
|
3634
4919
|
state2.__v++;
|
|
3635
4920
|
if (DEV) {
|
|
3636
4921
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
3637
|
-
if (hook) hook
|
|
4922
|
+
if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
3638
4923
|
}
|
|
3639
4924
|
if (!enqueueBatchedSignal(state2)) {
|
|
3640
4925
|
notifySubscribers2(state2);
|
|
@@ -3648,7 +4933,7 @@ function signal(initial, options) {
|
|
|
3648
4933
|
state2.value = newValue;
|
|
3649
4934
|
state2.__v++;
|
|
3650
4935
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
3651
|
-
if (hook) hook
|
|
4936
|
+
if (hook) emitDevtools(hook, "signal:update", { signal: state2, name: debugName, oldValue: prev, newValue });
|
|
3652
4937
|
if (!enqueueBatchedSignal(state2)) {
|
|
3653
4938
|
notifySubscribers2(state2);
|
|
3654
4939
|
}
|
|
@@ -3667,7 +4952,7 @@ function signal(initial, options) {
|
|
|
3667
4952
|
}
|
|
3668
4953
|
if (DEV) {
|
|
3669
4954
|
const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
3670
|
-
if (hook) hook
|
|
4955
|
+
if (hook) emitDevtools(hook, "signal:create", { signal: state2, name: debugName, getter: get, initial });
|
|
3671
4956
|
}
|
|
3672
4957
|
return [get, set];
|
|
3673
4958
|
}
|
|
@@ -4480,36 +5765,34 @@ function Loading(props = {}) {
|
|
|
4480
5765
|
const { text: text2, variant = "spinner", size = "md" } = props;
|
|
4481
5766
|
const sizeClass = size !== "md" ? ` sibu-loading-${size}` : "";
|
|
4482
5767
|
if (variant === "dots") {
|
|
4483
|
-
return div(
|
|
5768
|
+
return div(
|
|
5769
|
+
{
|
|
5770
|
+
class: `sibu-loading${sizeClass}`,
|
|
5771
|
+
role: "status",
|
|
5772
|
+
"aria-live": "polite",
|
|
5773
|
+
// When there's no visible text, give the live region an accessible name
|
|
5774
|
+
// so it isn't announced as an empty status.
|
|
5775
|
+
"aria-label": text2 ? void 0 : "Loading"
|
|
5776
|
+
},
|
|
5777
|
+
[
|
|
5778
|
+
div({ class: "sibu-loading-dots" }, [
|
|
5779
|
+
span({ class: "sibu-loading-dot" }),
|
|
5780
|
+
span({ class: "sibu-loading-dot" }),
|
|
5781
|
+
span({ class: "sibu-loading-dot" })
|
|
5782
|
+
]),
|
|
5783
|
+
text2 ? span({ class: "sibu-loading-text" }, text2) : null
|
|
5784
|
+
]
|
|
5785
|
+
);
|
|
5786
|
+
}
|
|
5787
|
+
return div(
|
|
5788
|
+
{
|
|
4484
5789
|
class: `sibu-loading${sizeClass}`,
|
|
4485
5790
|
role: "status",
|
|
4486
5791
|
"aria-live": "polite",
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
div({
|
|
4492
|
-
class: "sibu-loading-dots",
|
|
4493
|
-
nodes: [
|
|
4494
|
-
span({ class: "sibu-loading-dot" }),
|
|
4495
|
-
span({ class: "sibu-loading-dot" }),
|
|
4496
|
-
span({ class: "sibu-loading-dot" })
|
|
4497
|
-
]
|
|
4498
|
-
}),
|
|
4499
|
-
text2 ? span({ class: "sibu-loading-text", nodes: text2 }) : null
|
|
4500
|
-
].filter(Boolean)
|
|
4501
|
-
});
|
|
4502
|
-
}
|
|
4503
|
-
return div({
|
|
4504
|
-
class: `sibu-loading${sizeClass}`,
|
|
4505
|
-
role: "status",
|
|
4506
|
-
"aria-live": "polite",
|
|
4507
|
-
"aria-label": text2 ? void 0 : "Loading",
|
|
4508
|
-
nodes: [
|
|
4509
|
-
div({ class: "sibu-loading-spinner" }),
|
|
4510
|
-
text2 ? span({ class: "sibu-loading-text", nodes: text2 }) : null
|
|
4511
|
-
].filter(Boolean)
|
|
4512
|
-
});
|
|
5792
|
+
"aria-label": text2 ? void 0 : "Loading"
|
|
5793
|
+
},
|
|
5794
|
+
[div({ class: "sibu-loading-spinner" }), text2 ? span({ class: "sibu-loading-text" }, text2) : null]
|
|
5795
|
+
);
|
|
4513
5796
|
}
|
|
4514
5797
|
|
|
4515
5798
|
// src/core/rendering/action.ts
|
|
@@ -4615,13 +5898,35 @@ registerAction("copyOnClick", copyOnClick);
|
|
|
4615
5898
|
registerAction("autoResize", autoResize);
|
|
4616
5899
|
registerAction("trapFocus", trapFocus);
|
|
4617
5900
|
|
|
5901
|
+
// src/utils/adoptThenable.ts
|
|
5902
|
+
function adoptThenable(value) {
|
|
5903
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return null;
|
|
5904
|
+
let then;
|
|
5905
|
+
try {
|
|
5906
|
+
then = value.then;
|
|
5907
|
+
} catch (error) {
|
|
5908
|
+
return Promise.reject(error);
|
|
5909
|
+
}
|
|
5910
|
+
if (typeof then !== "function") return null;
|
|
5911
|
+
return new Promise((resolve, reject) => {
|
|
5912
|
+
queueMicrotask(() => {
|
|
5913
|
+
try {
|
|
5914
|
+
Reflect.apply(then, value, [resolve, reject]);
|
|
5915
|
+
} catch (error) {
|
|
5916
|
+
reject(error);
|
|
5917
|
+
}
|
|
5918
|
+
});
|
|
5919
|
+
});
|
|
5920
|
+
}
|
|
5921
|
+
|
|
4618
5922
|
// src/core/rendering/catch.ts
|
|
4619
5923
|
var globalErrorHandler = null;
|
|
4620
5924
|
function catchError(fn, onError) {
|
|
4621
5925
|
try {
|
|
4622
5926
|
const result = fn();
|
|
4623
|
-
|
|
4624
|
-
|
|
5927
|
+
const adopted = adoptThenable(result);
|
|
5928
|
+
if (adopted) {
|
|
5929
|
+
adopted.then(void 0, (err) => {
|
|
4625
5930
|
if (onError) {
|
|
4626
5931
|
onError(err, "async");
|
|
4627
5932
|
} else if (globalErrorHandler) {
|
|
@@ -4748,6 +6053,10 @@ function attachBranch(parent, anchor, branch, attachedOnce, where) {
|
|
|
4748
6053
|
parent.insertBefore(node, anchor.nextSibling);
|
|
4749
6054
|
return { node, owned };
|
|
4750
6055
|
}
|
|
6056
|
+
function releaseBranchNode(node, owned) {
|
|
6057
|
+
if (owned) dispose(node);
|
|
6058
|
+
node.parentNode?.removeChild(node);
|
|
6059
|
+
}
|
|
4751
6060
|
function when(condition, thenBranch, elseBranch) {
|
|
4752
6061
|
const anchor = document.createComment("when");
|
|
4753
6062
|
let currentNode = null;
|
|
@@ -4761,16 +6070,15 @@ function when(condition, thenBranch, elseBranch) {
|
|
|
4761
6070
|
const show2 = condition();
|
|
4762
6071
|
const parent = anchor.parentNode;
|
|
4763
6072
|
if (!parent) return;
|
|
4764
|
-
if (initialized && show2
|
|
6073
|
+
if (initialized && Object.is(show2, lastCondition)) return;
|
|
4765
6074
|
lastCondition = show2;
|
|
4766
6075
|
const focused = currentNode ? captureFocusWithin([currentNode]) : null;
|
|
4767
6076
|
if (currentNode?.parentNode) {
|
|
4768
|
-
|
|
4769
|
-
currentNode.parentNode.removeChild(currentNode);
|
|
6077
|
+
releaseBranchNode(currentNode, currentNodeOwned);
|
|
4770
6078
|
currentNode = null;
|
|
4771
6079
|
}
|
|
4772
6080
|
const branch = show2 ? thenBranch : elseBranch !== void 0 ? elseBranch : null;
|
|
4773
|
-
const attached = attachBranch(parent, anchor, branch, attachedOnce, "when");
|
|
6081
|
+
const attached = untracked2(() => attachBranch(parent, anchor, branch, attachedOnce, "when"));
|
|
4774
6082
|
currentNode = attached.node;
|
|
4775
6083
|
currentNodeOwned = attached.owned;
|
|
4776
6084
|
restoreFocusWithin(focused, currentNode ? [currentNode] : [], "when");
|
|
@@ -4780,6 +6088,8 @@ function when(condition, thenBranch, elseBranch) {
|
|
|
4780
6088
|
registerDisposer(anchor, () => {
|
|
4781
6089
|
disposed = true;
|
|
4782
6090
|
stopBinding();
|
|
6091
|
+
if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
|
|
6092
|
+
currentNode = null;
|
|
4783
6093
|
});
|
|
4784
6094
|
if (!initialized) {
|
|
4785
6095
|
queueMicrotask(() => {
|
|
@@ -4805,12 +6115,11 @@ function match(value, cases, fallback) {
|
|
|
4805
6115
|
lastKey = key;
|
|
4806
6116
|
const focused = currentNode ? captureFocusWithin([currentNode]) : null;
|
|
4807
6117
|
if (currentNode?.parentNode) {
|
|
4808
|
-
|
|
4809
|
-
currentNode.parentNode.removeChild(currentNode);
|
|
6118
|
+
releaseBranchNode(currentNode, currentNodeOwned);
|
|
4810
6119
|
currentNode = null;
|
|
4811
6120
|
}
|
|
4812
6121
|
const branch = Object.hasOwn(cases, key) ? cases[key] : fallback;
|
|
4813
|
-
const attached = attachBranch(parent, anchor, branch ?? null, attachedOnce, "match");
|
|
6122
|
+
const attached = untracked2(() => attachBranch(parent, anchor, branch ?? null, attachedOnce, "match"));
|
|
4814
6123
|
currentNode = attached.node;
|
|
4815
6124
|
currentNodeOwned = attached.owned;
|
|
4816
6125
|
restoreFocusWithin(focused, currentNode ? [currentNode] : [], "match");
|
|
@@ -4820,6 +6129,8 @@ function match(value, cases, fallback) {
|
|
|
4820
6129
|
registerDisposer(anchor, () => {
|
|
4821
6130
|
disposed = true;
|
|
4822
6131
|
stopBinding();
|
|
6132
|
+
if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
|
|
6133
|
+
currentNode = null;
|
|
4823
6134
|
});
|
|
4824
6135
|
if (!initialized) {
|
|
4825
6136
|
queueMicrotask(() => {
|
|
@@ -4840,11 +6151,17 @@ var componentRegistry = globalSingleton(
|
|
|
4840
6151
|
/* @__PURE__ */ Symbol.for("sibujs.components.registry.v1"),
|
|
4841
6152
|
() => /* @__PURE__ */ new Map()
|
|
4842
6153
|
);
|
|
6154
|
+
var registryVersion = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.components.registryVersion.v1"), () => signal(0));
|
|
6155
|
+
function bumpRegistry() {
|
|
6156
|
+
const [read, write] = registryVersion;
|
|
6157
|
+
write(untracked2(read) + 1);
|
|
6158
|
+
}
|
|
4843
6159
|
function registerComponent(name, component) {
|
|
4844
6160
|
componentRegistry.set(name, component);
|
|
6161
|
+
bumpRegistry();
|
|
4845
6162
|
}
|
|
4846
6163
|
function unregisterComponent(name) {
|
|
4847
|
-
componentRegistry.delete(name);
|
|
6164
|
+
if (componentRegistry.delete(name)) bumpRegistry();
|
|
4848
6165
|
}
|
|
4849
6166
|
function resolveComponent(name) {
|
|
4850
6167
|
const component = componentRegistry.get(name);
|
|
@@ -4855,14 +6172,21 @@ function resolveComponent(name) {
|
|
|
4855
6172
|
}
|
|
4856
6173
|
function DynamicComponent(is) {
|
|
4857
6174
|
const container = div({ class: "sibu-dynamic" });
|
|
6175
|
+
const NONE = {};
|
|
6176
|
+
let shown = NONE;
|
|
4858
6177
|
function render() {
|
|
4859
6178
|
const target = is();
|
|
4860
|
-
let
|
|
6179
|
+
let component;
|
|
4861
6180
|
if (typeof target === "function") {
|
|
4862
|
-
|
|
6181
|
+
component = target;
|
|
4863
6182
|
} else {
|
|
4864
|
-
|
|
6183
|
+
registryVersion[0]();
|
|
6184
|
+
component = componentRegistry.get(target);
|
|
4865
6185
|
}
|
|
6186
|
+
const next = component ?? `missing:${target}`;
|
|
6187
|
+
if (next === shown) return;
|
|
6188
|
+
const el = untracked2(() => component ? component() : div(`[Component "${target}" not found]`));
|
|
6189
|
+
shown = next;
|
|
4866
6190
|
replaceChildrenSafely(container, el);
|
|
4867
6191
|
}
|
|
4868
6192
|
const untrack = track2(render);
|
|
@@ -5126,31 +6450,29 @@ function Fragment(nodes) {
|
|
|
5126
6450
|
if (Array.isArray(child)) {
|
|
5127
6451
|
for (const nested of child) {
|
|
5128
6452
|
if (nested == null || typeof nested === "boolean") continue;
|
|
5129
|
-
|
|
6453
|
+
appendChild(frag, nested);
|
|
5130
6454
|
}
|
|
5131
6455
|
} else {
|
|
5132
|
-
|
|
6456
|
+
appendChild(frag, child);
|
|
5133
6457
|
}
|
|
5134
6458
|
}
|
|
5135
6459
|
return frag;
|
|
5136
6460
|
}
|
|
5137
|
-
function
|
|
5138
|
-
if (child == null) {
|
|
5139
|
-
return document.createTextNode("");
|
|
5140
|
-
}
|
|
6461
|
+
function appendChild(frag, child) {
|
|
5141
6462
|
if (child instanceof Node) {
|
|
5142
|
-
|
|
6463
|
+
frag.appendChild(child);
|
|
6464
|
+
return;
|
|
5143
6465
|
}
|
|
5144
6466
|
if (typeof child === "function") {
|
|
5145
|
-
const
|
|
5146
|
-
|
|
5147
|
-
|
|
6467
|
+
const placeholder = document.createComment("");
|
|
6468
|
+
frag.appendChild(placeholder);
|
|
6469
|
+
registerDisposer(placeholder, bindChildNode(placeholder, child));
|
|
6470
|
+
return;
|
|
5148
6471
|
}
|
|
5149
|
-
|
|
6472
|
+
frag.appendChild(document.createTextNode(String(child)));
|
|
5150
6473
|
}
|
|
5151
6474
|
|
|
5152
6475
|
// src/core/rendering/htm.ts
|
|
5153
|
-
var RAW_TEXT_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
5154
6476
|
var VOID_ELEMENTS3 = /* @__PURE__ */ new Set([
|
|
5155
6477
|
"area",
|
|
5156
6478
|
"base",
|
|
@@ -5191,7 +6513,7 @@ var SVG_TAGS2 = /* @__PURE__ */ new Set([
|
|
|
5191
6513
|
"marker"
|
|
5192
6514
|
]);
|
|
5193
6515
|
var cache = /* @__PURE__ */ new WeakMap();
|
|
5194
|
-
function
|
|
6516
|
+
function parseTemplate2(strings) {
|
|
5195
6517
|
const exprCount = strings.length - 1;
|
|
5196
6518
|
let template2 = strings[0];
|
|
5197
6519
|
for (let i2 = 0; i2 < exprCount; i2++) {
|
|
@@ -5373,7 +6695,7 @@ function parseTemplate(strings) {
|
|
|
5373
6695
|
children.push({ t: 0, el: { tag, svg: SVG_TAGS2.has(tag), attrs, children: [] } });
|
|
5374
6696
|
} else {
|
|
5375
6697
|
const inner = parseChildren();
|
|
5376
|
-
if (
|
|
6698
|
+
if (isCodeTextElement(tag)) {
|
|
5377
6699
|
for (let i2 = 0; i2 < inner.length; i2++) {
|
|
5378
6700
|
if (inner[i2].t === 2) {
|
|
5379
6701
|
throw new Error(
|
|
@@ -5399,12 +6721,12 @@ function parseTemplate(strings) {
|
|
|
5399
6721
|
return parseChildren();
|
|
5400
6722
|
}
|
|
5401
6723
|
function executeElement(tmpl, values) {
|
|
5402
|
-
const el = tmpl.svg ? document.createElementNS(
|
|
6724
|
+
const el = tmpl.svg ? document.createElementNS(SVG_NS4, tmpl.tag) : document.createElement(tmpl.tag);
|
|
5403
6725
|
for (let i2 = 0; i2 < tmpl.attrs.length; i2++) {
|
|
5404
6726
|
const attr = tmpl.attrs[i2];
|
|
5405
6727
|
switch (attr.t) {
|
|
5406
6728
|
case 0:
|
|
5407
|
-
el
|
|
6729
|
+
setTrustedAttribute(el, attr.name, attr.value);
|
|
5408
6730
|
break;
|
|
5409
6731
|
case 1: {
|
|
5410
6732
|
const name = attr.name;
|
|
@@ -5437,7 +6759,7 @@ function executeElement(tmpl, values) {
|
|
|
5437
6759
|
break;
|
|
5438
6760
|
}
|
|
5439
6761
|
case 4:
|
|
5440
|
-
el
|
|
6762
|
+
setTrustedAttribute(el, attr.name, "");
|
|
5441
6763
|
break;
|
|
5442
6764
|
}
|
|
5443
6765
|
}
|
|
@@ -5479,9 +6801,15 @@ function executeElement(tmpl, values) {
|
|
|
5479
6801
|
function html2(strings, ...values) {
|
|
5480
6802
|
let tmpl = cache.get(strings);
|
|
5481
6803
|
if (!tmpl) {
|
|
5482
|
-
tmpl =
|
|
6804
|
+
tmpl = parseTemplate2(strings);
|
|
5483
6805
|
cache.set(strings, tmpl);
|
|
5484
6806
|
}
|
|
6807
|
+
return renderTemplate(tmpl, values);
|
|
6808
|
+
}
|
|
6809
|
+
function __renderParsedTemplate(tree, values) {
|
|
6810
|
+
return renderTemplate(tree, values);
|
|
6811
|
+
}
|
|
6812
|
+
function renderTemplate(tmpl, values) {
|
|
5485
6813
|
if (tmpl.length === 1 && tmpl[0].t === 0) {
|
|
5486
6814
|
return executeElement(tmpl[0].el, values);
|
|
5487
6815
|
}
|
|
@@ -5616,25 +6944,77 @@ function mount(component, container) {
|
|
|
5616
6944
|
typeof component === "function" || component instanceof Node,
|
|
5617
6945
|
"mount: first argument must be a component function or a DOM Node."
|
|
5618
6946
|
);
|
|
5619
|
-
const
|
|
5620
|
-
const
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
6947
|
+
const now = () => typeof performance !== "undefined" ? performance.now() : 0;
|
|
6948
|
+
const startTime = now();
|
|
6949
|
+
let range = null;
|
|
6950
|
+
const attach = (built) => {
|
|
6951
|
+
if (built instanceof DocumentFragment) {
|
|
6952
|
+
const start = document.createComment("");
|
|
6953
|
+
const end = document.createComment("");
|
|
6954
|
+
built.insertBefore(start, built.firstChild);
|
|
6955
|
+
built.appendChild(end);
|
|
6956
|
+
range = { start, end };
|
|
6957
|
+
}
|
|
6958
|
+
container.appendChild(built);
|
|
6959
|
+
};
|
|
6960
|
+
let node;
|
|
6961
|
+
if (typeof component === "function") {
|
|
6962
|
+
node = withDisposerRollback(() => {
|
|
6963
|
+
const built = component();
|
|
6964
|
+
attach(built);
|
|
6965
|
+
return built;
|
|
6966
|
+
});
|
|
6967
|
+
} else {
|
|
6968
|
+
node = component;
|
|
6969
|
+
attach(node);
|
|
5626
6970
|
}
|
|
6971
|
+
const duration = now() - startTime;
|
|
6972
|
+
const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
6973
|
+
if (hook) emitDevtools(hook, "app:init", { rootElement: node, container, duration });
|
|
6974
|
+
const mounted = range;
|
|
5627
6975
|
return {
|
|
5628
6976
|
node,
|
|
5629
6977
|
unmount() {
|
|
5630
|
-
if (hook) hook
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
6978
|
+
if (hook) emitDevtools(hook, "app:unmount", { rootElement: node });
|
|
6979
|
+
if (mounted) {
|
|
6980
|
+
unmountRange(mounted.start, mounted.end);
|
|
6981
|
+
return;
|
|
5634
6982
|
}
|
|
6983
|
+
dispose(node);
|
|
6984
|
+
node.parentNode?.removeChild(node);
|
|
5635
6985
|
}
|
|
5636
6986
|
};
|
|
5637
6987
|
}
|
|
6988
|
+
function unmountRange(start, end) {
|
|
6989
|
+
const parent = start.parentNode;
|
|
6990
|
+
if (!parent && !end.parentNode) return;
|
|
6991
|
+
let budget = MAX_DRAIN_TEARDOWNS;
|
|
6992
|
+
for (let n = start.nextSibling; n && n !== end; n = n.nextSibling) budget++;
|
|
6993
|
+
let before = start;
|
|
6994
|
+
let after = null;
|
|
6995
|
+
let intact = true;
|
|
6996
|
+
for (; ; ) {
|
|
6997
|
+
if (start.parentNode !== parent || end.parentNode !== parent) intact = false;
|
|
6998
|
+
else if (start.previousSibling !== before || end.nextSibling !== after) {
|
|
6999
|
+
before = start.previousSibling;
|
|
7000
|
+
after = end.nextSibling;
|
|
7001
|
+
intact = !!(start.compareDocumentPosition(end) & 4);
|
|
7002
|
+
}
|
|
7003
|
+
const n = start.nextSibling;
|
|
7004
|
+
if (!intact || n === end) break;
|
|
7005
|
+
if (budget-- <= 0) {
|
|
7006
|
+
reportDrainRunaway("mount", MAX_DRAIN_TEARDOWNS, 1);
|
|
7007
|
+
return;
|
|
7008
|
+
}
|
|
7009
|
+
dispose(n);
|
|
7010
|
+
if (n.parentNode === parent) parent.removeChild(n);
|
|
7011
|
+
}
|
|
7012
|
+
if (!intact) {
|
|
7013
|
+
reportError(new Error("[SibuJS mount] fragment markers lost"), { phase: "cleanup", name: "mount" });
|
|
7014
|
+
}
|
|
7015
|
+
start.parentNode?.removeChild(start);
|
|
7016
|
+
end.parentNode?.removeChild(end);
|
|
7017
|
+
}
|
|
5638
7018
|
|
|
5639
7019
|
// src/core/rendering/portal.ts
|
|
5640
7020
|
function Portal(nodes, target) {
|
|
@@ -6070,17 +7450,17 @@ function derived(getter, options) {
|
|
|
6070
7450
|
cs._d = false;
|
|
6071
7451
|
cs._init = true;
|
|
6072
7452
|
};
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
try {
|
|
7453
|
+
try {
|
|
7454
|
+
track2(() => {
|
|
6076
7455
|
cs._v = getter();
|
|
6077
7456
|
cs._d = false;
|
|
6078
7457
|
cs._init = true;
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
7458
|
+
}, markDirty);
|
|
7459
|
+
} catch (err) {
|
|
7460
|
+
disposed = true;
|
|
7461
|
+
cleanup2(markDirty);
|
|
7462
|
+
throw err;
|
|
7463
|
+
}
|
|
6084
7464
|
const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
|
|
6085
7465
|
const validate = () => {
|
|
6086
7466
|
if (!cs._d || disposed || pendingError !== void 0) return;
|
|
@@ -6099,7 +7479,7 @@ function derived(getter, options) {
|
|
|
6099
7479
|
if (disposed) cleanup2(markDirty);
|
|
6100
7480
|
}
|
|
6101
7481
|
if (hook && !disposed && !Object.is(oldValue, cs._v)) {
|
|
6102
|
-
hook
|
|
7482
|
+
emitDevtools(hook, "computed:update", { signal: cs, oldValue, newValue: cs._v });
|
|
6103
7483
|
}
|
|
6104
7484
|
};
|
|
6105
7485
|
cs._validate = validate;
|
|
@@ -6150,7 +7530,7 @@ function derived(getter, options) {
|
|
|
6150
7530
|
}
|
|
6151
7531
|
}
|
|
6152
7532
|
};
|
|
6153
|
-
if (hook) hook
|
|
7533
|
+
if (hook) emitDevtools(hook, "computed:create", { signal: cs, name: debugName, getter: computedGetter });
|
|
6154
7534
|
return computedGetter;
|
|
6155
7535
|
}
|
|
6156
7536
|
|
|
@@ -6518,7 +7898,7 @@ function enhance(target, setup) {
|
|
|
6518
7898
|
bindNode(el, () => {
|
|
6519
7899
|
const v = value();
|
|
6520
7900
|
const next = v == null ? null : String(v);
|
|
6521
|
-
setSafeAttribute(el, name, next, { syncValueProperty: false, label: "enhance attr()" });
|
|
7901
|
+
setSafeAttribute(el, name, next, { syncValueProperty: false, label: "enhance attr()", reactive: true });
|
|
6522
7902
|
})
|
|
6523
7903
|
);
|
|
6524
7904
|
});
|
|
@@ -6790,27 +8170,6 @@ function trustHTML(html3) {
|
|
|
6790
8170
|
}
|
|
6791
8171
|
var DEFAULT_MAX_SSR_BYTES = 1024 * 1024;
|
|
6792
8172
|
|
|
6793
|
-
// src/utils/adoptThenable.ts
|
|
6794
|
-
function adoptThenable(value) {
|
|
6795
|
-
if (value === null || typeof value !== "object" && typeof value !== "function") return null;
|
|
6796
|
-
let then;
|
|
6797
|
-
try {
|
|
6798
|
-
then = value.then;
|
|
6799
|
-
} catch (error) {
|
|
6800
|
-
return Promise.reject(error);
|
|
6801
|
-
}
|
|
6802
|
-
if (typeof then !== "function") return null;
|
|
6803
|
-
return new Promise((resolve, reject) => {
|
|
6804
|
-
queueMicrotask(() => {
|
|
6805
|
-
try {
|
|
6806
|
-
Reflect.apply(then, value, [resolve, reject]);
|
|
6807
|
-
} catch (error) {
|
|
6808
|
-
reject(error);
|
|
6809
|
-
}
|
|
6810
|
-
});
|
|
6811
|
-
});
|
|
6812
|
-
}
|
|
6813
|
-
|
|
6814
8173
|
// src/reactivity/concurrent.ts
|
|
6815
8174
|
function defer(getter) {
|
|
6816
8175
|
const [value, setValue] = signal(getter());
|
|
@@ -6901,7 +8260,23 @@ function nextTick() {
|
|
|
6901
8260
|
}
|
|
6902
8261
|
|
|
6903
8262
|
// src/build/cdn.ts
|
|
6904
|
-
var PACKAGE_NAME = "
|
|
8263
|
+
var PACKAGE_NAME = "sibujs";
|
|
8264
|
+
var SUBPATH_ENTRIES = [
|
|
8265
|
+
"data",
|
|
8266
|
+
"browser",
|
|
8267
|
+
"patterns",
|
|
8268
|
+
"motion",
|
|
8269
|
+
"ui",
|
|
8270
|
+
"widgets",
|
|
8271
|
+
"ssr",
|
|
8272
|
+
"devtools",
|
|
8273
|
+
"performance",
|
|
8274
|
+
"ecosystem",
|
|
8275
|
+
"plugins",
|
|
8276
|
+
"build",
|
|
8277
|
+
"testing",
|
|
8278
|
+
"extras"
|
|
8279
|
+
];
|
|
6905
8280
|
function registerGlobal() {
|
|
6906
8281
|
if (typeof window === "undefined") return;
|
|
6907
8282
|
window.Sibu = { ...index_exports };
|
|
@@ -6947,7 +8322,7 @@ var cdnUrls = {
|
|
|
6947
8322
|
* @example
|
|
6948
8323
|
* ```ts
|
|
6949
8324
|
* cdnUrls.scriptTag('jsdelivr', '1.0.0')
|
|
6950
|
-
* // => '<script src="https://cdn.jsdelivr.net/npm/
|
|
8325
|
+
* // => '<script src="https://cdn.jsdelivr.net/npm/sibujs@1.0.0/dist/cdn.global.js"></script>'
|
|
6951
8326
|
* ```
|
|
6952
8327
|
*/
|
|
6953
8328
|
scriptTag: (provider = "jsdelivr", version) => {
|
|
@@ -6965,15 +8340,11 @@ function generateImportMap(baseUrl) {
|
|
|
6965
8340
|
const base2 = baseUrl || `https://cdn.jsdelivr.net/npm/${PACKAGE_NAME}@latest`;
|
|
6966
8341
|
const imports = {
|
|
6967
8342
|
// Main package entry
|
|
6968
|
-
[PACKAGE_NAME]: `${base2}/dist/index.js
|
|
6969
|
-
// Sub-path imports for tree-shaking in browsers
|
|
6970
|
-
[`${PACKAGE_NAME}/core`]: `${base2}/dist/core/index.js`,
|
|
6971
|
-
[`${PACKAGE_NAME}/reactivity`]: `${base2}/dist/reactivity/index.js`,
|
|
6972
|
-
[`${PACKAGE_NAME}/plugins`]: `${base2}/dist/plugins/index.js`,
|
|
6973
|
-
[`${PACKAGE_NAME}/components`]: `${base2}/dist/components/index.js`,
|
|
6974
|
-
[`${PACKAGE_NAME}/testing`]: `${base2}/dist/testing/index.js`,
|
|
6975
|
-
[`${PACKAGE_NAME}/build`]: `${base2}/dist/build/index.js`
|
|
8343
|
+
[PACKAGE_NAME]: `${base2}/dist/index.js`
|
|
6976
8344
|
};
|
|
8345
|
+
for (const entry of SUBPATH_ENTRIES) {
|
|
8346
|
+
imports[`${PACKAGE_NAME}/${entry}`] = `${base2}/dist/${entry}.js`;
|
|
8347
|
+
}
|
|
6977
8348
|
return {
|
|
6978
8349
|
imports,
|
|
6979
8350
|
/**
|
|
@@ -7056,9 +8427,9 @@ function generateTsConfig(options) {
|
|
|
7056
8427
|
if (paths && Object.keys(paths).length > 0) {
|
|
7057
8428
|
compilerOptions.baseUrl = ".";
|
|
7058
8429
|
compilerOptions.paths = {
|
|
7059
|
-
// Default
|
|
7060
|
-
|
|
7061
|
-
"
|
|
8430
|
+
// Default sibujs alias
|
|
8431
|
+
sibujs: ["node_modules/sibujs/dist/index.d.ts"],
|
|
8432
|
+
"sibujs/*": ["node_modules/sibujs/dist/*"],
|
|
7062
8433
|
// User-provided paths
|
|
7063
8434
|
...paths
|
|
7064
8435
|
};
|
|
@@ -8172,6 +9543,19 @@ function generateTypeStubs() {
|
|
|
8172
9543
|
};
|
|
8173
9544
|
}
|
|
8174
9545
|
|
|
9546
|
+
// src/build/compileTemplates.ts
|
|
9547
|
+
function compileHtmlTemplates(code2) {
|
|
9548
|
+
const plan = planHtmlTemplates(code2);
|
|
9549
|
+
const edits = plan.compiledCount > 0 ? normalizeEdits(plan.edits) : null;
|
|
9550
|
+
return {
|
|
9551
|
+
code: edits ? applyEdits(code2, edits, plan.append) : null,
|
|
9552
|
+
usedTags: plan.usedTags,
|
|
9553
|
+
usesSvg: plan.usesSvg,
|
|
9554
|
+
compiledCount: edits ? plan.compiledCount : 0,
|
|
9555
|
+
skippedCount: plan.skippedCount
|
|
9556
|
+
};
|
|
9557
|
+
}
|
|
9558
|
+
|
|
8175
9559
|
// src/build/routeSplitting.ts
|
|
8176
9560
|
function fileToRoute(relativePath) {
|
|
8177
9561
|
const basename = relativePath.split("/").pop() || "";
|
|
@@ -8227,7 +9611,7 @@ function generateRouteModule(entries, routesDir) {
|
|
|
8227
9611
|
(e, i2) => `const route${i2} = () => import(/* webpackChunkName: "${e.chunkName}" */ "${routesDir}/${e.importPath}");`
|
|
8228
9612
|
).join("\n");
|
|
8229
9613
|
const routes = entries.map((e, i2) => ` { path: "${e.path}", component: lazy(route${i2}) }`).join(",\n");
|
|
8230
|
-
return `import { lazy } from "
|
|
9614
|
+
return `import { lazy } from "sibujs";
|
|
8231
9615
|
|
|
8232
9616
|
${imports}
|
|
8233
9617
|
|