@fluixi/compiler 1.0.0-alpha.100
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/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/analyze/expr-shape.cjs +62 -0
- package/dist/analyze/expr-shape.d.cts +14 -0
- package/dist/analyze/expr-shape.d.ts +15 -0
- package/dist/analyze/expr-shape.d.ts.map +1 -0
- package/dist/analyze/expr-shape.js +37 -0
- package/dist/analyze/expr-shape.mjs +41 -0
- package/dist/analyze/intrinsics.cjs +112 -0
- package/dist/analyze/intrinsics.d.cts +80 -0
- package/dist/analyze/intrinsics.d.ts +81 -0
- package/dist/analyze/intrinsics.d.ts.map +1 -0
- package/dist/analyze/intrinsics.js +126 -0
- package/dist/analyze/intrinsics.mjs +91 -0
- package/dist/analyze/paren.cjs +134 -0
- package/dist/analyze/paren.d.cts +23 -0
- package/dist/analyze/paren.d.ts +24 -0
- package/dist/analyze/paren.d.ts.map +1 -0
- package/dist/analyze/paren.js +168 -0
- package/dist/analyze/paren.mjs +113 -0
- package/dist/analyze/props-destructure.cjs +226 -0
- package/dist/analyze/props-destructure.d.cts +83 -0
- package/dist/analyze/props-destructure.d.ts +84 -0
- package/dist/analyze/props-destructure.d.ts.map +1 -0
- package/dist/analyze/props-destructure.js +272 -0
- package/dist/analyze/props-destructure.mjs +205 -0
- package/dist/analyze/reactive-bindings.cjs +210 -0
- package/dist/analyze/reactive-bindings.d.cts +42 -0
- package/dist/analyze/reactive-bindings.d.ts +43 -0
- package/dist/analyze/reactive-bindings.d.ts.map +1 -0
- package/dist/analyze/reactive-bindings.js +191 -0
- package/dist/analyze/reactive-bindings.mjs +187 -0
- package/dist/analyze/reactive-expr.cjs +38 -0
- package/dist/analyze/reactive-expr.d.cts +38 -0
- package/dist/analyze/reactive-expr.d.ts +39 -0
- package/dist/analyze/reactive-expr.d.ts.map +1 -0
- package/dist/analyze/reactive-expr.js +31 -0
- package/dist/analyze/reactive-expr.mjs +17 -0
- package/dist/analyze/static-graph.cjs +831 -0
- package/dist/analyze/static-graph.d.cts +102 -0
- package/dist/analyze/static-graph.d.ts +103 -0
- package/dist/analyze/static-graph.d.ts.map +1 -0
- package/dist/analyze/static-graph.js +871 -0
- package/dist/analyze/static-graph.mjs +813 -0
- package/dist/babel-I6BUWUCU.mjs +636 -0
- package/dist/chunk-3AICWNF7.mjs +92 -0
- package/dist/chunk-6CWJWGE2.mjs +2170 -0
- package/dist/chunk-C3XPDB4Y.mjs +16 -0
- package/dist/chunk-GX5XV6Z7.mjs +190 -0
- package/dist/chunk-HXEXPWJ2.mjs +999 -0
- package/dist/chunk-NU3W67UZ.mjs +584 -0
- package/dist/chunk-SKAVY75W.mjs +11 -0
- package/dist/codegen/backend.cjs +18 -0
- package/dist/codegen/backend.d.cts +35 -0
- package/dist/codegen/backend.d.ts +36 -0
- package/dist/codegen/backend.d.ts.map +1 -0
- package/dist/codegen/backend.js +1 -0
- package/dist/codegen/backend.mjs +0 -0
- package/dist/codegen/backends/imperative.cjs +577 -0
- package/dist/codegen/backends/imperative.d.cts +11 -0
- package/dist/codegen/backends/imperative.d.ts +12 -0
- package/dist/codegen/backends/imperative.d.ts.map +1 -0
- package/dist/codegen/backends/imperative.js +362 -0
- package/dist/codegen/backends/imperative.mjs +554 -0
- package/dist/codegen/contract.cjs +52 -0
- package/dist/codegen/contract.d.cts +24 -0
- package/dist/codegen/contract.d.ts +25 -0
- package/dist/codegen/contract.d.ts.map +1 -0
- package/dist/codegen/contract.js +30 -0
- package/dist/codegen/contract.mjs +31 -0
- package/dist/codegen/partial-template.cjs +176 -0
- package/dist/codegen/partial-template.d.cts +61 -0
- package/dist/codegen/partial-template.d.ts +62 -0
- package/dist/codegen/partial-template.d.ts.map +1 -0
- package/dist/codegen/partial-template.js +0 -0
- package/dist/codegen/partial-template.mjs +153 -0
- package/dist/codegen/serialize-static.cjs +125 -0
- package/dist/codegen/serialize-static.d.cts +38 -0
- package/dist/codegen/serialize-static.d.ts +39 -0
- package/dist/codegen/serialize-static.d.ts.map +1 -0
- package/dist/codegen/serialize-static.js +165 -0
- package/dist/codegen/serialize-static.mjs +104 -0
- package/dist/frontend/babel/build-ir-lit.cjs +1933 -0
- package/dist/frontend/babel/build-ir-lit.d.cts +26 -0
- package/dist/frontend/babel/build-ir-lit.d.ts +27 -0
- package/dist/frontend/babel/build-ir-lit.d.ts.map +1 -0
- package/dist/frontend/babel/build-ir-lit.js +13 -0
- package/dist/frontend/babel/build-ir-lit.mjs +1902 -0
- package/dist/frontend/babel/build-ir.cjs +1948 -0
- package/dist/frontend/babel/build-ir.d.cts +35 -0
- package/dist/frontend/babel/build-ir.d.ts +36 -0
- package/dist/frontend/babel/build-ir.d.ts.map +1 -0
- package/dist/frontend/babel/build-ir.js +124 -0
- package/dist/frontend/babel/build-ir.mjs +1919 -0
- package/dist/frontend/babel/index.cjs +2610 -0
- package/dist/frontend/babel/index.d.cts +33 -0
- package/dist/frontend/babel/index.d.ts +34 -0
- package/dist/frontend/babel/index.d.ts.map +1 -0
- package/dist/frontend/babel/index.js +65 -0
- package/dist/frontend/babel/index.mjs +2580 -0
- package/dist/frontend/babel/lower-template.cjs +1931 -0
- package/dist/frontend/babel/lower-template.d.cts +23 -0
- package/dist/frontend/babel/lower-template.d.ts +24 -0
- package/dist/frontend/babel/lower-template.d.ts.map +1 -0
- package/dist/frontend/babel/lower-template.js +64 -0
- package/dist/frontend/babel/lower-template.mjs +1902 -0
- package/dist/frontend/babel/plugin.cjs +2556 -0
- package/dist/frontend/babel/plugin.d.cts +95 -0
- package/dist/frontend/babel/plugin.d.ts +96 -0
- package/dist/frontend/babel/plugin.d.ts.map +1 -0
- package/dist/frontend/babel/plugin.js +523 -0
- package/dist/frontend/babel/plugin.mjs +2527 -0
- package/dist/frontend/babel/server-functions.cjs +110 -0
- package/dist/frontend/babel/server-functions.d.cts +10 -0
- package/dist/frontend/babel/server-functions.d.ts +11 -0
- package/dist/frontend/babel/server-functions.d.ts.map +1 -0
- package/dist/frontend/babel/server-functions.js +81 -0
- package/dist/frontend/babel/server-functions.mjs +89 -0
- package/dist/frontend/babel/types.cjs +18 -0
- package/dist/frontend/babel/types.d.cts +33 -0
- package/dist/frontend/babel/types.d.ts +34 -0
- package/dist/frontend/babel/types.d.ts.map +1 -0
- package/dist/frontend/babel/types.js +1 -0
- package/dist/frontend/babel/types.mjs +0 -0
- package/dist/frontend/types.cjs +18 -0
- package/dist/frontend/types.d.cts +25 -0
- package/dist/frontend/types.d.ts +26 -0
- package/dist/frontend/types.d.ts.map +1 -0
- package/dist/frontend/types.js +1 -0
- package/dist/frontend/types.mjs +0 -0
- package/dist/frontend/vocabulary.cjs +98 -0
- package/dist/frontend/vocabulary.d.cts +79 -0
- package/dist/frontend/vocabulary.d.ts +80 -0
- package/dist/frontend/vocabulary.d.ts.map +1 -0
- package/dist/frontend/vocabulary.js +124 -0
- package/dist/frontend/vocabulary.mjs +77 -0
- package/dist/index.cjs +1957 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.mjs +1949 -0
- package/dist/integrations.cjs +5705 -0
- package/dist/integrations.d.cts +215 -0
- package/dist/integrations.d.ts +216 -0
- package/dist/integrations.d.ts.map +1 -0
- package/dist/integrations.js +566 -0
- package/dist/integrations.mjs +810 -0
- package/dist/ir/nodes.cjs +18 -0
- package/dist/ir/nodes.d.cts +168 -0
- package/dist/ir/nodes.d.ts +169 -0
- package/dist/ir/nodes.d.ts.map +1 -0
- package/dist/ir/nodes.js +1 -0
- package/dist/ir/nodes.mjs +0 -0
- package/dist/lower/compile-template.cjs +1670 -0
- package/dist/lower/compile-template.d.cts +82 -0
- package/dist/lower/compile-template.d.ts +83 -0
- package/dist/lower/compile-template.d.ts.map +1 -0
- package/dist/lower/compile-template.js +79 -0
- package/dist/lower/compile-template.mjs +1662 -0
- package/dist/lower/entities.cjs +288 -0
- package/dist/lower/entities.d.cts +1 -0
- package/dist/lower/entities.d.ts +2 -0
- package/dist/lower/entities.d.ts.map +1 -0
- package/dist/lower/entities.js +54 -0
- package/dist/lower/entities.mjs +267 -0
- package/dist/lower/jsx.cjs +1101 -0
- package/dist/lower/jsx.d.cts +33 -0
- package/dist/lower/jsx.d.ts +34 -0
- package/dist/lower/jsx.d.ts.map +1 -0
- package/dist/lower/jsx.js +414 -0
- package/dist/lower/jsx.mjs +1078 -0
- package/dist/lower/template.cjs +1354 -0
- package/dist/lower/template.d.cts +53 -0
- package/dist/lower/template.d.ts +54 -0
- package/dist/lower/template.d.ts.map +1 -0
- package/dist/lower/template.js +542 -0
- package/dist/lower/template.mjs +1335 -0
- package/dist/lower/text.cjs +42 -0
- package/dist/lower/text.d.cts +10 -0
- package/dist/lower/text.d.ts +11 -0
- package/dist/lower/text.d.ts.map +1 -0
- package/dist/lower/text.js +31 -0
- package/dist/lower/text.mjs +21 -0
- package/dist/optimize/analyze-static.cjs +112 -0
- package/dist/optimize/analyze-static.d.cts +39 -0
- package/dist/optimize/analyze-static.d.ts +40 -0
- package/dist/optimize/analyze-static.d.ts.map +1 -0
- package/dist/optimize/analyze-static.js +131 -0
- package/dist/optimize/analyze-static.mjs +91 -0
- package/dist/optimize/collapse-strategies.cjs +90 -0
- package/dist/optimize/collapse-strategies.d.cts +30 -0
- package/dist/optimize/collapse-strategies.d.ts +31 -0
- package/dist/optimize/collapse-strategies.d.ts.map +1 -0
- package/dist/optimize/collapse-strategies.js +33 -0
- package/dist/optimize/collapse-strategies.mjs +67 -0
- package/dist/options.cjs +33 -0
- package/dist/options.d.cts +39 -0
- package/dist/options.d.ts +40 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +8 -0
- package/dist/options.mjs +12 -0
- package/dist/resolve/builtins.cjs +73 -0
- package/dist/resolve/builtins.d.cts +68 -0
- package/dist/resolve/builtins.d.ts +69 -0
- package/dist/resolve/builtins.d.ts.map +1 -0
- package/dist/resolve/builtins.js +64 -0
- package/dist/resolve/builtins.mjs +53 -0
- package/dist/resolve/component-globals.cjs +272 -0
- package/dist/resolve/component-globals.d.cts +88 -0
- package/dist/resolve/component-globals.d.ts +89 -0
- package/dist/resolve/component-globals.d.ts.map +1 -0
- package/dist/resolve/component-globals.js +160 -0
- package/dist/resolve/component-globals.mjs +249 -0
- package/dist/resolve/component-resolver.cjs +80 -0
- package/dist/resolve/component-resolver.d.cts +68 -0
- package/dist/resolve/component-resolver.d.ts +69 -0
- package/dist/resolve/component-resolver.d.ts.map +1 -0
- package/dist/resolve/component-resolver.js +95 -0
- package/dist/resolve/component-resolver.mjs +59 -0
- package/dist/resolve/load-directive.cjs +93 -0
- package/dist/resolve/load-directive.d.cts +53 -0
- package/dist/resolve/load-directive.d.ts +54 -0
- package/dist/resolve/load-directive.d.ts.map +1 -0
- package/dist/resolve/load-directive.js +93 -0
- package/dist/resolve/load-directive.mjs +72 -0
- package/dist/resolve/resolve-ir.cjs +108 -0
- package/dist/resolve/resolve-ir.d.cts +53 -0
- package/dist/resolve/resolve-ir.d.ts +54 -0
- package/dist/resolve/resolve-ir.d.ts.map +1 -0
- package/dist/resolve/resolve-ir.js +58 -0
- package/dist/resolve/resolve-ir.mjs +85 -0
- package/dist/resolve/write-globals.cjs +383 -0
- package/dist/resolve/write-globals.d.cts +36 -0
- package/dist/resolve/write-globals.d.ts +37 -0
- package/dist/resolve/write-globals.d.ts.map +1 -0
- package/dist/resolve/write-globals.js +169 -0
- package/dist/resolve/write-globals.mjs +362 -0
- package/dist/server-fns-VZLHMQTC.mjs +79 -0
- package/dist/server-functions-UAZKOLZW.mjs +82 -0
- package/dist/transform/bindings.cjs +71 -0
- package/dist/transform/bindings.d.cts +16 -0
- package/dist/transform/bindings.d.ts +17 -0
- package/dist/transform/bindings.d.ts.map +1 -0
- package/dist/transform/bindings.js +69 -0
- package/dist/transform/bindings.mjs +50 -0
- package/dist/transform/index.cjs +3837 -0
- package/dist/transform/index.d.cts +15 -0
- package/dist/transform/index.d.ts +16 -0
- package/dist/transform/index.d.ts.map +1 -0
- package/dist/transform/index.js +12 -0
- package/dist/transform/index.mjs +4882 -0
- package/dist/transform/intrinsics.cjs +261 -0
- package/dist/transform/intrinsics.d.cts +33 -0
- package/dist/transform/intrinsics.d.ts +34 -0
- package/dist/transform/intrinsics.d.ts.map +1 -0
- package/dist/transform/intrinsics.js +120 -0
- package/dist/transform/intrinsics.mjs +238 -0
- package/dist/transform/props.cjs +441 -0
- package/dist/transform/props.d.cts +45 -0
- package/dist/transform/props.d.ts +46 -0
- package/dist/transform/props.d.ts.map +1 -0
- package/dist/transform/props.js +221 -0
- package/dist/transform/props.mjs +1487 -0
- package/dist/transform/server-fn-id.cjs +35 -0
- package/dist/transform/server-fn-id.d.cts +9 -0
- package/dist/transform/server-fn-id.d.ts +10 -0
- package/dist/transform/server-fn-id.d.ts.map +1 -0
- package/dist/transform/server-fn-id.js +18 -0
- package/dist/transform/server-fn-id.mjs +14 -0
- package/dist/transform/server-fns.cjs +114 -0
- package/dist/transform/server-fns.d.cts +12 -0
- package/dist/transform/server-fns.d.ts +13 -0
- package/dist/transform/server-fns.d.ts.map +1 -0
- package/dist/transform/server-fns.js +94 -0
- package/dist/transform/server-fns.mjs +1160 -0
- package/dist/transform/source-locations.cjs +393 -0
- package/dist/transform/source-locations.d.cts +48 -0
- package/dist/transform/source-locations.d.ts +49 -0
- package/dist/transform/source-locations.d.ts.map +1 -0
- package/dist/transform/source-locations.js +303 -0
- package/dist/transform/source-locations.mjs +370 -0
- package/dist/transform/styles.cjs +606 -0
- package/dist/transform/styles.d.cts +237 -0
- package/dist/transform/styles.d.ts +238 -0
- package/dist/transform/styles.d.ts.map +1 -0
- package/dist/transform/styles.js +743 -0
- package/dist/transform/styles.mjs +671 -0
- package/dist/transform/templates.cjs +3806 -0
- package/dist/transform/templates.d.cts +82 -0
- package/dist/transform/templates.d.ts +83 -0
- package/dist/transform/templates.d.ts.map +1 -0
- package/dist/transform/templates.js +613 -0
- package/dist/transform/templates.mjs +4852 -0
- package/dist/transform-3W45L3EA.mjs +951 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/dist/vite-styles.cjs +223 -0
- package/dist/vite-styles.d.cts +68 -0
- package/dist/vite-styles.d.ts +69 -0
- package/dist/vite-styles.d.ts.map +1 -0
- package/dist/vite-styles.js +241 -0
- package/dist/vite-styles.mjs +214 -0
- package/package.json +141 -0
|
@@ -0,0 +1,4852 @@
|
|
|
1
|
+
// src/transform/templates.ts
|
|
2
|
+
import { parse as parse2 } from "@babel/parser";
|
|
3
|
+
|
|
4
|
+
// ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.6.0/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
|
|
5
|
+
var comma = ",".charCodeAt(0);
|
|
6
|
+
var semicolon = ";".charCodeAt(0);
|
|
7
|
+
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
8
|
+
var intToChar = new Uint8Array(64);
|
|
9
|
+
var charToInt = new Uint8Array(128);
|
|
10
|
+
for (let i = 0; i < chars.length; i++) {
|
|
11
|
+
const c = chars.charCodeAt(i);
|
|
12
|
+
intToChar[i] = c;
|
|
13
|
+
charToInt[c] = i;
|
|
14
|
+
}
|
|
15
|
+
function encodeInteger(builder, num) {
|
|
16
|
+
do {
|
|
17
|
+
let clamped = num & 31;
|
|
18
|
+
num >>>= 5;
|
|
19
|
+
if (num > 0) clamped |= 32;
|
|
20
|
+
builder.write(intToChar[clamped]);
|
|
21
|
+
} while (num > 0);
|
|
22
|
+
}
|
|
23
|
+
function encodeSign(num) {
|
|
24
|
+
return num < 0 ? -num << 1 | 1 : num << 1;
|
|
25
|
+
}
|
|
26
|
+
var bufLength = 1024 * 16;
|
|
27
|
+
var td = typeof TextDecoder !== "undefined" ? /* @__PURE__ */ new TextDecoder() : typeof Buffer !== "undefined" ? {
|
|
28
|
+
decode(buf) {
|
|
29
|
+
const out = Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
30
|
+
return out.toString();
|
|
31
|
+
}
|
|
32
|
+
} : {
|
|
33
|
+
decode(buf) {
|
|
34
|
+
let out = "";
|
|
35
|
+
for (let i = 0; i < buf.length; i++) {
|
|
36
|
+
out += String.fromCharCode(buf[i]);
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var StringWriter = class {
|
|
42
|
+
constructor() {
|
|
43
|
+
this.pos = 0;
|
|
44
|
+
this.out = "";
|
|
45
|
+
this.buffer = new Uint8Array(bufLength);
|
|
46
|
+
}
|
|
47
|
+
write(v) {
|
|
48
|
+
const { buffer } = this;
|
|
49
|
+
buffer[this.pos++] = v;
|
|
50
|
+
if (this.pos === bufLength) {
|
|
51
|
+
this.out += td.decode(buffer);
|
|
52
|
+
this.pos = 0;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
flush() {
|
|
56
|
+
const { buffer, out, pos } = this;
|
|
57
|
+
return pos > 0 ? out + td.decode(buffer.subarray(0, pos)) : out;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
function encode(decoded) {
|
|
61
|
+
const writer = new StringWriter();
|
|
62
|
+
let sourcesIndex = 0;
|
|
63
|
+
let sourceLine = 0;
|
|
64
|
+
let sourceColumn = 0;
|
|
65
|
+
let namesIndex = 0;
|
|
66
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
67
|
+
const line = decoded[i];
|
|
68
|
+
if (i > 0) writer.write(semicolon);
|
|
69
|
+
if (line.length === 0) continue;
|
|
70
|
+
let genColumn = 0;
|
|
71
|
+
for (let j = 0; j < line.length; j++) {
|
|
72
|
+
const segment = line[j];
|
|
73
|
+
if (j > 0) writer.write(comma);
|
|
74
|
+
encodeInteger(writer, encodeSign(segment[0] - genColumn));
|
|
75
|
+
genColumn = segment[0];
|
|
76
|
+
if (segment.length === 1) continue;
|
|
77
|
+
encodeInteger(writer, encodeSign(segment[1] - sourcesIndex));
|
|
78
|
+
encodeInteger(writer, encodeSign(segment[2] - sourceLine));
|
|
79
|
+
encodeInteger(writer, encodeSign(segment[3] - sourceColumn));
|
|
80
|
+
sourcesIndex = segment[1];
|
|
81
|
+
sourceLine = segment[2];
|
|
82
|
+
sourceColumn = segment[3];
|
|
83
|
+
if (segment.length === 4) continue;
|
|
84
|
+
encodeInteger(writer, encodeSign(segment[4] - namesIndex));
|
|
85
|
+
namesIndex = segment[4];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return writer.flush();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ../../node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.mjs
|
|
92
|
+
var BitSet = class _BitSet {
|
|
93
|
+
constructor(arg) {
|
|
94
|
+
this.bits = arg instanceof _BitSet ? arg.bits.slice() : [];
|
|
95
|
+
}
|
|
96
|
+
add(n2) {
|
|
97
|
+
this.bits[n2 >> 5] |= 1 << (n2 & 31);
|
|
98
|
+
}
|
|
99
|
+
has(n2) {
|
|
100
|
+
return !!(this.bits[n2 >> 5] & 1 << (n2 & 31));
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
var Chunk = class _Chunk {
|
|
104
|
+
constructor(start, end, content) {
|
|
105
|
+
this.start = start;
|
|
106
|
+
this.end = end;
|
|
107
|
+
this.original = content;
|
|
108
|
+
this.intro = "";
|
|
109
|
+
this.outro = "";
|
|
110
|
+
this.content = content;
|
|
111
|
+
this.storeName = false;
|
|
112
|
+
this.edited = false;
|
|
113
|
+
{
|
|
114
|
+
this.previous = null;
|
|
115
|
+
this.next = null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
appendLeft(content) {
|
|
119
|
+
this.outro += content;
|
|
120
|
+
}
|
|
121
|
+
appendRight(content) {
|
|
122
|
+
this.intro = this.intro + content;
|
|
123
|
+
}
|
|
124
|
+
clone() {
|
|
125
|
+
const chunk = new _Chunk(this.start, this.end, this.original);
|
|
126
|
+
chunk.intro = this.intro;
|
|
127
|
+
chunk.outro = this.outro;
|
|
128
|
+
chunk.content = this.content;
|
|
129
|
+
chunk.storeName = this.storeName;
|
|
130
|
+
chunk.edited = this.edited;
|
|
131
|
+
return chunk;
|
|
132
|
+
}
|
|
133
|
+
contains(index) {
|
|
134
|
+
return this.start < index && index < this.end;
|
|
135
|
+
}
|
|
136
|
+
eachNext(fn) {
|
|
137
|
+
let chunk = this;
|
|
138
|
+
while (chunk) {
|
|
139
|
+
fn(chunk);
|
|
140
|
+
chunk = chunk.next;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
eachPrevious(fn) {
|
|
144
|
+
let chunk = this;
|
|
145
|
+
while (chunk) {
|
|
146
|
+
fn(chunk);
|
|
147
|
+
chunk = chunk.previous;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
edit(content, storeName, contentOnly) {
|
|
151
|
+
this.content = content;
|
|
152
|
+
if (!contentOnly) {
|
|
153
|
+
this.intro = "";
|
|
154
|
+
this.outro = "";
|
|
155
|
+
}
|
|
156
|
+
this.storeName = storeName;
|
|
157
|
+
this.edited = true;
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
prependLeft(content) {
|
|
161
|
+
this.outro = content + this.outro;
|
|
162
|
+
}
|
|
163
|
+
prependRight(content) {
|
|
164
|
+
this.intro = content + this.intro;
|
|
165
|
+
}
|
|
166
|
+
reset() {
|
|
167
|
+
this.intro = "";
|
|
168
|
+
this.outro = "";
|
|
169
|
+
if (this.edited) {
|
|
170
|
+
this.content = this.original;
|
|
171
|
+
this.storeName = false;
|
|
172
|
+
this.edited = false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
split(index) {
|
|
176
|
+
const sliceIndex = index - this.start;
|
|
177
|
+
const originalBefore = this.original.slice(0, sliceIndex);
|
|
178
|
+
const originalAfter = this.original.slice(sliceIndex);
|
|
179
|
+
this.original = originalBefore;
|
|
180
|
+
const newChunk = new _Chunk(index, this.end, originalAfter);
|
|
181
|
+
newChunk.outro = this.outro;
|
|
182
|
+
this.outro = "";
|
|
183
|
+
this.end = index;
|
|
184
|
+
if (this.edited) {
|
|
185
|
+
newChunk.edit("", false);
|
|
186
|
+
this.content = "";
|
|
187
|
+
} else {
|
|
188
|
+
this.content = originalBefore;
|
|
189
|
+
}
|
|
190
|
+
newChunk.next = this.next;
|
|
191
|
+
if (newChunk.next) newChunk.next.previous = newChunk;
|
|
192
|
+
newChunk.previous = this;
|
|
193
|
+
this.next = newChunk;
|
|
194
|
+
return newChunk;
|
|
195
|
+
}
|
|
196
|
+
toString() {
|
|
197
|
+
return this.intro + this.content + this.outro;
|
|
198
|
+
}
|
|
199
|
+
trimEnd(rx) {
|
|
200
|
+
this.outro = this.outro.replace(rx, "");
|
|
201
|
+
if (this.outro.length) return true;
|
|
202
|
+
const trimmed = this.content.replace(rx, "");
|
|
203
|
+
if (trimmed.length) {
|
|
204
|
+
if (trimmed !== this.content) {
|
|
205
|
+
this.split(this.start + trimmed.length).edit("", void 0, true);
|
|
206
|
+
if (this.edited) {
|
|
207
|
+
this.edit(trimmed, this.storeName, true);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return true;
|
|
211
|
+
} else {
|
|
212
|
+
this.edit("", void 0, true);
|
|
213
|
+
this.intro = this.intro.replace(rx, "");
|
|
214
|
+
if (this.intro.length) return true;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
trimStart(rx) {
|
|
218
|
+
this.intro = this.intro.replace(rx, "");
|
|
219
|
+
if (this.intro.length) return true;
|
|
220
|
+
const trimmed = this.content.replace(rx, "");
|
|
221
|
+
if (trimmed.length) {
|
|
222
|
+
if (trimmed !== this.content) {
|
|
223
|
+
const newChunk = this.split(this.end - trimmed.length);
|
|
224
|
+
if (this.edited) {
|
|
225
|
+
newChunk.edit(trimmed, this.storeName, true);
|
|
226
|
+
}
|
|
227
|
+
this.edit("", void 0, true);
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
230
|
+
} else {
|
|
231
|
+
this.edit("", void 0, true);
|
|
232
|
+
this.outro = this.outro.replace(rx, "");
|
|
233
|
+
if (this.outro.length) return true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
function getBtoa() {
|
|
238
|
+
if (typeof globalThis !== "undefined" && typeof globalThis.btoa === "function") {
|
|
239
|
+
return (str) => globalThis.btoa(unescape(encodeURIComponent(str)));
|
|
240
|
+
} else if (typeof Buffer === "function") {
|
|
241
|
+
return (str) => Buffer.from(str, "utf-8").toString("base64");
|
|
242
|
+
} else {
|
|
243
|
+
return () => {
|
|
244
|
+
throw new Error("Unsupported environment: `window.btoa` or `Buffer` should be supported.");
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
var btoa = /* @__PURE__ */ getBtoa();
|
|
249
|
+
var SourceMap = class {
|
|
250
|
+
constructor(properties) {
|
|
251
|
+
this.version = 3;
|
|
252
|
+
this.file = properties.file;
|
|
253
|
+
this.sources = properties.sources;
|
|
254
|
+
this.sourcesContent = properties.sourcesContent;
|
|
255
|
+
this.names = properties.names;
|
|
256
|
+
this.mappings = encode(properties.mappings);
|
|
257
|
+
if (typeof properties.x_google_ignoreList !== "undefined") {
|
|
258
|
+
this.x_google_ignoreList = properties.x_google_ignoreList;
|
|
259
|
+
}
|
|
260
|
+
if (typeof properties.debugId !== "undefined") {
|
|
261
|
+
this.debugId = properties.debugId;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
toString() {
|
|
265
|
+
return JSON.stringify(this);
|
|
266
|
+
}
|
|
267
|
+
toUrl() {
|
|
268
|
+
return "data:application/json;charset=utf-8;base64," + btoa(this.toString());
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
function guessIndent(code) {
|
|
272
|
+
const lines = code.split("\n");
|
|
273
|
+
const tabbed = lines.filter((line) => /^\t+/.test(line));
|
|
274
|
+
const spaced = lines.filter((line) => /^ {2,}/.test(line));
|
|
275
|
+
if (tabbed.length === 0 && spaced.length === 0) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
if (tabbed.length >= spaced.length) {
|
|
279
|
+
return " ";
|
|
280
|
+
}
|
|
281
|
+
const min = spaced.reduce((previous, current) => {
|
|
282
|
+
const numSpaces = /^ +/.exec(current)[0].length;
|
|
283
|
+
return Math.min(numSpaces, previous);
|
|
284
|
+
}, Infinity);
|
|
285
|
+
return new Array(min + 1).join(" ");
|
|
286
|
+
}
|
|
287
|
+
function getRelativePath(from, to) {
|
|
288
|
+
const fromParts = from.split(/[/\\]/);
|
|
289
|
+
const toParts = to.split(/[/\\]/);
|
|
290
|
+
fromParts.pop();
|
|
291
|
+
while (fromParts[0] === toParts[0]) {
|
|
292
|
+
fromParts.shift();
|
|
293
|
+
toParts.shift();
|
|
294
|
+
}
|
|
295
|
+
if (fromParts.length) {
|
|
296
|
+
let i = fromParts.length;
|
|
297
|
+
while (i--) fromParts[i] = "..";
|
|
298
|
+
}
|
|
299
|
+
return fromParts.concat(toParts).join("/");
|
|
300
|
+
}
|
|
301
|
+
var toString = Object.prototype.toString;
|
|
302
|
+
function isObject(thing) {
|
|
303
|
+
return toString.call(thing) === "[object Object]";
|
|
304
|
+
}
|
|
305
|
+
function getLocator(source) {
|
|
306
|
+
const originalLines = source.split("\n");
|
|
307
|
+
const lineOffsets = [];
|
|
308
|
+
for (let i = 0, pos = 0; i < originalLines.length; i++) {
|
|
309
|
+
lineOffsets.push(pos);
|
|
310
|
+
pos += originalLines[i].length + 1;
|
|
311
|
+
}
|
|
312
|
+
return function locate(index) {
|
|
313
|
+
let i = 0;
|
|
314
|
+
let j = lineOffsets.length;
|
|
315
|
+
while (i < j) {
|
|
316
|
+
const m = i + j >> 1;
|
|
317
|
+
if (index < lineOffsets[m]) {
|
|
318
|
+
j = m;
|
|
319
|
+
} else {
|
|
320
|
+
i = m + 1;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const line = i - 1;
|
|
324
|
+
const column = index - lineOffsets[line];
|
|
325
|
+
return { line, column };
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
var wordRegex = /\w/;
|
|
329
|
+
var Mappings = class {
|
|
330
|
+
constructor(hires) {
|
|
331
|
+
this.hires = hires;
|
|
332
|
+
this.generatedCodeLine = 0;
|
|
333
|
+
this.generatedCodeColumn = 0;
|
|
334
|
+
this.raw = [];
|
|
335
|
+
this.rawSegments = this.raw[this.generatedCodeLine] = [];
|
|
336
|
+
this.pending = null;
|
|
337
|
+
}
|
|
338
|
+
addEdit(sourceIndex, content, loc, nameIndex) {
|
|
339
|
+
if (content.length) {
|
|
340
|
+
const contentLengthMinusOne = content.length - 1;
|
|
341
|
+
let contentLineEnd = content.indexOf("\n", 0);
|
|
342
|
+
let previousContentLineEnd = -1;
|
|
343
|
+
while (contentLineEnd >= 0 && contentLengthMinusOne > contentLineEnd) {
|
|
344
|
+
const segment2 = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column];
|
|
345
|
+
if (nameIndex >= 0) {
|
|
346
|
+
segment2.push(nameIndex);
|
|
347
|
+
}
|
|
348
|
+
this.rawSegments.push(segment2);
|
|
349
|
+
this.generatedCodeLine += 1;
|
|
350
|
+
this.raw[this.generatedCodeLine] = this.rawSegments = [];
|
|
351
|
+
this.generatedCodeColumn = 0;
|
|
352
|
+
previousContentLineEnd = contentLineEnd;
|
|
353
|
+
contentLineEnd = content.indexOf("\n", contentLineEnd + 1);
|
|
354
|
+
}
|
|
355
|
+
const segment = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column];
|
|
356
|
+
if (nameIndex >= 0) {
|
|
357
|
+
segment.push(nameIndex);
|
|
358
|
+
}
|
|
359
|
+
this.rawSegments.push(segment);
|
|
360
|
+
this.advance(content.slice(previousContentLineEnd + 1));
|
|
361
|
+
} else if (this.pending) {
|
|
362
|
+
this.rawSegments.push(this.pending);
|
|
363
|
+
this.advance(content);
|
|
364
|
+
}
|
|
365
|
+
this.pending = null;
|
|
366
|
+
}
|
|
367
|
+
addUneditedChunk(sourceIndex, chunk, original, loc, sourcemapLocations) {
|
|
368
|
+
let originalCharIndex = chunk.start;
|
|
369
|
+
let first = true;
|
|
370
|
+
let charInHiresBoundary = false;
|
|
371
|
+
while (originalCharIndex < chunk.end) {
|
|
372
|
+
if (original[originalCharIndex] === "\n") {
|
|
373
|
+
loc.line += 1;
|
|
374
|
+
loc.column = 0;
|
|
375
|
+
this.generatedCodeLine += 1;
|
|
376
|
+
this.raw[this.generatedCodeLine] = this.rawSegments = [];
|
|
377
|
+
this.generatedCodeColumn = 0;
|
|
378
|
+
first = true;
|
|
379
|
+
charInHiresBoundary = false;
|
|
380
|
+
} else {
|
|
381
|
+
if (this.hires || first || sourcemapLocations.has(originalCharIndex)) {
|
|
382
|
+
const segment = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column];
|
|
383
|
+
if (this.hires === "boundary") {
|
|
384
|
+
if (wordRegex.test(original[originalCharIndex])) {
|
|
385
|
+
if (!charInHiresBoundary) {
|
|
386
|
+
this.rawSegments.push(segment);
|
|
387
|
+
charInHiresBoundary = true;
|
|
388
|
+
}
|
|
389
|
+
} else {
|
|
390
|
+
this.rawSegments.push(segment);
|
|
391
|
+
charInHiresBoundary = false;
|
|
392
|
+
}
|
|
393
|
+
} else {
|
|
394
|
+
this.rawSegments.push(segment);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
loc.column += 1;
|
|
398
|
+
this.generatedCodeColumn += 1;
|
|
399
|
+
first = false;
|
|
400
|
+
}
|
|
401
|
+
originalCharIndex += 1;
|
|
402
|
+
}
|
|
403
|
+
this.pending = null;
|
|
404
|
+
}
|
|
405
|
+
advance(str) {
|
|
406
|
+
if (!str) return;
|
|
407
|
+
const lines = str.split("\n");
|
|
408
|
+
if (lines.length > 1) {
|
|
409
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
410
|
+
this.generatedCodeLine++;
|
|
411
|
+
this.raw[this.generatedCodeLine] = this.rawSegments = [];
|
|
412
|
+
}
|
|
413
|
+
this.generatedCodeColumn = 0;
|
|
414
|
+
}
|
|
415
|
+
this.generatedCodeColumn += lines[lines.length - 1].length;
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
var n = "\n";
|
|
419
|
+
var warned = {
|
|
420
|
+
insertLeft: false,
|
|
421
|
+
insertRight: false,
|
|
422
|
+
storeName: false
|
|
423
|
+
};
|
|
424
|
+
var MagicString = class _MagicString {
|
|
425
|
+
constructor(string, options = {}) {
|
|
426
|
+
const chunk = new Chunk(0, string.length, string);
|
|
427
|
+
Object.defineProperties(this, {
|
|
428
|
+
original: { writable: true, value: string },
|
|
429
|
+
outro: { writable: true, value: "" },
|
|
430
|
+
intro: { writable: true, value: "" },
|
|
431
|
+
firstChunk: { writable: true, value: chunk },
|
|
432
|
+
lastChunk: { writable: true, value: chunk },
|
|
433
|
+
lastSearchedChunk: { writable: true, value: chunk },
|
|
434
|
+
byStart: { writable: true, value: {} },
|
|
435
|
+
byEnd: { writable: true, value: {} },
|
|
436
|
+
filename: { writable: true, value: options.filename },
|
|
437
|
+
indentExclusionRanges: { writable: true, value: options.indentExclusionRanges },
|
|
438
|
+
sourcemapLocations: { writable: true, value: new BitSet() },
|
|
439
|
+
storedNames: { writable: true, value: {} },
|
|
440
|
+
indentStr: { writable: true, value: void 0 },
|
|
441
|
+
ignoreList: { writable: true, value: options.ignoreList },
|
|
442
|
+
offset: { writable: true, value: options.offset || 0 }
|
|
443
|
+
});
|
|
444
|
+
this.byStart[0] = chunk;
|
|
445
|
+
this.byEnd[string.length] = chunk;
|
|
446
|
+
}
|
|
447
|
+
addSourcemapLocation(char) {
|
|
448
|
+
this.sourcemapLocations.add(char);
|
|
449
|
+
}
|
|
450
|
+
append(content) {
|
|
451
|
+
if (typeof content !== "string") throw new TypeError("outro content must be a string");
|
|
452
|
+
this.outro += content;
|
|
453
|
+
return this;
|
|
454
|
+
}
|
|
455
|
+
appendLeft(index, content) {
|
|
456
|
+
index = index + this.offset;
|
|
457
|
+
if (typeof content !== "string") throw new TypeError("inserted content must be a string");
|
|
458
|
+
this._split(index);
|
|
459
|
+
const chunk = this.byEnd[index];
|
|
460
|
+
if (chunk) {
|
|
461
|
+
chunk.appendLeft(content);
|
|
462
|
+
} else {
|
|
463
|
+
this.intro += content;
|
|
464
|
+
}
|
|
465
|
+
return this;
|
|
466
|
+
}
|
|
467
|
+
appendRight(index, content) {
|
|
468
|
+
index = index + this.offset;
|
|
469
|
+
if (typeof content !== "string") throw new TypeError("inserted content must be a string");
|
|
470
|
+
this._split(index);
|
|
471
|
+
const chunk = this.byStart[index];
|
|
472
|
+
if (chunk) {
|
|
473
|
+
chunk.appendRight(content);
|
|
474
|
+
} else {
|
|
475
|
+
this.outro += content;
|
|
476
|
+
}
|
|
477
|
+
return this;
|
|
478
|
+
}
|
|
479
|
+
clone() {
|
|
480
|
+
const cloned = new _MagicString(this.original, { filename: this.filename, offset: this.offset });
|
|
481
|
+
let originalChunk = this.firstChunk;
|
|
482
|
+
let clonedChunk = cloned.firstChunk = cloned.lastSearchedChunk = originalChunk.clone();
|
|
483
|
+
while (originalChunk) {
|
|
484
|
+
cloned.byStart[clonedChunk.start] = clonedChunk;
|
|
485
|
+
cloned.byEnd[clonedChunk.end] = clonedChunk;
|
|
486
|
+
const nextOriginalChunk = originalChunk.next;
|
|
487
|
+
const nextClonedChunk = nextOriginalChunk && nextOriginalChunk.clone();
|
|
488
|
+
if (nextClonedChunk) {
|
|
489
|
+
clonedChunk.next = nextClonedChunk;
|
|
490
|
+
nextClonedChunk.previous = clonedChunk;
|
|
491
|
+
clonedChunk = nextClonedChunk;
|
|
492
|
+
}
|
|
493
|
+
originalChunk = nextOriginalChunk;
|
|
494
|
+
}
|
|
495
|
+
cloned.lastChunk = clonedChunk;
|
|
496
|
+
if (this.indentExclusionRanges) {
|
|
497
|
+
cloned.indentExclusionRanges = this.indentExclusionRanges.slice();
|
|
498
|
+
}
|
|
499
|
+
cloned.sourcemapLocations = new BitSet(this.sourcemapLocations);
|
|
500
|
+
cloned.intro = this.intro;
|
|
501
|
+
cloned.outro = this.outro;
|
|
502
|
+
return cloned;
|
|
503
|
+
}
|
|
504
|
+
generateDecodedMap(options) {
|
|
505
|
+
options = options || {};
|
|
506
|
+
const sourceIndex = 0;
|
|
507
|
+
const names = Object.keys(this.storedNames);
|
|
508
|
+
const mappings = new Mappings(options.hires);
|
|
509
|
+
const locate = getLocator(this.original);
|
|
510
|
+
if (this.intro) {
|
|
511
|
+
mappings.advance(this.intro);
|
|
512
|
+
}
|
|
513
|
+
this.firstChunk.eachNext((chunk) => {
|
|
514
|
+
const loc = locate(chunk.start);
|
|
515
|
+
if (chunk.intro.length) mappings.advance(chunk.intro);
|
|
516
|
+
if (chunk.edited) {
|
|
517
|
+
mappings.addEdit(
|
|
518
|
+
sourceIndex,
|
|
519
|
+
chunk.content,
|
|
520
|
+
loc,
|
|
521
|
+
chunk.storeName ? names.indexOf(chunk.original) : -1
|
|
522
|
+
);
|
|
523
|
+
} else {
|
|
524
|
+
mappings.addUneditedChunk(sourceIndex, chunk, this.original, loc, this.sourcemapLocations);
|
|
525
|
+
}
|
|
526
|
+
if (chunk.outro.length) mappings.advance(chunk.outro);
|
|
527
|
+
});
|
|
528
|
+
if (this.outro) {
|
|
529
|
+
mappings.advance(this.outro);
|
|
530
|
+
}
|
|
531
|
+
return {
|
|
532
|
+
file: options.file ? options.file.split(/[/\\]/).pop() : void 0,
|
|
533
|
+
sources: [
|
|
534
|
+
options.source ? getRelativePath(options.file || "", options.source) : options.file || ""
|
|
535
|
+
],
|
|
536
|
+
sourcesContent: options.includeContent ? [this.original] : void 0,
|
|
537
|
+
names,
|
|
538
|
+
mappings: mappings.raw,
|
|
539
|
+
x_google_ignoreList: this.ignoreList ? [sourceIndex] : void 0
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
generateMap(options) {
|
|
543
|
+
return new SourceMap(this.generateDecodedMap(options));
|
|
544
|
+
}
|
|
545
|
+
_ensureindentStr() {
|
|
546
|
+
if (this.indentStr === void 0) {
|
|
547
|
+
this.indentStr = guessIndent(this.original);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
_getRawIndentString() {
|
|
551
|
+
this._ensureindentStr();
|
|
552
|
+
return this.indentStr;
|
|
553
|
+
}
|
|
554
|
+
getIndentString() {
|
|
555
|
+
this._ensureindentStr();
|
|
556
|
+
return this.indentStr === null ? " " : this.indentStr;
|
|
557
|
+
}
|
|
558
|
+
indent(indentStr, options) {
|
|
559
|
+
const pattern = /^[^\r\n]/gm;
|
|
560
|
+
if (isObject(indentStr)) {
|
|
561
|
+
options = indentStr;
|
|
562
|
+
indentStr = void 0;
|
|
563
|
+
}
|
|
564
|
+
if (indentStr === void 0) {
|
|
565
|
+
this._ensureindentStr();
|
|
566
|
+
indentStr = this.indentStr || " ";
|
|
567
|
+
}
|
|
568
|
+
if (indentStr === "") return this;
|
|
569
|
+
options = options || {};
|
|
570
|
+
const isExcluded = {};
|
|
571
|
+
if (options.exclude) {
|
|
572
|
+
const exclusions = typeof options.exclude[0] === "number" ? [options.exclude] : options.exclude;
|
|
573
|
+
exclusions.forEach((exclusion) => {
|
|
574
|
+
for (let i = exclusion[0]; i < exclusion[1]; i += 1) {
|
|
575
|
+
isExcluded[i] = true;
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
let shouldIndentNextCharacter = options.indentStart !== false;
|
|
580
|
+
const replacer = (match) => {
|
|
581
|
+
if (shouldIndentNextCharacter) return `${indentStr}${match}`;
|
|
582
|
+
shouldIndentNextCharacter = true;
|
|
583
|
+
return match;
|
|
584
|
+
};
|
|
585
|
+
this.intro = this.intro.replace(pattern, replacer);
|
|
586
|
+
let charIndex = 0;
|
|
587
|
+
let chunk = this.firstChunk;
|
|
588
|
+
while (chunk) {
|
|
589
|
+
const end = chunk.end;
|
|
590
|
+
if (chunk.edited) {
|
|
591
|
+
if (!isExcluded[charIndex]) {
|
|
592
|
+
chunk.content = chunk.content.replace(pattern, replacer);
|
|
593
|
+
if (chunk.content.length) {
|
|
594
|
+
shouldIndentNextCharacter = chunk.content[chunk.content.length - 1] === "\n";
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
} else {
|
|
598
|
+
charIndex = chunk.start;
|
|
599
|
+
while (charIndex < end) {
|
|
600
|
+
if (!isExcluded[charIndex]) {
|
|
601
|
+
const char = this.original[charIndex];
|
|
602
|
+
if (char === "\n") {
|
|
603
|
+
shouldIndentNextCharacter = true;
|
|
604
|
+
} else if (char !== "\r" && shouldIndentNextCharacter) {
|
|
605
|
+
shouldIndentNextCharacter = false;
|
|
606
|
+
if (charIndex === chunk.start) {
|
|
607
|
+
chunk.prependRight(indentStr);
|
|
608
|
+
} else {
|
|
609
|
+
this._splitChunk(chunk, charIndex);
|
|
610
|
+
chunk = chunk.next;
|
|
611
|
+
chunk.prependRight(indentStr);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
charIndex += 1;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
charIndex = chunk.end;
|
|
619
|
+
chunk = chunk.next;
|
|
620
|
+
}
|
|
621
|
+
this.outro = this.outro.replace(pattern, replacer);
|
|
622
|
+
return this;
|
|
623
|
+
}
|
|
624
|
+
insert() {
|
|
625
|
+
throw new Error(
|
|
626
|
+
"magicString.insert(...) is deprecated. Use prependRight(...) or appendLeft(...)"
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
insertLeft(index, content) {
|
|
630
|
+
if (!warned.insertLeft) {
|
|
631
|
+
console.warn(
|
|
632
|
+
"magicString.insertLeft(...) is deprecated. Use magicString.appendLeft(...) instead"
|
|
633
|
+
);
|
|
634
|
+
warned.insertLeft = true;
|
|
635
|
+
}
|
|
636
|
+
return this.appendLeft(index, content);
|
|
637
|
+
}
|
|
638
|
+
insertRight(index, content) {
|
|
639
|
+
if (!warned.insertRight) {
|
|
640
|
+
console.warn(
|
|
641
|
+
"magicString.insertRight(...) is deprecated. Use magicString.prependRight(...) instead"
|
|
642
|
+
);
|
|
643
|
+
warned.insertRight = true;
|
|
644
|
+
}
|
|
645
|
+
return this.prependRight(index, content);
|
|
646
|
+
}
|
|
647
|
+
move(start, end, index) {
|
|
648
|
+
start = start + this.offset;
|
|
649
|
+
end = end + this.offset;
|
|
650
|
+
index = index + this.offset;
|
|
651
|
+
if (index >= start && index <= end) throw new Error("Cannot move a selection inside itself");
|
|
652
|
+
this._split(start);
|
|
653
|
+
this._split(end);
|
|
654
|
+
this._split(index);
|
|
655
|
+
const first = this.byStart[start];
|
|
656
|
+
const last = this.byEnd[end];
|
|
657
|
+
const oldLeft = first.previous;
|
|
658
|
+
const oldRight = last.next;
|
|
659
|
+
const newRight = this.byStart[index];
|
|
660
|
+
if (!newRight && last === this.lastChunk) return this;
|
|
661
|
+
const newLeft = newRight ? newRight.previous : this.lastChunk;
|
|
662
|
+
if (oldLeft) oldLeft.next = oldRight;
|
|
663
|
+
if (oldRight) oldRight.previous = oldLeft;
|
|
664
|
+
if (newLeft) newLeft.next = first;
|
|
665
|
+
if (newRight) newRight.previous = last;
|
|
666
|
+
if (!first.previous) this.firstChunk = last.next;
|
|
667
|
+
if (!last.next) {
|
|
668
|
+
this.lastChunk = first.previous;
|
|
669
|
+
this.lastChunk.next = null;
|
|
670
|
+
}
|
|
671
|
+
first.previous = newLeft;
|
|
672
|
+
last.next = newRight || null;
|
|
673
|
+
if (!newLeft) this.firstChunk = first;
|
|
674
|
+
if (!newRight) this.lastChunk = last;
|
|
675
|
+
return this;
|
|
676
|
+
}
|
|
677
|
+
overwrite(start, end, content, options) {
|
|
678
|
+
options = options || {};
|
|
679
|
+
return this.update(start, end, content, { ...options, overwrite: !options.contentOnly });
|
|
680
|
+
}
|
|
681
|
+
update(start, end, content, options) {
|
|
682
|
+
start = start + this.offset;
|
|
683
|
+
end = end + this.offset;
|
|
684
|
+
if (typeof content !== "string") throw new TypeError("replacement content must be a string");
|
|
685
|
+
if (this.original.length !== 0) {
|
|
686
|
+
while (start < 0) start += this.original.length;
|
|
687
|
+
while (end < 0) end += this.original.length;
|
|
688
|
+
}
|
|
689
|
+
if (end > this.original.length) throw new Error("end is out of bounds");
|
|
690
|
+
if (start === end)
|
|
691
|
+
throw new Error(
|
|
692
|
+
"Cannot overwrite a zero-length range – use appendLeft or prependRight instead"
|
|
693
|
+
);
|
|
694
|
+
this._split(start);
|
|
695
|
+
this._split(end);
|
|
696
|
+
if (options === true) {
|
|
697
|
+
if (!warned.storeName) {
|
|
698
|
+
console.warn(
|
|
699
|
+
"The final argument to magicString.overwrite(...) should be an options object. See https://github.com/rich-harris/magic-string"
|
|
700
|
+
);
|
|
701
|
+
warned.storeName = true;
|
|
702
|
+
}
|
|
703
|
+
options = { storeName: true };
|
|
704
|
+
}
|
|
705
|
+
const storeName = options !== void 0 ? options.storeName : false;
|
|
706
|
+
const overwrite = options !== void 0 ? options.overwrite : false;
|
|
707
|
+
if (storeName) {
|
|
708
|
+
const original = this.original.slice(start, end);
|
|
709
|
+
Object.defineProperty(this.storedNames, original, {
|
|
710
|
+
writable: true,
|
|
711
|
+
value: true,
|
|
712
|
+
enumerable: true
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
const first = this.byStart[start];
|
|
716
|
+
const last = this.byEnd[end];
|
|
717
|
+
if (first) {
|
|
718
|
+
let chunk = first;
|
|
719
|
+
while (chunk !== last) {
|
|
720
|
+
if (chunk.next !== this.byStart[chunk.end]) {
|
|
721
|
+
throw new Error("Cannot overwrite across a split point");
|
|
722
|
+
}
|
|
723
|
+
chunk = chunk.next;
|
|
724
|
+
chunk.edit("", false);
|
|
725
|
+
}
|
|
726
|
+
first.edit(content, storeName, !overwrite);
|
|
727
|
+
} else {
|
|
728
|
+
const newChunk = new Chunk(start, end, "").edit(content, storeName);
|
|
729
|
+
last.next = newChunk;
|
|
730
|
+
newChunk.previous = last;
|
|
731
|
+
}
|
|
732
|
+
return this;
|
|
733
|
+
}
|
|
734
|
+
prepend(content) {
|
|
735
|
+
if (typeof content !== "string") throw new TypeError("outro content must be a string");
|
|
736
|
+
this.intro = content + this.intro;
|
|
737
|
+
return this;
|
|
738
|
+
}
|
|
739
|
+
prependLeft(index, content) {
|
|
740
|
+
index = index + this.offset;
|
|
741
|
+
if (typeof content !== "string") throw new TypeError("inserted content must be a string");
|
|
742
|
+
this._split(index);
|
|
743
|
+
const chunk = this.byEnd[index];
|
|
744
|
+
if (chunk) {
|
|
745
|
+
chunk.prependLeft(content);
|
|
746
|
+
} else {
|
|
747
|
+
this.intro = content + this.intro;
|
|
748
|
+
}
|
|
749
|
+
return this;
|
|
750
|
+
}
|
|
751
|
+
prependRight(index, content) {
|
|
752
|
+
index = index + this.offset;
|
|
753
|
+
if (typeof content !== "string") throw new TypeError("inserted content must be a string");
|
|
754
|
+
this._split(index);
|
|
755
|
+
const chunk = this.byStart[index];
|
|
756
|
+
if (chunk) {
|
|
757
|
+
chunk.prependRight(content);
|
|
758
|
+
} else {
|
|
759
|
+
this.outro = content + this.outro;
|
|
760
|
+
}
|
|
761
|
+
return this;
|
|
762
|
+
}
|
|
763
|
+
remove(start, end) {
|
|
764
|
+
start = start + this.offset;
|
|
765
|
+
end = end + this.offset;
|
|
766
|
+
if (this.original.length !== 0) {
|
|
767
|
+
while (start < 0) start += this.original.length;
|
|
768
|
+
while (end < 0) end += this.original.length;
|
|
769
|
+
}
|
|
770
|
+
if (start === end) return this;
|
|
771
|
+
if (start < 0 || end > this.original.length) throw new Error("Character is out of bounds");
|
|
772
|
+
if (start > end) throw new Error("end must be greater than start");
|
|
773
|
+
this._split(start);
|
|
774
|
+
this._split(end);
|
|
775
|
+
let chunk = this.byStart[start];
|
|
776
|
+
while (chunk) {
|
|
777
|
+
chunk.intro = "";
|
|
778
|
+
chunk.outro = "";
|
|
779
|
+
chunk.edit("");
|
|
780
|
+
chunk = end > chunk.end ? this.byStart[chunk.end] : null;
|
|
781
|
+
}
|
|
782
|
+
return this;
|
|
783
|
+
}
|
|
784
|
+
reset(start, end) {
|
|
785
|
+
start = start + this.offset;
|
|
786
|
+
end = end + this.offset;
|
|
787
|
+
if (this.original.length !== 0) {
|
|
788
|
+
while (start < 0) start += this.original.length;
|
|
789
|
+
while (end < 0) end += this.original.length;
|
|
790
|
+
}
|
|
791
|
+
if (start === end) return this;
|
|
792
|
+
if (start < 0 || end > this.original.length) throw new Error("Character is out of bounds");
|
|
793
|
+
if (start > end) throw new Error("end must be greater than start");
|
|
794
|
+
this._split(start);
|
|
795
|
+
this._split(end);
|
|
796
|
+
let chunk = this.byStart[start];
|
|
797
|
+
while (chunk) {
|
|
798
|
+
chunk.reset();
|
|
799
|
+
chunk = end > chunk.end ? this.byStart[chunk.end] : null;
|
|
800
|
+
}
|
|
801
|
+
return this;
|
|
802
|
+
}
|
|
803
|
+
lastChar() {
|
|
804
|
+
if (this.outro.length) return this.outro[this.outro.length - 1];
|
|
805
|
+
let chunk = this.lastChunk;
|
|
806
|
+
do {
|
|
807
|
+
if (chunk.outro.length) return chunk.outro[chunk.outro.length - 1];
|
|
808
|
+
if (chunk.content.length) return chunk.content[chunk.content.length - 1];
|
|
809
|
+
if (chunk.intro.length) return chunk.intro[chunk.intro.length - 1];
|
|
810
|
+
} while (chunk = chunk.previous);
|
|
811
|
+
if (this.intro.length) return this.intro[this.intro.length - 1];
|
|
812
|
+
return "";
|
|
813
|
+
}
|
|
814
|
+
lastLine() {
|
|
815
|
+
let lineIndex = this.outro.lastIndexOf(n);
|
|
816
|
+
if (lineIndex !== -1) return this.outro.substr(lineIndex + 1);
|
|
817
|
+
let lineStr = this.outro;
|
|
818
|
+
let chunk = this.lastChunk;
|
|
819
|
+
do {
|
|
820
|
+
if (chunk.outro.length > 0) {
|
|
821
|
+
lineIndex = chunk.outro.lastIndexOf(n);
|
|
822
|
+
if (lineIndex !== -1) return chunk.outro.substr(lineIndex + 1) + lineStr;
|
|
823
|
+
lineStr = chunk.outro + lineStr;
|
|
824
|
+
}
|
|
825
|
+
if (chunk.content.length > 0) {
|
|
826
|
+
lineIndex = chunk.content.lastIndexOf(n);
|
|
827
|
+
if (lineIndex !== -1) return chunk.content.substr(lineIndex + 1) + lineStr;
|
|
828
|
+
lineStr = chunk.content + lineStr;
|
|
829
|
+
}
|
|
830
|
+
if (chunk.intro.length > 0) {
|
|
831
|
+
lineIndex = chunk.intro.lastIndexOf(n);
|
|
832
|
+
if (lineIndex !== -1) return chunk.intro.substr(lineIndex + 1) + lineStr;
|
|
833
|
+
lineStr = chunk.intro + lineStr;
|
|
834
|
+
}
|
|
835
|
+
} while (chunk = chunk.previous);
|
|
836
|
+
lineIndex = this.intro.lastIndexOf(n);
|
|
837
|
+
if (lineIndex !== -1) return this.intro.substr(lineIndex + 1) + lineStr;
|
|
838
|
+
return this.intro + lineStr;
|
|
839
|
+
}
|
|
840
|
+
slice(start = 0, end = this.original.length - this.offset) {
|
|
841
|
+
start = start + this.offset;
|
|
842
|
+
end = end + this.offset;
|
|
843
|
+
if (this.original.length !== 0) {
|
|
844
|
+
while (start < 0) start += this.original.length;
|
|
845
|
+
while (end < 0) end += this.original.length;
|
|
846
|
+
}
|
|
847
|
+
let result = "";
|
|
848
|
+
let chunk = this.firstChunk;
|
|
849
|
+
while (chunk && (chunk.start > start || chunk.end <= start)) {
|
|
850
|
+
if (chunk.start < end && chunk.end >= end) {
|
|
851
|
+
return result;
|
|
852
|
+
}
|
|
853
|
+
chunk = chunk.next;
|
|
854
|
+
}
|
|
855
|
+
if (chunk && chunk.edited && chunk.start !== start)
|
|
856
|
+
throw new Error(`Cannot use replaced character ${start} as slice start anchor.`);
|
|
857
|
+
const startChunk = chunk;
|
|
858
|
+
while (chunk) {
|
|
859
|
+
if (chunk.intro && (startChunk !== chunk || chunk.start === start)) {
|
|
860
|
+
result += chunk.intro;
|
|
861
|
+
}
|
|
862
|
+
const containsEnd = chunk.start < end && chunk.end >= end;
|
|
863
|
+
if (containsEnd && chunk.edited && chunk.end !== end)
|
|
864
|
+
throw new Error(`Cannot use replaced character ${end} as slice end anchor.`);
|
|
865
|
+
const sliceStart = startChunk === chunk ? start - chunk.start : 0;
|
|
866
|
+
const sliceEnd = containsEnd ? chunk.content.length + end - chunk.end : chunk.content.length;
|
|
867
|
+
result += chunk.content.slice(sliceStart, sliceEnd);
|
|
868
|
+
if (chunk.outro && (!containsEnd || chunk.end === end)) {
|
|
869
|
+
result += chunk.outro;
|
|
870
|
+
}
|
|
871
|
+
if (containsEnd) {
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
874
|
+
chunk = chunk.next;
|
|
875
|
+
}
|
|
876
|
+
return result;
|
|
877
|
+
}
|
|
878
|
+
// TODO deprecate this? not really very useful
|
|
879
|
+
snip(start, end) {
|
|
880
|
+
const clone = this.clone();
|
|
881
|
+
clone.remove(0, start);
|
|
882
|
+
clone.remove(end, clone.original.length);
|
|
883
|
+
return clone;
|
|
884
|
+
}
|
|
885
|
+
_split(index) {
|
|
886
|
+
if (this.byStart[index] || this.byEnd[index]) return;
|
|
887
|
+
let chunk = this.lastSearchedChunk;
|
|
888
|
+
let previousChunk = chunk;
|
|
889
|
+
const searchForward = index > chunk.end;
|
|
890
|
+
while (chunk) {
|
|
891
|
+
if (chunk.contains(index)) return this._splitChunk(chunk, index);
|
|
892
|
+
chunk = searchForward ? this.byStart[chunk.end] : this.byEnd[chunk.start];
|
|
893
|
+
if (chunk === previousChunk) return;
|
|
894
|
+
previousChunk = chunk;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
_splitChunk(chunk, index) {
|
|
898
|
+
if (chunk.edited && chunk.content.length) {
|
|
899
|
+
const loc = getLocator(this.original)(index);
|
|
900
|
+
throw new Error(
|
|
901
|
+
`Cannot split a chunk that has already been edited (${loc.line}:${loc.column} – "${chunk.original}")`
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
const newChunk = chunk.split(index);
|
|
905
|
+
this.byEnd[index] = chunk;
|
|
906
|
+
this.byStart[index] = newChunk;
|
|
907
|
+
this.byEnd[newChunk.end] = newChunk;
|
|
908
|
+
if (chunk === this.lastChunk) this.lastChunk = newChunk;
|
|
909
|
+
this.lastSearchedChunk = chunk;
|
|
910
|
+
return true;
|
|
911
|
+
}
|
|
912
|
+
toString() {
|
|
913
|
+
let str = this.intro;
|
|
914
|
+
let chunk = this.firstChunk;
|
|
915
|
+
while (chunk) {
|
|
916
|
+
str += chunk.toString();
|
|
917
|
+
chunk = chunk.next;
|
|
918
|
+
}
|
|
919
|
+
return str + this.outro;
|
|
920
|
+
}
|
|
921
|
+
isEmpty() {
|
|
922
|
+
let chunk = this.firstChunk;
|
|
923
|
+
do {
|
|
924
|
+
if (chunk.intro.length && chunk.intro.trim() || chunk.content.length && chunk.content.trim() || chunk.outro.length && chunk.outro.trim())
|
|
925
|
+
return false;
|
|
926
|
+
} while (chunk = chunk.next);
|
|
927
|
+
return true;
|
|
928
|
+
}
|
|
929
|
+
length() {
|
|
930
|
+
let chunk = this.firstChunk;
|
|
931
|
+
let length = 0;
|
|
932
|
+
do {
|
|
933
|
+
length += chunk.intro.length + chunk.content.length + chunk.outro.length;
|
|
934
|
+
} while (chunk = chunk.next);
|
|
935
|
+
return length;
|
|
936
|
+
}
|
|
937
|
+
trimLines() {
|
|
938
|
+
return this.trim("[\\r\\n]");
|
|
939
|
+
}
|
|
940
|
+
trim(charType) {
|
|
941
|
+
return this.trimStart(charType).trimEnd(charType);
|
|
942
|
+
}
|
|
943
|
+
trimEndAborted(charType) {
|
|
944
|
+
const rx = new RegExp((charType || "\\s") + "+$");
|
|
945
|
+
this.outro = this.outro.replace(rx, "");
|
|
946
|
+
if (this.outro.length) return true;
|
|
947
|
+
let chunk = this.lastChunk;
|
|
948
|
+
do {
|
|
949
|
+
const end = chunk.end;
|
|
950
|
+
const aborted = chunk.trimEnd(rx);
|
|
951
|
+
if (chunk.end !== end) {
|
|
952
|
+
if (this.lastChunk === chunk) {
|
|
953
|
+
this.lastChunk = chunk.next;
|
|
954
|
+
}
|
|
955
|
+
this.byEnd[chunk.end] = chunk;
|
|
956
|
+
this.byStart[chunk.next.start] = chunk.next;
|
|
957
|
+
this.byEnd[chunk.next.end] = chunk.next;
|
|
958
|
+
}
|
|
959
|
+
if (aborted) return true;
|
|
960
|
+
chunk = chunk.previous;
|
|
961
|
+
} while (chunk);
|
|
962
|
+
return false;
|
|
963
|
+
}
|
|
964
|
+
trimEnd(charType) {
|
|
965
|
+
this.trimEndAborted(charType);
|
|
966
|
+
return this;
|
|
967
|
+
}
|
|
968
|
+
trimStartAborted(charType) {
|
|
969
|
+
const rx = new RegExp("^" + (charType || "\\s") + "+");
|
|
970
|
+
this.intro = this.intro.replace(rx, "");
|
|
971
|
+
if (this.intro.length) return true;
|
|
972
|
+
let chunk = this.firstChunk;
|
|
973
|
+
do {
|
|
974
|
+
const end = chunk.end;
|
|
975
|
+
const aborted = chunk.trimStart(rx);
|
|
976
|
+
if (chunk.end !== end) {
|
|
977
|
+
if (chunk === this.lastChunk) this.lastChunk = chunk.next;
|
|
978
|
+
this.byEnd[chunk.end] = chunk;
|
|
979
|
+
this.byStart[chunk.next.start] = chunk.next;
|
|
980
|
+
this.byEnd[chunk.next.end] = chunk.next;
|
|
981
|
+
}
|
|
982
|
+
if (aborted) return true;
|
|
983
|
+
chunk = chunk.next;
|
|
984
|
+
} while (chunk);
|
|
985
|
+
return false;
|
|
986
|
+
}
|
|
987
|
+
trimStart(charType) {
|
|
988
|
+
this.trimStartAborted(charType);
|
|
989
|
+
return this;
|
|
990
|
+
}
|
|
991
|
+
hasChanged() {
|
|
992
|
+
return this.original !== this.toString();
|
|
993
|
+
}
|
|
994
|
+
_replaceRegexp(searchValue, replacement) {
|
|
995
|
+
function getReplacement(match, str) {
|
|
996
|
+
if (typeof replacement === "string") {
|
|
997
|
+
return replacement.replace(/\$(\$|&|\d+)/g, (_, i) => {
|
|
998
|
+
if (i === "$") return "$";
|
|
999
|
+
if (i === "&") return match[0];
|
|
1000
|
+
const num = +i;
|
|
1001
|
+
if (num < match.length) return match[+i];
|
|
1002
|
+
return `$${i}`;
|
|
1003
|
+
});
|
|
1004
|
+
} else {
|
|
1005
|
+
return replacement(...match, match.index, str, match.groups);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
function matchAll(re, str) {
|
|
1009
|
+
let match;
|
|
1010
|
+
const matches = [];
|
|
1011
|
+
while (match = re.exec(str)) {
|
|
1012
|
+
matches.push(match);
|
|
1013
|
+
}
|
|
1014
|
+
return matches;
|
|
1015
|
+
}
|
|
1016
|
+
if (searchValue.global) {
|
|
1017
|
+
const matches = matchAll(searchValue, this.original);
|
|
1018
|
+
matches.forEach((match) => {
|
|
1019
|
+
if (match.index != null) {
|
|
1020
|
+
const replacement2 = getReplacement(match, this.original);
|
|
1021
|
+
if (replacement2 !== match[0]) {
|
|
1022
|
+
this.overwrite(match.index, match.index + match[0].length, replacement2);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
} else {
|
|
1027
|
+
const match = this.original.match(searchValue);
|
|
1028
|
+
if (match && match.index != null) {
|
|
1029
|
+
const replacement2 = getReplacement(match, this.original);
|
|
1030
|
+
if (replacement2 !== match[0]) {
|
|
1031
|
+
this.overwrite(match.index, match.index + match[0].length, replacement2);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
return this;
|
|
1036
|
+
}
|
|
1037
|
+
_replaceString(string, replacement) {
|
|
1038
|
+
const { original } = this;
|
|
1039
|
+
const index = original.indexOf(string);
|
|
1040
|
+
if (index !== -1) {
|
|
1041
|
+
if (typeof replacement === "function") {
|
|
1042
|
+
replacement = replacement(string, index, original);
|
|
1043
|
+
}
|
|
1044
|
+
if (string !== replacement) {
|
|
1045
|
+
this.overwrite(index, index + string.length, replacement);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
return this;
|
|
1049
|
+
}
|
|
1050
|
+
replace(searchValue, replacement) {
|
|
1051
|
+
if (typeof searchValue === "string") {
|
|
1052
|
+
return this._replaceString(searchValue, replacement);
|
|
1053
|
+
}
|
|
1054
|
+
return this._replaceRegexp(searchValue, replacement);
|
|
1055
|
+
}
|
|
1056
|
+
_replaceAllString(string, replacement) {
|
|
1057
|
+
const { original } = this;
|
|
1058
|
+
const stringLength = string.length;
|
|
1059
|
+
for (let index = original.indexOf(string); index !== -1; index = original.indexOf(string, index + stringLength)) {
|
|
1060
|
+
const previous = original.slice(index, index + stringLength);
|
|
1061
|
+
let _replacement = replacement;
|
|
1062
|
+
if (typeof replacement === "function") {
|
|
1063
|
+
_replacement = replacement(previous, index, original);
|
|
1064
|
+
}
|
|
1065
|
+
if (previous !== _replacement) this.overwrite(index, index + stringLength, _replacement);
|
|
1066
|
+
}
|
|
1067
|
+
return this;
|
|
1068
|
+
}
|
|
1069
|
+
replaceAll(searchValue, replacement) {
|
|
1070
|
+
if (typeof searchValue === "string") {
|
|
1071
|
+
return this._replaceAllString(searchValue, replacement);
|
|
1072
|
+
}
|
|
1073
|
+
if (!searchValue.global) {
|
|
1074
|
+
throw new TypeError(
|
|
1075
|
+
"MagicString.prototype.replaceAll called with a non-global RegExp argument"
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
return this._replaceRegexp(searchValue, replacement);
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
|
|
1082
|
+
// src/transform/styles.ts
|
|
1083
|
+
var SCOPE_ATTR = "data-fx-s";
|
|
1084
|
+
var FUNCTIONS = /* @__PURE__ */ new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression", "ObjectMethod", "ClassMethod"]);
|
|
1085
|
+
function collectStyles(program, sourceName, options, tags = { html: /* @__PURE__ */ new Map([["html", "html"]]) }, module) {
|
|
1086
|
+
const plan = {
|
|
1087
|
+
scopes: [],
|
|
1088
|
+
templateOwners: /* @__PURE__ */ new Map(),
|
|
1089
|
+
drop: /* @__PURE__ */ new Set(),
|
|
1090
|
+
styles: [],
|
|
1091
|
+
diagnostics: [],
|
|
1092
|
+
edits: [],
|
|
1093
|
+
literals: [],
|
|
1094
|
+
references: [],
|
|
1095
|
+
shadowClasses: /* @__PURE__ */ new Map()
|
|
1096
|
+
};
|
|
1097
|
+
if (!options) return plan;
|
|
1098
|
+
const literalsOf = findLiterals(program, options.cssModules ?? ["@fluixi/core", "@fluixi/dom"], plan, tags.css ?? []);
|
|
1099
|
+
plan.names = literalsOf;
|
|
1100
|
+
const classOf = /* @__PURE__ */ new Map();
|
|
1101
|
+
const shadowOf = (owner) => {
|
|
1102
|
+
const cls = classOf.get(owner);
|
|
1103
|
+
return cls ? plan.shadowClasses.get(cls) : void 0;
|
|
1104
|
+
};
|
|
1105
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
1106
|
+
const piecesToNodes = (quasis, expressions, at, stack) => {
|
|
1107
|
+
const out = [];
|
|
1108
|
+
for (let i = 0; i < quasis.length; i++) {
|
|
1109
|
+
const text = quasis[i].value.cooked ?? quasis[i].value.raw;
|
|
1110
|
+
if (text.trim()) {
|
|
1111
|
+
try {
|
|
1112
|
+
const start = quasis[i].loc?.start;
|
|
1113
|
+
out.push(...options.process(text, sourceName).map((n2) => start ? shiftLoc(n2, sourceName, start) : n2));
|
|
1114
|
+
} catch (error) {
|
|
1115
|
+
plan.diagnostics.push({ ...at, message: `CSS could not be processed: ${error.message}` });
|
|
1116
|
+
return null;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
const expr = expressions[i];
|
|
1120
|
+
if (!expr) continue;
|
|
1121
|
+
const value = expr.type === "Identifier" ? resolveLiteral(expr.name, at, stack) : void 0;
|
|
1122
|
+
if (value === void 0) {
|
|
1123
|
+
plan.diagnostics.push({
|
|
1124
|
+
...at,
|
|
1125
|
+
message: "Only css`` values can be interpolated into styles, and only by name: ${base}. Dynamic values go through custom properties (style:--x={...} and var(--x))."
|
|
1126
|
+
});
|
|
1127
|
+
return null;
|
|
1128
|
+
}
|
|
1129
|
+
if (value === null) return null;
|
|
1130
|
+
out.push(...value);
|
|
1131
|
+
}
|
|
1132
|
+
return out;
|
|
1133
|
+
};
|
|
1134
|
+
function resolveLiteral(name, at, stack) {
|
|
1135
|
+
const imported = literalsOf.imports.get(name);
|
|
1136
|
+
if (imported) {
|
|
1137
|
+
const nodes = options?.imported?.get(`${imported.source}#${imported.name}`);
|
|
1138
|
+
if (nodes) return nodes.map((n2) => keepLocIn(n2, options?.importedModules));
|
|
1139
|
+
plan.references.push({ name: imported.name, source: imported.source, ...at });
|
|
1140
|
+
plan.diagnostics.push({
|
|
1141
|
+
...at,
|
|
1142
|
+
message: options?.imported ? `${name} from ${imported.source} is not a css\`\` value the build could find.` : `${name} comes from ${imported.source}: style values from another module are resolved by the build.`
|
|
1143
|
+
});
|
|
1144
|
+
return null;
|
|
1145
|
+
}
|
|
1146
|
+
const literal = literalsOf.literals.get(name);
|
|
1147
|
+
if (!literal) return void 0;
|
|
1148
|
+
if (stack.includes(name)) {
|
|
1149
|
+
plan.diagnostics.push({ ...at, message: `css\`\` values include each other: ${[...stack, name].join(" → ")}.` });
|
|
1150
|
+
return null;
|
|
1151
|
+
}
|
|
1152
|
+
if (!resolved.has(name)) {
|
|
1153
|
+
resolved.set(name, piecesToNodes(literal.quasi.quasis, literal.quasi.expressions, at, [...stack, name]));
|
|
1154
|
+
}
|
|
1155
|
+
return resolved.get(name);
|
|
1156
|
+
}
|
|
1157
|
+
for (const [name, literal] of literalsOf.literals) {
|
|
1158
|
+
const at = { line: literal.loc?.start.line ?? 0, column: literal.loc?.start.column ?? 0 };
|
|
1159
|
+
const nodes = resolveLiteral(name, at, []);
|
|
1160
|
+
const id = hash(`${sourceName}:css:${name}`);
|
|
1161
|
+
plan.edits.push({ start: literal.start, end: literal.end, code: `({ $fxStyle: ${JSON.stringify(id)} })` });
|
|
1162
|
+
if (nodes) plan.literals.push({ id, name, css: printStyle(nodes, options.minify), nodes });
|
|
1163
|
+
}
|
|
1164
|
+
const scopeOf = /* @__PURE__ */ new Map();
|
|
1165
|
+
const names = /* @__PURE__ */ new Map();
|
|
1166
|
+
const named = /* @__PURE__ */ new Map();
|
|
1167
|
+
const visit = (node, owners) => {
|
|
1168
|
+
if (!node || typeof node !== "object") return;
|
|
1169
|
+
if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.init && FUNCTIONS.has(node.init.type)) {
|
|
1170
|
+
named.set(node.init, node.id.name);
|
|
1171
|
+
}
|
|
1172
|
+
if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.id) {
|
|
1173
|
+
for (const member of node.body.body) if (member.type === "ClassMethod") named.set(member, node.id.name);
|
|
1174
|
+
}
|
|
1175
|
+
if (node.type === "ClassDeclaration" || node.type === "ClassExpression") {
|
|
1176
|
+
for (const member of node.body.body) if (member.type === "ClassMethod") classOf.set(member, node);
|
|
1177
|
+
const shadow = staticMember(node, "shadow");
|
|
1178
|
+
if (shadow?.value && !(shadow.value.type === "BooleanLiteral" && shadow.value.value === false)) {
|
|
1179
|
+
plan.shadowClasses.set(node, { node, styles: staticMember(node, "styles"), indexes: [] });
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
if (node.type === "TaggedTemplateExpression" && node.tag.type === "Identifier" && tags.html.get(node.tag.name) === "html") {
|
|
1183
|
+
const text = node.quasi.quasis.map((q) => q.value.raw).join("");
|
|
1184
|
+
if (/<style[\s>]/.test(text)) {
|
|
1185
|
+
const at = { line: node.loc?.start.line ?? 0, column: node.loc?.start.column ?? 0 };
|
|
1186
|
+
const owner = owners[0];
|
|
1187
|
+
if (!owner) plan.diagnostics.push({ ...at, message: "<style> has to be written inside a component." });
|
|
1188
|
+
else {
|
|
1189
|
+
const id = idFor(owner);
|
|
1190
|
+
const shadow = shadowOf(owner);
|
|
1191
|
+
plan.templateOwners.set(node.start, { id, component: functionName(owner, named) });
|
|
1192
|
+
for (const block of templateBlocks(node.quasi)) compileBlock(block, block.scoped, owner, at);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
const inner = FUNCTIONS.has(node.type) ? [...owners, node] : owners;
|
|
1197
|
+
if (node.type === "JSXElement" && isStyle(node)) {
|
|
1198
|
+
handle(node, owners);
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
for (const key of Object.keys(node)) {
|
|
1202
|
+
if (key === "loc" || key === "leadingComments" || key === "trailingComments" || key === "innerComments") continue;
|
|
1203
|
+
const value = node[key];
|
|
1204
|
+
if (Array.isArray(value)) for (const v of value) visit(v, inner);
|
|
1205
|
+
else if (value && typeof value === "object" && "type" in value) visit(value, inner);
|
|
1206
|
+
}
|
|
1207
|
+
};
|
|
1208
|
+
const handle = (node, owners) => {
|
|
1209
|
+
const at = { line: node.loc?.start.line ?? 0, column: node.loc?.start.column ?? 0 };
|
|
1210
|
+
const pieces = blockPieces(node);
|
|
1211
|
+
if (pieces === null) {
|
|
1212
|
+
plan.diagnostics.push({
|
|
1213
|
+
...at,
|
|
1214
|
+
message: "<style> needs its CSS as one template literal, <style>{`...`}</style>: JSX reads a bare `{` as an expression."
|
|
1215
|
+
});
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
const owner = owners[0];
|
|
1219
|
+
if (!owner) {
|
|
1220
|
+
plan.diagnostics.push({ ...at, message: "<style> has to be written inside a component." });
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
compileBlock(pieces, isScoped(node), owner, at);
|
|
1224
|
+
plan.drop.add(node.start);
|
|
1225
|
+
};
|
|
1226
|
+
const compileBlock = (pieces, scoped, owner, at) => {
|
|
1227
|
+
const component = functionName(owner, named);
|
|
1228
|
+
const id = idFor(owner);
|
|
1229
|
+
const processed = piecesToNodes(pieces.quasis, pieces.expressions, at, []);
|
|
1230
|
+
if (!processed) return;
|
|
1231
|
+
let nodes = processed;
|
|
1232
|
+
const shadow = shadowOf(owner);
|
|
1233
|
+
if (scoped && !shadow) {
|
|
1234
|
+
if (!plan.scopes.some((s) => s.value === id)) plan.scopes.push({ start: owner.start, end: owner.end, value: id });
|
|
1235
|
+
nodes = scopeNodes(nodes, id, (message) => plan.diagnostics.push({ ...at, message }));
|
|
1236
|
+
}
|
|
1237
|
+
const printed = module ? printStyleWithMap(nodes, options.minify, sourceName, module, options.importedModules) : { css: printStyle(nodes, options.minify) };
|
|
1238
|
+
plan.styles.push({ id, scoped: scoped && !shadow, component, ...printed, ...shadow ? { shadow: true } : {}, ...at });
|
|
1239
|
+
if (shadow) shadow.indexes.push(plan.styles.length - 1);
|
|
1240
|
+
};
|
|
1241
|
+
function idFor(owner) {
|
|
1242
|
+
let id = scopeOf.get(owner);
|
|
1243
|
+
if (!id) {
|
|
1244
|
+
const component = functionName(owner, named);
|
|
1245
|
+
const seen = names.get(component) ?? 0;
|
|
1246
|
+
names.set(component, seen + 1);
|
|
1247
|
+
id = hash(`${sourceName}:${component}${seen ? ":" + seen : ""}`);
|
|
1248
|
+
scopeOf.set(owner, id);
|
|
1249
|
+
}
|
|
1250
|
+
return id;
|
|
1251
|
+
}
|
|
1252
|
+
visit(program, []);
|
|
1253
|
+
return plan;
|
|
1254
|
+
}
|
|
1255
|
+
function applyTemplateStyles(ir, t) {
|
|
1256
|
+
const walk8 = (node) => {
|
|
1257
|
+
const children = node.children;
|
|
1258
|
+
if (children) {
|
|
1259
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
1260
|
+
const child = children[i];
|
|
1261
|
+
if (child.kind === "element" && child.tag === "style" && t.owner) children.splice(i, 1);
|
|
1262
|
+
else walk8(child);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
if (t.scope && node.kind === "element" && node.tag !== "style" && node.props && !node.props.some((p) => p.name === SCOPE_ATTR)) {
|
|
1266
|
+
node.props.unshift({ name: SCOPE_ATTR, kind: "attr", literal: t.scope });
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
walk8(ir);
|
|
1270
|
+
}
|
|
1271
|
+
function staticMember(cls, name) {
|
|
1272
|
+
return cls.body.body.find(
|
|
1273
|
+
(m) => m.type === "ClassProperty" && m.static && (m.key.type === "Identifier" && m.key.name === name || m.key.type === "StringLiteral" && m.key.value === name)
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
var styleIds = {
|
|
1277
|
+
block: (owner, index) => `${owner}.fx-${index}.css`,
|
|
1278
|
+
inline: (owner, index) => `${owner}.fx-${index}.css?inline`,
|
|
1279
|
+
literal: (owner, name) => `${owner}.fx-literal-${name}.css?inline`
|
|
1280
|
+
};
|
|
1281
|
+
function finishShadowStyles(plan, code, moduleId) {
|
|
1282
|
+
const edits = [];
|
|
1283
|
+
const imports = [];
|
|
1284
|
+
let next = 0;
|
|
1285
|
+
const importOf = (specifier) => {
|
|
1286
|
+
const local = `__fxShadow${next++}`;
|
|
1287
|
+
imports.push(`import ${local} from ${JSON.stringify(specifier)};
|
|
1288
|
+
`);
|
|
1289
|
+
return local;
|
|
1290
|
+
};
|
|
1291
|
+
for (const shadow of plan.shadowClasses.values()) {
|
|
1292
|
+
const blocks = shadow.indexes.map((i) => importOf(styleIds.inline(moduleId, i)));
|
|
1293
|
+
let value;
|
|
1294
|
+
const prop = shadow.styles;
|
|
1295
|
+
if (prop?.value) {
|
|
1296
|
+
const start = prop.value.start;
|
|
1297
|
+
let text = code.slice(start, prop.value.end);
|
|
1298
|
+
const replacements = [];
|
|
1299
|
+
walkIdentifiers(prop.value, (id) => {
|
|
1300
|
+
const local = plan.names?.literals.has(id.name) ? importOf(styleIds.literal(moduleId, id.name)) : plan.names?.imports.has(id.name) && !/\.css(\?|$)/.test(plan.names.imports.get(id.name).source) ? importOf(styleIds.literal(plan.names.imports.get(id.name).source, plan.names.imports.get(id.name).name)) : void 0;
|
|
1301
|
+
if (local) replacements.push({ at: id.start - start, length: id.name.length, with: local });
|
|
1302
|
+
});
|
|
1303
|
+
for (const r of replacements.sort((a, b) => b.at - a.at)) text = text.slice(0, r.at) + r.with + text.slice(r.at + r.length);
|
|
1304
|
+
value = text;
|
|
1305
|
+
}
|
|
1306
|
+
if (!blocks.length && value === void 0) continue;
|
|
1307
|
+
if (prop?.value) {
|
|
1308
|
+
const merged = blocks.length ? `[${value}, ${blocks.join(", ")}]` : value;
|
|
1309
|
+
edits.push({ start: prop.value.start, end: prop.value.end, code: merged });
|
|
1310
|
+
} else if (blocks.length) {
|
|
1311
|
+
const open = shadow.node.body.start + 1;
|
|
1312
|
+
edits.push({ start: open, end: open, code: ` static styles = [${blocks.join(", ")}];` });
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
if (imports.length) edits.push({ start: 0, end: 0, code: imports.join("") });
|
|
1316
|
+
return edits;
|
|
1317
|
+
}
|
|
1318
|
+
function walkIdentifiers(node, visit) {
|
|
1319
|
+
if (!node || typeof node !== "object") return;
|
|
1320
|
+
if (node.type === "Identifier") return visit(node);
|
|
1321
|
+
if (node.type === "MemberExpression") return walkIdentifiers(node.object, visit);
|
|
1322
|
+
if (node.type === "ObjectProperty") return walkIdentifiers(node.value, visit);
|
|
1323
|
+
for (const key of Object.keys(node)) {
|
|
1324
|
+
if (key === "loc") continue;
|
|
1325
|
+
const value = node[key];
|
|
1326
|
+
if (Array.isArray(value)) for (const v of value) walkIdentifiers(v, visit);
|
|
1327
|
+
else if (value && typeof value === "object" && "type" in value) walkIdentifiers(value, visit);
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
function isStyle(node) {
|
|
1331
|
+
const name = node.openingElement.name;
|
|
1332
|
+
return name.type === "JSXIdentifier" && name.name === "style";
|
|
1333
|
+
}
|
|
1334
|
+
function isScoped(node) {
|
|
1335
|
+
return node.openingElement.attributes.some((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === "scoped");
|
|
1336
|
+
}
|
|
1337
|
+
function templateBlocks(quasi) {
|
|
1338
|
+
const blocks = [];
|
|
1339
|
+
let open = null;
|
|
1340
|
+
quasi.quasis.forEach((q, i) => {
|
|
1341
|
+
const raw = q.value.raw;
|
|
1342
|
+
let from = 0;
|
|
1343
|
+
while (from <= raw.length) {
|
|
1344
|
+
if (!open) {
|
|
1345
|
+
const tag = /<style\b([^>]*)>/g;
|
|
1346
|
+
tag.lastIndex = from;
|
|
1347
|
+
const m = tag.exec(raw);
|
|
1348
|
+
if (!m) break;
|
|
1349
|
+
open = { quasis: [], expressions: [], scoped: /\bscoped\b/.test(m[1]) };
|
|
1350
|
+
from = m.index + m[0].length;
|
|
1351
|
+
}
|
|
1352
|
+
const close = raw.indexOf("</style", from);
|
|
1353
|
+
open.quasis.push(slicePiece(q, raw, from, close === -1 ? raw.length : close));
|
|
1354
|
+
if (close === -1) break;
|
|
1355
|
+
blocks.push(open);
|
|
1356
|
+
open = null;
|
|
1357
|
+
from = close;
|
|
1358
|
+
}
|
|
1359
|
+
const expr = quasi.expressions[i];
|
|
1360
|
+
if (open && expr) open.expressions.push(expr);
|
|
1361
|
+
});
|
|
1362
|
+
return blocks;
|
|
1363
|
+
}
|
|
1364
|
+
function slicePiece(q, raw, from, to) {
|
|
1365
|
+
const text = raw.slice(from, to);
|
|
1366
|
+
const start = q.loc?.start;
|
|
1367
|
+
if (!start) return { type: "TemplateElement", value: { raw: text, cooked: text } };
|
|
1368
|
+
const before = raw.slice(0, from).split("\n");
|
|
1369
|
+
const line = start.line + before.length - 1;
|
|
1370
|
+
const column = before.length > 1 ? before[before.length - 1].length : start.column + from;
|
|
1371
|
+
return { type: "TemplateElement", value: { raw: text, cooked: text }, loc: { start: { line, column } } };
|
|
1372
|
+
}
|
|
1373
|
+
function blockPieces(node) {
|
|
1374
|
+
const meaningful = node.children.filter((c) => !(c.type === "JSXText" && !c.value.trim()));
|
|
1375
|
+
if (meaningful.length === 0) return { quasis: [], expressions: [] };
|
|
1376
|
+
if (meaningful.length !== 1) return null;
|
|
1377
|
+
const only = meaningful[0];
|
|
1378
|
+
if (only.type !== "JSXExpressionContainer") return null;
|
|
1379
|
+
const expr = only.expression;
|
|
1380
|
+
if (expr.type === "StringLiteral") return { quasis: [{ type: "TemplateElement", value: { raw: expr.value, cooked: expr.value } }], expressions: [] };
|
|
1381
|
+
if (expr.type === "TemplateLiteral") return { quasis: expr.quasis, expressions: expr.expressions };
|
|
1382
|
+
return null;
|
|
1383
|
+
}
|
|
1384
|
+
function findLiterals(program, modules, plan, intrinsic) {
|
|
1385
|
+
const literals = /* @__PURE__ */ new Map();
|
|
1386
|
+
const imports = /* @__PURE__ */ new Map();
|
|
1387
|
+
const tags = new Set(intrinsic);
|
|
1388
|
+
for (const statement of program.body ?? []) {
|
|
1389
|
+
if (statement.type !== "ImportDeclaration") continue;
|
|
1390
|
+
const source = statement.source.value;
|
|
1391
|
+
const specifiers = statement.specifiers;
|
|
1392
|
+
for (const sp of specifiers) {
|
|
1393
|
+
if (sp.type === "ImportSpecifier") imports.set(sp.local.name, { source, name: sp.imported.name ?? sp.imported.value });
|
|
1394
|
+
}
|
|
1395
|
+
if (!modules.includes(source)) continue;
|
|
1396
|
+
const css = specifiers.find((sp) => sp.type === "ImportSpecifier" && (sp.imported.name ?? sp.imported.value) === "css");
|
|
1397
|
+
if (!css) continue;
|
|
1398
|
+
const local = css.local.name;
|
|
1399
|
+
tags.add(local);
|
|
1400
|
+
imports.delete(local);
|
|
1401
|
+
plan.edits.push({ start: statement.start, end: statement.end, code: importWithout(statement, css) });
|
|
1402
|
+
}
|
|
1403
|
+
if (tags.size === 0) return { literals, imports };
|
|
1404
|
+
const visit = (node) => {
|
|
1405
|
+
if (!node || typeof node !== "object") return;
|
|
1406
|
+
if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.init?.type === "TaggedTemplateExpression" && node.init.tag.type === "Identifier" && tags.has(node.init.tag.name)) {
|
|
1407
|
+
literals.set(node.id.name, node.init);
|
|
1408
|
+
}
|
|
1409
|
+
for (const key of Object.keys(node)) {
|
|
1410
|
+
if (key === "loc") continue;
|
|
1411
|
+
const value = node[key];
|
|
1412
|
+
if (Array.isArray(value)) for (const v of value) visit(v);
|
|
1413
|
+
else if (value && typeof value === "object" && "type" in value) visit(value);
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
visit(program);
|
|
1417
|
+
return { literals, imports };
|
|
1418
|
+
}
|
|
1419
|
+
function importWithout(statement, removed) {
|
|
1420
|
+
const rest = statement.specifiers.filter((sp) => sp !== removed);
|
|
1421
|
+
const source = JSON.stringify(statement.source.value);
|
|
1422
|
+
if (rest.length === 0) return "";
|
|
1423
|
+
const def = rest.find((sp) => sp.type === "ImportDefaultSpecifier");
|
|
1424
|
+
const ns = rest.find((sp) => sp.type === "ImportNamespaceSpecifier");
|
|
1425
|
+
const named = rest.filter((sp) => sp.type === "ImportSpecifier").map((sp) => {
|
|
1426
|
+
const imported = sp.imported.name ?? JSON.stringify(sp.imported.value);
|
|
1427
|
+
return imported === sp.local.name ? imported : `${imported} as ${sp.local.name}`;
|
|
1428
|
+
});
|
|
1429
|
+
const parts = [def?.local.name, ns ? `* as ${ns.local.name}` : void 0, named.length ? `{ ${named.join(", ")} }` : void 0].filter(Boolean);
|
|
1430
|
+
return `import ${parts.join(", ")} from ${source};`;
|
|
1431
|
+
}
|
|
1432
|
+
function functionName(fn, named) {
|
|
1433
|
+
if ((fn.type === "FunctionDeclaration" || fn.type === "FunctionExpression") && fn.id) return fn.id.name;
|
|
1434
|
+
return named.get(fn) ?? "anonymous";
|
|
1435
|
+
}
|
|
1436
|
+
function hash(text) {
|
|
1437
|
+
let h = 2166136261;
|
|
1438
|
+
for (let i = 0; i < text.length; i++) {
|
|
1439
|
+
h ^= text.charCodeAt(i);
|
|
1440
|
+
h = Math.imul(h, 16777619);
|
|
1441
|
+
}
|
|
1442
|
+
return (h >>> 0).toString(36);
|
|
1443
|
+
}
|
|
1444
|
+
var OPAQUE = /(^|-)keyframes$|^font-face$|^property$|^counter-style$|^page$|^font-feature-values$/;
|
|
1445
|
+
function scopeNodes(nodes, id, warn = () => {
|
|
1446
|
+
}) {
|
|
1447
|
+
return nodes.map((node) => {
|
|
1448
|
+
if (node.kind === "rule") return { ...node, selector: scopeSelector(node.selector, id, warn) };
|
|
1449
|
+
if (node.kind === "at-rule" && !OPAQUE.test(node.name)) return { ...node, nodes: scopeNodes(node.nodes, id, warn) };
|
|
1450
|
+
return node;
|
|
1451
|
+
});
|
|
1452
|
+
}
|
|
1453
|
+
function scopeSelector(selector, id, warn = () => {
|
|
1454
|
+
}) {
|
|
1455
|
+
return splitTop(selector, ",").map((complex) => scopeComplex(complex.trim(), `[${SCOPE_ATTR}="${id}"]`, warn)).join(", ");
|
|
1456
|
+
}
|
|
1457
|
+
function scopeComplex(selector, attr, warn) {
|
|
1458
|
+
if (/:host\b|::slotted\(/.test(selector)) {
|
|
1459
|
+
warn(`\`${selector}\` only means something in a shadow root; in a light-DOM component it is left as written.`);
|
|
1460
|
+
return selector;
|
|
1461
|
+
}
|
|
1462
|
+
const parts = compounds(selector);
|
|
1463
|
+
const deep = parts.findIndex((p) => p.text.startsWith(":deep("));
|
|
1464
|
+
if (deep !== -1) {
|
|
1465
|
+
const inner = unwrap(parts[deep].text, ":deep(");
|
|
1466
|
+
const before = parts.slice(0, deep);
|
|
1467
|
+
if (before.length === 0) return `${attr} ${inner}`;
|
|
1468
|
+
const scopedBefore = scopeAt(before, before.length - 1, attr);
|
|
1469
|
+
return `${join(scopedBefore)} ${inner}`;
|
|
1470
|
+
}
|
|
1471
|
+
let target = -1;
|
|
1472
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
1473
|
+
if (!parts[i].text.startsWith(":global(")) {
|
|
1474
|
+
target = i;
|
|
1475
|
+
break;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
const out = target === -1 ? parts : scopeAt(parts, target, attr);
|
|
1479
|
+
return join(out.map((p) => p.text.startsWith(":global(") ? { ...p, text: unwrap(p.text, ":global(") } : p));
|
|
1480
|
+
}
|
|
1481
|
+
function scopeAt(parts, index, attr) {
|
|
1482
|
+
return parts.map((p, i) => i === index ? { ...p, text: insertAttr(p.text, attr) } : p);
|
|
1483
|
+
}
|
|
1484
|
+
function insertAttr(compound, attr) {
|
|
1485
|
+
let depth = 0;
|
|
1486
|
+
let quote = "";
|
|
1487
|
+
for (let i = 0; i < compound.length; i++) {
|
|
1488
|
+
const c = compound[i];
|
|
1489
|
+
if (quote) {
|
|
1490
|
+
if (c === "\\") i++;
|
|
1491
|
+
else if (c === quote) quote = "";
|
|
1492
|
+
continue;
|
|
1493
|
+
}
|
|
1494
|
+
if (c === "\\") {
|
|
1495
|
+
i++;
|
|
1496
|
+
continue;
|
|
1497
|
+
}
|
|
1498
|
+
if (c === '"' || c === "'") quote = c;
|
|
1499
|
+
else if (c === "(" || c === "[") depth++;
|
|
1500
|
+
else if (c === ")" || c === "]") depth--;
|
|
1501
|
+
else if (c === ":" && depth === 0 && i > 0) return compound.slice(0, i) + attr + compound.slice(i);
|
|
1502
|
+
}
|
|
1503
|
+
return compound + attr;
|
|
1504
|
+
}
|
|
1505
|
+
function compounds(selector) {
|
|
1506
|
+
const out = [];
|
|
1507
|
+
let depth = 0;
|
|
1508
|
+
let quote = "";
|
|
1509
|
+
let current = "";
|
|
1510
|
+
let combinator = "";
|
|
1511
|
+
const push = () => {
|
|
1512
|
+
if (current.trim()) out.push({ combinator: out.length ? combinator || " " : "", text: current.trim() });
|
|
1513
|
+
current = "";
|
|
1514
|
+
combinator = "";
|
|
1515
|
+
};
|
|
1516
|
+
for (let i = 0; i < selector.length; i++) {
|
|
1517
|
+
const c = selector[i];
|
|
1518
|
+
if (quote) {
|
|
1519
|
+
current += c;
|
|
1520
|
+
if (c === "\\") current += selector[++i] ?? "";
|
|
1521
|
+
else if (c === quote) quote = "";
|
|
1522
|
+
continue;
|
|
1523
|
+
}
|
|
1524
|
+
if (c === "\\") {
|
|
1525
|
+
current += c + (selector[++i] ?? "");
|
|
1526
|
+
continue;
|
|
1527
|
+
}
|
|
1528
|
+
if (c === '"' || c === "'") quote = c;
|
|
1529
|
+
if (c === "(" || c === "[") depth++;
|
|
1530
|
+
if (c === ")" || c === "]") depth--;
|
|
1531
|
+
if (depth === 0 && (c === ">" || c === "+" || c === "~")) {
|
|
1532
|
+
push();
|
|
1533
|
+
combinator = c;
|
|
1534
|
+
continue;
|
|
1535
|
+
}
|
|
1536
|
+
if (depth === 0 && /\s/.test(c)) {
|
|
1537
|
+
if (current.trim()) {
|
|
1538
|
+
const keep = combinator;
|
|
1539
|
+
push();
|
|
1540
|
+
combinator = keep;
|
|
1541
|
+
}
|
|
1542
|
+
continue;
|
|
1543
|
+
}
|
|
1544
|
+
current += c;
|
|
1545
|
+
}
|
|
1546
|
+
push();
|
|
1547
|
+
return out;
|
|
1548
|
+
}
|
|
1549
|
+
function join(parts) {
|
|
1550
|
+
return parts.map((p, i) => i === 0 ? p.text : p.combinator === " " ? ` ${p.text}` : ` ${p.combinator} ${p.text}`).join("");
|
|
1551
|
+
}
|
|
1552
|
+
function unwrap(text, prefix) {
|
|
1553
|
+
return text.slice(prefix.length, text.lastIndexOf(")")).trim() + text.slice(text.lastIndexOf(")") + 1);
|
|
1554
|
+
}
|
|
1555
|
+
function splitTop(selector, separator) {
|
|
1556
|
+
const parts = [];
|
|
1557
|
+
let depth = 0;
|
|
1558
|
+
let quote = "";
|
|
1559
|
+
let start = 0;
|
|
1560
|
+
for (let i = 0; i < selector.length; i++) {
|
|
1561
|
+
const c = selector[i];
|
|
1562
|
+
if (quote) {
|
|
1563
|
+
if (c === "\\") i++;
|
|
1564
|
+
else if (c === quote) quote = "";
|
|
1565
|
+
} else if (c === '"' || c === "'") quote = c;
|
|
1566
|
+
else if (c === "\\") i++;
|
|
1567
|
+
else if (c === "(" || c === "[") depth++;
|
|
1568
|
+
else if (c === ")" || c === "]") depth--;
|
|
1569
|
+
else if (c === separator && depth === 0) {
|
|
1570
|
+
parts.push(selector.slice(start, i));
|
|
1571
|
+
start = i + 1;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
parts.push(selector.slice(start));
|
|
1575
|
+
return parts.filter((p) => p.trim());
|
|
1576
|
+
}
|
|
1577
|
+
function shiftLoc(node, source, start) {
|
|
1578
|
+
const loc = node.loc && node.loc.source === source ? { source, line: start.line + node.loc.line - 1, column: node.loc.line === 1 ? start.column + node.loc.column : node.loc.column } : node.loc;
|
|
1579
|
+
if (node.kind === "rule" || node.kind === "at-rule") return { ...node, loc, nodes: node.nodes.map((n2) => shiftLoc(n2, source, start)) };
|
|
1580
|
+
return { ...node, loc };
|
|
1581
|
+
}
|
|
1582
|
+
function keepLocIn(node, modules) {
|
|
1583
|
+
const keep = node.loc !== void 0 && modules?.has(node.loc.source) === true;
|
|
1584
|
+
const { loc, ...rest } = node;
|
|
1585
|
+
const kept = keep ? { ...rest, loc } : rest;
|
|
1586
|
+
if (kept.kind === "rule" || kept.kind === "at-rule") return { ...kept, nodes: kept.nodes.map((n2) => keepLocIn(n2, modules)) };
|
|
1587
|
+
return kept;
|
|
1588
|
+
}
|
|
1589
|
+
function printStyleWithMap(nodes, minify, sourceName, module, others) {
|
|
1590
|
+
const sources = [module];
|
|
1591
|
+
const index = /* @__PURE__ */ new Map([[sourceName, 0]]);
|
|
1592
|
+
const sourceOf = (name) => {
|
|
1593
|
+
if (index.has(name)) return index.get(name);
|
|
1594
|
+
const other = others?.get(name);
|
|
1595
|
+
if (!other) return void 0;
|
|
1596
|
+
index.set(name, sources.push(other) - 1);
|
|
1597
|
+
return index.get(name);
|
|
1598
|
+
};
|
|
1599
|
+
const lines = [[]];
|
|
1600
|
+
let css = "";
|
|
1601
|
+
let column = 0;
|
|
1602
|
+
const emit = (text) => {
|
|
1603
|
+
for (const ch of text) {
|
|
1604
|
+
css += ch;
|
|
1605
|
+
if (ch === "\n") {
|
|
1606
|
+
lines.push([]);
|
|
1607
|
+
column = 0;
|
|
1608
|
+
} else column++;
|
|
1609
|
+
}
|
|
1610
|
+
};
|
|
1611
|
+
const mark = (loc) => {
|
|
1612
|
+
const at = loc ? sourceOf(loc.source) : void 0;
|
|
1613
|
+
if (loc && at !== void 0) lines[lines.length - 1].push([column, at, loc.line - 1, loc.column]);
|
|
1614
|
+
};
|
|
1615
|
+
const write = (node, depth) => {
|
|
1616
|
+
const pad = minify ? "" : " ".repeat(depth);
|
|
1617
|
+
const nl = minify ? "" : "\n";
|
|
1618
|
+
const sp = minify ? "" : " ";
|
|
1619
|
+
emit(pad);
|
|
1620
|
+
mark(node.loc);
|
|
1621
|
+
if (node.kind === "declaration") {
|
|
1622
|
+
emit(`${node.property}:${sp}${node.value}${node.important ? `${sp}!important` : ""};${nl}`);
|
|
1623
|
+
} else if (node.kind === "raw") {
|
|
1624
|
+
emit(`${node.text}${nl}`);
|
|
1625
|
+
} else {
|
|
1626
|
+
emit(`${node.kind === "rule" ? node.selector : `@${node.name}${node.params ? " " + node.params : ""}`}${sp}{${nl}`);
|
|
1627
|
+
for (const child of node.nodes) write(child, depth + 1);
|
|
1628
|
+
emit(`${pad}}${nl}`);
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
for (const node of nodes) write(node, 0);
|
|
1632
|
+
return { css, map: { version: 3, sources: sources.map((s) => s.id), sourcesContent: sources.map((s) => s.code), names: [], mappings: encode(lines) } };
|
|
1633
|
+
}
|
|
1634
|
+
function printStyle(nodes, minify = false) {
|
|
1635
|
+
const out = [];
|
|
1636
|
+
const write = (node, depth) => {
|
|
1637
|
+
const pad = minify ? "" : " ".repeat(depth);
|
|
1638
|
+
const nl = minify ? "" : "\n";
|
|
1639
|
+
const sp = minify ? "" : " ";
|
|
1640
|
+
if (node.kind === "declaration") {
|
|
1641
|
+
out.push(`${pad}${node.property}:${sp}${node.value}${node.important ? `${sp}!important` : ""};${nl}`);
|
|
1642
|
+
} else if (node.kind === "raw") {
|
|
1643
|
+
out.push(`${pad}${node.text}${nl}`);
|
|
1644
|
+
} else {
|
|
1645
|
+
const header = node.kind === "rule" ? node.selector : `@${node.name}${node.params ? " " + node.params : ""}`;
|
|
1646
|
+
out.push(`${pad}${header}${sp}{${nl}`);
|
|
1647
|
+
for (const child of node.nodes) write(child, depth + 1);
|
|
1648
|
+
out.push(`${pad}}${nl}`);
|
|
1649
|
+
}
|
|
1650
|
+
};
|
|
1651
|
+
for (const node of nodes) write(node, 0);
|
|
1652
|
+
return out.join("");
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
// src/optimize/analyze-static.ts
|
|
1656
|
+
function propReason(prop) {
|
|
1657
|
+
switch (prop.kind) {
|
|
1658
|
+
case "event":
|
|
1659
|
+
return "event";
|
|
1660
|
+
case "ref":
|
|
1661
|
+
return "ref";
|
|
1662
|
+
case "spread":
|
|
1663
|
+
return "spread";
|
|
1664
|
+
case "class":
|
|
1665
|
+
case "style":
|
|
1666
|
+
return "class-or-style-directive";
|
|
1667
|
+
case "attr":
|
|
1668
|
+
case "prop":
|
|
1669
|
+
if (prop.reactive) return "reactive-prop";
|
|
1670
|
+
if (prop.expr !== void 0) return "expression-prop";
|
|
1671
|
+
return void 0;
|
|
1672
|
+
/* c8 ignore next 2 */
|
|
1673
|
+
default:
|
|
1674
|
+
return "expression-prop";
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
function analyzeStatic(root) {
|
|
1678
|
+
const staticElements = [];
|
|
1679
|
+
const reasons = /* @__PURE__ */ new Map();
|
|
1680
|
+
const visit = (node) => {
|
|
1681
|
+
switch (node.kind) {
|
|
1682
|
+
case "text":
|
|
1683
|
+
return true;
|
|
1684
|
+
case "expr":
|
|
1685
|
+
return false;
|
|
1686
|
+
case "component":
|
|
1687
|
+
case "control":
|
|
1688
|
+
for (const child of node.children) visit(child);
|
|
1689
|
+
return false;
|
|
1690
|
+
case "fragment":
|
|
1691
|
+
for (const child of node.children) visit(child);
|
|
1692
|
+
return false;
|
|
1693
|
+
case "element": {
|
|
1694
|
+
let childrenStatic = true;
|
|
1695
|
+
for (const child of node.children) {
|
|
1696
|
+
if (!visit(child)) childrenStatic = false;
|
|
1697
|
+
}
|
|
1698
|
+
let reason;
|
|
1699
|
+
for (const prop of node.props) {
|
|
1700
|
+
reason = propReason(prop);
|
|
1701
|
+
if (reason) break;
|
|
1702
|
+
}
|
|
1703
|
+
if (!reason && !childrenStatic) {
|
|
1704
|
+
reason = childReason(node);
|
|
1705
|
+
}
|
|
1706
|
+
node.static = !reason;
|
|
1707
|
+
if (reason) reasons.set(node, reason);
|
|
1708
|
+
else staticElements.push(node);
|
|
1709
|
+
return node.static;
|
|
1710
|
+
}
|
|
1711
|
+
/* c8 ignore next 2 */
|
|
1712
|
+
default:
|
|
1713
|
+
return false;
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
for (const node of Array.isArray(root) ? root : [root]) visit(node);
|
|
1717
|
+
return { staticElements, reasons };
|
|
1718
|
+
}
|
|
1719
|
+
function childReason(node) {
|
|
1720
|
+
for (const child of node.children) {
|
|
1721
|
+
if (child.kind === "expr") return "expression-child";
|
|
1722
|
+
if (child.kind === "component") return "component-child";
|
|
1723
|
+
if (child.kind === "control") return "control-child";
|
|
1724
|
+
if (child.kind === "element" && !child.static) return "expression-child";
|
|
1725
|
+
if (child.kind === "fragment") return "expression-child";
|
|
1726
|
+
}
|
|
1727
|
+
return "expression-child";
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
// src/resolve/load-directive.ts
|
|
1731
|
+
var EAGER = { kind: "eager" };
|
|
1732
|
+
var DEFAULT_INTERACTION_EVENTS = ["pointerdown", "focusin", "keydown"];
|
|
1733
|
+
var STRATEGIES = /* @__PURE__ */ new Set(["eager", "idle", "visible", "interaction", "media", "never"]);
|
|
1734
|
+
var LoadDirectiveError = class extends Error {
|
|
1735
|
+
};
|
|
1736
|
+
function isLoadDirective(name) {
|
|
1737
|
+
return name.startsWith("load:");
|
|
1738
|
+
}
|
|
1739
|
+
function parseLoadDirective(name, value) {
|
|
1740
|
+
const strategy = name.slice("load:".length);
|
|
1741
|
+
if (!STRATEGIES.has(strategy)) {
|
|
1742
|
+
throw new LoadDirectiveError(
|
|
1743
|
+
`Unknown load strategy 'load:${strategy}'. Expected one of ${[...STRATEGIES].join(", ")}.`
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
switch (strategy) {
|
|
1747
|
+
case "eager":
|
|
1748
|
+
return EAGER;
|
|
1749
|
+
case "idle":
|
|
1750
|
+
return { kind: "idle" };
|
|
1751
|
+
case "never":
|
|
1752
|
+
return { kind: "never" };
|
|
1753
|
+
case "visible":
|
|
1754
|
+
return value ? { kind: "visible", rootMargin: value } : { kind: "visible" };
|
|
1755
|
+
case "interaction":
|
|
1756
|
+
return {
|
|
1757
|
+
kind: "interaction",
|
|
1758
|
+
events: value ? splitEvents(value) : [...DEFAULT_INTERACTION_EVENTS]
|
|
1759
|
+
};
|
|
1760
|
+
case "media":
|
|
1761
|
+
if (!value) {
|
|
1762
|
+
throw new LoadDirectiveError(
|
|
1763
|
+
`'load:media' needs a query, e.g. load:media="(min-width: 1024px)".`
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
return { kind: "media", query: value };
|
|
1767
|
+
default:
|
|
1768
|
+
throw new LoadDirectiveError(`Unhandled load strategy '${strategy}'.`);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
function splitEvents(value) {
|
|
1772
|
+
const events = value.split(/[\s,]+/).map((e) => e.trim()).filter(Boolean);
|
|
1773
|
+
if (events.length === 0) {
|
|
1774
|
+
throw new LoadDirectiveError(`'load:interaction' was given no event names.`);
|
|
1775
|
+
}
|
|
1776
|
+
return events;
|
|
1777
|
+
}
|
|
1778
|
+
function isDeferred(strategy) {
|
|
1779
|
+
return strategy.kind !== "eager" && strategy.kind !== "never";
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
// src/resolve/builtins.ts
|
|
1783
|
+
var DOM_CONTROL_FLOW = [
|
|
1784
|
+
"Show",
|
|
1785
|
+
"For",
|
|
1786
|
+
"Index",
|
|
1787
|
+
"Switch",
|
|
1788
|
+
"Match",
|
|
1789
|
+
"Portal",
|
|
1790
|
+
"Dynamic",
|
|
1791
|
+
"ErrorBoundary"
|
|
1792
|
+
];
|
|
1793
|
+
var CORE_CONTROL_FLOW = ["Suspense", "SuspenseList", "Await"];
|
|
1794
|
+
var ROUTER_COMPONENTS = ["Router", "Outlet", "Redirect", "Link"];
|
|
1795
|
+
var BUILTIN_COMPONENTS = [
|
|
1796
|
+
...DOM_CONTROL_FLOW,
|
|
1797
|
+
...CORE_CONTROL_FLOW,
|
|
1798
|
+
...ROUTER_COMPONENTS
|
|
1799
|
+
];
|
|
1800
|
+
var RESERVED_COMPONENTS = /* @__PURE__ */ new Set([
|
|
1801
|
+
...DOM_CONTROL_FLOW,
|
|
1802
|
+
...CORE_CONTROL_FLOW
|
|
1803
|
+
]);
|
|
1804
|
+
function builtinComponentMap(modules = {}) {
|
|
1805
|
+
const {
|
|
1806
|
+
controlFlowModule = "@fluixi/dom",
|
|
1807
|
+
coreModule = "@fluixi/core",
|
|
1808
|
+
routerModule = "@fluixi/core/router"
|
|
1809
|
+
} = modules;
|
|
1810
|
+
const map = {};
|
|
1811
|
+
for (const name of DOM_CONTROL_FLOW) map[name] = controlFlowModule;
|
|
1812
|
+
for (const name of CORE_CONTROL_FLOW) map[name] = coreModule;
|
|
1813
|
+
for (const name of ROUTER_COMPONENTS) map[name] = routerModule;
|
|
1814
|
+
return map;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
// src/resolve/resolve-ir.ts
|
|
1818
|
+
function resolveComponentSources(root, options = {}) {
|
|
1819
|
+
const { resolver, isBound, modules, strategyFor } = options;
|
|
1820
|
+
const builtins = builtinComponentMap(modules);
|
|
1821
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
1822
|
+
const unresolved = /* @__PURE__ */ new Set();
|
|
1823
|
+
const annotate = (node) => {
|
|
1824
|
+
const { name } = node;
|
|
1825
|
+
if (!name || name.includes(".")) return;
|
|
1826
|
+
if (isBound?.(name)) return;
|
|
1827
|
+
const source = sourceFor(name);
|
|
1828
|
+
if (!source) {
|
|
1829
|
+
unresolved.add(name);
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
const loading = source.origin === "builtin" && RESERVED_COMPONENTS.has(name) ? EAGER : strategyFor?.(node) ?? EAGER;
|
|
1833
|
+
node.source = { ...source, loading };
|
|
1834
|
+
resolved.set(name, node.source);
|
|
1835
|
+
};
|
|
1836
|
+
const sourceFor = (name) => {
|
|
1837
|
+
if (RESERVED_COMPONENTS.has(name)) {
|
|
1838
|
+
return { module: builtins[name], export: name, origin: "builtin" };
|
|
1839
|
+
}
|
|
1840
|
+
const rule = resolver?.resolve(name);
|
|
1841
|
+
if (rule) return { module: rule.module, export: rule.export, origin: "rule" };
|
|
1842
|
+
if (ROUTER_COMPONENTS.includes(name)) {
|
|
1843
|
+
return { module: builtins[name], export: name, origin: "builtin" };
|
|
1844
|
+
}
|
|
1845
|
+
return void 0;
|
|
1846
|
+
};
|
|
1847
|
+
walk(root, (node) => {
|
|
1848
|
+
if (node.kind === "component") annotate(node);
|
|
1849
|
+
});
|
|
1850
|
+
return { resolved, unresolved: [...unresolved] };
|
|
1851
|
+
}
|
|
1852
|
+
function walk(root, visit) {
|
|
1853
|
+
const nodes = Array.isArray(root) ? root : [root];
|
|
1854
|
+
for (const node of nodes) {
|
|
1855
|
+
visit(node);
|
|
1856
|
+
const children = node.children;
|
|
1857
|
+
if (children) walk(children, visit);
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
// src/optimize/collapse-strategies.ts
|
|
1862
|
+
function collapseStrategies(root) {
|
|
1863
|
+
const components = [];
|
|
1864
|
+
walk(root, (node) => {
|
|
1865
|
+
if (node.kind === "component" && node.source) components.push(node);
|
|
1866
|
+
});
|
|
1867
|
+
const eager = /* @__PURE__ */ new Set();
|
|
1868
|
+
const never = /* @__PURE__ */ new Set();
|
|
1869
|
+
for (const node of components) {
|
|
1870
|
+
const { module, loading } = node.source;
|
|
1871
|
+
if (loading.kind === "eager") eager.add(module);
|
|
1872
|
+
if (loading.kind === "never") never.add(module);
|
|
1873
|
+
}
|
|
1874
|
+
const collapsed = /* @__PURE__ */ new Map();
|
|
1875
|
+
for (const node of components) {
|
|
1876
|
+
const source = node.source;
|
|
1877
|
+
if (!isDeferred(source.loading)) continue;
|
|
1878
|
+
if (!eager.has(source.module)) continue;
|
|
1879
|
+
source.loading = { kind: "eager" };
|
|
1880
|
+
collapsed.set(source.module, (collapsed.get(source.module) ?? 0) + 1);
|
|
1881
|
+
}
|
|
1882
|
+
return {
|
|
1883
|
+
collapsed,
|
|
1884
|
+
conflicted: [...never].filter((m) => eager.has(m))
|
|
1885
|
+
};
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
// src/codegen/serialize-static.ts
|
|
1889
|
+
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
1890
|
+
"area",
|
|
1891
|
+
"base",
|
|
1892
|
+
"br",
|
|
1893
|
+
"col",
|
|
1894
|
+
"embed",
|
|
1895
|
+
"hr",
|
|
1896
|
+
"img",
|
|
1897
|
+
"input",
|
|
1898
|
+
"link",
|
|
1899
|
+
"meta",
|
|
1900
|
+
"param",
|
|
1901
|
+
"source",
|
|
1902
|
+
"track",
|
|
1903
|
+
"wbr"
|
|
1904
|
+
]);
|
|
1905
|
+
var HTML_NAME = {
|
|
1906
|
+
className: "class",
|
|
1907
|
+
htmlFor: "for"
|
|
1908
|
+
};
|
|
1909
|
+
var PROPERTY_ONLY = /* @__PURE__ */ new Set([
|
|
1910
|
+
"innerHTML",
|
|
1911
|
+
"outerHTML",
|
|
1912
|
+
"innerText",
|
|
1913
|
+
"textContent",
|
|
1914
|
+
"value",
|
|
1915
|
+
"checked",
|
|
1916
|
+
"selected",
|
|
1917
|
+
"muted",
|
|
1918
|
+
"defaultValue",
|
|
1919
|
+
"defaultChecked",
|
|
1920
|
+
"children",
|
|
1921
|
+
"ref"
|
|
1922
|
+
]);
|
|
1923
|
+
var RAW_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style", "textarea", "title"]);
|
|
1924
|
+
function isRawTextElement(tag) {
|
|
1925
|
+
return RAW_TEXT_ELEMENTS.has(tag);
|
|
1926
|
+
}
|
|
1927
|
+
function htmlAttrName(name) {
|
|
1928
|
+
return HTML_NAME[name] ?? name;
|
|
1929
|
+
}
|
|
1930
|
+
function isPlainLiteralAttr(prop) {
|
|
1931
|
+
if (prop.kind !== "attr") return false;
|
|
1932
|
+
if (prop.expr !== void 0) return false;
|
|
1933
|
+
if (prop.name.includes(":")) return false;
|
|
1934
|
+
return !PROPERTY_ONLY.has(prop.name);
|
|
1935
|
+
}
|
|
1936
|
+
function isSerializable(node) {
|
|
1937
|
+
if (!node.static) return false;
|
|
1938
|
+
if (isRawTextElement(node.tag)) return false;
|
|
1939
|
+
for (const prop of node.props) {
|
|
1940
|
+
if (!isPlainLiteralAttr(prop)) return false;
|
|
1941
|
+
}
|
|
1942
|
+
for (const child of node.children) {
|
|
1943
|
+
if (child.kind === "text") continue;
|
|
1944
|
+
if (child.kind === "element" && isSerializable(child)) continue;
|
|
1945
|
+
return false;
|
|
1946
|
+
}
|
|
1947
|
+
return true;
|
|
1948
|
+
}
|
|
1949
|
+
function serializeStatic(node) {
|
|
1950
|
+
const attrs = node.props.map(serializeProp).filter(Boolean).join("");
|
|
1951
|
+
const open = `<${node.tag}${attrs}>`;
|
|
1952
|
+
if (VOID_ELEMENTS.has(node.tag)) return open;
|
|
1953
|
+
return `${open}${node.children.map(serializeChild).join("")}</${node.tag}>`;
|
|
1954
|
+
}
|
|
1955
|
+
function serializeChild(child) {
|
|
1956
|
+
if (child.kind === "text") return escapeText(child.value);
|
|
1957
|
+
if (child.kind !== "element") throw new Error(`serializeStatic: unexpected ${child.kind}`);
|
|
1958
|
+
return serializeStatic(child);
|
|
1959
|
+
}
|
|
1960
|
+
function serializeProp(prop) {
|
|
1961
|
+
const name = HTML_NAME[prop.name] ?? prop.name;
|
|
1962
|
+
const value = prop.literal;
|
|
1963
|
+
if (value === true || value === void 0) return ` ${name}`;
|
|
1964
|
+
if (value === false || value === null) return "";
|
|
1965
|
+
return ` ${name}="${escapeAttr(String(value))}"`;
|
|
1966
|
+
}
|
|
1967
|
+
function escapeAttr(value) {
|
|
1968
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
1969
|
+
}
|
|
1970
|
+
function escapeText(value) {
|
|
1971
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1972
|
+
}
|
|
1973
|
+
function templatePositions(root) {
|
|
1974
|
+
const pos = [];
|
|
1975
|
+
let file;
|
|
1976
|
+
const walk8 = (el) => {
|
|
1977
|
+
file ??= el.at?.file;
|
|
1978
|
+
pos.push(el.at?.line ?? 0, el.at?.column ?? 0);
|
|
1979
|
+
for (const child of el.children) if (child.kind === "element") walk8(child);
|
|
1980
|
+
};
|
|
1981
|
+
walk8(root);
|
|
1982
|
+
return file && pos.some((n2) => n2 !== 0) ? { file, pos } : void 0;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
// src/codegen/partial-template.ts
|
|
1986
|
+
var HOLE_START = "<!--fx-->";
|
|
1987
|
+
var HOLE_END = "<!--fx/-->";
|
|
1988
|
+
function isHole(node) {
|
|
1989
|
+
return node.kind === "expr" || node.kind === "component" || node.kind === "control";
|
|
1990
|
+
}
|
|
1991
|
+
function isTemplateChild(node) {
|
|
1992
|
+
return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
|
|
1993
|
+
}
|
|
1994
|
+
function isTemplateElement(node) {
|
|
1995
|
+
if (node.svg) return false;
|
|
1996
|
+
if (isRawTextElement(node.tag)) return false;
|
|
1997
|
+
if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
|
|
1998
|
+
return node.children.every((c) => isTemplateChild(c) || isHole(c));
|
|
1999
|
+
}
|
|
2000
|
+
function containsHole(node) {
|
|
2001
|
+
if (isHole(node)) return true;
|
|
2002
|
+
const children = node.children;
|
|
2003
|
+
return children ? children.some(containsHole) : false;
|
|
2004
|
+
}
|
|
2005
|
+
function addressable(el) {
|
|
2006
|
+
for (let i = 0; i < el.children.length; i++) {
|
|
2007
|
+
const child = el.children[i];
|
|
2008
|
+
if (child.kind === "text") {
|
|
2009
|
+
if (child.value === "") return false;
|
|
2010
|
+
if (el.children[i + 1]?.kind === "text") return false;
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
return el.children.every((c) => c.kind !== "element" || addressable(c));
|
|
2014
|
+
}
|
|
2015
|
+
function planPartialTemplate(root) {
|
|
2016
|
+
if (!isTemplateElement(root)) return null;
|
|
2017
|
+
if (!addressable(root)) return null;
|
|
2018
|
+
if (!root.children.some(containsHole)) return null;
|
|
2019
|
+
const steps = [];
|
|
2020
|
+
const holes = [];
|
|
2021
|
+
let refCount = 0;
|
|
2022
|
+
const declare = (expr) => {
|
|
2023
|
+
const ref = `_n$${refCount++}`;
|
|
2024
|
+
steps.push({ ref, expr });
|
|
2025
|
+
return ref;
|
|
2026
|
+
};
|
|
2027
|
+
walk8(root, "_el$");
|
|
2028
|
+
return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
|
|
2029
|
+
function walk8(el, elementRef) {
|
|
2030
|
+
let last = -1;
|
|
2031
|
+
el.children.forEach((child, i) => {
|
|
2032
|
+
if (containsHole(child)) last = i;
|
|
2033
|
+
});
|
|
2034
|
+
let previous = null;
|
|
2035
|
+
for (let i = 0; i <= last; i++) {
|
|
2036
|
+
const child = el.children[i];
|
|
2037
|
+
const expr = previous ? `${previous}.nextSibling` : `${elementRef}.firstChild`;
|
|
2038
|
+
if (isHole(child)) {
|
|
2039
|
+
const startRef = declare(expr);
|
|
2040
|
+
const endRef = declare(`holeEnd(${startRef})`);
|
|
2041
|
+
holes.push({ parentRef: elementRef, startRef, endRef, node: child });
|
|
2042
|
+
previous = endRef;
|
|
2043
|
+
continue;
|
|
2044
|
+
}
|
|
2045
|
+
const ref = declare(expr);
|
|
2046
|
+
if (child.kind === "element" && containsHole(child)) walk8(child, ref);
|
|
2047
|
+
previous = ref;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
function serializeWithMarkers(el) {
|
|
2052
|
+
return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
|
|
2053
|
+
}
|
|
2054
|
+
function withSentinels(el) {
|
|
2055
|
+
return {
|
|
2056
|
+
...el,
|
|
2057
|
+
children: el.children.map(
|
|
2058
|
+
(child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
|
|
2059
|
+
)
|
|
2060
|
+
};
|
|
2061
|
+
}
|
|
2062
|
+
var SENTINEL = "\0fx-hole\0";
|
|
2063
|
+
|
|
2064
|
+
// src/codegen/contract.ts
|
|
2065
|
+
var RUNTIME_CONTRACT_V1 = {
|
|
2066
|
+
version: 1,
|
|
2067
|
+
module: "@fluixi/dom",
|
|
2068
|
+
symbols: [
|
|
2069
|
+
"createNativeElement",
|
|
2070
|
+
"insert",
|
|
2071
|
+
"spread",
|
|
2072
|
+
"setAttribute",
|
|
2073
|
+
"delegateEvents",
|
|
2074
|
+
"createComponent",
|
|
2075
|
+
"createMemo",
|
|
2076
|
+
"untrack",
|
|
2077
|
+
"Show",
|
|
2078
|
+
"For",
|
|
2079
|
+
"Index",
|
|
2080
|
+
"Switch",
|
|
2081
|
+
"Match",
|
|
2082
|
+
"Dynamic",
|
|
2083
|
+
"ErrorBoundary"
|
|
2084
|
+
]
|
|
2085
|
+
};
|
|
2086
|
+
var RUNTIME_CONTRACT_V2 = {
|
|
2087
|
+
version: 2,
|
|
2088
|
+
module: "@fluixi/dom",
|
|
2089
|
+
symbols: [...RUNTIME_CONTRACT_V1.symbols, "template", "cloneTemplate", "walk"]
|
|
2090
|
+
};
|
|
2091
|
+
|
|
2092
|
+
// src/analyze/intrinsics.ts
|
|
2093
|
+
var REACTIVE_MODULE = "@fluixi/reactive/signal";
|
|
2094
|
+
var INTRINSICS = {
|
|
2095
|
+
$signal: { export: "signal", module: REACTIVE_MODULE, returns: "signal-handle" },
|
|
2096
|
+
$memo: { export: "memo", module: REACTIVE_MODULE, returns: "memo-handle" },
|
|
2097
|
+
$effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
|
|
2098
|
+
$store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
|
|
2099
|
+
$resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
|
|
2100
|
+
$cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
|
|
2101
|
+
// No short runtime form for these yet, so the intrinsic stands for the `create*`
|
|
2102
|
+
// name. Still worth having: no import to write, and when a shorter form is
|
|
2103
|
+
// designed, the change is this line rather than a compiler pass.
|
|
2104
|
+
$selector: { export: "createSelector", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
2105
|
+
$deferred: { export: "createDeferred", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
2106
|
+
// Not value constructors, but the compiler has to know them: they change what a read
|
|
2107
|
+
// does. `untrack` suppresses dependency collection, which is exactly the kind of thing
|
|
2108
|
+
// dependency analysis must not guess at.
|
|
2109
|
+
$untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
|
|
2110
|
+
$untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
|
|
2111
|
+
// Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
|
|
2112
|
+
// no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
|
|
2113
|
+
$batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
|
|
2114
|
+
$cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
|
|
2115
|
+
$root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
|
|
2116
|
+
$context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
|
|
2117
|
+
$renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
|
|
2118
|
+
$computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
|
|
2119
|
+
// Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
|
|
2120
|
+
// handle as far as reads go: the same accessor with `set` on it.
|
|
2121
|
+
$storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
2122
|
+
$asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
2123
|
+
$persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
|
|
2124
|
+
// An environment variable, public or server-only; the browser build refuses a secret.
|
|
2125
|
+
$env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
|
|
2126
|
+
};
|
|
2127
|
+
var RUNTIME_PRIMITIVES = {
|
|
2128
|
+
signal: "signal-handle",
|
|
2129
|
+
memo: "memo-handle",
|
|
2130
|
+
effect: "effect",
|
|
2131
|
+
store: "store-handle",
|
|
2132
|
+
createSignal: ["signal-accessor", "signal-setter"],
|
|
2133
|
+
createMemo: "memo-accessor",
|
|
2134
|
+
createEffect: "effect",
|
|
2135
|
+
createRenderEffect: "effect",
|
|
2136
|
+
renderEffect: "effect",
|
|
2137
|
+
computed: "effect",
|
|
2138
|
+
createStore: "reactive-object",
|
|
2139
|
+
resource: "resource-handle",
|
|
2140
|
+
cachedResource: "resource-handle",
|
|
2141
|
+
createResource: "reactive-object",
|
|
2142
|
+
createSelector: "memo-accessor",
|
|
2143
|
+
createDeferred: "memo-accessor"
|
|
2144
|
+
};
|
|
2145
|
+
var PRIMITIVE_MODULES = [
|
|
2146
|
+
"@fluixi/reactive",
|
|
2147
|
+
"@fluixi/reactive/signal",
|
|
2148
|
+
"@fluixi/reactive/store",
|
|
2149
|
+
"@fluixi/reactive/cached-resource",
|
|
2150
|
+
"@fluixi/core"
|
|
2151
|
+
];
|
|
2152
|
+
var TAG_INTRINSICS = {
|
|
2153
|
+
$html: { export: "html", module: "@fluixi/core" },
|
|
2154
|
+
$svg: { export: "svg", module: "@fluixi/core" },
|
|
2155
|
+
$css: { export: "css", module: "@fluixi/core" }
|
|
2156
|
+
};
|
|
2157
|
+
function tagIntrinsics(bound) {
|
|
2158
|
+
const tags = /* @__PURE__ */ new Map();
|
|
2159
|
+
for (const [name, tag] of Object.entries(TAG_INTRINSICS)) if (!bound.has(name)) tags.set(name, tag.export);
|
|
2160
|
+
return tags;
|
|
2161
|
+
}
|
|
2162
|
+
var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n2) => n2.slice(1)).join("|")})\\s*\\(`);
|
|
2163
|
+
function mayHaveIntrinsic(code) {
|
|
2164
|
+
return INTRINSIC_CALL.test(code);
|
|
2165
|
+
}
|
|
2166
|
+
function isIntrinsicName(name) {
|
|
2167
|
+
return Object.prototype.hasOwnProperty.call(INTRINSICS, name);
|
|
2168
|
+
}
|
|
2169
|
+
function isPrimitiveModule(source) {
|
|
2170
|
+
return PRIMITIVE_MODULES.includes(source);
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
// src/analyze/reactive-bindings.ts
|
|
2174
|
+
function patternNames(node, out) {
|
|
2175
|
+
if (!node) return;
|
|
2176
|
+
switch (node.type) {
|
|
2177
|
+
case "Identifier":
|
|
2178
|
+
out.add(node.name);
|
|
2179
|
+
return;
|
|
2180
|
+
case "ObjectPattern":
|
|
2181
|
+
for (const p of node.properties ?? []) {
|
|
2182
|
+
if (p.type === "RestElement") patternNames(p.argument, out);
|
|
2183
|
+
else patternNames(p.value, out);
|
|
2184
|
+
}
|
|
2185
|
+
return;
|
|
2186
|
+
case "ArrayPattern":
|
|
2187
|
+
for (const e of node.elements ?? []) patternNames(e, out);
|
|
2188
|
+
return;
|
|
2189
|
+
case "AssignmentPattern":
|
|
2190
|
+
patternNames(node.left, out);
|
|
2191
|
+
return;
|
|
2192
|
+
case "RestElement":
|
|
2193
|
+
patternNames(node.argument, out);
|
|
2194
|
+
return;
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
function walk2(root, visit) {
|
|
2198
|
+
if (!root || typeof root !== "object" || typeof root.type !== "string") return;
|
|
2199
|
+
visit(root);
|
|
2200
|
+
for (const key of Object.keys(root)) {
|
|
2201
|
+
if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
|
|
2202
|
+
const value = root[key];
|
|
2203
|
+
if (Array.isArray(value)) for (const item of value) walk2(item, visit);
|
|
2204
|
+
else if (value && typeof value === "object") walk2(value, visit);
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
function calledPrimitive(node, bindings) {
|
|
2208
|
+
if (node.type !== "CallExpression") return void 0;
|
|
2209
|
+
const callee = node.callee;
|
|
2210
|
+
if (callee?.type !== "Identifier") return void 0;
|
|
2211
|
+
const name = callee.name;
|
|
2212
|
+
const imported = bindings.primitives.get(name);
|
|
2213
|
+
if (imported) return imported;
|
|
2214
|
+
const intrinsic = INTRINSICS[name];
|
|
2215
|
+
if (intrinsic && !bindings.shadowed.has(name)) return intrinsic.returns;
|
|
2216
|
+
return void 0;
|
|
2217
|
+
}
|
|
2218
|
+
function classify(id, returns, kinds) {
|
|
2219
|
+
if (Array.isArray(returns)) {
|
|
2220
|
+
if (id.type === "ArrayPattern") {
|
|
2221
|
+
id.elements.forEach((element, index) => {
|
|
2222
|
+
const kind = returns[index];
|
|
2223
|
+
if (element?.type === "Identifier" && kind) kinds.set(element.name, kind);
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
return;
|
|
2227
|
+
}
|
|
2228
|
+
if (id.type === "Identifier") kinds.set(id.name, returns);
|
|
2229
|
+
}
|
|
2230
|
+
function declaredNames(program) {
|
|
2231
|
+
const names = /* @__PURE__ */ new Set();
|
|
2232
|
+
walk2(program, (node) => {
|
|
2233
|
+
switch (node.type) {
|
|
2234
|
+
case "VariableDeclarator":
|
|
2235
|
+
patternNames(node.id, names);
|
|
2236
|
+
return;
|
|
2237
|
+
case "FunctionDeclaration":
|
|
2238
|
+
case "FunctionExpression":
|
|
2239
|
+
case "ArrowFunctionExpression":
|
|
2240
|
+
patternNames(node.id, names);
|
|
2241
|
+
for (const p of node.params ?? []) patternNames(p, names);
|
|
2242
|
+
return;
|
|
2243
|
+
case "ClassDeclaration":
|
|
2244
|
+
case "ClassExpression":
|
|
2245
|
+
patternNames(node.id, names);
|
|
2246
|
+
return;
|
|
2247
|
+
case "ImportSpecifier":
|
|
2248
|
+
case "ImportDefaultSpecifier":
|
|
2249
|
+
case "ImportNamespaceSpecifier":
|
|
2250
|
+
patternNames(node.local, names);
|
|
2251
|
+
return;
|
|
2252
|
+
case "CatchClause":
|
|
2253
|
+
patternNames(node.param, names);
|
|
2254
|
+
return;
|
|
2255
|
+
}
|
|
2256
|
+
});
|
|
2257
|
+
return names;
|
|
2258
|
+
}
|
|
2259
|
+
function resolveReactiveBindings(program) {
|
|
2260
|
+
const bindings = { kinds: /* @__PURE__ */ new Map(), primitives: /* @__PURE__ */ new Map(), shadowed: /* @__PURE__ */ new Set() };
|
|
2261
|
+
const root = program;
|
|
2262
|
+
walk2(root, (node) => {
|
|
2263
|
+
const names = /* @__PURE__ */ new Set();
|
|
2264
|
+
if (node.type === "VariableDeclarator") patternNames(node.id, names);
|
|
2265
|
+
else if (node.type === "FunctionDeclaration" || node.type === "ClassDeclaration") patternNames(node.id, names);
|
|
2266
|
+
else if (node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier") patternNames(node.local, names);
|
|
2267
|
+
else if (node.type === "ImportSpecifier") patternNames(node.local, names);
|
|
2268
|
+
else if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration") {
|
|
2269
|
+
for (const p of node.params ?? []) patternNames(p, names);
|
|
2270
|
+
}
|
|
2271
|
+
for (const name of names) if (INTRINSICS[name]) bindings.shadowed.add(name);
|
|
2272
|
+
});
|
|
2273
|
+
for (const statement of root.body ?? []) {
|
|
2274
|
+
if (statement.type !== "ImportDeclaration") continue;
|
|
2275
|
+
if (!isPrimitiveModule(statement.source?.value)) continue;
|
|
2276
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
2277
|
+
if (specifier.type !== "ImportSpecifier") continue;
|
|
2278
|
+
const importedNode = specifier.imported;
|
|
2279
|
+
const imported = importedNode.type === "Identifier" ? importedNode.name : importedNode.value;
|
|
2280
|
+
const returns = RUNTIME_PRIMITIVES[imported];
|
|
2281
|
+
if (returns) bindings.primitives.set(specifier.local.name, returns);
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
walk2(root, (node) => {
|
|
2285
|
+
if (node.type !== "VariableDeclarator" || !node.init) return;
|
|
2286
|
+
const returns = calledPrimitive(node.init, bindings);
|
|
2287
|
+
if (returns) classify(node.id, returns, bindings.kinds);
|
|
2288
|
+
});
|
|
2289
|
+
return bindings;
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
// src/transform/source-locations.ts
|
|
2293
|
+
var SOURCE_MARKER = "__fx_source";
|
|
2294
|
+
var COMPONENT_MARKER = "__fx_component";
|
|
2295
|
+
var CLASS_MARKER = "__fx_class";
|
|
2296
|
+
var HOLE_MARKER = "__fx_hole";
|
|
2297
|
+
var markHole = (accessor, line, column, name) => `(globalThis.${HOLE_MARKER} ?? ((f) => f))(${accessor},${line},${column}${name === void 0 ? "" : `,${JSON.stringify(name)}`})`;
|
|
2298
|
+
var PROPS_MARKER = "__fx_props";
|
|
2299
|
+
var markProps = (object, at) => `(globalThis.${PROPS_MARKER} ?? ((p) => p))(${object},${JSON.stringify(at)})`;
|
|
2300
|
+
var RUNTIME_PRIMITIVES2 = /* @__PURE__ */ new Set([
|
|
2301
|
+
"signal",
|
|
2302
|
+
"memo",
|
|
2303
|
+
"effect",
|
|
2304
|
+
"store",
|
|
2305
|
+
"resource",
|
|
2306
|
+
"watch",
|
|
2307
|
+
"createSignal",
|
|
2308
|
+
"createMemo",
|
|
2309
|
+
"createEffect",
|
|
2310
|
+
"createStore",
|
|
2311
|
+
"createResource"
|
|
2312
|
+
]);
|
|
2313
|
+
function mayHaveSourceMarks(code) {
|
|
2314
|
+
for (const name of RUNTIME_PRIMITIVES2) {
|
|
2315
|
+
if (code.includes(name)) return true;
|
|
2316
|
+
}
|
|
2317
|
+
if (code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store")) return true;
|
|
2318
|
+
return /\bclass\b[^{;]*\bextends\b/.test(code);
|
|
2319
|
+
}
|
|
2320
|
+
var SINGLE_STATEMENT_PARENTS = /* @__PURE__ */ new Set([
|
|
2321
|
+
"IfStatement",
|
|
2322
|
+
"ForStatement",
|
|
2323
|
+
"ForInStatement",
|
|
2324
|
+
"ForOfStatement",
|
|
2325
|
+
"WhileStatement",
|
|
2326
|
+
"DoWhileStatement",
|
|
2327
|
+
"LabeledStatement",
|
|
2328
|
+
"WithStatement"
|
|
2329
|
+
]);
|
|
2330
|
+
function isLoneBranch(statement, parent) {
|
|
2331
|
+
if (!parent || statement.type === "BlockStatement") return false;
|
|
2332
|
+
return SINGLE_STATEMENT_PARENTS.has(parent.type);
|
|
2333
|
+
}
|
|
2334
|
+
function isExport(node) {
|
|
2335
|
+
return node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration";
|
|
2336
|
+
}
|
|
2337
|
+
var CLASS_FIELDS = /* @__PURE__ */ new Set(["PropertyDefinition", "ClassProperty", "ClassPrivateProperty", "AccessorProperty"]);
|
|
2338
|
+
function isStatement(node) {
|
|
2339
|
+
return node.type.endsWith("Statement") || node.type === "VariableDeclaration";
|
|
2340
|
+
}
|
|
2341
|
+
function walk3(node, visit, stack = []) {
|
|
2342
|
+
if (!node || typeof node.type !== "string") return;
|
|
2343
|
+
visit(node, stack);
|
|
2344
|
+
stack.push(node);
|
|
2345
|
+
for (const key of Object.keys(node)) {
|
|
2346
|
+
if (key === "loc" || key === "parent") continue;
|
|
2347
|
+
const value = node[key];
|
|
2348
|
+
if (Array.isArray(value)) {
|
|
2349
|
+
for (const child of value) walk3(child, visit, stack);
|
|
2350
|
+
} else if (value && typeof value.type === "string") {
|
|
2351
|
+
walk3(value, visit, stack);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
stack.pop();
|
|
2355
|
+
}
|
|
2356
|
+
function nameFor(stack) {
|
|
2357
|
+
const declarator = stack[stack.length - 1];
|
|
2358
|
+
if (declarator && CLASS_FIELDS.has(declarator.type)) {
|
|
2359
|
+
const key = declarator.key;
|
|
2360
|
+
if (key?.type === "Identifier" || key?.type === "PrivateIdentifier" || key?.type === "PrivateName") {
|
|
2361
|
+
const name = key.name ?? key.id?.name;
|
|
2362
|
+
return name;
|
|
2363
|
+
}
|
|
2364
|
+
return void 0;
|
|
2365
|
+
}
|
|
2366
|
+
if (declarator?.type !== "VariableDeclarator") return void 0;
|
|
2367
|
+
const id = declarator.id;
|
|
2368
|
+
if (id?.type === "Identifier") return id.name;
|
|
2369
|
+
if (id?.type === "ArrayPattern") {
|
|
2370
|
+
const first = id.elements?.[0];
|
|
2371
|
+
if (first?.type === "Identifier") return first.name;
|
|
2372
|
+
}
|
|
2373
|
+
return void 0;
|
|
2374
|
+
}
|
|
2375
|
+
function componentName(node) {
|
|
2376
|
+
if (node.type === "FunctionDeclaration") {
|
|
2377
|
+
const name = node.id?.name;
|
|
2378
|
+
return name && name[0] === name[0]?.toUpperCase() ? name : void 0;
|
|
2379
|
+
}
|
|
2380
|
+
if (node.type === "VariableDeclarator") {
|
|
2381
|
+
const id = node.id;
|
|
2382
|
+
const init = node.init;
|
|
2383
|
+
if (id?.type !== "Identifier" || !init) return void 0;
|
|
2384
|
+
if (init.type !== "ArrowFunctionExpression" && init.type !== "FunctionExpression") return void 0;
|
|
2385
|
+
const name = id.name;
|
|
2386
|
+
return name[0] === name[0]?.toUpperCase() ? name : void 0;
|
|
2387
|
+
}
|
|
2388
|
+
return void 0;
|
|
2389
|
+
}
|
|
2390
|
+
function collectSourceEdits(program, filename) {
|
|
2391
|
+
const edits = [];
|
|
2392
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
2393
|
+
const { primitives, shadowed } = resolveReactiveBindings(program);
|
|
2394
|
+
walk3(program, (node, stack) => {
|
|
2395
|
+
const component = componentName(node);
|
|
2396
|
+
if (component) {
|
|
2397
|
+
const at = node.loc?.start;
|
|
2398
|
+
let end2 = node.end;
|
|
2399
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
2400
|
+
const up = stack[i];
|
|
2401
|
+
if (up.type !== "VariableDeclaration" && up.type !== "ExportNamedDeclaration" && up.type !== "ExportDefaultDeclaration") {
|
|
2402
|
+
break;
|
|
2403
|
+
}
|
|
2404
|
+
end2 = up.end;
|
|
2405
|
+
}
|
|
2406
|
+
if (at) {
|
|
2407
|
+
edits.push({
|
|
2408
|
+
start: end2,
|
|
2409
|
+
end: end2,
|
|
2410
|
+
code: `;globalThis.${COMPONENT_MARKER}?.(${JSON.stringify(component)},${JSON.stringify(filename)},${at.line},${at.column});`
|
|
2411
|
+
});
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.superClass && !node.declare) {
|
|
2415
|
+
const at = node.loc?.start;
|
|
2416
|
+
const body = node.body;
|
|
2417
|
+
if (at && body) {
|
|
2418
|
+
edits.push({
|
|
2419
|
+
start: body.start + 1,
|
|
2420
|
+
end: body.start + 1,
|
|
2421
|
+
code: `static{globalThis.${CLASS_MARKER}?.(this,${JSON.stringify(filename)},${at.line},${at.column});}`
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
if (node.type !== "CallExpression") return;
|
|
2426
|
+
const callee = node.callee;
|
|
2427
|
+
if (callee?.type !== "Identifier") return;
|
|
2428
|
+
const name = callee.name;
|
|
2429
|
+
const intrinsic = isIntrinsicName(name) && !shadowed.has(name) ? INTRINSICS[name] : void 0;
|
|
2430
|
+
const imported = primitives.has(name) || RUNTIME_PRIMITIVES2.has(name);
|
|
2431
|
+
if (!intrinsic && !imported) return;
|
|
2432
|
+
const position = node.loc?.start;
|
|
2433
|
+
if (!position) return;
|
|
2434
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
2435
|
+
const up = stack[i];
|
|
2436
|
+
if (isStatement(up)) break;
|
|
2437
|
+
if (CLASS_FIELDS.has(up.type)) {
|
|
2438
|
+
if (claimed.has(node.start)) return;
|
|
2439
|
+
claimed.add(node.start);
|
|
2440
|
+
const label2 = nameFor(stack);
|
|
2441
|
+
const own = !up.static;
|
|
2442
|
+
const args2 = [
|
|
2443
|
+
JSON.stringify(filename),
|
|
2444
|
+
String(position.line),
|
|
2445
|
+
String(position.column),
|
|
2446
|
+
label2 ? JSON.stringify(label2) : own ? "undefined" : void 0,
|
|
2447
|
+
own ? "this" : void 0
|
|
2448
|
+
].filter((a) => a !== void 0).join(",");
|
|
2449
|
+
edits.push({ start: node.start, end: node.start, code: `(globalThis.${SOURCE_MARKER}?.(${args2}),` });
|
|
2450
|
+
edits.push({ start: node.end, end: node.end, code: ")" });
|
|
2451
|
+
return;
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
let statement;
|
|
2455
|
+
let parent;
|
|
2456
|
+
let index = -1;
|
|
2457
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
2458
|
+
if (isStatement(stack[i]) || isExport(stack[i])) {
|
|
2459
|
+
statement = stack[i];
|
|
2460
|
+
parent = stack[i - 1];
|
|
2461
|
+
index = i;
|
|
2462
|
+
break;
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
if (!statement) return;
|
|
2466
|
+
let start = statement.start;
|
|
2467
|
+
let end = statement.end;
|
|
2468
|
+
for (let i = index - 1; i >= 0; i--) {
|
|
2469
|
+
if (!isExport(stack[i])) break;
|
|
2470
|
+
start = stack[i].start;
|
|
2471
|
+
end = stack[i].end;
|
|
2472
|
+
parent = stack[i - 1];
|
|
2473
|
+
}
|
|
2474
|
+
if (claimed.has(start)) return;
|
|
2475
|
+
claimed.add(start);
|
|
2476
|
+
const label = nameFor(stack);
|
|
2477
|
+
const args = [
|
|
2478
|
+
JSON.stringify(filename),
|
|
2479
|
+
String(position.line),
|
|
2480
|
+
String(position.column),
|
|
2481
|
+
label ? JSON.stringify(label) : void 0
|
|
2482
|
+
].filter((a) => a !== void 0).join(",");
|
|
2483
|
+
const mark = `globalThis.${SOURCE_MARKER}?.(${args});`;
|
|
2484
|
+
if (isLoneBranch(statement, parent)) {
|
|
2485
|
+
edits.push({ start, end: start, code: `{${mark}` });
|
|
2486
|
+
edits.push({ start: end, end, code: "}" });
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
edits.push({ start, end: start, code: mark });
|
|
2490
|
+
});
|
|
2491
|
+
return { edits, marked: edits.length };
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
// src/analyze/paren.ts
|
|
2495
|
+
function skipQuoted(src, start) {
|
|
2496
|
+
const quote = src[start];
|
|
2497
|
+
for (let i = start + 1; i < src.length; i++) {
|
|
2498
|
+
const c = src[i];
|
|
2499
|
+
if (c === "\\") i++;
|
|
2500
|
+
else if (c === quote) return i + 1;
|
|
2501
|
+
else if (c === "\n") return -1;
|
|
2502
|
+
}
|
|
2503
|
+
return -1;
|
|
2504
|
+
}
|
|
2505
|
+
function skipTemplate(src, start) {
|
|
2506
|
+
let i = start + 1;
|
|
2507
|
+
while (i < src.length) {
|
|
2508
|
+
const c = src[i];
|
|
2509
|
+
if (c === "\\") {
|
|
2510
|
+
i += 2;
|
|
2511
|
+
} else if (c === "`") {
|
|
2512
|
+
return i + 1;
|
|
2513
|
+
} else if (c === "$" && src[i + 1] === "{") {
|
|
2514
|
+
let depth = 1;
|
|
2515
|
+
i += 2;
|
|
2516
|
+
while (i < src.length && depth > 0) {
|
|
2517
|
+
const k = src[i];
|
|
2518
|
+
if (k === "\\") i += 2;
|
|
2519
|
+
else if (k === "`") {
|
|
2520
|
+
const end = skipTemplate(src, i);
|
|
2521
|
+
if (end < 0) return -1;
|
|
2522
|
+
i = end;
|
|
2523
|
+
} else if (k === '"' || k === "'") {
|
|
2524
|
+
const end = skipQuoted(src, i);
|
|
2525
|
+
if (end < 0) return -1;
|
|
2526
|
+
i = end;
|
|
2527
|
+
} else {
|
|
2528
|
+
if (k === "{") depth++;
|
|
2529
|
+
else if (k === "}") depth--;
|
|
2530
|
+
i++;
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
} else {
|
|
2534
|
+
i++;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
return -1;
|
|
2538
|
+
}
|
|
2539
|
+
function skipRegex(src, start) {
|
|
2540
|
+
let inClass = false;
|
|
2541
|
+
for (let i = start + 1; i < src.length; i++) {
|
|
2542
|
+
const c = src[i];
|
|
2543
|
+
if (c === "\\") i++;
|
|
2544
|
+
else if (c === "[") inClass = true;
|
|
2545
|
+
else if (c === "]") inClass = false;
|
|
2546
|
+
else if (c === "\n") return -1;
|
|
2547
|
+
else if (c === "/" && !inClass) {
|
|
2548
|
+
let end = i + 1;
|
|
2549
|
+
while (end < src.length && /[a-z]/i.test(src[end])) end++;
|
|
2550
|
+
return end;
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
return -1;
|
|
2554
|
+
}
|
|
2555
|
+
function divides(prev) {
|
|
2556
|
+
return prev !== "" && /[A-Za-z0-9_$)\]]/.test(prev);
|
|
2557
|
+
}
|
|
2558
|
+
function topLevelComma(src) {
|
|
2559
|
+
let depth = 0;
|
|
2560
|
+
let prev = "";
|
|
2561
|
+
let i = 0;
|
|
2562
|
+
while (i < src.length) {
|
|
2563
|
+
const c = src[i];
|
|
2564
|
+
if (c === '"' || c === "'") {
|
|
2565
|
+
const end = skipQuoted(src, i);
|
|
2566
|
+
if (end < 0) return null;
|
|
2567
|
+
i = end;
|
|
2568
|
+
prev = c;
|
|
2569
|
+
} else if (c === "`") {
|
|
2570
|
+
const end = skipTemplate(src, i);
|
|
2571
|
+
if (end < 0) return null;
|
|
2572
|
+
i = end;
|
|
2573
|
+
prev = c;
|
|
2574
|
+
} else if (c === "/" && src[i + 1] === "/") {
|
|
2575
|
+
return null;
|
|
2576
|
+
} else if (c === "/" && src[i + 1] === "*") {
|
|
2577
|
+
const end = src.indexOf("*/", i + 2);
|
|
2578
|
+
if (end < 0) return null;
|
|
2579
|
+
i = end + 2;
|
|
2580
|
+
} else if (c === "/" && !divides(prev)) {
|
|
2581
|
+
const end = skipRegex(src, i);
|
|
2582
|
+
if (end < 0) return null;
|
|
2583
|
+
i = end;
|
|
2584
|
+
prev = "/";
|
|
2585
|
+
} else {
|
|
2586
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
2587
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
2588
|
+
depth--;
|
|
2589
|
+
if (depth < 0) return null;
|
|
2590
|
+
} else if (c === "," && depth === 0) return true;
|
|
2591
|
+
if (!/\s/.test(c)) prev = c;
|
|
2592
|
+
i++;
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
return depth === 0 ? false : null;
|
|
2596
|
+
}
|
|
2597
|
+
function paren(code, position) {
|
|
2598
|
+
const src = code.trim();
|
|
2599
|
+
if (src === "") return `(${code})`;
|
|
2600
|
+
if (position === "arrowBody" && src[0] === "{") return `(${code})`;
|
|
2601
|
+
return topLevelComma(src) === false ? code : `(${code})`;
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
// src/codegen/backends/imperative.ts
|
|
2605
|
+
var CONTROL_COMPONENT = {
|
|
2606
|
+
show: "Show",
|
|
2607
|
+
for: "For",
|
|
2608
|
+
index: "Index",
|
|
2609
|
+
switch: "Switch",
|
|
2610
|
+
match: "Match",
|
|
2611
|
+
dynamic: "Dynamic",
|
|
2612
|
+
errorBoundary: "ErrorBoundary",
|
|
2613
|
+
suspense: "Suspense"
|
|
2614
|
+
};
|
|
2615
|
+
function isIdent(name) {
|
|
2616
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
2617
|
+
}
|
|
2618
|
+
function propKey(name) {
|
|
2619
|
+
return isIdent(name) ? name : JSON.stringify(name);
|
|
2620
|
+
}
|
|
2621
|
+
function propValue(p) {
|
|
2622
|
+
if (p.expr !== void 0) {
|
|
2623
|
+
if (p.name === "ref" && p.at)
|
|
2624
|
+
return markHole(paren(p.expr, "value"), p.at.line, p.at.column, p.expr);
|
|
2625
|
+
if (!p.reactive) return paren(p.expr, "value");
|
|
2626
|
+
const accessor = `() => ${paren(p.expr, "arrowBody")}`;
|
|
2627
|
+
return p.at ? markHole(accessor, p.at.line, p.at.column, p.directive) : accessor;
|
|
2628
|
+
}
|
|
2629
|
+
return JSON.stringify(p.literal ?? true);
|
|
2630
|
+
}
|
|
2631
|
+
function componentPropValue(p) {
|
|
2632
|
+
if (p.expr !== void 0) return paren(p.expr, "value");
|
|
2633
|
+
return JSON.stringify(p.literal ?? true);
|
|
2634
|
+
}
|
|
2635
|
+
function emitProps(props, childrenExpr, used) {
|
|
2636
|
+
const spreads = props.filter((p) => p.kind === "spread");
|
|
2637
|
+
const normal = props.filter((p) => p.kind !== "spread");
|
|
2638
|
+
const entries = normal.map((p) => `${propKey(p.name)}: ${propValue(p)}`);
|
|
2639
|
+
if (childrenExpr != null) entries.push(`children: ${childrenExpr}`);
|
|
2640
|
+
const obj = `{ ${entries.join(", ")} }`;
|
|
2641
|
+
if (spreads.length > 0) {
|
|
2642
|
+
used.add("mergeProps");
|
|
2643
|
+
return `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
|
|
2644
|
+
}
|
|
2645
|
+
return obj;
|
|
2646
|
+
}
|
|
2647
|
+
function markBind(code, at) {
|
|
2648
|
+
return at ? markHole(code, at.line, at.column) : code;
|
|
2649
|
+
}
|
|
2650
|
+
function emitChildren(children, used, templates) {
|
|
2651
|
+
if (children.length === 1) return emitNode(children[0], used, templates);
|
|
2652
|
+
let deferred = false;
|
|
2653
|
+
const items = children.map((child) => {
|
|
2654
|
+
const code = emitNode(child, used, templates);
|
|
2655
|
+
if (child.kind === "element" && deferred) {
|
|
2656
|
+
used.add("deferElement");
|
|
2657
|
+
return `deferElement(() => ${paren(code, "arrowBody")})`;
|
|
2658
|
+
}
|
|
2659
|
+
if (child.kind === "component" || child.kind === "control" || child.kind === "expr" && child.reactive) deferred = true;
|
|
2660
|
+
return code;
|
|
2661
|
+
});
|
|
2662
|
+
return `[${items.join(", ")}]`;
|
|
2663
|
+
}
|
|
2664
|
+
function emitComponent(name, props, children, used, templates, at) {
|
|
2665
|
+
used.add("createMemo");
|
|
2666
|
+
used.add("createComponent");
|
|
2667
|
+
const spreads = props.filter((p) => p.kind === "spread");
|
|
2668
|
+
const normal = props.filter((p) => p.kind !== "spread");
|
|
2669
|
+
const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
|
|
2670
|
+
if (children.length > 0) {
|
|
2671
|
+
bodies.push(["children", emitChildren(children, used, templates)]);
|
|
2672
|
+
}
|
|
2673
|
+
let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
|
|
2674
|
+
if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
|
|
2675
|
+
const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => (${body})`);
|
|
2676
|
+
const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
|
|
2677
|
+
obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
|
|
2678
|
+
}
|
|
2679
|
+
if (spreads.length > 0) {
|
|
2680
|
+
used.add("mergeProps");
|
|
2681
|
+
obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
|
|
2682
|
+
}
|
|
2683
|
+
const propAt = {};
|
|
2684
|
+
for (const p of normal) if (p.at) propAt[p.name] = [p.at.line, p.at.column];
|
|
2685
|
+
if (Object.keys(propAt).length) obj = markProps(obj, propAt);
|
|
2686
|
+
const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
|
|
2687
|
+
return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
|
|
2688
|
+
}
|
|
2689
|
+
function staticAttrAssignment(el, prop) {
|
|
2690
|
+
const name = htmlAttrName(prop.name);
|
|
2691
|
+
const value = prop.literal;
|
|
2692
|
+
if (value === true || value === void 0) return `${el}.setAttribute(${JSON.stringify(name)}, "");`;
|
|
2693
|
+
if (value === false || value === null) return "";
|
|
2694
|
+
return `${el}.setAttribute(${JSON.stringify(name)}, ${JSON.stringify(String(value))});`;
|
|
2695
|
+
}
|
|
2696
|
+
var partial = false;
|
|
2697
|
+
function emitNode(node, used, templates) {
|
|
2698
|
+
switch (node.kind) {
|
|
2699
|
+
case "text":
|
|
2700
|
+
return JSON.stringify(node.value);
|
|
2701
|
+
case "expr": {
|
|
2702
|
+
if (!node.reactive) return paren(node.code, "value");
|
|
2703
|
+
const accessor = `() => ${paren(node.code, "arrowBody")}`;
|
|
2704
|
+
return node.at ? markHole(accessor, node.at.line, node.at.column) : accessor;
|
|
2705
|
+
}
|
|
2706
|
+
case "fragment":
|
|
2707
|
+
if (node.children.length === 0) return "null";
|
|
2708
|
+
return emitChildren(node.children, used, templates);
|
|
2709
|
+
case "component":
|
|
2710
|
+
return markBind(emitComponent(node.name, node.props, node.children, used, templates, node.at), node.bindAt ?? node.at);
|
|
2711
|
+
case "control": {
|
|
2712
|
+
const name = CONTROL_COMPONENT[node.control] ?? node.control;
|
|
2713
|
+
used.add(name);
|
|
2714
|
+
return markBind(emitComponent(name, node.props, node.children, used, templates), node.bindAt);
|
|
2715
|
+
}
|
|
2716
|
+
case "element": {
|
|
2717
|
+
if (templates && node.static && !node.svg && isSerializable(node)) {
|
|
2718
|
+
used.add("templateNode");
|
|
2719
|
+
const id = `_tmpl$${templates.length}`;
|
|
2720
|
+
templates.push({ id, html: serializeStatic(node), tag: node.tag, svg: false });
|
|
2721
|
+
const at = templatePositions(node);
|
|
2722
|
+
return at ? `templateNode(${id}, ${JSON.stringify(node.tag)}, false, false, ${JSON.stringify(at)})` : `templateNode(${id}, ${JSON.stringify(node.tag)})`;
|
|
2723
|
+
}
|
|
2724
|
+
if (templates && partial) {
|
|
2725
|
+
const plan = planPartialTemplate(node);
|
|
2726
|
+
if (plan) {
|
|
2727
|
+
used.add("templateNode");
|
|
2728
|
+
used.add("insert");
|
|
2729
|
+
used.add("holeEnd");
|
|
2730
|
+
used.add("holeContent");
|
|
2731
|
+
used.add("holeScope");
|
|
2732
|
+
const id = `_tmpl$${templates.length}`;
|
|
2733
|
+
templates.push({ id, html: plan.html, tag: plan.tag, svg: false });
|
|
2734
|
+
const at = templatePositions(node);
|
|
2735
|
+
const lines = [
|
|
2736
|
+
`const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
|
|
2737
|
+
];
|
|
2738
|
+
for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
|
|
2739
|
+
for (const hole of plan.holes) {
|
|
2740
|
+
lines.push(
|
|
2741
|
+
`insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`
|
|
2742
|
+
);
|
|
2743
|
+
}
|
|
2744
|
+
lines.push("return _el$;");
|
|
2745
|
+
return `(() => { ${lines.join(" ")} })()`;
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
used.add("createNativeElement");
|
|
2749
|
+
const tag = JSON.stringify(node.tag);
|
|
2750
|
+
const el = "_el$";
|
|
2751
|
+
const parts = [];
|
|
2752
|
+
const createArgs = node.at ? `${tag}, ${node.svg}, ${JSON.stringify(node.at)}` : node.svg ? `${tag}, true` : tag;
|
|
2753
|
+
parts.push(`const ${el} = createNativeElement(${createArgs});`);
|
|
2754
|
+
if (node.props.length > 0) {
|
|
2755
|
+
if (!node.svg && node.props.every(isPlainLiteralAttr)) {
|
|
2756
|
+
for (const p of node.props) parts.push(staticAttrAssignment(el, p));
|
|
2757
|
+
} else {
|
|
2758
|
+
used.add("spread");
|
|
2759
|
+
const svgFlag = node.svg ? ", isSVG: true" : "";
|
|
2760
|
+
const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
|
|
2761
|
+
const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
|
|
2762
|
+
parts.push(
|
|
2763
|
+
`spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
|
|
2764
|
+
);
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
for (const child of node.children) {
|
|
2768
|
+
used.add("insert");
|
|
2769
|
+
const childCode = emitNode(child, used, templates);
|
|
2770
|
+
const anchored = child.kind === "expr" && (child.reactive || !isLiteralCode(child.code)) || child.kind === "component" || child.kind === "control";
|
|
2771
|
+
parts.push(anchored ? `insert(${el}, ${childCode}, null);` : `insert(${el}, ${childCode});`);
|
|
2772
|
+
}
|
|
2773
|
+
parts.push(`return ${el};`);
|
|
2774
|
+
return `(() => { ${parts.join(" ")} })()`;
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
var LITERAL = /^\s*(?:'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`[^`$]*`|-?\d[\d_.eE+-]*|true|false|null|undefined)\s*$/;
|
|
2779
|
+
var isLiteralCode = (code) => LITERAL.test(code);
|
|
2780
|
+
function inlineTemplates(code, templates) {
|
|
2781
|
+
if (!templates || templates.length === 0) return code;
|
|
2782
|
+
const byId = new Map(templates.map((t) => [t.id, JSON.stringify(t.html)]));
|
|
2783
|
+
return code.replace(/_tmpl\$\d+/g, (id) => byId.get(id) ?? id);
|
|
2784
|
+
}
|
|
2785
|
+
var imperativeBackend = {
|
|
2786
|
+
name: "imperative",
|
|
2787
|
+
contract: RUNTIME_CONTRACT_V1,
|
|
2788
|
+
emit(node, options) {
|
|
2789
|
+
const used = /* @__PURE__ */ new Set();
|
|
2790
|
+
const templates = options?.templateClone !== false ? [] : void 0;
|
|
2791
|
+
partial = options?.partialTemplates === true;
|
|
2792
|
+
const code = emitNode(node, used, templates);
|
|
2793
|
+
return { code, imports: Array.from(used), templates };
|
|
2794
|
+
}
|
|
2795
|
+
};
|
|
2796
|
+
|
|
2797
|
+
// src/resolve/component-resolver.ts
|
|
2798
|
+
var isMapRule = (rule) => "components" in rule;
|
|
2799
|
+
function substitute(template, match) {
|
|
2800
|
+
return template.replace(/\$(\d+)/g, (whole, index) => {
|
|
2801
|
+
const group = match[Number(index)];
|
|
2802
|
+
return group ?? whole;
|
|
2803
|
+
});
|
|
2804
|
+
}
|
|
2805
|
+
function normalise(name, entry) {
|
|
2806
|
+
return typeof entry === "string" ? { module: entry, export: name } : entry;
|
|
2807
|
+
}
|
|
2808
|
+
function createComponentResolver(rules = []) {
|
|
2809
|
+
const exact = /* @__PURE__ */ new Map();
|
|
2810
|
+
const conflicts = [];
|
|
2811
|
+
const patterns = [];
|
|
2812
|
+
for (const rule of rules) {
|
|
2813
|
+
if (!isMapRule(rule)) {
|
|
2814
|
+
patterns.push(rule);
|
|
2815
|
+
continue;
|
|
2816
|
+
}
|
|
2817
|
+
for (const [name, entry] of Object.entries(rule.components)) {
|
|
2818
|
+
const resolved = normalise(name, entry);
|
|
2819
|
+
const existing = exact.get(name);
|
|
2820
|
+
if (existing && existing.module !== resolved.module) {
|
|
2821
|
+
const conflict = conflicts.find((c) => c.name === name);
|
|
2822
|
+
if (conflict) conflict.modules.push(resolved.module);
|
|
2823
|
+
else conflicts.push({ name, modules: [existing.module, resolved.module] });
|
|
2824
|
+
continue;
|
|
2825
|
+
}
|
|
2826
|
+
exact.set(name, resolved);
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2830
|
+
const resolve = (name) => {
|
|
2831
|
+
if (cache.has(name)) return cache.get(name);
|
|
2832
|
+
let result = exact.get(name);
|
|
2833
|
+
if (!result) {
|
|
2834
|
+
for (const rule of patterns) {
|
|
2835
|
+
const match = name.match(new RegExp(rule.match.source, rule.match.flags.replace("g", "")));
|
|
2836
|
+
if (!match) continue;
|
|
2837
|
+
result = {
|
|
2838
|
+
module: substitute(rule.module, match),
|
|
2839
|
+
export: rule.export ? substitute(rule.export, match) : name
|
|
2840
|
+
};
|
|
2841
|
+
break;
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
cache.set(name, result);
|
|
2845
|
+
return result;
|
|
2846
|
+
};
|
|
2847
|
+
return {
|
|
2848
|
+
resolve,
|
|
2849
|
+
names: () => [...exact.keys()],
|
|
2850
|
+
conflicts: () => conflicts
|
|
2851
|
+
};
|
|
2852
|
+
}
|
|
2853
|
+
|
|
2854
|
+
// src/lower/template.ts
|
|
2855
|
+
import {
|
|
2856
|
+
parseTemplate
|
|
2857
|
+
} from "@fluixi/template-parser";
|
|
2858
|
+
|
|
2859
|
+
// src/lower/text.ts
|
|
2860
|
+
function cleanTemplateText(value) {
|
|
2861
|
+
const lines = value.split(/\r\n|\n|\r/);
|
|
2862
|
+
let lastNonEmpty = 0;
|
|
2863
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2864
|
+
if (/[^ \t]/.test(lines[i])) lastNonEmpty = i;
|
|
2865
|
+
}
|
|
2866
|
+
let out = "";
|
|
2867
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2868
|
+
let line = lines[i].replace(/\t/g, " ");
|
|
2869
|
+
if (i !== 0) line = line.replace(/^ +/, "");
|
|
2870
|
+
if (i !== lines.length - 1) line = line.replace(/ +$/, "");
|
|
2871
|
+
if (!line) continue;
|
|
2872
|
+
if (i !== lastNonEmpty) line += " ";
|
|
2873
|
+
out += line;
|
|
2874
|
+
}
|
|
2875
|
+
return out;
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
// src/lower/entities.ts
|
|
2879
|
+
var NAMED = {
|
|
2880
|
+
quot: 34,
|
|
2881
|
+
amp: 38,
|
|
2882
|
+
apos: 39,
|
|
2883
|
+
lt: 60,
|
|
2884
|
+
gt: 62,
|
|
2885
|
+
nbsp: 160,
|
|
2886
|
+
iexcl: 161,
|
|
2887
|
+
cent: 162,
|
|
2888
|
+
pound: 163,
|
|
2889
|
+
curren: 164,
|
|
2890
|
+
yen: 165,
|
|
2891
|
+
brvbar: 166,
|
|
2892
|
+
sect: 167,
|
|
2893
|
+
uml: 168,
|
|
2894
|
+
copy: 169,
|
|
2895
|
+
ordf: 170,
|
|
2896
|
+
laquo: 171,
|
|
2897
|
+
not: 172,
|
|
2898
|
+
shy: 173,
|
|
2899
|
+
reg: 174,
|
|
2900
|
+
macr: 175,
|
|
2901
|
+
deg: 176,
|
|
2902
|
+
plusmn: 177,
|
|
2903
|
+
sup2: 178,
|
|
2904
|
+
sup3: 179,
|
|
2905
|
+
acute: 180,
|
|
2906
|
+
micro: 181,
|
|
2907
|
+
para: 182,
|
|
2908
|
+
middot: 183,
|
|
2909
|
+
cedil: 184,
|
|
2910
|
+
sup1: 185,
|
|
2911
|
+
ordm: 186,
|
|
2912
|
+
raquo: 187,
|
|
2913
|
+
frac14: 188,
|
|
2914
|
+
frac12: 189,
|
|
2915
|
+
frac34: 190,
|
|
2916
|
+
iquest: 191,
|
|
2917
|
+
Agrave: 192,
|
|
2918
|
+
Aacute: 193,
|
|
2919
|
+
Acirc: 194,
|
|
2920
|
+
Atilde: 195,
|
|
2921
|
+
Auml: 196,
|
|
2922
|
+
Aring: 197,
|
|
2923
|
+
AElig: 198,
|
|
2924
|
+
Ccedil: 199,
|
|
2925
|
+
Egrave: 200,
|
|
2926
|
+
Eacute: 201,
|
|
2927
|
+
Ecirc: 202,
|
|
2928
|
+
Euml: 203,
|
|
2929
|
+
Igrave: 204,
|
|
2930
|
+
Iacute: 205,
|
|
2931
|
+
Icirc: 206,
|
|
2932
|
+
Iuml: 207,
|
|
2933
|
+
ETH: 208,
|
|
2934
|
+
Ntilde: 209,
|
|
2935
|
+
Ograve: 210,
|
|
2936
|
+
Oacute: 211,
|
|
2937
|
+
Ocirc: 212,
|
|
2938
|
+
Otilde: 213,
|
|
2939
|
+
Ouml: 214,
|
|
2940
|
+
times: 215,
|
|
2941
|
+
Oslash: 216,
|
|
2942
|
+
Ugrave: 217,
|
|
2943
|
+
Uacute: 218,
|
|
2944
|
+
Ucirc: 219,
|
|
2945
|
+
Uuml: 220,
|
|
2946
|
+
Yacute: 221,
|
|
2947
|
+
THORN: 222,
|
|
2948
|
+
szlig: 223,
|
|
2949
|
+
agrave: 224,
|
|
2950
|
+
aacute: 225,
|
|
2951
|
+
acirc: 226,
|
|
2952
|
+
atilde: 227,
|
|
2953
|
+
auml: 228,
|
|
2954
|
+
aring: 229,
|
|
2955
|
+
aelig: 230,
|
|
2956
|
+
ccedil: 231,
|
|
2957
|
+
egrave: 232,
|
|
2958
|
+
eacute: 233,
|
|
2959
|
+
ecirc: 234,
|
|
2960
|
+
euml: 235,
|
|
2961
|
+
igrave: 236,
|
|
2962
|
+
iacute: 237,
|
|
2963
|
+
icirc: 238,
|
|
2964
|
+
iuml: 239,
|
|
2965
|
+
eth: 240,
|
|
2966
|
+
ntilde: 241,
|
|
2967
|
+
ograve: 242,
|
|
2968
|
+
oacute: 243,
|
|
2969
|
+
ocirc: 244,
|
|
2970
|
+
otilde: 245,
|
|
2971
|
+
ouml: 246,
|
|
2972
|
+
divide: 247,
|
|
2973
|
+
oslash: 248,
|
|
2974
|
+
ugrave: 249,
|
|
2975
|
+
uacute: 250,
|
|
2976
|
+
ucirc: 251,
|
|
2977
|
+
uuml: 252,
|
|
2978
|
+
yacute: 253,
|
|
2979
|
+
thorn: 254,
|
|
2980
|
+
yuml: 255,
|
|
2981
|
+
OElig: 338,
|
|
2982
|
+
oelig: 339,
|
|
2983
|
+
Scaron: 352,
|
|
2984
|
+
scaron: 353,
|
|
2985
|
+
Yuml: 376,
|
|
2986
|
+
fnof: 402,
|
|
2987
|
+
circ: 710,
|
|
2988
|
+
tilde: 732,
|
|
2989
|
+
Alpha: 913,
|
|
2990
|
+
Beta: 914,
|
|
2991
|
+
Gamma: 915,
|
|
2992
|
+
Delta: 916,
|
|
2993
|
+
Epsilon: 917,
|
|
2994
|
+
Zeta: 918,
|
|
2995
|
+
Eta: 919,
|
|
2996
|
+
Theta: 920,
|
|
2997
|
+
Iota: 921,
|
|
2998
|
+
Kappa: 922,
|
|
2999
|
+
Lambda: 923,
|
|
3000
|
+
Mu: 924,
|
|
3001
|
+
Nu: 925,
|
|
3002
|
+
Xi: 926,
|
|
3003
|
+
Omicron: 927,
|
|
3004
|
+
Pi: 928,
|
|
3005
|
+
Rho: 929,
|
|
3006
|
+
Sigma: 931,
|
|
3007
|
+
Tau: 932,
|
|
3008
|
+
Upsilon: 933,
|
|
3009
|
+
Phi: 934,
|
|
3010
|
+
Chi: 935,
|
|
3011
|
+
Psi: 936,
|
|
3012
|
+
Omega: 937,
|
|
3013
|
+
alpha: 945,
|
|
3014
|
+
beta: 946,
|
|
3015
|
+
gamma: 947,
|
|
3016
|
+
delta: 948,
|
|
3017
|
+
epsilon: 949,
|
|
3018
|
+
zeta: 950,
|
|
3019
|
+
eta: 951,
|
|
3020
|
+
theta: 952,
|
|
3021
|
+
iota: 953,
|
|
3022
|
+
kappa: 954,
|
|
3023
|
+
lambda: 955,
|
|
3024
|
+
mu: 956,
|
|
3025
|
+
nu: 957,
|
|
3026
|
+
xi: 958,
|
|
3027
|
+
omicron: 959,
|
|
3028
|
+
pi: 960,
|
|
3029
|
+
rho: 961,
|
|
3030
|
+
sigmaf: 962,
|
|
3031
|
+
sigma: 963,
|
|
3032
|
+
tau: 964,
|
|
3033
|
+
upsilon: 965,
|
|
3034
|
+
phi: 966,
|
|
3035
|
+
chi: 967,
|
|
3036
|
+
psi: 968,
|
|
3037
|
+
omega: 969,
|
|
3038
|
+
thetasym: 977,
|
|
3039
|
+
upsih: 978,
|
|
3040
|
+
piv: 982,
|
|
3041
|
+
ensp: 8194,
|
|
3042
|
+
emsp: 8195,
|
|
3043
|
+
thinsp: 8201,
|
|
3044
|
+
zwnj: 8204,
|
|
3045
|
+
zwj: 8205,
|
|
3046
|
+
lrm: 8206,
|
|
3047
|
+
rlm: 8207,
|
|
3048
|
+
ndash: 8211,
|
|
3049
|
+
mdash: 8212,
|
|
3050
|
+
lsquo: 8216,
|
|
3051
|
+
rsquo: 8217,
|
|
3052
|
+
sbquo: 8218,
|
|
3053
|
+
ldquo: 8220,
|
|
3054
|
+
rdquo: 8221,
|
|
3055
|
+
bdquo: 8222,
|
|
3056
|
+
dagger: 8224,
|
|
3057
|
+
Dagger: 8225,
|
|
3058
|
+
bull: 8226,
|
|
3059
|
+
hellip: 8230,
|
|
3060
|
+
permil: 8240,
|
|
3061
|
+
prime: 8242,
|
|
3062
|
+
Prime: 8243,
|
|
3063
|
+
lsaquo: 8249,
|
|
3064
|
+
rsaquo: 8250,
|
|
3065
|
+
oline: 8254,
|
|
3066
|
+
frasl: 8260,
|
|
3067
|
+
euro: 8364,
|
|
3068
|
+
image: 8465,
|
|
3069
|
+
weierp: 8472,
|
|
3070
|
+
real: 8476,
|
|
3071
|
+
trade: 8482,
|
|
3072
|
+
alefsym: 8501,
|
|
3073
|
+
larr: 8592,
|
|
3074
|
+
uarr: 8593,
|
|
3075
|
+
rarr: 8594,
|
|
3076
|
+
darr: 8595,
|
|
3077
|
+
harr: 8596,
|
|
3078
|
+
crarr: 8629,
|
|
3079
|
+
lArr: 8656,
|
|
3080
|
+
uArr: 8657,
|
|
3081
|
+
rArr: 8658,
|
|
3082
|
+
dArr: 8659,
|
|
3083
|
+
hArr: 8660,
|
|
3084
|
+
forall: 8704,
|
|
3085
|
+
part: 8706,
|
|
3086
|
+
exist: 8707,
|
|
3087
|
+
empty: 8709,
|
|
3088
|
+
nabla: 8711,
|
|
3089
|
+
isin: 8712,
|
|
3090
|
+
notin: 8713,
|
|
3091
|
+
ni: 8715,
|
|
3092
|
+
prod: 8719,
|
|
3093
|
+
sum: 8721,
|
|
3094
|
+
minus: 8722,
|
|
3095
|
+
lowast: 8727,
|
|
3096
|
+
radic: 8730,
|
|
3097
|
+
prop: 8733,
|
|
3098
|
+
infin: 8734,
|
|
3099
|
+
ang: 8736,
|
|
3100
|
+
and: 8743,
|
|
3101
|
+
or: 8744,
|
|
3102
|
+
cap: 8745,
|
|
3103
|
+
cup: 8746,
|
|
3104
|
+
int: 8747,
|
|
3105
|
+
there4: 8756,
|
|
3106
|
+
sim: 8764,
|
|
3107
|
+
cong: 8773,
|
|
3108
|
+
asymp: 8776,
|
|
3109
|
+
ne: 8800,
|
|
3110
|
+
equiv: 8801,
|
|
3111
|
+
le: 8804,
|
|
3112
|
+
ge: 8805,
|
|
3113
|
+
sub: 8834,
|
|
3114
|
+
sup: 8835,
|
|
3115
|
+
nsub: 8836,
|
|
3116
|
+
sube: 8838,
|
|
3117
|
+
supe: 8839,
|
|
3118
|
+
oplus: 8853,
|
|
3119
|
+
otimes: 8855,
|
|
3120
|
+
perp: 8869,
|
|
3121
|
+
sdot: 8901,
|
|
3122
|
+
lceil: 8968,
|
|
3123
|
+
rceil: 8969,
|
|
3124
|
+
lfloor: 8970,
|
|
3125
|
+
rfloor: 8971,
|
|
3126
|
+
lang: 9001,
|
|
3127
|
+
rang: 9002,
|
|
3128
|
+
loz: 9674,
|
|
3129
|
+
spades: 9824,
|
|
3130
|
+
clubs: 9827,
|
|
3131
|
+
hearts: 9829,
|
|
3132
|
+
diams: 9830
|
|
3133
|
+
};
|
|
3134
|
+
var REFERENCE = /&(?:#[xX]([0-9a-fA-F]{1,6})|#([0-9]{1,7})|([a-zA-Z][a-zA-Z0-9]{1,31}));/g;
|
|
3135
|
+
function decodeEntities(value) {
|
|
3136
|
+
if (!value.includes("&")) return value;
|
|
3137
|
+
return value.replace(REFERENCE, (match, hex, dec, name) => {
|
|
3138
|
+
const code = hex ? parseInt(hex, 16) : dec ? parseInt(dec, 10) : Object.prototype.hasOwnProperty.call(NAMED, name) ? NAMED[name] : void 0;
|
|
3139
|
+
return code !== void 0 && code <= 1114111 ? String.fromCodePoint(code) : match;
|
|
3140
|
+
});
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
// src/lower/template.ts
|
|
3144
|
+
var DELEGATED = /* @__PURE__ */ new Set([
|
|
3145
|
+
"click",
|
|
3146
|
+
"dblclick",
|
|
3147
|
+
"input",
|
|
3148
|
+
"change",
|
|
3149
|
+
"submit",
|
|
3150
|
+
"focus",
|
|
3151
|
+
"blur",
|
|
3152
|
+
"keydown",
|
|
3153
|
+
"keyup",
|
|
3154
|
+
"keypress",
|
|
3155
|
+
"mousedown",
|
|
3156
|
+
"mouseup"
|
|
3157
|
+
]);
|
|
3158
|
+
function escapeTemplate(s) {
|
|
3159
|
+
return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
3160
|
+
}
|
|
3161
|
+
var CONTAINER = "container";
|
|
3162
|
+
function capitalize(s) {
|
|
3163
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
3164
|
+
}
|
|
3165
|
+
var Lowerer = class {
|
|
3166
|
+
constructor(holes, used, sourceFile, positionAt) {
|
|
3167
|
+
this.holes = holes;
|
|
3168
|
+
this.used = used;
|
|
3169
|
+
this.sourceFile = sourceFile;
|
|
3170
|
+
this.positionAt = positionAt;
|
|
3171
|
+
}
|
|
3172
|
+
/**
|
|
3173
|
+
* Where a tag is written, for the mark a component node carries.
|
|
3174
|
+
*
|
|
3175
|
+
* The parser reports offsets, and they are offsets into the file: the pieces it was given
|
|
3176
|
+
* carry the positions the front-end recorded. Only built when the host asked for source
|
|
3177
|
+
* locations, which is the only time either of these is set.
|
|
3178
|
+
*/
|
|
3179
|
+
tagAt(node) {
|
|
3180
|
+
const start = node.loc?.start;
|
|
3181
|
+
if (!this.sourceFile || !this.positionAt || start == null) return void 0;
|
|
3182
|
+
const { line, column } = this.positionAt(start);
|
|
3183
|
+
return { file: this.sourceFile, line, column };
|
|
3184
|
+
}
|
|
3185
|
+
hole(i) {
|
|
3186
|
+
return this.holes[i] ?? { code: "undefined", reactive: false };
|
|
3187
|
+
}
|
|
3188
|
+
/** Emit a nested IR subtree to code (for `Show` fallback / `For` children). */
|
|
3189
|
+
emit(node) {
|
|
3190
|
+
const { code, imports, templates } = imperativeBackend.emit(node, {});
|
|
3191
|
+
for (const s of imports) this.used.add(s);
|
|
3192
|
+
return inlineTemplates(code, templates);
|
|
3193
|
+
}
|
|
3194
|
+
// --- content ------------------------------------------------------------
|
|
3195
|
+
lowerRoot(children) {
|
|
3196
|
+
const nodes = this.lowerChildren(children);
|
|
3197
|
+
if (nodes.length === 1) return nodes[0];
|
|
3198
|
+
return { kind: "fragment", children: nodes };
|
|
3199
|
+
}
|
|
3200
|
+
/** Lower a sibling list, handling text-drop and if/else/each restructuring. */
|
|
3201
|
+
lowerChildren(children) {
|
|
3202
|
+
const out = [];
|
|
3203
|
+
for (let i = 0; i < children.length; i++) {
|
|
3204
|
+
const child = children[i];
|
|
3205
|
+
if (child.kind === "Element" || child.kind === "Component") {
|
|
3206
|
+
const ifDir = child.attributes.find((a) => a.kind === "IfDirective");
|
|
3207
|
+
if (ifDir && ifDir.kind === "IfDirective") {
|
|
3208
|
+
let elseIdx = i + 1;
|
|
3209
|
+
if (elseIdx < children.length && this.isBlankText(children[elseIdx])) elseIdx++;
|
|
3210
|
+
const elseNode = children[elseIdx];
|
|
3211
|
+
const hasElse = elseNode && (elseNode.kind === "Element" || elseNode.kind === "Component") && elseNode.attributes.some((a) => a.kind === "ElseDirective");
|
|
3212
|
+
out.push(this.lowerIf(child, ifDir.hole, hasElse ? elseNode : null));
|
|
3213
|
+
if (hasElse) i = elseIdx;
|
|
3214
|
+
continue;
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
const node = this.lowerNode(child);
|
|
3218
|
+
if (node) out.push(node);
|
|
3219
|
+
}
|
|
3220
|
+
return out;
|
|
3221
|
+
}
|
|
3222
|
+
isBlankText(n2) {
|
|
3223
|
+
return n2.kind === "Text" && !n2.raw && cleanTemplateText(n2.value) === "";
|
|
3224
|
+
}
|
|
3225
|
+
lowerNode(node) {
|
|
3226
|
+
switch (node.kind) {
|
|
3227
|
+
case "Text": {
|
|
3228
|
+
if (node.raw) return { kind: "text", value: node.value };
|
|
3229
|
+
const cleaned = decodeEntities(cleanTemplateText(node.value));
|
|
3230
|
+
return cleaned ? { kind: "text", value: cleaned } : null;
|
|
3231
|
+
}
|
|
3232
|
+
case "Comment":
|
|
3233
|
+
return null;
|
|
3234
|
+
// dropped, like JSX comments
|
|
3235
|
+
case "Expression": {
|
|
3236
|
+
const h = this.hole(node.hole);
|
|
3237
|
+
return { kind: "expr", code: h.code, reactive: h.reactive, ...h.at ? { at: h.at } : {} };
|
|
3238
|
+
}
|
|
3239
|
+
case "Fragment":
|
|
3240
|
+
return { kind: "fragment", children: this.lowerChildren(node.children) };
|
|
3241
|
+
case "Element":
|
|
3242
|
+
return this.lowerElement(node);
|
|
3243
|
+
case "Component":
|
|
3244
|
+
return this.lowerComponent(node);
|
|
3245
|
+
default:
|
|
3246
|
+
return null;
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
lowerElement(el) {
|
|
3250
|
+
const isAttr = el.attributes.find((a) => a.kind === "Attribute" && a.name === "is");
|
|
3251
|
+
if (el.tag === "component" && isAttr && isAttr.value && isAttr.value.kind === "hole") {
|
|
3252
|
+
const rest = el.attributes.filter((a) => a !== isAttr);
|
|
3253
|
+
const node = this.lowerComponent({ ...el, kind: "Component", tag: "Dynamic", tagHole: null, attributes: rest });
|
|
3254
|
+
node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
|
|
3255
|
+
return node;
|
|
3256
|
+
}
|
|
3257
|
+
const each = this.lowerEach(el);
|
|
3258
|
+
const children = each ? [each] : this.lowerChildren(el.children);
|
|
3259
|
+
if (el.tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
|
|
3260
|
+
const at = this.tagAt(el);
|
|
3261
|
+
return {
|
|
3262
|
+
kind: "element",
|
|
3263
|
+
tag: el.tag,
|
|
3264
|
+
svg: el.namespace === "svg",
|
|
3265
|
+
props: this.lowerAttributes(el.attributes, true),
|
|
3266
|
+
children,
|
|
3267
|
+
static: false,
|
|
3268
|
+
...at ? { at } : {}
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
lowerComponent(el) {
|
|
3272
|
+
const name = el.tagHole != null ? this.hole(el.tagHole).code : el.tag;
|
|
3273
|
+
const props = this.lowerAttributes(el.attributes);
|
|
3274
|
+
const { slots, rest } = this.partitionSlots(el.children);
|
|
3275
|
+
for (const [slotName, nodes] of slots) {
|
|
3276
|
+
const ir = nodes.length === 1 ? nodes[0] : { kind: "fragment", children: nodes };
|
|
3277
|
+
const slotProp = {
|
|
3278
|
+
name: slotName,
|
|
3279
|
+
kind: "attr",
|
|
3280
|
+
expr: this.emit(ir),
|
|
3281
|
+
jsxElement: true
|
|
3282
|
+
};
|
|
3283
|
+
const clash = props.findIndex((p) => p.name === slotName);
|
|
3284
|
+
if (clash >= 0) props[clash] = slotProp;
|
|
3285
|
+
else props.push(slotProp);
|
|
3286
|
+
}
|
|
3287
|
+
const loadAttr = el.attributes.find((a) => a.kind === "LoadDirective");
|
|
3288
|
+
const load = loadAttr ? parseLoadDirective(`load:${loadAttr.strategy}`, loadAttr.modifier) : void 0;
|
|
3289
|
+
const bindAt = props.find((p) => p.at && p.reactive)?.at;
|
|
3290
|
+
const at = this.tagAt(el);
|
|
3291
|
+
return {
|
|
3292
|
+
kind: "component",
|
|
3293
|
+
name,
|
|
3294
|
+
props,
|
|
3295
|
+
children: this.lowerChildren(rest),
|
|
3296
|
+
...at ? { at } : {},
|
|
3297
|
+
...bindAt ? { bindAt } : {},
|
|
3298
|
+
...load ? { load } : {}
|
|
3299
|
+
};
|
|
3300
|
+
}
|
|
3301
|
+
/** Split a component's children into named slots (`slot="x"`) and the rest. */
|
|
3302
|
+
partitionSlots(children) {
|
|
3303
|
+
const slots = /* @__PURE__ */ new Map();
|
|
3304
|
+
const rest = [];
|
|
3305
|
+
for (const child of children) {
|
|
3306
|
+
if (child.kind === "Element" || child.kind === "Component") {
|
|
3307
|
+
const slot = child.attributes.find(
|
|
3308
|
+
(a) => a.kind === "Attribute" && a.name === "slot"
|
|
3309
|
+
);
|
|
3310
|
+
if (slot && slot.value && slot.value.kind === "static") {
|
|
3311
|
+
const stripped = { ...child, attributes: child.attributes.filter((a) => a !== slot) };
|
|
3312
|
+
const ir = stripped.kind === "Element" ? this.lowerElement(stripped) : this.lowerComponent(stripped);
|
|
3313
|
+
const bucket = slots.get(slot.value.value) ?? [];
|
|
3314
|
+
bucket.push(ir);
|
|
3315
|
+
slots.set(slot.value.value, bucket);
|
|
3316
|
+
continue;
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
rest.push(child);
|
|
3320
|
+
}
|
|
3321
|
+
return { slots, rest };
|
|
3322
|
+
}
|
|
3323
|
+
// --- control-flow sugar -------------------------------------------------
|
|
3324
|
+
/** `<el if=${cond}>…</el>` (+ optional `<el else>`) → `<Show when fallback>`. */
|
|
3325
|
+
lowerIf(el, condHole, elseEl) {
|
|
3326
|
+
const cond = this.hole(condHole);
|
|
3327
|
+
const props = [
|
|
3328
|
+
{ name: "when", kind: "attr", expr: cond.code, reactive: cond.reactive, ...cond.at ? { at: cond.at } : {} }
|
|
3329
|
+
];
|
|
3330
|
+
if (elseEl) {
|
|
3331
|
+
const elseIR = this.stripAndLower(elseEl, (a) => a.kind === "ElseDirective");
|
|
3332
|
+
props.push({ name: "fallback", kind: "attr", expr: this.emit(elseIR), jsxElement: true });
|
|
3333
|
+
}
|
|
3334
|
+
const child = this.stripAndLower(el, (a) => a.kind === "IfDirective");
|
|
3335
|
+
const at = this.tagAt(el);
|
|
3336
|
+
return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
|
|
3337
|
+
}
|
|
3338
|
+
/**
|
|
3339
|
+
* `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
|
|
3340
|
+
* content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
|
|
3341
|
+
* it is. Null when the element has no `each`.
|
|
3342
|
+
*/
|
|
3343
|
+
lowerEach(el) {
|
|
3344
|
+
const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
|
|
3345
|
+
if (!eachDir || eachDir.kind !== "EachDirective") return null;
|
|
3346
|
+
const each = this.hole(eachDir.hole);
|
|
3347
|
+
const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
|
|
3348
|
+
if (eachDir.key) {
|
|
3349
|
+
const by = "static" in eachDir.key ? `(item) => item[${JSON.stringify(eachDir.key.static)}]` : this.hole(eachDir.key.hole).code;
|
|
3350
|
+
props.push({ name: "by", kind: "attr", expr: by });
|
|
3351
|
+
}
|
|
3352
|
+
const arrow = this.itemArrow(el);
|
|
3353
|
+
let childrenCode;
|
|
3354
|
+
if (arrow) {
|
|
3355
|
+
const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
|
|
3356
|
+
childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
|
|
3357
|
+
} else {
|
|
3358
|
+
const content = this.lowerChildren(el.children);
|
|
3359
|
+
const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
|
|
3360
|
+
childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
|
|
3361
|
+
}
|
|
3362
|
+
const children = [{ kind: "expr", code: childrenCode, reactive: false }];
|
|
3363
|
+
const at = this.tagAt(el);
|
|
3364
|
+
return { kind: "component", name: "For", props, children, ...at ? { at } : {}, ...each.at ? { bindAt: each.at } : {} };
|
|
3365
|
+
}
|
|
3366
|
+
/** The single `${item => expr}` child arrow, if that's the element's content. */
|
|
3367
|
+
itemArrow(el) {
|
|
3368
|
+
const kids = el.children.filter((c) => !this.isBlankText(c));
|
|
3369
|
+
if (kids.length !== 1 || kids[0].kind !== "Expression") return null;
|
|
3370
|
+
return this.hole(kids[0].hole).arrow ?? null;
|
|
3371
|
+
}
|
|
3372
|
+
/** Lower an element to IR, dropping the directive attribute matched by `drop`. */
|
|
3373
|
+
stripAndLower(el, drop) {
|
|
3374
|
+
const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
|
|
3375
|
+
return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
|
|
3376
|
+
}
|
|
3377
|
+
// --- attributes ---------------------------------------------------------
|
|
3378
|
+
/**
|
|
3379
|
+
* `element`: a DOM element, where each class:/style: value that moves is its own accessor.
|
|
3380
|
+
* A component gets the object as before, rebuilt whole when any value moves.
|
|
3381
|
+
*/
|
|
3382
|
+
lowerAttributes(attrs, element = false) {
|
|
3383
|
+
let anyReactive = false;
|
|
3384
|
+
const entry = (name, h) => {
|
|
3385
|
+
anyReactive ||= h.reactive;
|
|
3386
|
+
if (!element || !h.reactive) return `${JSON.stringify(name)}: ${h.code}`;
|
|
3387
|
+
const accessor = `() => ${paren(h.code, "arrowBody")}`;
|
|
3388
|
+
return `${JSON.stringify(name)}: ${h.at ? markHole(accessor, h.at.line, h.at.column) : accessor}`;
|
|
3389
|
+
};
|
|
3390
|
+
const props = [];
|
|
3391
|
+
const classEntries = [];
|
|
3392
|
+
let classAt;
|
|
3393
|
+
const styleEntries = [];
|
|
3394
|
+
let styleAt;
|
|
3395
|
+
const usePairs = [];
|
|
3396
|
+
for (const a of attrs) {
|
|
3397
|
+
switch (a.kind) {
|
|
3398
|
+
case "IfDirective":
|
|
3399
|
+
case "EachDirective":
|
|
3400
|
+
case "ElseDirective":
|
|
3401
|
+
break;
|
|
3402
|
+
// handled as control-flow at the parent level
|
|
3403
|
+
case "Attribute":
|
|
3404
|
+
props.push(this.plainAttr(a));
|
|
3405
|
+
break;
|
|
3406
|
+
case "PropertyBinding":
|
|
3407
|
+
props.push({
|
|
3408
|
+
name: a.name,
|
|
3409
|
+
kind: "prop",
|
|
3410
|
+
expr: this.hole(a.hole).code,
|
|
3411
|
+
reactive: this.hole(a.hole).reactive,
|
|
3412
|
+
...this.hole(a.hole).at ? { at: this.hole(a.hole).at } : {}
|
|
3413
|
+
});
|
|
3414
|
+
break;
|
|
3415
|
+
case "EventBinding":
|
|
3416
|
+
props.push(this.eventProp(a));
|
|
3417
|
+
break;
|
|
3418
|
+
case "RefBinding":
|
|
3419
|
+
props.push({
|
|
3420
|
+
name: "ref",
|
|
3421
|
+
kind: "ref",
|
|
3422
|
+
expr: this.hole(a.hole).code,
|
|
3423
|
+
reactive: this.hole(a.hole).reactive,
|
|
3424
|
+
// Which variable ends up holding the element, and where it was written.
|
|
3425
|
+
...this.hole(a.hole).at ? { at: this.hole(a.hole).at } : {}
|
|
3426
|
+
});
|
|
3427
|
+
break;
|
|
3428
|
+
case "Spread":
|
|
3429
|
+
props.push({ name: "", kind: "spread", expr: this.hole(a.hole).code });
|
|
3430
|
+
break;
|
|
3431
|
+
case "ClassDirective": {
|
|
3432
|
+
const h = this.hole(a.hole);
|
|
3433
|
+
classEntries.push(entry(a.name, h));
|
|
3434
|
+
classAt ??= h.at;
|
|
3435
|
+
break;
|
|
3436
|
+
}
|
|
3437
|
+
case "StyleDirective": {
|
|
3438
|
+
const h = this.hole(a.hole);
|
|
3439
|
+
styleEntries.push(entry(a.name, h));
|
|
3440
|
+
styleAt ??= h.at;
|
|
3441
|
+
break;
|
|
3442
|
+
}
|
|
3443
|
+
case "BindDirective":
|
|
3444
|
+
props.push(...this.bindProps(a.name, this.hole(a.hole)));
|
|
3445
|
+
break;
|
|
3446
|
+
case "UseDirective": {
|
|
3447
|
+
const dir = a.name ?? (a.hole != null ? this.hole(a.hole).code : null);
|
|
3448
|
+
if (!dir) break;
|
|
3449
|
+
usePairs.push(a.name != null && a.hole != null ? `[${dir}, () => ${paren(this.hole(a.hole).code, "arrowBody")}]` : `[${dir}]`);
|
|
3450
|
+
break;
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
if (classEntries.length > 0) {
|
|
3455
|
+
props.push({
|
|
3456
|
+
name: "classList",
|
|
3457
|
+
kind: "attr",
|
|
3458
|
+
expr: `{ ${classEntries.join(", ")} }`,
|
|
3459
|
+
reactive: !element && anyReactive,
|
|
3460
|
+
...classAt ? { at: classAt } : {}
|
|
3461
|
+
});
|
|
3462
|
+
}
|
|
3463
|
+
if (styleEntries.length > 0) {
|
|
3464
|
+
const entries = `{ ${styleEntries.join(", ")} }`;
|
|
3465
|
+
const base = props.findIndex((p) => p.name === "style");
|
|
3466
|
+
if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: !element && anyReactive, ...styleAt ? { at: styleAt } : {} });
|
|
3467
|
+
else {
|
|
3468
|
+
const prop = props[base];
|
|
3469
|
+
const value = prop.expr === void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
|
|
3470
|
+
props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
if (usePairs.length > 0) {
|
|
3474
|
+
props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
|
|
3475
|
+
}
|
|
3476
|
+
return props;
|
|
3477
|
+
}
|
|
3478
|
+
/**
|
|
3479
|
+
* Lower an event binding. Plain `@click`/`onClick` (no modifiers) stays a
|
|
3480
|
+
* DELEGATED handler (unchanged, byte-identical with JSX). `on:click` or any
|
|
3481
|
+
* modifier (`.capture`/`.once`/`.passive`/`.prevent`/`.stop`/`.self`) emits a
|
|
3482
|
+
* NATIVE `on:name` prop the runtime attaches via addEventListener.
|
|
3483
|
+
*/
|
|
3484
|
+
eventProp(a) {
|
|
3485
|
+
const dom = a.name.toLowerCase();
|
|
3486
|
+
const handler = this.hole(a.hole).code;
|
|
3487
|
+
const native = a.syntax === "colon" || a.modifiers.length > 0;
|
|
3488
|
+
if (!native) {
|
|
3489
|
+
return {
|
|
3490
|
+
name: "on" + capitalize(a.name),
|
|
3491
|
+
kind: "event",
|
|
3492
|
+
event: { name: dom, delegated: DELEGATED.has(dom) },
|
|
3493
|
+
expr: handler
|
|
3494
|
+
};
|
|
3495
|
+
}
|
|
3496
|
+
const wrapped = this.wrapHandler(handler, a.modifiers);
|
|
3497
|
+
const options = this.eventOptions(a.modifiers);
|
|
3498
|
+
const value = options ? `[${wrapped}, ${options}]` : wrapped;
|
|
3499
|
+
return { name: "on:" + dom, kind: "attr", expr: value };
|
|
3500
|
+
}
|
|
3501
|
+
/** Wrap a handler for `.prevent`/`.stop`/`.self` (no wrap when none apply). */
|
|
3502
|
+
wrapHandler(handler, mods) {
|
|
3503
|
+
const guard = mods.includes("self") ? "if (e.target !== e.currentTarget) return; " : "";
|
|
3504
|
+
const pre = [];
|
|
3505
|
+
if (mods.includes("prevent")) pre.push("e.preventDefault();");
|
|
3506
|
+
if (mods.includes("stop")) pre.push("e.stopPropagation();");
|
|
3507
|
+
if (!guard && pre.length === 0) return handler;
|
|
3508
|
+
return `(e) => { ${guard}${pre.join(" ")} return (${handler})(e); }`;
|
|
3509
|
+
}
|
|
3510
|
+
/** addEventListener options object from `.capture`/`.once`/`.passive`, or null. */
|
|
3511
|
+
eventOptions(mods) {
|
|
3512
|
+
const opts = [];
|
|
3513
|
+
if (mods.includes("capture")) opts.push("capture: true");
|
|
3514
|
+
if (mods.includes("once")) opts.push("once: true");
|
|
3515
|
+
if (mods.includes("passive")) opts.push("passive: true");
|
|
3516
|
+
return opts.length ? `{ ${opts.join(", ")} }` : null;
|
|
3517
|
+
}
|
|
3518
|
+
/** `bind:value=${sig}` → `value={read()}` + `onInput={e => write(e…value)}`. */
|
|
3519
|
+
bindProps(prop, h) {
|
|
3520
|
+
const sigCode = h.code;
|
|
3521
|
+
const checked = prop === "checked";
|
|
3522
|
+
const evt = checked ? "change" : "input";
|
|
3523
|
+
const accessor = checked ? "checked" : "value";
|
|
3524
|
+
this.used.add("bindPair");
|
|
3525
|
+
const sig = `bindPair(${sigCode})`;
|
|
3526
|
+
return [
|
|
3527
|
+
{
|
|
3528
|
+
name: prop,
|
|
3529
|
+
kind: "attr",
|
|
3530
|
+
expr: `${sig}[0]()`,
|
|
3531
|
+
reactive: true,
|
|
3532
|
+
directive: `bind:${prop}`,
|
|
3533
|
+
...h.at ? { at: h.at } : {}
|
|
3534
|
+
},
|
|
3535
|
+
{
|
|
3536
|
+
name: "on" + capitalize(evt),
|
|
3537
|
+
kind: "event",
|
|
3538
|
+
event: { name: evt, delegated: DELEGATED.has(evt) },
|
|
3539
|
+
// delegated handler: `target` is the bound element (currentTarget is the root)
|
|
3540
|
+
expr: `(e) => ${sig}[1](e.target.${accessor})`
|
|
3541
|
+
}
|
|
3542
|
+
];
|
|
3543
|
+
}
|
|
3544
|
+
/** A plain attribute (incl. lit `?bool`, mixed values), old `mkProp` behavior. */
|
|
3545
|
+
plainAttr(a) {
|
|
3546
|
+
const v = a.value;
|
|
3547
|
+
let name = a.name;
|
|
3548
|
+
if (a.name === "class") {
|
|
3549
|
+
name = v && v.kind === "hole" && this.hole(v.hole).object ? "classList" : "className";
|
|
3550
|
+
} else if (a.name === "html") {
|
|
3551
|
+
name = "innerHTML";
|
|
3552
|
+
}
|
|
3553
|
+
const kind = "attr";
|
|
3554
|
+
const base = { name, kind };
|
|
3555
|
+
if (v == null) {
|
|
3556
|
+
base.literal = true;
|
|
3557
|
+
return base;
|
|
3558
|
+
}
|
|
3559
|
+
if (v.kind === "static") {
|
|
3560
|
+
base.literal = decodeEntities(v.value);
|
|
3561
|
+
return base;
|
|
3562
|
+
}
|
|
3563
|
+
if (v.kind === "hole") {
|
|
3564
|
+
const h = this.hole(v.hole);
|
|
3565
|
+
base.expr = h.code;
|
|
3566
|
+
base.reactive = h.reactive;
|
|
3567
|
+
if (h.at) base.at = h.at;
|
|
3568
|
+
return base;
|
|
3569
|
+
}
|
|
3570
|
+
let reactive = false;
|
|
3571
|
+
let at;
|
|
3572
|
+
const body = v.parts.map((p) => {
|
|
3573
|
+
if ("text" in p) return escapeTemplate(decodeEntities(p.text));
|
|
3574
|
+
const h = this.hole(p.hole);
|
|
3575
|
+
reactive = reactive || h.reactive;
|
|
3576
|
+
at ??= h.at;
|
|
3577
|
+
return "${" + h.code + "}";
|
|
3578
|
+
}).join("");
|
|
3579
|
+
base.expr = "`" + body + "`";
|
|
3580
|
+
base.reactive = reactive;
|
|
3581
|
+
if (at) base.at = at;
|
|
3582
|
+
return base;
|
|
3583
|
+
}
|
|
3584
|
+
};
|
|
3585
|
+
function lowerTemplate(pieces, holes, used, opts = {}) {
|
|
3586
|
+
const { root } = parseTemplate(pieces, { svg: opts.svg });
|
|
3587
|
+
return new Lowerer(holes, used, opts.sourceFile, opts.positionAt).lowerRoot(root.children);
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3590
|
+
// src/lower/compile-template.ts
|
|
3591
|
+
function compilePieces(pieces, holes, options = {}) {
|
|
3592
|
+
const used = /* @__PURE__ */ new Set();
|
|
3593
|
+
const ir = lowerTemplate(pieces, [...holes], used, {
|
|
3594
|
+
svg: options.svg,
|
|
3595
|
+
...options.sourceFile ? { sourceFile: options.sourceFile } : {},
|
|
3596
|
+
...options.positionAt ? { positionAt: options.positionAt } : {}
|
|
3597
|
+
});
|
|
3598
|
+
if (options.templateStyles) applyTemplateStyles(ir, options.templateStyles);
|
|
3599
|
+
analyzeStatic(ir);
|
|
3600
|
+
resolveComponentSources(ir, {
|
|
3601
|
+
resolver: createComponentResolver(options.resolve ?? []),
|
|
3602
|
+
modules: {
|
|
3603
|
+
controlFlowModule: options.controlFlowModule ?? "@fluixi/dom",
|
|
3604
|
+
coreModule: options.coreModule ?? "@fluixi/core",
|
|
3605
|
+
routerModule: options.routerModule ?? "@fluixi/core/router"
|
|
3606
|
+
},
|
|
3607
|
+
strategyFor: (node) => node.load
|
|
3608
|
+
});
|
|
3609
|
+
collapseStrategies(ir);
|
|
3610
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, {
|
|
3611
|
+
templateClone: options.templateClone,
|
|
3612
|
+
partialTemplates: options.partialTemplates
|
|
3613
|
+
});
|
|
3614
|
+
for (const symbol of imports) used.add(symbol);
|
|
3615
|
+
if (options.hoistTemplates) return { code, imports: [...used], ir, templates };
|
|
3616
|
+
return { code: inlineTemplates(code, templates), imports: [...used], ir };
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
// src/analyze/reactive-expr.ts
|
|
3620
|
+
var STABLE_MEMBER = "children";
|
|
3621
|
+
function isReactiveShape(shape) {
|
|
3622
|
+
switch (shape.kind) {
|
|
3623
|
+
case "call":
|
|
3624
|
+
return true;
|
|
3625
|
+
case "member":
|
|
3626
|
+
return shape.property !== STABLE_MEMBER;
|
|
3627
|
+
case "compound":
|
|
3628
|
+
return shape.parts.some(isReactiveShape);
|
|
3629
|
+
case "opaque":
|
|
3630
|
+
return false;
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3634
|
+
// src/analyze/expr-shape.ts
|
|
3635
|
+
var CALL = /* @__PURE__ */ new Set(["CallExpression", "OptionalCallExpression"]);
|
|
3636
|
+
var MEMBER = /* @__PURE__ */ new Set(["MemberExpression", "OptionalMemberExpression"]);
|
|
3637
|
+
function shapeOf(node) {
|
|
3638
|
+
if (!node) return { kind: "opaque" };
|
|
3639
|
+
if (CALL.has(node.type)) return { kind: "call" };
|
|
3640
|
+
if (MEMBER.has(node.type)) {
|
|
3641
|
+
const property = node.property;
|
|
3642
|
+
const computed = node.computed === true;
|
|
3643
|
+
return {
|
|
3644
|
+
kind: "member",
|
|
3645
|
+
property: !computed && property?.type === "Identifier" ? property.name : null
|
|
3646
|
+
};
|
|
3647
|
+
}
|
|
3648
|
+
if (node.type === "ConditionalExpression") {
|
|
3649
|
+
return { kind: "compound", parts: [node.test, node.consequent, node.alternate].map(part) };
|
|
3650
|
+
}
|
|
3651
|
+
if (node.type === "LogicalExpression" || node.type === "BinaryExpression") {
|
|
3652
|
+
return { kind: "compound", parts: [node.left, node.right].map(part) };
|
|
3653
|
+
}
|
|
3654
|
+
if (node.type === "TemplateLiteral") {
|
|
3655
|
+
return { kind: "compound", parts: node.expressions.map(part) };
|
|
3656
|
+
}
|
|
3657
|
+
if (node.type === "ObjectExpression") {
|
|
3658
|
+
const props = node.properties.filter(
|
|
3659
|
+
(p) => (p.type === "ObjectProperty" || p.type === "Property") && p.computed !== true
|
|
3660
|
+
);
|
|
3661
|
+
return { kind: "compound", parts: props.map((p) => part(p.value)) };
|
|
3662
|
+
}
|
|
3663
|
+
if (node.type === "ArrayExpression") {
|
|
3664
|
+
const items = node.elements.filter(
|
|
3665
|
+
(e) => e != null && e.type !== "SpreadElement"
|
|
3666
|
+
);
|
|
3667
|
+
return { kind: "compound", parts: items.map(part) };
|
|
3668
|
+
}
|
|
3669
|
+
return { kind: "opaque" };
|
|
3670
|
+
}
|
|
3671
|
+
var part = (n2) => shapeOf(n2);
|
|
3672
|
+
|
|
3673
|
+
// src/lower/jsx.ts
|
|
3674
|
+
var SVG_TAGS = /* @__PURE__ */ new Set([
|
|
3675
|
+
"svg",
|
|
3676
|
+
"path",
|
|
3677
|
+
"circle",
|
|
3678
|
+
"rect",
|
|
3679
|
+
"line",
|
|
3680
|
+
"polygon",
|
|
3681
|
+
"polyline",
|
|
3682
|
+
"ellipse",
|
|
3683
|
+
"g",
|
|
3684
|
+
"defs",
|
|
3685
|
+
"clipPath",
|
|
3686
|
+
"text"
|
|
3687
|
+
]);
|
|
3688
|
+
var EVENT_RE = /^on[A-Z]/;
|
|
3689
|
+
var DELEGATED2 = /* @__PURE__ */ new Set([
|
|
3690
|
+
"click",
|
|
3691
|
+
"dblclick",
|
|
3692
|
+
"input",
|
|
3693
|
+
"change",
|
|
3694
|
+
"submit",
|
|
3695
|
+
"focus",
|
|
3696
|
+
"blur",
|
|
3697
|
+
"keydown",
|
|
3698
|
+
"keyup",
|
|
3699
|
+
"keypress",
|
|
3700
|
+
"mousedown",
|
|
3701
|
+
"mouseup"
|
|
3702
|
+
]);
|
|
3703
|
+
var isReactive = (node) => isReactiveShape(shapeOf(node));
|
|
3704
|
+
var CONTAINER2 = "container";
|
|
3705
|
+
function directive(node, name) {
|
|
3706
|
+
if (node.type !== "JSXElement") return void 0;
|
|
3707
|
+
const opening = node.openingElement;
|
|
3708
|
+
if (opening.name.type !== "JSXIdentifier" || opening.name.name[0] !== opening.name.name[0].toLowerCase()) return void 0;
|
|
3709
|
+
return opening.attributes.find((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === name);
|
|
3710
|
+
}
|
|
3711
|
+
function directiveExpr(attr) {
|
|
3712
|
+
const v = attr.value;
|
|
3713
|
+
return v?.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression" ? v.expression : void 0;
|
|
3714
|
+
}
|
|
3715
|
+
function emitIR(ir, ctx) {
|
|
3716
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, {});
|
|
3717
|
+
for (const s of imports) ctx.used.add(s);
|
|
3718
|
+
return inlineTemplates(code, templates);
|
|
3719
|
+
}
|
|
3720
|
+
var posOf = (node, ctx) => {
|
|
3721
|
+
if (!ctx.sourceFile) return void 0;
|
|
3722
|
+
const at = node.loc?.start;
|
|
3723
|
+
return at ? { line: at.line, column: at.column } : void 0;
|
|
3724
|
+
};
|
|
3725
|
+
function literalOf(node) {
|
|
3726
|
+
if (node.type === "StringLiteral" || node.type === "NumericLiteral" || node.type === "BooleanLiteral") {
|
|
3727
|
+
return node.value;
|
|
3728
|
+
}
|
|
3729
|
+
if (node.type === "Literal" && (typeof node.value === "string" || typeof node.value === "number" || typeof node.value === "boolean")) {
|
|
3730
|
+
return node.value;
|
|
3731
|
+
}
|
|
3732
|
+
return void 0;
|
|
3733
|
+
}
|
|
3734
|
+
var isString = (node) => !!node && typeof literalOf(node) === "string";
|
|
3735
|
+
function tagInfo(name, ctx) {
|
|
3736
|
+
if (name.type === "JSXIdentifier") {
|
|
3737
|
+
return { tag: name.name, component: name.name[0] !== name.name[0].toLowerCase() };
|
|
3738
|
+
}
|
|
3739
|
+
if (name.type === "JSXMemberExpression") return { tag: ctx.code(name), component: true };
|
|
3740
|
+
if (name.type === "JSXNamespacedName") {
|
|
3741
|
+
return { tag: `${name.namespace.name}:${name.name.name}`, component: false };
|
|
3742
|
+
}
|
|
3743
|
+
return { tag: "div", component: false };
|
|
3744
|
+
}
|
|
3745
|
+
function attrName(name) {
|
|
3746
|
+
if (name.type === "JSXIdentifier") return name.name === "class" ? "className" : name.name;
|
|
3747
|
+
if (name.type === "JSXNamespacedName") return `${name.namespace.name}:${name.name.name}`;
|
|
3748
|
+
return "unknown";
|
|
3749
|
+
}
|
|
3750
|
+
function buildAttr(attr, ctx) {
|
|
3751
|
+
const name = attrName(attr.name);
|
|
3752
|
+
const isEvent = EVENT_RE.test(name);
|
|
3753
|
+
const isHandler = isEvent || name.startsWith("on:") || name === "ref";
|
|
3754
|
+
const kind = isEvent ? "event" : "attr";
|
|
3755
|
+
const base = { name, kind };
|
|
3756
|
+
if (isEvent) {
|
|
3757
|
+
const evt = name.slice(2).toLowerCase();
|
|
3758
|
+
base.event = { name: evt, delegated: DELEGATED2.has(evt) };
|
|
3759
|
+
}
|
|
3760
|
+
const v = attr.value;
|
|
3761
|
+
if (v == null) {
|
|
3762
|
+
base.literal = true;
|
|
3763
|
+
base.at = posOf(attr, ctx);
|
|
3764
|
+
return base;
|
|
3765
|
+
}
|
|
3766
|
+
if (isString(v)) {
|
|
3767
|
+
base.literal = literalOf(v);
|
|
3768
|
+
base.at = posOf(v, ctx);
|
|
3769
|
+
return base;
|
|
3770
|
+
}
|
|
3771
|
+
if (v.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression") {
|
|
3772
|
+
const expr = v.expression;
|
|
3773
|
+
const literal = literalOf(expr);
|
|
3774
|
+
if (literal !== void 0) {
|
|
3775
|
+
base.literal = literal;
|
|
3776
|
+
base.at = posOf(expr, ctx);
|
|
3777
|
+
return base;
|
|
3778
|
+
}
|
|
3779
|
+
base.expr = ctx.code(expr);
|
|
3780
|
+
base.reactive = isHandler ? false : isReactive(expr);
|
|
3781
|
+
base.at = posOf(expr, ctx);
|
|
3782
|
+
if (expr.type === "JSXElement" || expr.type === "JSXFragment") base.jsxElement = true;
|
|
3783
|
+
return base;
|
|
3784
|
+
}
|
|
3785
|
+
base.literal = true;
|
|
3786
|
+
return base;
|
|
3787
|
+
}
|
|
3788
|
+
function attrExprCode(attr, ctx) {
|
|
3789
|
+
const v = attr.value;
|
|
3790
|
+
if (v == null) return null;
|
|
3791
|
+
if (isString(v)) return JSON.stringify(literalOf(v));
|
|
3792
|
+
if (v.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression") {
|
|
3793
|
+
return ctx.code(v.expression);
|
|
3794
|
+
}
|
|
3795
|
+
return null;
|
|
3796
|
+
}
|
|
3797
|
+
function buildProps(attrs, ctx, element = false) {
|
|
3798
|
+
const props = [];
|
|
3799
|
+
const usePairs = [];
|
|
3800
|
+
const classEntries = [];
|
|
3801
|
+
const styleEntries = [];
|
|
3802
|
+
let styleAt;
|
|
3803
|
+
for (const a of attrs) {
|
|
3804
|
+
if (a.type === "JSXSpreadAttribute") {
|
|
3805
|
+
props.push({ name: "", kind: "spread", expr: ctx.code(a.argument) });
|
|
3806
|
+
continue;
|
|
3807
|
+
}
|
|
3808
|
+
if (a.type !== "JSXAttribute") continue;
|
|
3809
|
+
if (isLoadDirective(attrName(a.name))) continue;
|
|
3810
|
+
const ns = a.name.type === "JSXNamespacedName" ? a.name.namespace.name : null;
|
|
3811
|
+
if (ns === "use") {
|
|
3812
|
+
const dir = a.name.name.name;
|
|
3813
|
+
ctx.used.add(dir);
|
|
3814
|
+
const opts = attrExprCode(a, ctx);
|
|
3815
|
+
usePairs.push(opts != null ? `[${dir}, () => ${paren(opts, "arrowBody")}]` : `[${dir}]`);
|
|
3816
|
+
continue;
|
|
3817
|
+
}
|
|
3818
|
+
if (element && (ns === "class" || ns === "style")) {
|
|
3819
|
+
const key = JSON.stringify(a.name.name.name);
|
|
3820
|
+
const v = a.value;
|
|
3821
|
+
let value;
|
|
3822
|
+
if (v == null) value = "true";
|
|
3823
|
+
else if (isString(v)) value = JSON.stringify(literalOf(v));
|
|
3824
|
+
else if (v.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression") {
|
|
3825
|
+
value = keyValue(v.expression, ctx);
|
|
3826
|
+
if (ns === "style") styleAt ??= posOf(v.expression, ctx);
|
|
3827
|
+
} else continue;
|
|
3828
|
+
(ns === "class" ? classEntries : styleEntries).push(`${key}: ${value}`);
|
|
3829
|
+
continue;
|
|
3830
|
+
}
|
|
3831
|
+
if (element && a.name.type === "JSXIdentifier" && a.name.name === "style" && a.value?.type === "JSXExpressionContainer") {
|
|
3832
|
+
const entries = objectEntries(a.value.expression, ctx);
|
|
3833
|
+
if (entries) {
|
|
3834
|
+
styleEntries.unshift(...entries);
|
|
3835
|
+
styleAt = posOf(a.value.expression, ctx);
|
|
3836
|
+
continue;
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
if (ns === "oncapture") {
|
|
3840
|
+
const evt = a.name.name.name.toLowerCase();
|
|
3841
|
+
const h = attrExprCode(a, ctx) ?? "undefined";
|
|
3842
|
+
props.push({ name: "on:" + evt, kind: "attr", expr: `[${h}, { capture: true }]` });
|
|
3843
|
+
continue;
|
|
3844
|
+
}
|
|
3845
|
+
props.push(buildAttr(a, ctx));
|
|
3846
|
+
}
|
|
3847
|
+
if (classEntries.length > 0) props.push({ name: "classList", kind: "attr", expr: `{ ${classEntries.join(", ")} }`, reactive: false });
|
|
3848
|
+
if (styleEntries.length > 0) {
|
|
3849
|
+
const entries = `{ ${styleEntries.join(", ")} }`;
|
|
3850
|
+
const base = props.findIndex((p) => p.name === "style" && p.kind === "attr");
|
|
3851
|
+
if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: false, ...styleAt ? { at: styleAt } : {} });
|
|
3852
|
+
else {
|
|
3853
|
+
const prop = props[base];
|
|
3854
|
+
const value = prop.literal !== void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
|
|
3855
|
+
props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
if (usePairs.length > 0) props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
|
|
3859
|
+
return props;
|
|
3860
|
+
}
|
|
3861
|
+
function keyValue(expr, ctx) {
|
|
3862
|
+
const code = ctx.code(expr);
|
|
3863
|
+
if (!isReactive(expr)) return code;
|
|
3864
|
+
const accessor = `() => ${paren(code, "arrowBody")}`;
|
|
3865
|
+
const at = posOf(expr, ctx);
|
|
3866
|
+
return at ? markHole(accessor, at.line, at.column) : accessor;
|
|
3867
|
+
}
|
|
3868
|
+
function objectEntries(expr, ctx) {
|
|
3869
|
+
if (expr?.type !== "ObjectExpression") return null;
|
|
3870
|
+
const entries = [];
|
|
3871
|
+
for (const p of expr.properties) {
|
|
3872
|
+
if (p.type !== "ObjectProperty") return null;
|
|
3873
|
+
const key = p.computed ? `[${ctx.code(p.key)}]` : p.key.type === "Identifier" ? JSON.stringify(p.key.name) : JSON.stringify(String(p.key.value));
|
|
3874
|
+
entries.push(`${key}: ${keyValue(p.value, ctx)}`);
|
|
3875
|
+
}
|
|
3876
|
+
return entries;
|
|
3877
|
+
}
|
|
3878
|
+
function buildChildren(children, ctx) {
|
|
3879
|
+
const out = [];
|
|
3880
|
+
for (let i = 0; i < children.length; i++) {
|
|
3881
|
+
const child = children[i];
|
|
3882
|
+
if (directive(child, "if")) {
|
|
3883
|
+
let next = i + 1;
|
|
3884
|
+
while (next < children.length && children[next].type === "JSXText" && !cleanTemplateText(children[next].value)) next++;
|
|
3885
|
+
const fallback = directive(children[next], "else") ? children[next] : null;
|
|
3886
|
+
out.push(buildIf(child, fallback, ctx));
|
|
3887
|
+
if (fallback) i = next;
|
|
3888
|
+
continue;
|
|
3889
|
+
}
|
|
3890
|
+
if (child.type === "JSXText") {
|
|
3891
|
+
const text = cleanTemplateText(child.value);
|
|
3892
|
+
if (text) out.push({ kind: "text", value: text });
|
|
3893
|
+
} else if (child.type === "JSXExpressionContainer") {
|
|
3894
|
+
if (child.expression?.type !== "JSXEmptyExpression") {
|
|
3895
|
+
const expr = child.expression;
|
|
3896
|
+
const reactive = isReactive(expr);
|
|
3897
|
+
out.push({
|
|
3898
|
+
kind: "expr",
|
|
3899
|
+
code: ctx.code(expr),
|
|
3900
|
+
reactive,
|
|
3901
|
+
...reactive ? { at: posOf(expr, ctx) } : {}
|
|
3902
|
+
});
|
|
3903
|
+
}
|
|
3904
|
+
} else if (child.type === "JSXElement" || child.type === "JSXFragment") {
|
|
3905
|
+
if (ctx.dropStyles?.has(child.start)) continue;
|
|
3906
|
+
out.push(buildNode(child, ctx));
|
|
3907
|
+
} else if (child.type === "JSXSpreadChild") {
|
|
3908
|
+
out.push({ kind: "expr", code: ctx.code(child.expression), reactive: false });
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
return out;
|
|
3912
|
+
}
|
|
3913
|
+
function readLoad(attrs) {
|
|
3914
|
+
for (const a of attrs) {
|
|
3915
|
+
if (a.type !== "JSXAttribute") continue;
|
|
3916
|
+
const name = attrName(a.name);
|
|
3917
|
+
if (!isLoadDirective(name)) continue;
|
|
3918
|
+
if (a.value && !isString(a.value)) {
|
|
3919
|
+
throw new LoadDirectiveError(
|
|
3920
|
+
`'${name}' needs a literal value, not an expression — the strategy is compile-time.`
|
|
3921
|
+
);
|
|
3922
|
+
}
|
|
3923
|
+
return parseLoadDirective(name, a.value ? literalOf(a.value) : null);
|
|
3924
|
+
}
|
|
3925
|
+
return void 0;
|
|
3926
|
+
}
|
|
3927
|
+
function buildIf(node, fallback, ctx) {
|
|
3928
|
+
const cond = directiveExpr(directive(node, "if"));
|
|
3929
|
+
const props = [
|
|
3930
|
+
cond ? { name: "when", kind: "attr", expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) } : { name: "when", kind: "attr", literal: true }
|
|
3931
|
+
];
|
|
3932
|
+
if (fallback) {
|
|
3933
|
+
props.push({ name: "fallback", kind: "attr", expr: emitIR(buildElement(fallback, ctx, ["else"]), ctx), jsxElement: true });
|
|
3934
|
+
}
|
|
3935
|
+
return { kind: "component", name: "Show", props, children: [buildElement(node, ctx, ["if"])] };
|
|
3936
|
+
}
|
|
3937
|
+
function buildEach(node, ctx) {
|
|
3938
|
+
const attr = directive(node, "each");
|
|
3939
|
+
if (!attr) return null;
|
|
3940
|
+
const list = directiveExpr(attr);
|
|
3941
|
+
const props = [
|
|
3942
|
+
list ? { name: "each", kind: "attr", expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) } : { name: "each", kind: "attr", expr: "[]" }
|
|
3943
|
+
];
|
|
3944
|
+
const key = directive(node, "key");
|
|
3945
|
+
if (key) {
|
|
3946
|
+
const keyExpr = directiveExpr(key);
|
|
3947
|
+
const by = isString(key.value) ? `(item) => item[${JSON.stringify(literalOf(key.value))}]` : keyExpr ? ctx.code(keyExpr) : void 0;
|
|
3948
|
+
if (by) props.push({ name: "by", kind: "attr", expr: by });
|
|
3949
|
+
}
|
|
3950
|
+
const content = node.children.filter((c) => !(c.type === "JSXText" && !cleanTemplateText(c.value)));
|
|
3951
|
+
const only = content.length === 1 && content[0].type === "JSXExpressionContainer" ? content[0].expression : null;
|
|
3952
|
+
let render;
|
|
3953
|
+
if (only && (only.type === "ArrowFunctionExpression" || only.type === "FunctionExpression")) {
|
|
3954
|
+
const fn = ctx.code(only);
|
|
3955
|
+
const live = only.type === "ArrowFunctionExpression" && only.body.type !== "BlockStatement" && isReactive(only.body);
|
|
3956
|
+
render = live ? `(...args) => () => (${fn})(...args)` : fn;
|
|
3957
|
+
} else {
|
|
3958
|
+
const built = buildChildren(node.children, ctx);
|
|
3959
|
+
const ir = built.length === 1 ? built[0] : { kind: "fragment", children: built };
|
|
3960
|
+
render = `() => ${paren(emitIR(ir, ctx), "arrowBody")}`;
|
|
3961
|
+
}
|
|
3962
|
+
return { kind: "component", name: "For", props, children: [{ kind: "expr", code: render, reactive: false }] };
|
|
3963
|
+
}
|
|
3964
|
+
function buildElement(node, ctx, handled) {
|
|
3965
|
+
const skip = new Set(handled);
|
|
3966
|
+
const directives = /* @__PURE__ */ new Set(["if", "else", "each", ...directive(node, "each") ? ["key"] : []]);
|
|
3967
|
+
const attributes = node.openingElement.attributes.filter(
|
|
3968
|
+
(a) => !(a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && (skip.has(a.name.name) || directives.has(a.name.name)))
|
|
3969
|
+
);
|
|
3970
|
+
const { tag } = tagInfo(node.openingElement.name, ctx);
|
|
3971
|
+
const each = buildEach(node, ctx);
|
|
3972
|
+
const children = each ? [each] : buildChildren(node.children, ctx);
|
|
3973
|
+
if (tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
|
|
3974
|
+
const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
|
|
3975
|
+
const props = buildProps(attributes, ctx, true);
|
|
3976
|
+
const scope = ctx.scopes?.find((s) => node.start >= s.start && node.end <= s.end);
|
|
3977
|
+
if (scope) props.unshift({ name: "data-fx-s", kind: "attr", literal: scope.value });
|
|
3978
|
+
return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
|
|
3979
|
+
}
|
|
3980
|
+
function buildNode(node, ctx) {
|
|
3981
|
+
if (node.type === "JSXFragment") {
|
|
3982
|
+
return { kind: "fragment", children: buildChildren(node.children, ctx) };
|
|
3983
|
+
}
|
|
3984
|
+
if (directive(node, "if")) return buildIf(node, null, ctx);
|
|
3985
|
+
if (ctx.dropStyles?.has(node.start)) return { kind: "fragment", children: [] };
|
|
3986
|
+
const { tag, component } = tagInfo(node.openingElement.name, ctx);
|
|
3987
|
+
if (!component) return buildElement(node, ctx, []);
|
|
3988
|
+
const props = buildProps(node.openingElement.attributes, ctx);
|
|
3989
|
+
const children = buildChildren(node.children, ctx);
|
|
3990
|
+
const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
|
|
3991
|
+
const load = readLoad(node.openingElement.attributes);
|
|
3992
|
+
return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
|
|
3993
|
+
}
|
|
3994
|
+
function buildJsxIR(node, ctx) {
|
|
3995
|
+
const ir = buildNode(node, ctx);
|
|
3996
|
+
analyzeStatic(ir);
|
|
3997
|
+
return ir;
|
|
3998
|
+
}
|
|
3999
|
+
|
|
4000
|
+
// src/transform/bindings.ts
|
|
4001
|
+
function patternNames2(node, out) {
|
|
4002
|
+
if (!node) return;
|
|
4003
|
+
switch (node.type) {
|
|
4004
|
+
case "Identifier":
|
|
4005
|
+
out.add(node.name);
|
|
4006
|
+
return;
|
|
4007
|
+
case "ObjectPattern":
|
|
4008
|
+
for (const p of node.properties) {
|
|
4009
|
+
if (p.type === "RestElement") patternNames2(p.argument, out);
|
|
4010
|
+
else patternNames2(p.value, out);
|
|
4011
|
+
}
|
|
4012
|
+
return;
|
|
4013
|
+
case "ArrayPattern":
|
|
4014
|
+
for (const e of node.elements) patternNames2(e, out);
|
|
4015
|
+
return;
|
|
4016
|
+
case "AssignmentPattern":
|
|
4017
|
+
patternNames2(node.left, out);
|
|
4018
|
+
return;
|
|
4019
|
+
case "RestElement":
|
|
4020
|
+
patternNames2(node.argument, out);
|
|
4021
|
+
return;
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
function declared(node, out) {
|
|
4025
|
+
switch (node.type) {
|
|
4026
|
+
case "ImportDeclaration":
|
|
4027
|
+
for (const s of node.specifiers) patternNames2(s.local, out);
|
|
4028
|
+
return;
|
|
4029
|
+
case "VariableDeclaration":
|
|
4030
|
+
for (const d of node.declarations) patternNames2(d.id, out);
|
|
4031
|
+
return;
|
|
4032
|
+
case "FunctionDeclaration":
|
|
4033
|
+
case "ClassDeclaration":
|
|
4034
|
+
patternNames2(node.id, out);
|
|
4035
|
+
return;
|
|
4036
|
+
case "ExportNamedDeclaration":
|
|
4037
|
+
case "ExportDefaultDeclaration":
|
|
4038
|
+
if (node.declaration) declared(node.declaration, out);
|
|
4039
|
+
return;
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
function moduleBindings(program) {
|
|
4043
|
+
const names = /* @__PURE__ */ new Set();
|
|
4044
|
+
for (const statement of program.body) declared(statement, names);
|
|
4045
|
+
return names;
|
|
4046
|
+
}
|
|
4047
|
+
|
|
4048
|
+
// src/transform/props.ts
|
|
4049
|
+
import { parse } from "@babel/parser";
|
|
4050
|
+
|
|
4051
|
+
// src/analyze/props-destructure.ts
|
|
4052
|
+
function patternNames3(node, out) {
|
|
4053
|
+
if (!node) return;
|
|
4054
|
+
switch (node.type) {
|
|
4055
|
+
case "Identifier":
|
|
4056
|
+
out.add(node.name);
|
|
4057
|
+
return;
|
|
4058
|
+
case "ObjectPattern":
|
|
4059
|
+
for (const p of node.properties) {
|
|
4060
|
+
if (p.type === "RestElement") patternNames3(p.argument, out);
|
|
4061
|
+
else patternNames3(p.value, out);
|
|
4062
|
+
}
|
|
4063
|
+
return;
|
|
4064
|
+
case "ArrayPattern":
|
|
4065
|
+
for (const e of node.elements) patternNames3(e, out);
|
|
4066
|
+
return;
|
|
4067
|
+
case "AssignmentPattern":
|
|
4068
|
+
patternNames3(node.left, out);
|
|
4069
|
+
return;
|
|
4070
|
+
case "RestElement":
|
|
4071
|
+
patternNames3(node.argument, out);
|
|
4072
|
+
return;
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
function isSafeDefault(node) {
|
|
4076
|
+
switch (node.type) {
|
|
4077
|
+
case "StringLiteral":
|
|
4078
|
+
case "NumericLiteral":
|
|
4079
|
+
case "BooleanLiteral":
|
|
4080
|
+
case "NullLiteral":
|
|
4081
|
+
case "BigIntLiteral":
|
|
4082
|
+
case "RegExpLiteral":
|
|
4083
|
+
case "Identifier":
|
|
4084
|
+
return true;
|
|
4085
|
+
// ESTree spells every literal as `Literal`; both shapes reach this analysis.
|
|
4086
|
+
case "Literal":
|
|
4087
|
+
return true;
|
|
4088
|
+
case "TemplateLiteral":
|
|
4089
|
+
return node.expressions.every(isSafeDefault);
|
|
4090
|
+
case "UnaryExpression":
|
|
4091
|
+
return isSafeDefault(node.argument);
|
|
4092
|
+
case "MemberExpression":
|
|
4093
|
+
return false;
|
|
4094
|
+
default:
|
|
4095
|
+
return false;
|
|
4096
|
+
}
|
|
4097
|
+
}
|
|
4098
|
+
function walk4(root, visit) {
|
|
4099
|
+
if (!root || typeof root !== "object") return;
|
|
4100
|
+
visit(root);
|
|
4101
|
+
for (const key of Object.keys(root)) {
|
|
4102
|
+
if (key === "loc" || key === "range" || key === "leadingComments" || key === "trailingComments") continue;
|
|
4103
|
+
const value = root[key];
|
|
4104
|
+
if (Array.isArray(value)) {
|
|
4105
|
+
for (const item of value) if (item && typeof item === "object") walk4(item, visit);
|
|
4106
|
+
} else if (value && typeof value === "object" && typeof value.type === "string") {
|
|
4107
|
+
walk4(value, visit);
|
|
4108
|
+
}
|
|
4109
|
+
}
|
|
4110
|
+
}
|
|
4111
|
+
function reassignedNames(body) {
|
|
4112
|
+
const written = /* @__PURE__ */ new Set();
|
|
4113
|
+
walk4(body, (node) => {
|
|
4114
|
+
if (node.type === "AssignmentExpression") patternNames3(node.left, written);
|
|
4115
|
+
else if (node.type === "UpdateExpression") {
|
|
4116
|
+
const arg = node.argument;
|
|
4117
|
+
if (arg?.type === "Identifier") written.add(arg.name);
|
|
4118
|
+
}
|
|
4119
|
+
});
|
|
4120
|
+
return written;
|
|
4121
|
+
}
|
|
4122
|
+
function shadowedNames(body, candidates) {
|
|
4123
|
+
const shadowed = /* @__PURE__ */ new Set();
|
|
4124
|
+
const note = (node) => {
|
|
4125
|
+
const names = /* @__PURE__ */ new Set();
|
|
4126
|
+
patternNames3(node, names);
|
|
4127
|
+
for (const n2 of names) if (candidates.has(n2)) shadowed.add(n2);
|
|
4128
|
+
};
|
|
4129
|
+
walk4(body, (node) => {
|
|
4130
|
+
switch (node.type) {
|
|
4131
|
+
case "VariableDeclarator":
|
|
4132
|
+
note(node.id);
|
|
4133
|
+
return;
|
|
4134
|
+
case "FunctionDeclaration":
|
|
4135
|
+
case "FunctionExpression":
|
|
4136
|
+
case "ArrowFunctionExpression":
|
|
4137
|
+
note(node.id);
|
|
4138
|
+
for (const p of node.params ?? []) note(p);
|
|
4139
|
+
return;
|
|
4140
|
+
case "CatchClause":
|
|
4141
|
+
note(node.param);
|
|
4142
|
+
return;
|
|
4143
|
+
case "ClassDeclaration":
|
|
4144
|
+
case "ClassExpression":
|
|
4145
|
+
note(node.id);
|
|
4146
|
+
return;
|
|
4147
|
+
}
|
|
4148
|
+
});
|
|
4149
|
+
return shadowed;
|
|
4150
|
+
}
|
|
4151
|
+
function collect(pattern, path, plan) {
|
|
4152
|
+
for (const property of pattern.properties ?? []) {
|
|
4153
|
+
if (property.type === "RestElement") {
|
|
4154
|
+
const argument = property.argument;
|
|
4155
|
+
if (argument?.type !== "Identifier" || path.length > 0) {
|
|
4156
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
4157
|
+
patternNames3(argument, names2);
|
|
4158
|
+
for (const name of names2) plan.bails.push({ name, reason: "rest" });
|
|
4159
|
+
continue;
|
|
4160
|
+
}
|
|
4161
|
+
plan.rest = { name: argument.name, keys: [] };
|
|
4162
|
+
continue;
|
|
4163
|
+
}
|
|
4164
|
+
if (property.computed) {
|
|
4165
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
4166
|
+
patternNames3(property.value, names2);
|
|
4167
|
+
for (const name of names2) plan.bails.push({ name, reason: "computed" });
|
|
4168
|
+
continue;
|
|
4169
|
+
}
|
|
4170
|
+
const key = property.key;
|
|
4171
|
+
const propertyName = key.type === "Identifier" ? key.name : key.value;
|
|
4172
|
+
let value = property.value;
|
|
4173
|
+
let fallback;
|
|
4174
|
+
if (value.type === "AssignmentPattern") {
|
|
4175
|
+
fallback = value.right;
|
|
4176
|
+
value = value.left;
|
|
4177
|
+
}
|
|
4178
|
+
const here = [...path, propertyName];
|
|
4179
|
+
if (value.type === "Identifier") {
|
|
4180
|
+
if (fallback && !isSafeDefault(fallback)) {
|
|
4181
|
+
plan.bails.push({ name: value.name, reason: "unsafe-default" });
|
|
4182
|
+
continue;
|
|
4183
|
+
}
|
|
4184
|
+
plan.reads.push({ name: value.name, path: here, ...fallback ? { fallback } : {} });
|
|
4185
|
+
continue;
|
|
4186
|
+
}
|
|
4187
|
+
if (value.type === "ObjectPattern") {
|
|
4188
|
+
if (fallback) {
|
|
4189
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
4190
|
+
patternNames3(value, names2);
|
|
4191
|
+
for (const name of names2) plan.bails.push({ name, reason: "unsafe-default" });
|
|
4192
|
+
continue;
|
|
4193
|
+
}
|
|
4194
|
+
collect(value, here, plan);
|
|
4195
|
+
continue;
|
|
4196
|
+
}
|
|
4197
|
+
const names = /* @__PURE__ */ new Set();
|
|
4198
|
+
patternNames3(value, names);
|
|
4199
|
+
for (const name of names) plan.bails.push({ name, reason: "computed" });
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
function planPropsDestructure(pattern, body) {
|
|
4203
|
+
const plan = { reads: [], bails: [] };
|
|
4204
|
+
if (pattern?.type !== "ObjectPattern") return plan;
|
|
4205
|
+
collect(pattern, [], plan);
|
|
4206
|
+
if (plan.rest) {
|
|
4207
|
+
if (body?.type !== "BlockStatement") {
|
|
4208
|
+
plan.bails.push({ name: plan.rest.name, reason: "rest" });
|
|
4209
|
+
delete plan.rest;
|
|
4210
|
+
} else {
|
|
4211
|
+
plan.rest.keys = (pattern.properties ?? []).filter((p) => p.type !== "RestElement" && !p.computed).map((p) => {
|
|
4212
|
+
const key = p.key;
|
|
4213
|
+
return key.type === "Identifier" ? key.name : key.value;
|
|
4214
|
+
});
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4217
|
+
if (plan.reads.length === 0 && !plan.rest) return plan;
|
|
4218
|
+
const candidates = new Set(plan.reads.map((r) => r.name));
|
|
4219
|
+
if (plan.rest) candidates.add(plan.rest.name);
|
|
4220
|
+
const written = reassignedNames(body);
|
|
4221
|
+
const shadowed = shadowedNames(body, candidates);
|
|
4222
|
+
const kept = [];
|
|
4223
|
+
for (const read of plan.reads) {
|
|
4224
|
+
if (written.has(read.name)) plan.bails.push({ name: read.name, reason: "reassigned" });
|
|
4225
|
+
else if (shadowed.has(read.name)) plan.bails.push({ name: read.name, reason: "shadowed" });
|
|
4226
|
+
else kept.push(read);
|
|
4227
|
+
}
|
|
4228
|
+
plan.reads = kept;
|
|
4229
|
+
if (plan.rest && written.has(plan.rest.name)) {
|
|
4230
|
+
plan.bails.push({ name: plan.rest.name, reason: "reassigned" });
|
|
4231
|
+
delete plan.rest;
|
|
4232
|
+
} else if (plan.rest && shadowed.has(plan.rest.name)) {
|
|
4233
|
+
plan.bails.push({ name: plan.rest.name, reason: "shadowed" });
|
|
4234
|
+
delete plan.rest;
|
|
4235
|
+
}
|
|
4236
|
+
return plan;
|
|
4237
|
+
}
|
|
4238
|
+
function explainBail(reason) {
|
|
4239
|
+
switch (reason) {
|
|
4240
|
+
case "rest":
|
|
4241
|
+
return "this rest element cannot be served by splitProps, and copying the props into a plain object would lose the getters";
|
|
4242
|
+
case "computed":
|
|
4243
|
+
return "the property is not known until it runs";
|
|
4244
|
+
case "reassigned":
|
|
4245
|
+
return "the binding is assigned to, and props are read-only";
|
|
4246
|
+
case "shadowed":
|
|
4247
|
+
return "an inner scope binds the same name";
|
|
4248
|
+
case "unsafe-default":
|
|
4249
|
+
return "the default would have to run again on every read";
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
|
|
4253
|
+
// src/transform/props.ts
|
|
4254
|
+
function walk5(root, visit, parent = null) {
|
|
4255
|
+
if (!root || typeof root !== "object" || typeof root.type !== "string") return;
|
|
4256
|
+
if (root.type.startsWith("TS")) return;
|
|
4257
|
+
if (visit(root, parent) === false) return;
|
|
4258
|
+
for (const key of Object.keys(root)) {
|
|
4259
|
+
if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
|
|
4260
|
+
const value = root[key];
|
|
4261
|
+
if (Array.isArray(value)) {
|
|
4262
|
+
for (const item of value) walk5(item, visit, root);
|
|
4263
|
+
} else if (value && typeof value === "object") {
|
|
4264
|
+
walk5(value, visit, root);
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
}
|
|
4268
|
+
function isComponentName(name) {
|
|
4269
|
+
return !!name && name[0] >= "A" && name[0] <= "Z";
|
|
4270
|
+
}
|
|
4271
|
+
function componentFunctions(program) {
|
|
4272
|
+
const found = [];
|
|
4273
|
+
walk5(program, (node) => {
|
|
4274
|
+
if (node.type === "FunctionDeclaration" && isComponentName(node.id?.name)) {
|
|
4275
|
+
found.push(node);
|
|
4276
|
+
return;
|
|
4277
|
+
}
|
|
4278
|
+
if (node.type === "VariableDeclarator" && isComponentName(node.id?.name)) {
|
|
4279
|
+
const init = node.init;
|
|
4280
|
+
if (init && (init.type === "ArrowFunctionExpression" || init.type === "FunctionExpression")) found.push(init);
|
|
4281
|
+
}
|
|
4282
|
+
});
|
|
4283
|
+
return found;
|
|
4284
|
+
}
|
|
4285
|
+
function usedNames(fn) {
|
|
4286
|
+
const names = /* @__PURE__ */ new Set();
|
|
4287
|
+
walk5(fn, (node) => {
|
|
4288
|
+
if (node.type === "Identifier") names.add(node.name);
|
|
4289
|
+
});
|
|
4290
|
+
return names;
|
|
4291
|
+
}
|
|
4292
|
+
function isReferencePosition(node, parent) {
|
|
4293
|
+
if (!parent) return true;
|
|
4294
|
+
switch (parent.type) {
|
|
4295
|
+
case "MemberExpression":
|
|
4296
|
+
case "OptionalMemberExpression":
|
|
4297
|
+
return !(parent.property === node && !parent.computed);
|
|
4298
|
+
case "ObjectProperty":
|
|
4299
|
+
case "ObjectMethod":
|
|
4300
|
+
case "ClassProperty":
|
|
4301
|
+
case "ClassMethod":
|
|
4302
|
+
return !(parent.key === node && !parent.computed);
|
|
4303
|
+
case "LabeledStatement":
|
|
4304
|
+
case "BreakStatement":
|
|
4305
|
+
case "ContinueStatement":
|
|
4306
|
+
return parent.label !== node;
|
|
4307
|
+
case "ImportSpecifier":
|
|
4308
|
+
case "ExportSpecifier":
|
|
4309
|
+
return false;
|
|
4310
|
+
default:
|
|
4311
|
+
return true;
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
4314
|
+
function collectPropsEdits(program, code, options = {}) {
|
|
4315
|
+
const edits = [];
|
|
4316
|
+
const diagnostics = [];
|
|
4317
|
+
const used = /* @__PURE__ */ new Set();
|
|
4318
|
+
for (const fn of componentFunctions(program)) {
|
|
4319
|
+
const pattern = fn.params?.[0];
|
|
4320
|
+
if (pattern?.type !== "ObjectPattern") continue;
|
|
4321
|
+
const plan = planPropsDestructure(pattern, fn.body);
|
|
4322
|
+
for (const b of plan.bails) {
|
|
4323
|
+
diagnostics.push({ name: b.name, reason: b.reason, message: explainBail(b.reason), start: pattern.start });
|
|
4324
|
+
}
|
|
4325
|
+
if (plan.bails.length > 0) continue;
|
|
4326
|
+
if (plan.reads.length === 0 && !plan.rest) continue;
|
|
4327
|
+
const taken = usedNames(fn);
|
|
4328
|
+
let parameter = options.parameterName ?? "props";
|
|
4329
|
+
while (taken.has(parameter)) parameter = `_${parameter}`;
|
|
4330
|
+
const replacement = /* @__PURE__ */ new Map();
|
|
4331
|
+
for (const read of plan.reads) {
|
|
4332
|
+
const access = `${parameter}.${read.path.join(".")}`;
|
|
4333
|
+
const fallback = read.fallback;
|
|
4334
|
+
replacement.set(
|
|
4335
|
+
read.name,
|
|
4336
|
+
fallback ? `(${access} === undefined ? ${code.slice(fallback.start, fallback.end)} : ${access})` : access
|
|
4337
|
+
);
|
|
4338
|
+
}
|
|
4339
|
+
const annotation = pattern.typeAnnotation;
|
|
4340
|
+
edits.push({ start: pattern.start, end: annotation?.start ?? pattern.end, code: parameter });
|
|
4341
|
+
if (plan.rest) {
|
|
4342
|
+
const keys = plan.rest.keys.map((k) => JSON.stringify(k)).join(", ");
|
|
4343
|
+
const body = fn.body;
|
|
4344
|
+
edits.push({
|
|
4345
|
+
start: body.start + 1,
|
|
4346
|
+
end: body.start + 1,
|
|
4347
|
+
code: `
|
|
4348
|
+
const [, ${plan.rest.name}] = splitProps(${parameter}, [${keys}]);`
|
|
4349
|
+
});
|
|
4350
|
+
used.add("splitProps");
|
|
4351
|
+
}
|
|
4352
|
+
const matches = [];
|
|
4353
|
+
walk5(fn.body, (node, parent) => {
|
|
4354
|
+
if (node.type !== "Identifier") return void 0;
|
|
4355
|
+
const text = replacement.get(node.name);
|
|
4356
|
+
if (!text) return void 0;
|
|
4357
|
+
const shorthand = parent?.type === "ObjectProperty" && parent.shorthand && parent.value === node;
|
|
4358
|
+
if (!shorthand && !isReferencePosition(node, parent)) return void 0;
|
|
4359
|
+
const path = plan.reads.find((r) => r.name === node.name).path;
|
|
4360
|
+
matches.push({ node, parent: shorthand ? parent : null, text, property: path[path.length - 1] });
|
|
4361
|
+
return void 0;
|
|
4362
|
+
});
|
|
4363
|
+
for (const match of matches) {
|
|
4364
|
+
if (match.parent) {
|
|
4365
|
+
edits.push({ start: match.parent.start, end: match.parent.end, code: `${match.node.name}: ${match.text}` });
|
|
4366
|
+
} else {
|
|
4367
|
+
edits.push({ start: match.node.start, end: match.node.end, code: match.text });
|
|
4368
|
+
}
|
|
4369
|
+
asMemberRead(match.node, parameter, match.property);
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
return { edits, diagnostics, used };
|
|
4373
|
+
}
|
|
4374
|
+
function asMemberRead(node, parameter, property) {
|
|
4375
|
+
node.type = "MemberExpression";
|
|
4376
|
+
node.computed = false;
|
|
4377
|
+
node.optional = false;
|
|
4378
|
+
node.object = { type: "Identifier", name: parameter, start: node.start, end: node.start };
|
|
4379
|
+
node.property = { type: "Identifier", name: property, start: node.end, end: node.end };
|
|
4380
|
+
delete node["name"];
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
// src/transform/intrinsics.ts
|
|
4384
|
+
function walk6(root, visit) {
|
|
4385
|
+
if (!root || typeof root !== "object" || typeof root.type !== "string") return;
|
|
4386
|
+
visit(root);
|
|
4387
|
+
for (const key of Object.keys(root)) {
|
|
4388
|
+
if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
|
|
4389
|
+
const value = root[key];
|
|
4390
|
+
if (Array.isArray(value)) for (const item of value) walk6(item, visit);
|
|
4391
|
+
else if (value && typeof value === "object") walk6(value, visit);
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
function collectIntrinsicEdits(program) {
|
|
4395
|
+
const edits = [];
|
|
4396
|
+
const diagnostics = [];
|
|
4397
|
+
const imports = /* @__PURE__ */ new Map();
|
|
4398
|
+
const reported = /* @__PURE__ */ new Set();
|
|
4399
|
+
const { shadowed } = resolveReactiveBindings(program);
|
|
4400
|
+
walk6(program, (node) => {
|
|
4401
|
+
if (node.type !== "CallExpression") return;
|
|
4402
|
+
const callee = node.callee;
|
|
4403
|
+
if (callee?.type !== "Identifier") return;
|
|
4404
|
+
const name = callee.name;
|
|
4405
|
+
if (!isIntrinsicName(name)) return;
|
|
4406
|
+
if (shadowed.has(name)) {
|
|
4407
|
+
if (!reported.has(name)) {
|
|
4408
|
+
reported.add(name);
|
|
4409
|
+
diagnostics.push({
|
|
4410
|
+
name,
|
|
4411
|
+
message: `${name} is reserved for the compiler, and this module binds it. The call keeps your binding's meaning; rename it to use the intrinsic.`,
|
|
4412
|
+
start: callee.start
|
|
4413
|
+
});
|
|
4414
|
+
}
|
|
4415
|
+
return;
|
|
4416
|
+
}
|
|
4417
|
+
const intrinsic = INTRINSICS[name];
|
|
4418
|
+
edits.push({ start: callee.start, end: callee.end, code: intrinsic.export });
|
|
4419
|
+
const forModule = imports.get(intrinsic.module) ?? /* @__PURE__ */ new Set();
|
|
4420
|
+
forModule.add(intrinsic.export);
|
|
4421
|
+
imports.set(intrinsic.module, forModule);
|
|
4422
|
+
});
|
|
4423
|
+
return { edits, diagnostics, imports };
|
|
4424
|
+
}
|
|
4425
|
+
function avoidBindingClashes(program, result, bound) {
|
|
4426
|
+
const importedAsIs = /* @__PURE__ */ new Set();
|
|
4427
|
+
for (const stmt of program.body ?? []) {
|
|
4428
|
+
if (stmt.type !== "ImportDeclaration") continue;
|
|
4429
|
+
const module = stmt.source.value;
|
|
4430
|
+
for (const spec of stmt.specifiers ?? []) {
|
|
4431
|
+
if (spec.type !== "ImportSpecifier") continue;
|
|
4432
|
+
const imported = spec.imported.name ?? spec.imported.value;
|
|
4433
|
+
if (imported === spec.local.name && result.imports.get(module)?.has(imported)) {
|
|
4434
|
+
importedAsIs.add(imported);
|
|
4435
|
+
}
|
|
4436
|
+
}
|
|
4437
|
+
}
|
|
4438
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
4439
|
+
for (const names of result.imports.values()) {
|
|
4440
|
+
for (const name of names) if (bound.has(name) && !importedAsIs.has(name)) aliases.set(name, `__fx_${name}`);
|
|
4441
|
+
}
|
|
4442
|
+
if (!aliases.size) return;
|
|
4443
|
+
for (const edit of result.edits) {
|
|
4444
|
+
const alias = aliases.get(edit.code);
|
|
4445
|
+
if (alias) edit.code = alias;
|
|
4446
|
+
}
|
|
4447
|
+
result.aliases = aliases;
|
|
4448
|
+
}
|
|
4449
|
+
function intrinsicImports(result, bound) {
|
|
4450
|
+
const lines = [];
|
|
4451
|
+
for (const [module, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
|
|
4452
|
+
const wanted = [...names].filter((name) => result.aliases?.has(name) || !bound.has(name)).sort().map((name) => result.aliases?.has(name) ? `${name} as ${result.aliases.get(name)}` : name);
|
|
4453
|
+
if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module)};`);
|
|
4454
|
+
}
|
|
4455
|
+
return lines.length ? `${lines.join("\n")}
|
|
4456
|
+
` : "";
|
|
4457
|
+
}
|
|
4458
|
+
|
|
4459
|
+
// src/transform/templates.ts
|
|
4460
|
+
var CONTROL_FLOW = new Set(DOM_CONTROL_FLOW);
|
|
4461
|
+
var CORE_ONLY = new Set(CORE_CONTROL_FLOW);
|
|
4462
|
+
var ROUTER = new Set(ROUTER_COMPONENTS);
|
|
4463
|
+
var REACTIVE = /* @__PURE__ */ new Set([
|
|
4464
|
+
"createMemo",
|
|
4465
|
+
"createEffect",
|
|
4466
|
+
"createRenderEffect",
|
|
4467
|
+
"createRoot",
|
|
4468
|
+
"createSignal",
|
|
4469
|
+
"onCleanup",
|
|
4470
|
+
"batch",
|
|
4471
|
+
"untrack"
|
|
4472
|
+
]);
|
|
4473
|
+
function walk7(node, visit, parent = null, key = "") {
|
|
4474
|
+
if (!node || typeof node !== "object") return;
|
|
4475
|
+
if (Array.isArray(node)) {
|
|
4476
|
+
for (const child of node) walk7(child, visit, parent, key);
|
|
4477
|
+
return;
|
|
4478
|
+
}
|
|
4479
|
+
if (typeof node.type === "string") visit(node, parent, key);
|
|
4480
|
+
for (const k of Object.keys(node)) {
|
|
4481
|
+
if (k === "loc" || k === "leadingComments" || k === "trailingComments") continue;
|
|
4482
|
+
walk7(node[k], visit, typeof node.type === "string" ? node : parent, k);
|
|
4483
|
+
}
|
|
4484
|
+
}
|
|
4485
|
+
var isJsx = (node) => node.type === "JSXElement" || node.type === "JSXFragment";
|
|
4486
|
+
function isJsxRoot(node, parent, key) {
|
|
4487
|
+
if (!isJsx(node)) return false;
|
|
4488
|
+
return !(parent && isJsx(parent) && key === "children");
|
|
4489
|
+
}
|
|
4490
|
+
function isTemplateTag(node, tags) {
|
|
4491
|
+
return node.type === "TaggedTemplateExpression" && node.tag?.type === "Identifier" && tags.has(node.tag.name);
|
|
4492
|
+
}
|
|
4493
|
+
function outermost(list) {
|
|
4494
|
+
return list.filter(
|
|
4495
|
+
(e) => !list.some(
|
|
4496
|
+
(o) => o !== e && o.start <= e.start && o.end >= e.end && o.end - o.start > e.end - e.start && // An insertion at either edge of the container sits beside it, not inside it, so
|
|
4497
|
+
// it is not something the container's code already folded in. A statement can
|
|
4498
|
+
// start where its callee starts (`$effect(…)`) and a declarator can end where its
|
|
4499
|
+
// JSX ends (`const Row = () => <b/>`).
|
|
4500
|
+
!(e.start === e.end && (e.start === o.start || e.start === o.end))
|
|
4501
|
+
)
|
|
4502
|
+
);
|
|
4503
|
+
}
|
|
4504
|
+
function slice(code, start, end, edits) {
|
|
4505
|
+
const inside = outermost(edits.filter((e) => e.start >= start && e.end <= end)).sort((a, b) => b.start - a.start);
|
|
4506
|
+
let out = code.slice(start, end);
|
|
4507
|
+
for (const e of inside) out = out.slice(0, e.start - start) + e.code + out.slice(e.end - start);
|
|
4508
|
+
return out;
|
|
4509
|
+
}
|
|
4510
|
+
function bindHole(code, expr, edits, keepPosition = false) {
|
|
4511
|
+
const at = keepPosition ? expr.loc?.start : void 0;
|
|
4512
|
+
const hole = {
|
|
4513
|
+
code: slice(code, expr.start, expr.end, edits),
|
|
4514
|
+
reactive: isReactiveShape(shapeOf(expr)),
|
|
4515
|
+
// Where the `${…}` is, so a binding made from it can say so. The source map cannot:
|
|
4516
|
+
// the whole template is one overwrite. Only when source locations were asked for.
|
|
4517
|
+
...at ? { at: { line: at.line, column: at.column } } : {}
|
|
4518
|
+
};
|
|
4519
|
+
if (expr.type === "ArrowFunctionExpression" && expr.body?.type !== "BlockStatement") {
|
|
4520
|
+
hole.arrow = {
|
|
4521
|
+
params: expr.params.map((p) => slice(code, p.start, p.end, edits)),
|
|
4522
|
+
body: slice(code, expr.body.start, expr.body.end, edits),
|
|
4523
|
+
bodyReactive: isReactiveShape(shapeOf(expr.body))
|
|
4524
|
+
};
|
|
4525
|
+
}
|
|
4526
|
+
if (expr.type === "ObjectExpression") hole.object = true;
|
|
4527
|
+
return hole;
|
|
4528
|
+
}
|
|
4529
|
+
function adoptTemplates(code, templates, hoisted) {
|
|
4530
|
+
if (!templates || templates.length === 0) return code;
|
|
4531
|
+
const rename = /* @__PURE__ */ new Map();
|
|
4532
|
+
for (const tpl of templates) {
|
|
4533
|
+
const key = `${tpl.svg ? "svg:" : ""}${tpl.html}`;
|
|
4534
|
+
let name = hoisted.get(key);
|
|
4535
|
+
if (!name) {
|
|
4536
|
+
name = `_fxTmpl$${hoisted.size}`;
|
|
4537
|
+
hoisted.set(key, name);
|
|
4538
|
+
}
|
|
4539
|
+
rename.set(tpl.id, name);
|
|
4540
|
+
}
|
|
4541
|
+
return code.replace(/_tmpl\$\d+/g, (id) => rename.get(id) ?? id);
|
|
4542
|
+
}
|
|
4543
|
+
function collectNeeds(node, out) {
|
|
4544
|
+
if (node.kind === "component" && node.load && !node.source && isDeferred(node.load)) {
|
|
4545
|
+
if (!out.ignoredLoad.has(node.name)) out.ignoredLoad.set(node.name, node.load);
|
|
4546
|
+
}
|
|
4547
|
+
if (node.kind === "component" && node.source) {
|
|
4548
|
+
const src = node.source;
|
|
4549
|
+
if (src.origin === "builtin") out.builtins.add(node.name);
|
|
4550
|
+
else if (isDeferred(src.loading) && !out.resolved.has(node.name)) out.deferred.set(node.name, src);
|
|
4551
|
+
else {
|
|
4552
|
+
out.deferred.delete(node.name);
|
|
4553
|
+
out.resolved.set(node.name, src);
|
|
4554
|
+
}
|
|
4555
|
+
}
|
|
4556
|
+
if ("props" in node && node.props) {
|
|
4557
|
+
for (const p of node.props) {
|
|
4558
|
+
if (p.kind === "event" && p.event?.delegated) out.delegatedEvents.add(p.event.name);
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
if ("children" in node && node.children) for (const c of node.children) collectNeeds(c, out);
|
|
4562
|
+
}
|
|
4563
|
+
function deferrableImport(program, name) {
|
|
4564
|
+
for (const statement of program.body ?? []) {
|
|
4565
|
+
if (statement.type !== "ImportDeclaration") continue;
|
|
4566
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
4567
|
+
if (specifier.local?.name !== name) continue;
|
|
4568
|
+
if (specifier.type === "ImportNamespaceSpecifier") return void 0;
|
|
4569
|
+
const exported = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported?.name ?? specifier.imported?.value;
|
|
4570
|
+
return { module: statement.source.value, export: exported, declaration: statement, specifier };
|
|
4571
|
+
}
|
|
4572
|
+
}
|
|
4573
|
+
return void 0;
|
|
4574
|
+
}
|
|
4575
|
+
function hasNamespaceImport(program, name) {
|
|
4576
|
+
for (const statement of program.body ?? []) {
|
|
4577
|
+
if (statement.type !== "ImportDeclaration") continue;
|
|
4578
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
4579
|
+
if (specifier.type === "ImportNamespaceSpecifier" && specifier.local?.name === name) return true;
|
|
4580
|
+
}
|
|
4581
|
+
}
|
|
4582
|
+
return false;
|
|
4583
|
+
}
|
|
4584
|
+
function usedAsValue(program, name, specifier) {
|
|
4585
|
+
let seen = false;
|
|
4586
|
+
walk7(program, (node) => {
|
|
4587
|
+
if (seen || node.type !== "Identifier" || node.name !== name) return;
|
|
4588
|
+
if (node.start === specifier.local?.start && node.end === specifier.local?.end) return;
|
|
4589
|
+
seen = true;
|
|
4590
|
+
});
|
|
4591
|
+
return seen;
|
|
4592
|
+
}
|
|
4593
|
+
function strategyLiteral(s) {
|
|
4594
|
+
const parts = [`kind: ${JSON.stringify(s.kind)}`];
|
|
4595
|
+
if (s.kind === "visible" && s.rootMargin) parts.push(`rootMargin: ${JSON.stringify(s.rootMargin)}`);
|
|
4596
|
+
if (s.kind === "interaction") parts.push(`events: ${JSON.stringify(s.events)}`);
|
|
4597
|
+
if (s.kind === "media") parts.push(`query: ${JSON.stringify(s.query)}`);
|
|
4598
|
+
return `{ ${parts.join(", ")} }`;
|
|
4599
|
+
}
|
|
4600
|
+
function positionsIn(code) {
|
|
4601
|
+
const starts = [0];
|
|
4602
|
+
for (let i = 0; i < code.length; i++) if (code.charCodeAt(i) === 10) starts.push(i + 1);
|
|
4603
|
+
return (offset) => {
|
|
4604
|
+
let low = 0;
|
|
4605
|
+
let high = starts.length - 1;
|
|
4606
|
+
while (low < high) {
|
|
4607
|
+
const mid = low + high + 1 >> 1;
|
|
4608
|
+
if (starts[mid] <= offset) low = mid;
|
|
4609
|
+
else high = mid - 1;
|
|
4610
|
+
}
|
|
4611
|
+
return { line: low + 1, column: offset - starts[low] };
|
|
4612
|
+
};
|
|
4613
|
+
}
|
|
4614
|
+
function toPieces(node) {
|
|
4615
|
+
const pieces = [];
|
|
4616
|
+
node.quasi.quasis.forEach((q, i) => {
|
|
4617
|
+
pieces.push({ kind: "static", text: q.value.cooked ?? q.value.raw, start: q.start });
|
|
4618
|
+
if (i < node.quasi.expressions.length) {
|
|
4619
|
+
const e = node.quasi.expressions[i];
|
|
4620
|
+
pieces.push({ kind: "hole", index: i, start: e.start, end: e.end });
|
|
4621
|
+
}
|
|
4622
|
+
});
|
|
4623
|
+
return pieces;
|
|
4624
|
+
}
|
|
4625
|
+
function relativeToRoot(id, root) {
|
|
4626
|
+
if (!root) return id;
|
|
4627
|
+
const base = root.endsWith("/") ? root : `${root}/`;
|
|
4628
|
+
return id.startsWith(base) ? id.slice(base.length) : id;
|
|
4629
|
+
}
|
|
4630
|
+
function transformTemplates(code, id, options = {}) {
|
|
4631
|
+
const litTag = options.litTag ?? "html";
|
|
4632
|
+
const format = options.format ?? "both";
|
|
4633
|
+
const wantsLit = format !== "jsx";
|
|
4634
|
+
const wantsJsx = format !== "lit";
|
|
4635
|
+
const mayHaveTemplate = wantsLit && (code.includes(`${litTag}\``) || code.includes("svg`"));
|
|
4636
|
+
const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
|
|
4637
|
+
const wantsSources = options.sourceLocations === true && mayHaveSourceMarks(code);
|
|
4638
|
+
const sourceName = relativeToRoot(id, options.sourceRoot);
|
|
4639
|
+
const wantsStyles = options.styles !== void 0 && (code.includes("<style") || code.includes("css`"));
|
|
4640
|
+
if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources && !wantsStyles) return null;
|
|
4641
|
+
const ast = parse2(code, {
|
|
4642
|
+
sourceType: "module",
|
|
4643
|
+
plugins: ["jsx", "typescript"],
|
|
4644
|
+
errorRecovery: true
|
|
4645
|
+
});
|
|
4646
|
+
const intrinsicTags = options.intrinsics === false ? /* @__PURE__ */ new Map() : tagIntrinsics(moduleBindings(ast.program));
|
|
4647
|
+
const templateTags = /* @__PURE__ */ new Map([[litTag, "html"], ["svg", "svg"]]);
|
|
4648
|
+
for (const [name, tag] of intrinsicTags) if (tag !== "css") templateTags.set(name, tag);
|
|
4649
|
+
const cssTags = [...intrinsicTags].filter(([, tag]) => tag === "css").map(([name]) => name);
|
|
4650
|
+
const found = [];
|
|
4651
|
+
walk7(ast.program, (n2, parent, key) => {
|
|
4652
|
+
if (wantsLit && isTemplateTag(n2, templateTags)) found.push(n2);
|
|
4653
|
+
else if (wantsJsx && isJsxRoot(n2, parent, key)) found.push(n2);
|
|
4654
|
+
});
|
|
4655
|
+
const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
|
|
4656
|
+
const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
|
|
4657
|
+
if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
|
|
4658
|
+
const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
|
|
4659
|
+
const styles = wantsStyles ? collectStyles(ast.program, sourceName, options.styles, { html: templateTags, css: cssTags }, { id, code }) : void 0;
|
|
4660
|
+
const silent = found.length === 0 && props.edits.length === 0 && sources.edits.length === 0 && intrinsics.edits.length === 0 && intrinsics.diagnostics.length === 0 && props.diagnostics.length === 0 && !styles?.edits.length && !styles?.diagnostics.length;
|
|
4661
|
+
if (silent) return null;
|
|
4662
|
+
found.sort((a, b) => b.start - a.start || a.end - b.end);
|
|
4663
|
+
const used = new Set(props.used);
|
|
4664
|
+
const needs = {
|
|
4665
|
+
builtins: /* @__PURE__ */ new Set(),
|
|
4666
|
+
resolved: /* @__PURE__ */ new Map(),
|
|
4667
|
+
deferred: /* @__PURE__ */ new Map(),
|
|
4668
|
+
delegatedEvents: /* @__PURE__ */ new Set(),
|
|
4669
|
+
ignoredLoad: /* @__PURE__ */ new Map(),
|
|
4670
|
+
unresolved: /* @__PURE__ */ new Set(),
|
|
4671
|
+
declared: declaredNames(ast.program)
|
|
4672
|
+
};
|
|
4673
|
+
const hoisted = /* @__PURE__ */ new Map();
|
|
4674
|
+
const edits = [...props.edits, ...intrinsics.edits, ...sources.edits, ...styles?.edits ?? []];
|
|
4675
|
+
for (const node of found) {
|
|
4676
|
+
const nested = found.some(
|
|
4677
|
+
(o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
|
|
4678
|
+
);
|
|
4679
|
+
if (isJsx(node)) {
|
|
4680
|
+
edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName, styles) });
|
|
4681
|
+
continue;
|
|
4682
|
+
}
|
|
4683
|
+
const holes = node.quasi.expressions.map(
|
|
4684
|
+
(e) => bindHole(code, e, edits, options.sourceLocations === true)
|
|
4685
|
+
);
|
|
4686
|
+
const scope = styles?.scopes.find((s) => node.start >= s.start && node.end <= s.end)?.value;
|
|
4687
|
+
const owner = styles?.templateOwners.get(node.start);
|
|
4688
|
+
const templateStyles = options.styles && styles && (scope || owner) ? {
|
|
4689
|
+
options: options.styles,
|
|
4690
|
+
...scope ? { scope } : {},
|
|
4691
|
+
...owner ? { owner } : {},
|
|
4692
|
+
line: node.loc?.start.line ?? 0,
|
|
4693
|
+
column: node.loc?.start.column ?? 0,
|
|
4694
|
+
styles: styles.styles,
|
|
4695
|
+
diagnostics: styles.diagnostics
|
|
4696
|
+
} : void 0;
|
|
4697
|
+
const result = compilePieces(toPieces(node), holes, {
|
|
4698
|
+
...options,
|
|
4699
|
+
...templateStyles ? { templateStyles } : {},
|
|
4700
|
+
hoistTemplates: true,
|
|
4701
|
+
// A tag inside a template gets the same mark a JSX tag does. Without one, the nodes it
|
|
4702
|
+
// makes are the only ones in the module carrying no mark, and they take whichever was
|
|
4703
|
+
// left behind by the last declaration that did.
|
|
4704
|
+
...options.sourceLocations === true ? { sourceFile: sourceName, positionAt: positionsIn(code) } : {},
|
|
4705
|
+
// Same defaults as the plugin, so moving a build over is not a rendering change.
|
|
4706
|
+
templateClone: options.templateClone ?? true,
|
|
4707
|
+
partialTemplates: nested ? false : options.partialTemplates ?? true,
|
|
4708
|
+
svg: templateTags.get(node.tag.name) === "svg"
|
|
4709
|
+
});
|
|
4710
|
+
for (const symbol of result.imports) used.add(symbol);
|
|
4711
|
+
collectNeeds(result.ir, needs);
|
|
4712
|
+
edits.push({ start: node.start, end: node.end, code: adoptTemplates(result.code, result.templates, hoisted) });
|
|
4713
|
+
}
|
|
4714
|
+
if (styles && options.styles) edits.push(...finishShadowStyles(styles, code, id));
|
|
4715
|
+
const out = new MagicString(code);
|
|
4716
|
+
for (const e of outermost(edits)) {
|
|
4717
|
+
if (e.start === e.end) out.appendLeft(e.start, e.code);
|
|
4718
|
+
else out.overwrite(e.start, e.end, e.code);
|
|
4719
|
+
}
|
|
4720
|
+
const bound = moduleBindings(ast.program);
|
|
4721
|
+
const why = /* @__PURE__ */ new Map();
|
|
4722
|
+
for (const [name] of needs.ignoredLoad) {
|
|
4723
|
+
if (!bound.has(name)) why.set(name, "unsupplied");
|
|
4724
|
+
}
|
|
4725
|
+
for (const [name, strategy] of [...needs.ignoredLoad]) {
|
|
4726
|
+
if (!bound.has(name)) continue;
|
|
4727
|
+
const found2 = deferrableImport(ast.program, name);
|
|
4728
|
+
if (!found2) {
|
|
4729
|
+
why.set(name, hasNamespaceImport(ast.program, name) ? "namespace" : "local");
|
|
4730
|
+
continue;
|
|
4731
|
+
}
|
|
4732
|
+
if (usedAsValue(ast.program, name, found2.specifier)) {
|
|
4733
|
+
why.set(name, "value");
|
|
4734
|
+
continue;
|
|
4735
|
+
}
|
|
4736
|
+
const rest = found2.declaration.specifiers.filter((sp) => sp !== found2.specifier);
|
|
4737
|
+
const end = rest.length === 0 && code[found2.declaration.end] === "\n" ? found2.declaration.end + 1 : found2.declaration.end;
|
|
4738
|
+
out.overwrite(
|
|
4739
|
+
found2.declaration.start,
|
|
4740
|
+
end,
|
|
4741
|
+
rest.length === 0 ? "" : `import { ${rest.map((sp) => code.slice(sp.start, sp.end)).join(", ")} } from ${JSON.stringify(found2.declaration.source.value)};`
|
|
4742
|
+
);
|
|
4743
|
+
needs.deferred.set(name, { module: found2.module, export: found2.export, origin: "rule", loading: strategy });
|
|
4744
|
+
bound.delete(name);
|
|
4745
|
+
needs.ignoredLoad.delete(name);
|
|
4746
|
+
}
|
|
4747
|
+
const prologue = buildPrologue(used, needs, hoisted, bound, options);
|
|
4748
|
+
if (prologue) out.prepend(prologue);
|
|
4749
|
+
const runtimeImports = intrinsicImports(intrinsics, bound);
|
|
4750
|
+
if (runtimeImports) out.prepend(runtimeImports);
|
|
4751
|
+
const reasons = {
|
|
4752
|
+
value: (name) => `${name} is used as a value here, not only as a tag, so its import has to stay — deferring would hand those references a lazy wrapper instead of the component. Defer it at the point it is rendered, or keep it eager.`,
|
|
4753
|
+
namespace: (name) => `${name} came in through a namespace import, which has no single export to defer. Import ${name} by name.`,
|
|
4754
|
+
local: (name) => `${name} is declared in this file, so there is no module to load separately. Move it to its own file and import it.`,
|
|
4755
|
+
unsupplied: (name) => `nothing supplies ${name}, so there is no import to defer. Import it, or add a \`resolve\` rule for it.`
|
|
4756
|
+
};
|
|
4757
|
+
const loadDiagnostics = [...needs.ignoredLoad].map(([name, strategy]) => ({
|
|
4758
|
+
name,
|
|
4759
|
+
strategy,
|
|
4760
|
+
message: `load:${strategy.kind} has no effect on <${name}>: ${reasons[why.get(name) ?? "unsupplied"](name)}`
|
|
4761
|
+
}));
|
|
4762
|
+
const unresolvedDiagnostics = [...needs.unresolved].map((name) => ({
|
|
4763
|
+
name,
|
|
4764
|
+
message: `<${name}> is not defined: nothing imports it and no \`resolve\` rule supplies it. This compiles to a reference to a name that does not exist, so the component renders nothing. Import ${name}, or add a \`resolve\` rule for it.`
|
|
4765
|
+
}));
|
|
4766
|
+
return {
|
|
4767
|
+
code: out.toString(),
|
|
4768
|
+
map: out.generateMap({ source: id, includeContent: true, hires: true }),
|
|
4769
|
+
...loadDiagnostics.length ? { loadDiagnostics } : {},
|
|
4770
|
+
...unresolvedDiagnostics.length ? { unresolvedDiagnostics } : {},
|
|
4771
|
+
...props.diagnostics.length ? { propsDiagnostics: props.diagnostics } : {},
|
|
4772
|
+
...intrinsics.diagnostics.length ? { intrinsicDiagnostics: intrinsics.diagnostics } : {},
|
|
4773
|
+
...styles?.styles.length ? { styles: styles.styles } : {},
|
|
4774
|
+
...styles?.diagnostics.length ? { styleDiagnostics: styles.diagnostics } : {},
|
|
4775
|
+
...styles?.literals.length ? { styleLiterals: styles.literals } : {},
|
|
4776
|
+
...styles?.references.length ? { styleReferences: styles.references } : {}
|
|
4777
|
+
};
|
|
4778
|
+
}
|
|
4779
|
+
function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile, styles) {
|
|
4780
|
+
const ir = buildJsxIR(node, {
|
|
4781
|
+
code: (n2) => slice(code, n2.start, n2.end, edits),
|
|
4782
|
+
used,
|
|
4783
|
+
...styles?.scopes.length ? { scopes: styles.scopes } : {},
|
|
4784
|
+
...styles?.drop.size ? { dropStyles: styles.drop } : {},
|
|
4785
|
+
...options.sourceLocations === true && sourceFile ? { sourceFile } : {}
|
|
4786
|
+
});
|
|
4787
|
+
analyzeStatic(ir);
|
|
4788
|
+
const report = resolveComponentSources(ir, {
|
|
4789
|
+
resolver: createComponentResolver(options.resolve ?? []),
|
|
4790
|
+
// Without this the pass calls every author-imported component unresolved, and the
|
|
4791
|
+
// report is unusable for diagnostics.
|
|
4792
|
+
isBound: (name) => needs.declared.has(name),
|
|
4793
|
+
modules: {
|
|
4794
|
+
controlFlowModule: options.controlFlowModule ?? options.runtimeModule ?? "@fluixi/dom",
|
|
4795
|
+
coreModule: options.coreModule ?? "@fluixi/core",
|
|
4796
|
+
routerModule: options.routerModule ?? "@fluixi/core/router"
|
|
4797
|
+
},
|
|
4798
|
+
strategyFor: (n2) => n2.load
|
|
4799
|
+
});
|
|
4800
|
+
for (const name of report.unresolved) needs.unresolved.add(name);
|
|
4801
|
+
collapseStrategies(ir);
|
|
4802
|
+
const emitted = imperativeBackend.emit(ir, {
|
|
4803
|
+
templateClone: options.templateClone ?? true,
|
|
4804
|
+
partialTemplates: nested ? false : options.partialTemplates ?? true
|
|
4805
|
+
});
|
|
4806
|
+
for (const symbol of emitted.imports) used.add(symbol);
|
|
4807
|
+
collectNeeds(ir, needs);
|
|
4808
|
+
return adoptTemplates(emitted.code, emitted.templates, hoisted);
|
|
4809
|
+
}
|
|
4810
|
+
function buildPrologue(used, needs, hoisted, bound, options) {
|
|
4811
|
+
const runtime = options.runtimeModule ?? "@fluixi/dom";
|
|
4812
|
+
const core = options.coreModule ?? "@fluixi/core";
|
|
4813
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4814
|
+
const add = (mod, name) => groups.set(mod, [...groups.get(mod) ?? [], name]);
|
|
4815
|
+
const wanted = new Set(used);
|
|
4816
|
+
for (const name of needs.builtins) wanted.add(name);
|
|
4817
|
+
if (needs.delegatedEvents.size > 0) wanted.add("delegateEvents");
|
|
4818
|
+
for (const name of [...wanted].sort()) {
|
|
4819
|
+
if (bound.has(name)) continue;
|
|
4820
|
+
if (REACTIVE.has(name)) add(options.reactiveModule ?? "@fluixi/reactive/signal", name);
|
|
4821
|
+
else if (ROUTER.has(name)) add(options.routerModule ?? "@fluixi/core/router", name);
|
|
4822
|
+
else if (CORE_ONLY.has(name)) add(core, name);
|
|
4823
|
+
else if (CONTROL_FLOW.has(name)) add(options.controlFlowModule ?? runtime, name);
|
|
4824
|
+
else add(runtime, name);
|
|
4825
|
+
}
|
|
4826
|
+
for (const [name, src] of needs.resolved) {
|
|
4827
|
+
if (!bound.has(name)) add(src.module, src.export === "default" ? `default as ${name}` : name === src.export ? name : `${src.export} as ${name}`);
|
|
4828
|
+
}
|
|
4829
|
+
const lines = [];
|
|
4830
|
+
for (const [mod, names] of groups) {
|
|
4831
|
+
lines.push(`import { ${names.join(", ")} } from ${JSON.stringify(mod)};`);
|
|
4832
|
+
}
|
|
4833
|
+
const lazy = [...needs.deferred].filter(([name]) => !bound.has(name));
|
|
4834
|
+
if (lazy.length > 0) {
|
|
4835
|
+
if (!bound.has("deferred")) lines.push(`import { deferred } from ${JSON.stringify(core)};`);
|
|
4836
|
+
for (const [name, src] of lazy) {
|
|
4837
|
+
lines.push(
|
|
4838
|
+
`const ${name} = deferred(() => import(${JSON.stringify(src.module)}), { strategy: ${strategyLiteral(src.loading)}, export: ${JSON.stringify(src.export)} });`
|
|
4839
|
+
);
|
|
4840
|
+
}
|
|
4841
|
+
}
|
|
4842
|
+
for (const [key, name] of hoisted) {
|
|
4843
|
+
lines.push(`const ${name} = ${JSON.stringify(key.startsWith("svg:") ? key.slice(4) : key)};`);
|
|
4844
|
+
}
|
|
4845
|
+
if (needs.delegatedEvents.size > 0) {
|
|
4846
|
+
lines.push(`delegateEvents(${JSON.stringify([...needs.delegatedEvents])});`);
|
|
4847
|
+
}
|
|
4848
|
+
return lines.length > 0 ? lines.join("\n") + "\n" : null;
|
|
4849
|
+
}
|
|
4850
|
+
export {
|
|
4851
|
+
transformTemplates
|
|
4852
|
+
};
|