@fluixi/compiler 1.0.0-alpha.73 → 1.0.0-alpha.75

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.
Files changed (109) hide show
  1. package/README.md +41 -16
  2. package/dist/analyze/expr-shape.cjs +1 -0
  3. package/dist/analyze/expr-shape.d.ts +15 -0
  4. package/dist/analyze/expr-shape.d.ts.map +1 -0
  5. package/dist/analyze/expr-shape.js +37 -0
  6. package/dist/analyze/expr-shape.mjs +1 -0
  7. package/dist/analyze/reactive-expr.cjs +1 -0
  8. package/dist/analyze/reactive-expr.d.ts +39 -0
  9. package/dist/analyze/reactive-expr.d.ts.map +1 -0
  10. package/dist/analyze/reactive-expr.js +31 -0
  11. package/dist/analyze/reactive-expr.mjs +1 -0
  12. package/dist/babel-GXO3KAVI.mjs +1 -0
  13. package/dist/chunk-3SAEGOMQ.mjs +1 -0
  14. package/dist/chunk-E2PW2OZU.mjs +1 -0
  15. package/dist/chunk-IBRM4W7I.mjs +10 -0
  16. package/dist/chunk-OHHZCYIQ.mjs +1 -0
  17. package/dist/chunk-TIE4XNAM.mjs +1 -0
  18. package/dist/frontend/babel/build-ir-lit.cjs +1 -1
  19. package/dist/frontend/babel/build-ir-lit.d.ts +1 -0
  20. package/dist/frontend/babel/build-ir-lit.d.ts.map +1 -1
  21. package/dist/frontend/babel/build-ir-lit.mjs +1 -1
  22. package/dist/frontend/babel/build-ir.cjs +1 -1
  23. package/dist/frontend/babel/build-ir.d.ts +13 -11
  24. package/dist/frontend/babel/build-ir.d.ts.map +1 -1
  25. package/dist/frontend/babel/build-ir.js +27 -217
  26. package/dist/frontend/babel/build-ir.mjs +1 -1
  27. package/dist/frontend/babel/index.cjs +1 -2
  28. package/dist/frontend/babel/index.mjs +1 -2
  29. package/dist/frontend/babel/lower-template.cjs +1 -1
  30. package/dist/frontend/babel/lower-template.d.ts +12 -9
  31. package/dist/frontend/babel/lower-template.d.ts.map +1 -1
  32. package/dist/frontend/babel/lower-template.js +33 -445
  33. package/dist/frontend/babel/lower-template.mjs +1 -1
  34. package/dist/frontend/babel/plugin.cjs +1 -2
  35. package/dist/frontend/babel/plugin.d.ts +24 -85
  36. package/dist/frontend/babel/plugin.d.ts.map +1 -1
  37. package/dist/frontend/babel/plugin.js +52 -1285
  38. package/dist/frontend/babel/plugin.mjs +1 -2
  39. package/dist/frontend/babel/server-functions.cjs +1 -1
  40. package/dist/frontend/babel/server-functions.d.ts.map +1 -1
  41. package/dist/frontend/babel/server-functions.js +2 -9
  42. package/dist/frontend/babel/server-functions.mjs +1 -1
  43. package/dist/index.cjs +8 -8
  44. package/dist/index.d.ts +4 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +8 -0
  47. package/dist/index.mjs +9 -9
  48. package/dist/integrations.cjs +15 -19
  49. package/dist/integrations.d.ts +39 -151
  50. package/dist/integrations.d.ts.map +1 -1
  51. package/dist/integrations.js +79 -491
  52. package/dist/integrations.mjs +11 -17
  53. package/dist/lower/compile-template.cjs +1 -0
  54. package/dist/lower/compile-template.d.ts +57 -0
  55. package/dist/lower/compile-template.d.ts.map +1 -0
  56. package/dist/lower/compile-template.js +72 -0
  57. package/dist/lower/compile-template.mjs +1 -0
  58. package/dist/lower/jsx.cjs +1 -0
  59. package/dist/lower/jsx.d.ts +24 -0
  60. package/dist/lower/jsx.d.ts.map +1 -0
  61. package/dist/lower/jsx.js +193 -0
  62. package/dist/lower/jsx.mjs +1 -0
  63. package/dist/lower/template.cjs +1 -0
  64. package/dist/lower/template.d.ts +41 -0
  65. package/dist/lower/template.d.ts.map +1 -0
  66. package/dist/lower/template.js +445 -0
  67. package/dist/lower/template.mjs +1 -0
  68. package/dist/lower/text.cjs +1 -0
  69. package/dist/lower/text.d.ts +11 -0
  70. package/dist/lower/text.d.ts.map +1 -0
  71. package/dist/lower/text.js +31 -0
  72. package/dist/lower/text.mjs +1 -0
  73. package/dist/options.cjs +1 -1
  74. package/dist/options.d.ts +0 -2
  75. package/dist/options.d.ts.map +1 -1
  76. package/dist/options.js +0 -1
  77. package/dist/options.mjs +1 -1
  78. package/dist/server-fns-6QM243HC.mjs +2 -0
  79. package/dist/server-functions-E3LKCZ4R.mjs +1 -0
  80. package/dist/transform/bindings.cjs +1 -0
  81. package/dist/transform/bindings.d.ts +17 -0
  82. package/dist/transform/bindings.d.ts.map +1 -0
  83. package/dist/transform/bindings.js +69 -0
  84. package/dist/transform/bindings.mjs +1 -0
  85. package/dist/transform/index.cjs +3 -0
  86. package/dist/transform/index.d.ts +12 -0
  87. package/dist/transform/index.d.ts.map +1 -0
  88. package/dist/transform/index.js +10 -0
  89. package/dist/transform/index.mjs +12 -0
  90. package/dist/transform/server-fn-id.cjs +1 -0
  91. package/dist/transform/server-fn-id.d.ts +10 -0
  92. package/dist/transform/server-fn-id.d.ts.map +1 -0
  93. package/dist/transform/server-fn-id.js +18 -0
  94. package/dist/transform/server-fn-id.mjs +1 -0
  95. package/dist/transform/server-fns.cjs +2 -0
  96. package/dist/transform/server-fns.d.ts +13 -0
  97. package/dist/transform/server-fns.d.ts.map +1 -0
  98. package/dist/transform/server-fns.js +94 -0
  99. package/dist/transform/server-fns.mjs +11 -0
  100. package/dist/transform/templates.cjs +3 -0
  101. package/dist/transform/templates.d.ts +26 -0
  102. package/dist/transform/templates.d.ts.map +1 -0
  103. package/dist/transform/templates.js +347 -0
  104. package/dist/transform/templates.mjs +12 -0
  105. package/dist/transform-PJX2GNSV.mjs +3 -0
  106. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  107. package/package.json +30 -8
  108. package/dist/babel-E7EQLX36.mjs +0 -2
  109. package/dist/chunk-EF6V4GTD.mjs +0 -1
@@ -1,465 +1,53 @@
1
1
  /**
2
- * Lower a parsed Template AST (`@fluixi/template-parser`) into the compiler's
3
- * host-agnostic IR. This is the Babel-aware half the parser deliberately is not:
4
- * it binds each opaque hole slot to its Babel `${…}` expression (via `genExpr`,
5
- * which also compiles any JSX/`` html`` `` nested inside the hole) and reproduces
6
- * the exact IR the old single-pass `build-ir-lit` scanner produced — the byte-
7
- * identity gate — while adding the new directive lowerings on top.
2
+ * Babel adapter for `` html`...` `` templates.
8
3
  *
9
- * Pipeline: pieces parseTemplate Template AST lowerTemplate IRNode
4
+ * The lowering itself is in ../../lower/template.ts and takes no Babel. What is
5
+ * left here is the part that genuinely needs to read JavaScript: turning each
6
+ * `${…}` into a `TemplateHole` — its source text, whether it is reactive, and
7
+ * the two structural facts the lowering branches on (a single-expression arrow,
8
+ * an object literal).
9
+ *
10
+ * Nested JSX and nested `` html`` `` inside a hole are compiled here too, by
11
+ * `genExpr`, so the code the lowering receives is already plain JavaScript.
10
12
  */
11
13
  import { types as t } from '@babel/core';
12
14
  import _generate from '@babel/generator';
13
- import { parseTemplate, } from '@fluixi/template-parser';
14
- import { parseLoadDirective } from '../../resolve/load-directive.js';
15
- import { imperativeBackend, inlineTemplates } from '../../codegen/backends/imperative.js';
16
- import { cleanJSXText, genExpr, isReactiveExpr } from './build-ir.js';
15
+ import { lowerTemplate } from '../../lower/template.js';
16
+ import { genExpr, isReactiveExpr } from './build-ir.js';
17
17
  const generate = _generate.default ?? _generate;
18
18
  function gen(node) {
19
19
  return generate(node, { concise: true }).code;
20
20
  }
21
- const DELEGATED = new Set([
22
- 'click', 'dblclick', 'input', 'change', 'submit', 'focus', 'blur',
23
- 'keydown', 'keyup', 'keypress', 'mousedown', 'mouseup',
24
- ]);
25
- /** Escape a static text run for embedding in a template literal. */
26
- function escapeTemplate(s) {
27
- return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
28
- }
29
- function capitalize(s) {
30
- return s.charAt(0).toUpperCase() + s.slice(1);
31
- }
32
- class Lowerer {
33
- holes;
34
- used;
35
- constructor(holes, used) {
36
- this.holes = holes;
37
- this.used = used;
38
- }
39
- hole(i) {
40
- // -1 marks a recovered-from missing binding; emit a harmless undefined.
41
- return this.holes[i] ?? { node: t.identifier('undefined'), code: 'undefined', reactive: false };
42
- }
43
- /** Emit a nested IR subtree to code (for `Show` fallback / `For` children). */
44
- emit(node) {
45
- const { code, imports, templates } = imperativeBackend.emit(node, {});
46
- for (const s of imports)
47
- this.used.add(s);
48
- // No module scope reachable from a nested subtree, so templates are inlined;
49
- // `createTemplate` caches by HTML, so this is a lookup rather than a re-parse.
50
- return inlineTemplates(code, templates);
51
- }
52
- // --- content ------------------------------------------------------------
53
- lowerRoot(children) {
54
- const nodes = this.lowerChildren(children);
55
- if (nodes.length === 1)
56
- return nodes[0];
57
- return { kind: 'fragment', children: nodes };
58
- }
59
- /** Lower a sibling list, handling text-drop and if/else/each restructuring. */
60
- lowerChildren(children) {
61
- const out = [];
62
- for (let i = 0; i < children.length; i++) {
63
- const child = children[i];
64
- if (child.kind === 'Element' || child.kind === 'Component') {
65
- const ifDir = child.attributes.find((a) => a.kind === 'IfDirective');
66
- if (ifDir && ifDir.kind === 'IfDirective') {
67
- // Pair with a following `else` sibling (skipping a whitespace-only text).
68
- let elseIdx = i + 1;
69
- if (elseIdx < children.length && this.isBlankText(children[elseIdx]))
70
- elseIdx++;
71
- const elseNode = children[elseIdx];
72
- const hasElse = elseNode &&
73
- (elseNode.kind === 'Element' || elseNode.kind === 'Component') &&
74
- elseNode.attributes.some((a) => a.kind === 'ElseDirective');
75
- out.push(this.lowerIf(child, ifDir.hole, hasElse ? elseNode : null));
76
- if (hasElse)
77
- i = elseIdx;
78
- continue;
79
- }
80
- if (child.attributes.some((a) => a.kind === 'EachDirective')) {
81
- out.push(this.lowerEach(child));
82
- continue;
83
- }
84
- }
85
- const node = this.lowerNode(child);
86
- if (node)
87
- out.push(node);
88
- }
89
- return out;
90
- }
91
- isBlankText(n) {
92
- return n.kind === 'Text' && !n.raw && cleanJSXText(n.value) === '';
93
- }
94
- lowerNode(node) {
95
- switch (node.kind) {
96
- case 'Text': {
97
- if (node.raw)
98
- return { kind: 'text', value: node.value };
99
- const cleaned = cleanJSXText(node.value);
100
- return cleaned ? { kind: 'text', value: cleaned } : null;
101
- }
102
- case 'Comment':
103
- return null; // dropped, like JSX comments
104
- case 'Expression': {
105
- const h = this.hole(node.hole);
106
- return { kind: 'expr', code: h.code, reactive: h.reactive };
107
- }
108
- case 'Fragment':
109
- return { kind: 'fragment', children: this.lowerChildren(node.children) };
110
- case 'Element':
111
- return this.lowerElement(node);
112
- case 'Component':
113
- return this.lowerComponent(node);
114
- default:
115
- return null;
116
- }
117
- }
118
- lowerElement(el) {
119
- // `<component is=${C} …>…</component>` → `<Dynamic component=${C} …>` (a
120
- // reactive component swap). Dynamic reads `component` via normalizeAccessor,
121
- // so it must be an ACCESSOR `() => C` (a bare function would be mis-called).
122
- const isAttr = el.attributes.find((a) => a.kind === 'Attribute' && a.name === 'is');
123
- if (el.tag === 'component' && isAttr && isAttr.value && isAttr.value.kind === 'hole') {
124
- const rest = el.attributes.filter((a) => a !== isAttr);
125
- const node = this.lowerComponent({ ...el, kind: 'Component', tag: 'Dynamic', tagHole: null, attributes: rest });
126
- node.props.unshift({ name: 'component', kind: 'attr', expr: `() => (${this.hole(isAttr.value.hole).code})` });
127
- return node;
128
- }
129
- return {
130
- kind: 'element',
131
- tag: el.tag,
132
- svg: el.namespace === 'svg',
133
- props: this.lowerAttributes(el.attributes),
134
- children: this.lowerChildren(el.children),
135
- static: false,
136
- };
137
- }
138
- lowerComponent(el) {
139
- // `<${Comp} />`: the tag is an interpolated expression — use the hole's code
140
- // as the component identity, so `createComponent(<expr>, …)` is emitted.
141
- const name = el.tagHole != null ? this.hole(el.tagHole).code : el.tag;
142
- const props = this.lowerAttributes(el.attributes);
143
- // Named slots: a child with `slot="header"` becomes `props.header` (a lazy
144
- // getter, like `children`); the rest stay the default `children`. This is the
145
- // Solid convention — the component reads `props.header` / `props.children`.
146
- const { slots, rest } = this.partitionSlots(el.children);
147
- for (const [slotName, nodes] of slots) {
148
- const ir = nodes.length === 1 ? nodes[0] : { kind: 'fragment', children: nodes };
149
- const slotProp = {
150
- name: slotName,
151
- kind: 'attr',
152
- expr: this.emit(ir),
153
- jsxElement: true,
154
- };
155
- // A slot replaces a same-named attribute rather than joining it. `<Card header>`
156
- // alongside `<span slot="header">` otherwise emits the key twice — valid JS where
157
- // the last wins, but the first is dead code and esbuild warns on it. Content is
158
- // the more specific intent, so the slot is what survives.
159
- const clash = props.findIndex((p) => p.name === slotName);
160
- if (clash >= 0)
161
- props[clash] = slotProp;
162
- else
163
- props.push(slotProp);
164
- }
165
- // `load:` is a directive, not a prop: it says when this component's module is
166
- // fetched. Parsed with the same helper the JSX path uses so the two cannot drift.
167
- const loadAttr = el.attributes.find((a) => a.kind === 'LoadDirective');
168
- const load = loadAttr
169
- ? parseLoadDirective(`load:${loadAttr.strategy}`, loadAttr.modifier)
170
- : undefined;
171
- return {
172
- kind: 'component',
173
- name,
174
- props,
175
- children: this.lowerChildren(rest),
176
- ...(load ? { load } : {}),
21
+ /** Describe one `${…}` for the lowering. */
22
+ function bindHole(expr, used, onNested) {
23
+ const hole = {
24
+ code: genExpr(expr, used, onNested),
25
+ reactive: isReactiveExpr(expr),
26
+ };
27
+ // `${item => <li>${item}</li>}` — `each` lowers this into For's render
28
+ // function, which needs the parameters and the body apart from each other. A
29
+ // block body is not a render expression, so it stays an ordinary hole.
30
+ if (t.isArrowFunctionExpression(expr) && !t.isBlockStatement(expr.body)) {
31
+ const body = expr.body;
32
+ hole.arrow = {
33
+ params: expr.params.map((p) => gen(p)),
34
+ body: genExpr(body, used, onNested),
35
+ bodyReactive: isReactiveExpr(body),
177
36
  };
178
37
  }
179
- /** Split a component's children into named slots (`slot="x"`) and the rest. */
180
- partitionSlots(children) {
181
- const slots = new Map();
182
- const rest = [];
183
- for (const child of children) {
184
- if (child.kind === 'Element' || child.kind === 'Component') {
185
- const slot = child.attributes.find((a) => a.kind === 'Attribute' && a.name === 'slot');
186
- if (slot && slot.value && slot.value.kind === 'static') {
187
- const stripped = { ...child, attributes: child.attributes.filter((a) => a !== slot) };
188
- const ir = stripped.kind === 'Element' ? this.lowerElement(stripped) : this.lowerComponent(stripped);
189
- const bucket = slots.get(slot.value.value) ?? [];
190
- bucket.push(ir);
191
- slots.set(slot.value.value, bucket);
192
- continue;
193
- }
194
- }
195
- rest.push(child);
196
- }
197
- return { slots, rest };
198
- }
199
- // --- control-flow sugar -------------------------------------------------
200
- /** `<el if=${cond}>…</el>` (+ optional `<el else>`) → `<Show when fallback>`. */
201
- lowerIf(el, condHole, elseEl) {
202
- const cond = this.hole(condHole);
203
- const props = [
204
- { name: 'when', kind: 'attr', expr: cond.code, reactive: cond.reactive },
205
- ];
206
- if (elseEl) {
207
- const elseIR = this.stripAndLower(elseEl, (a) => a.kind === 'ElseDirective');
208
- props.push({ name: 'fallback', kind: 'attr', expr: this.emit(elseIR), jsxElement: true });
209
- }
210
- const child = this.stripAndLower(el, (a) => a.kind === 'IfDirective');
211
- return { kind: 'component', name: 'Show', props, children: [child] };
212
- }
213
- /** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
214
- lowerEach(el) {
215
- const eachDir = el.attributes.find((a) => a.kind === 'EachDirective');
216
- if (!eachDir || eachDir.kind !== 'EachDirective')
217
- return this.lowerNode(el);
218
- const each = this.hole(eachDir.hole);
219
- const props = [{ name: 'each', kind: 'attr', expr: each.code, reactive: each.reactive }];
220
- if (eachDir.key) {
221
- // `<For by>` wants a KEY FUNCTION, not a string. `key="id"` selects the
222
- // `id` field: `(item) => item["id"]`; `key=${fn}` passes the function.
223
- const by = 'static' in eachDir.key
224
- ? `(item) => item[${JSON.stringify(eachDir.key.static)}]`
225
- : this.hole(eachDir.key.hole).code;
226
- props.push({ name: 'by', kind: 'attr', expr: by });
227
- }
228
- // The element minus its each/key, repeated per item.
229
- const arrow = this.itemArrow(el);
230
- let childrenCode;
231
- if (arrow) {
232
- const bodyExpr = arrow.body;
233
- const bodyIR = { kind: 'expr', code: genExpr(bodyExpr, this.used), reactive: isReactiveExpr(bodyExpr) };
234
- const repeated = this.rebuildWithChildren(el, [bodyIR]);
235
- childrenCode = `(${arrow.params.map((p) => gen(p)).join(', ')}) => (${this.emit(repeated)})`;
236
- }
237
- else {
238
- const repeated = this.stripAndLower(el, (a) => a.kind === 'EachDirective');
239
- childrenCode = `() => (${this.emit(repeated)})`;
240
- }
241
- const children = [{ kind: 'expr', code: childrenCode, reactive: false }];
242
- return { kind: 'component', name: 'For', props, children };
243
- }
244
- /** The single `${item => expr}` child arrow, if that's the element's content. */
245
- itemArrow(el) {
246
- const kids = el.children.filter((c) => !this.isBlankText(c));
247
- if (kids.length !== 1 || kids[0].kind !== 'Expression')
248
- return null;
249
- const node = this.hole(kids[0].hole).node;
250
- if (t.isArrowFunctionExpression(node) && !t.isBlockStatement(node.body))
251
- return node;
252
- return null;
253
- }
254
- /** Lower an element to IR, dropping the directive attribute matched by `drop`. */
255
- stripAndLower(el, drop) {
256
- const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
257
- return clone.kind === 'Element' ? this.lowerElement(clone) : this.lowerComponent(clone);
258
- }
259
- /** Same element (minus each/key) but with explicit IR children. */
260
- rebuildWithChildren(el, children) {
261
- const props = this.lowerAttributes(el.attributes.filter((a) => a.kind !== 'EachDirective'));
262
- if (el.kind === 'Element') {
263
- return { kind: 'element', tag: el.tag, svg: el.namespace === 'svg', props, children, static: false };
264
- }
265
- return { kind: 'component', name: el.tag, props, children };
266
- }
267
- // --- attributes ---------------------------------------------------------
268
- lowerAttributes(attrs) {
269
- const props = [];
270
- const classEntries = [];
271
- let classReactive = false;
272
- const styleEntries = [];
273
- let styleReactive = false;
274
- const usePairs = [];
275
- for (const a of attrs) {
276
- switch (a.kind) {
277
- case 'IfDirective':
278
- case 'EachDirective':
279
- case 'ElseDirective':
280
- break; // handled as control-flow at the parent level
281
- case 'Attribute':
282
- props.push(this.plainAttr(a));
283
- break;
284
- case 'PropertyBinding':
285
- props.push({ name: a.name, kind: 'prop', expr: this.hole(a.hole).code, reactive: this.hole(a.hole).reactive });
286
- break;
287
- case 'EventBinding':
288
- props.push(this.eventProp(a));
289
- break;
290
- case 'RefBinding':
291
- props.push({ name: 'ref', kind: 'ref', expr: this.hole(a.hole).code, reactive: this.hole(a.hole).reactive });
292
- break;
293
- case 'Spread':
294
- props.push({ name: '', kind: 'spread', expr: this.hole(a.hole).code });
295
- break;
296
- case 'ClassDirective': {
297
- const h = this.hole(a.hole);
298
- classEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
299
- classReactive = classReactive || h.reactive;
300
- break;
301
- }
302
- case 'StyleDirective': {
303
- const h = this.hole(a.hole);
304
- styleEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
305
- styleReactive = styleReactive || h.reactive;
306
- break;
307
- }
308
- case 'BindDirective':
309
- props.push(...this.bindProps(a.name, this.hole(a.hole).code));
310
- break;
311
- case 'UseDirective': {
312
- // `use=${dir}` → [dir]; `use:name` → [name]; `use:name=${opts}` →
313
- // [name, () => opts]. `name` is an in-scope identifier (like Solid).
314
- const dir = a.name ?? (a.hole != null ? this.hole(a.hole).code : null);
315
- if (!dir)
316
- break;
317
- // parens so an object literal opts isn't read as a block body
318
- usePairs.push(a.name != null && a.hole != null ? `[${dir}, () => (${this.hole(a.hole).code})]` : `[${dir}]`);
319
- break;
320
- }
321
- }
322
- }
323
- // Merge all class:/style: directives into one classList/style prop so they
324
- // don't collide as duplicate keys in the emitted props object.
325
- if (classEntries.length > 0) {
326
- props.push({ name: 'classList', kind: 'attr', expr: `{ ${classEntries.join(', ')} }`, reactive: classReactive });
327
- }
328
- if (styleEntries.length > 0) {
329
- props.push({ name: 'style', kind: 'attr', expr: `{ ${styleEntries.join(', ')} }`, reactive: styleReactive });
330
- }
331
- // All use: directives normalize to one `use` prop = an array of [dir, accessor?] pairs.
332
- if (usePairs.length > 0) {
333
- props.push({ name: 'use', kind: 'attr', expr: `[${usePairs.join(', ')}]` });
334
- }
335
- return props;
336
- }
337
- /**
338
- * Lower an event binding. Plain `@click`/`onClick` (no modifiers) stays a
339
- * DELEGATED handler (unchanged, byte-identical with JSX). `on:click` or any
340
- * modifier (`.capture`/`.once`/`.passive`/`.prevent`/`.stop`/`.self`) emits a
341
- * NATIVE `on:name` prop the runtime attaches via addEventListener.
342
- */
343
- eventProp(a) {
344
- const dom = a.name.toLowerCase();
345
- const handler = this.hole(a.hole).code;
346
- const native = a.syntax === 'colon' || a.modifiers.length > 0;
347
- if (!native) {
348
- return {
349
- name: 'on' + capitalize(a.name),
350
- kind: 'event',
351
- event: { name: dom, delegated: DELEGATED.has(dom) },
352
- expr: handler,
353
- };
354
- }
355
- const wrapped = this.wrapHandler(handler, a.modifiers);
356
- const options = this.eventOptions(a.modifiers);
357
- const value = options ? `[${wrapped}, ${options}]` : wrapped;
358
- return { name: 'on:' + dom, kind: 'attr', expr: value };
359
- }
360
- /** Wrap a handler for `.prevent`/`.stop`/`.self` (no wrap when none apply). */
361
- wrapHandler(handler, mods) {
362
- const guard = mods.includes('self') ? 'if (e.target !== e.currentTarget) return; ' : '';
363
- const pre = [];
364
- if (mods.includes('prevent'))
365
- pre.push('e.preventDefault();');
366
- if (mods.includes('stop'))
367
- pre.push('e.stopPropagation();');
368
- if (!guard && pre.length === 0)
369
- return handler;
370
- return `(e) => { ${guard}${pre.join(' ')} return (${handler})(e); }`;
371
- }
372
- /** addEventListener options object from `.capture`/`.once`/`.passive`, or null. */
373
- eventOptions(mods) {
374
- const opts = [];
375
- if (mods.includes('capture'))
376
- opts.push('capture: true');
377
- if (mods.includes('once'))
378
- opts.push('once: true');
379
- if (mods.includes('passive'))
380
- opts.push('passive: true');
381
- return opts.length ? `{ ${opts.join(', ')} }` : null;
382
- }
383
- /** `bind:value=${sig}` → `value={sig[0]()}` + `onInput={e => sig[1](e…value)}`. */
384
- bindProps(prop, sigCode) {
385
- const checked = prop === 'checked';
386
- const evt = checked ? 'change' : 'input';
387
- const accessor = checked ? 'checked' : 'value';
388
- // Parenthesize the signal expression — it may be more than an identifier
389
- // (`[get, set] as const`, `props.model`, a call), and `expr[0]()` would then
390
- // mis-parse (e.g. `[...] as const[0]`).
391
- const sig = `(${sigCode})`;
392
- return [
393
- { name: prop, kind: 'attr', expr: `${sig}[0]()`, reactive: true },
394
- {
395
- name: 'on' + capitalize(evt),
396
- kind: 'event',
397
- event: { name: evt, delegated: DELEGATED.has(evt) },
398
- // delegated handler: `target` is the bound element (currentTarget is the root)
399
- expr: `(e) => ${sig}[1](e.target.${accessor})`,
400
- },
401
- ];
402
- }
403
- /** A plain attribute (incl. lit `?bool`, mixed values) — old `mkProp` behavior. */
404
- plainAttr(a) {
405
- const v = a.value;
406
- // `class=${{...}}` (object literal) -> classList (Solid convention), so it
407
- // doesn't collide with a static `class="box"` (which stays className) — both
408
- // apply. `class` -> className; `style=${{...}}` stays `style` (runtime merges).
409
- // `html=${x}` is the raw-HTML escape hatch -> innerHTML.
410
- let name = a.name;
411
- if (a.name === 'class') {
412
- name = v && v.kind === 'hole' && t.isObjectExpression(this.hole(v.hole).node) ? 'classList' : 'className';
413
- }
414
- else if (a.name === 'html') {
415
- name = 'innerHTML';
416
- }
417
- const kind = 'attr';
418
- const base = { name, kind };
419
- if (v == null) {
420
- base.literal = true;
421
- return base;
422
- }
423
- if (v.kind === 'static') {
424
- base.literal = v.value;
425
- return base;
426
- }
427
- if (v.kind === 'hole') {
428
- const h = this.hole(v.hole);
429
- base.expr = h.code;
430
- base.reactive = h.reactive;
431
- return base;
432
- }
433
- // mixed: template literal, reactive if any hole is
434
- let reactive = false;
435
- const body = v.parts
436
- .map((p) => {
437
- if ('text' in p)
438
- return escapeTemplate(p.text);
439
- const h = this.hole(p.hole);
440
- reactive = reactive || h.reactive;
441
- return '${' + h.code + '}';
442
- })
443
- .join('');
444
- base.expr = '`' + body + '`';
445
- base.reactive = reactive;
446
- return base;
447
- }
38
+ // `class=${{ active: on() }}` lowers to classList rather than className.
39
+ if (t.isObjectExpression(expr))
40
+ hole.object = true;
41
+ return hole;
448
42
  }
449
43
  /**
450
44
  * Build IR from a lit `` html`...` `` / `` svg`...` `` TaggedTemplateExpression.
451
- * Parses (Babel-free) then lowers (Babel-aware) a drop-in for the old
452
- * single-pass scanner, with the same signature.
45
+ * `used` collects runtime symbols emitted for anything nested inside a hole.
453
46
  */
454
47
  export function lowerLitTemplate(node, used, opts = {}) {
455
48
  const quasi = node.quasi;
456
- const holes = quasi.expressions.map((e) => {
457
- const expr = e;
458
- return { node: expr, code: genExpr(expr, used), reactive: isReactiveExpr(expr) };
459
- });
460
- const pieces = buildPieces(quasi);
461
- const { root } = parseTemplate(pieces, { svg: opts.svg });
462
- return new Lowerer(holes, used).lowerRoot(root.children);
49
+ const holes = quasi.expressions.map((e) => bindHole(e, used, opts.onNested));
50
+ return lowerTemplate(buildPieces(quasi), holes, used, opts);
463
51
  }
464
52
  /** Turn a Babel TemplateLiteral into position-carrying parser pieces. */
465
53
  function buildPieces(quasi) {
@@ -1 +1 @@
1
- import{types as w}from"@babel/core";import ne from"@babel/generator";import{parseTemplate as _e}from"@fluixi/template-parser";var se={kind:"eager"},oe=["pointerdown","focusin","keydown"],O=new Set(["eager","idle","visible","interaction","media","never"]),f=class extends Error{};function T(t){return t.startsWith("load:")}function S(t,e){let n=t.slice(5);if(!O.has(n))throw new f(`Unknown load strategy 'load:${n}'. Expected one of ${[...O].join(", ")}.`);switch(n){case"eager":return se;case"idle":return{kind:"idle"};case"never":return{kind:"never"};case"visible":return e?{kind:"visible",rootMargin:e}:{kind:"visible"};case"interaction":return{kind:"interaction",events:e?ae(e):[...oe]};case"media":if(!e)throw new f(`'load:media' needs a query, e.g. load:media="(min-width: 1024px)".`);return{kind:"media",query:e};default:throw new f(`Unhandled load strategy '${n}'.`)}}function ae(t){let e=t.split(/[\s,]+/).map(n=>n.trim()).filter(Boolean);if(e.length===0)throw new f("'load:interaction' was given no event names.");return e}var le=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),_={className:"class",htmlFor:"for"},ce=new Set(["innerHTML","outerHTML","innerText","textContent","value","checked","selected","muted","defaultValue","defaultChecked","children","ref"]),pe=new Set(["script","style","textarea","title"]);function C(t){return pe.has(t)}function M(t){return _[t]??t}function v(t){return t.kind!=="attr"||t.expr!==void 0||t.name.includes(":")?!1:!ce.has(t.name)}function A(t){if(!t.static||C(t.tag))return!1;for(let e of t.props)if(!v(e))return!1;for(let e of t.children)if(e.kind!=="text"&&!(e.kind==="element"&&A(e)))return!1;return!0}function x(t){let e=t.props.map(de).filter(Boolean).join(""),n=`<${t.tag}${e}>`;return le.has(t.tag)?n:`${n}${t.children.map(ue).join("")}</${t.tag}>`}function ue(t){if(t.kind==="text")return fe(t.value);if(t.kind!=="element")throw new Error(`serializeStatic: unexpected ${t.kind}`);return x(t)}function de(t){let e=_[t.name]??t.name,n=t.literal;return n===!0||n===void 0?` ${e}`:n===!1||n===null?"":` ${e}="${me(String(n))}"`}function me(t){return t.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function fe(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}var he="<!--fx-->",ge="<!--fx/-->";function y(t){return t.kind==="expr"||t.kind==="component"||t.kind==="control"}function ve(t){return t.kind==="text"||t.kind==="element"&&B(t)}function B(t){return t.svg||C(t.tag)||!t.props.every(e=>v(e))?!1:t.children.every(e=>ve(e)||y(e))}function b(t){if(y(t))return!0;let e=t.children;return e?e.some(b):!1}function H(t){for(let e=0;e<t.children.length;e++){let n=t.children[e];if(n.kind==="text"&&(n.value===""||t.children[e+1]?.kind==="text"))return!1}return t.children.every(e=>e.kind!=="element"||H(e))}function F(t){if(!B(t)||!H(t)||!t.children.some(b))return null;let e=[],n=[],r=0,i=a=>{let s=`_n$${r++}`;return e.push({ref:s,expr:a}),s};return o(t,"_el$"),{html:xe(t),tag:t.tag,steps:e,holes:n};function o(a,s){let l=-1;a.children.forEach((u,d)=>{b(u)&&(l=d)});let c=null;for(let u=0;u<=l;u++){let d=a.children[u],g=c?`${c}.nextSibling`:`${s}.firstChild`;if(y(d)){let D=i(g),j=i(`holeEnd(${D})`);n.push({parentRef:s,startRef:D,endRef:j,node:d}),c=j;continue}let N=i(g);d.kind==="element"&&b(d)&&o(d,N),c=N}}}function xe(t){return x(z(t)).split(V).join(he+ge)}function z(t){return{...t,children:t.children.map(e=>y(e)?{kind:"text",value:V}:e.kind==="element"?z(e):e)}}var V="\0fx-hole\0";var P={version:1,module:"@fluixi/dom",symbols:["createNativeElement","insert","spread","setAttribute","delegateEvents","createComponent","createMemo","untrack","Show","For","Index","Switch","Match","Dynamic","ErrorBoundary"]},Ge={version:2,module:"@fluixi/dom",symbols:[...P.symbols,"template","cloneTemplate","walk"]};var ke={show:"Show",for:"For",index:"Index",switch:"Switch",match:"Match",dynamic:"Dynamic",errorBoundary:"ErrorBoundary",suspense:"Suspense"};function Ee(t){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(t)}function U(t){return Ee(t)?t:JSON.stringify(t)}function Re(t){return t.expr!==void 0?t.reactive?`() => (${t.expr})`:`(${t.expr})`:JSON.stringify(t.literal??!0)}function Ne(t){return t.expr!==void 0?`(${t.expr})`:JSON.stringify(t.literal??!0)}function Se(t,e,n){let r=t.filter(s=>s.kind==="spread"),o=t.filter(s=>s.kind!=="spread").map(s=>`${U(s.name)}: ${Re(s)}`);e!=null&&o.push(`children: ${e}`);let a=`{ ${o.join(", ")} }`;return r.length>0?(n.add("mergeProps"),`mergeProps(${r.map(s=>s.expr).join(", ")}, ${a})`):a}function G(t,e,n){return t.length===1?k(t[0],e,n):`[${t.map(r=>k(r,e,n)).join(", ")}]`}function W(t,e,n,r,i){r.add("createMemo"),r.add("createComponent");let o=e.filter(c=>c.kind==="spread"),s=e.filter(c=>c.kind!=="spread").map(c=>`get ${U(c.name)}() { return ${Ne(c)}; }`);n.length>0&&s.push(`get children() { return ${G(n,r,i)}; }`);let l=`{ ${s.join(", ")} }`;return o.length>0&&(r.add("mergeProps"),l=`mergeProps(${o.map(c=>c.expr).join(", ")}, ${l})`),`createMemo(() => createComponent(${t}, ${l}))`}function be(t,e){let n=M(e.name),r=e.literal;return r===!0||r===void 0?`${t}.setAttribute(${JSON.stringify(n)}, "");`:r===!1||r===null?"":`${t}.setAttribute(${JSON.stringify(n)}, ${JSON.stringify(String(r))});`}var K=!1;function k(t,e,n){switch(t.kind){case"text":return JSON.stringify(t.value);case"expr":return t.reactive?`() => (${t.code})`:`(${t.code})`;case"fragment":return t.children.length===0?"null":G(t.children,e,n);case"component":return W(t.name,t.props,t.children,e,n);case"control":{let r=ke[t.control]??t.control;return e.add(r),W(r,t.props,t.children,e,n)}case"element":{if(n&&t.static&&!t.svg&&A(t)){e.add("templateNode");let s=`_tmpl$${n.length}`;return n.push({id:s,html:x(t),tag:t.tag,svg:!1}),`templateNode(${s}, ${JSON.stringify(t.tag)})`}if(n&&K){let s=F(t);if(s){e.add("templateNode"),e.add("insert"),e.add("holeEnd"),e.add("holeContent"),e.add("holeScope");let l=`_tmpl$${n.length}`;n.push({id:l,html:s.html,tag:s.tag,svg:!1});let c=[`const _el$ = templateNode(${l}, ${JSON.stringify(s.tag)}, true);`];for(let u of s.steps)c.push(`const ${u.ref} = ${u.expr};`);for(let u of s.holes)c.push(`insert(${u.parentRef}, holeScope(${u.startRef}, () => (${k(u.node,e,n)})), ${u.endRef}, holeContent(${u.startRef}, ${u.endRef}));`);return c.push("return _el$;"),`(() => { ${c.join(" ")} })()`}}e.add("createNativeElement");let r=JSON.stringify(t.tag),i="_el$",o=[],a=t.svg?`${r}, true`:r;if(o.push(`const ${i} = createNativeElement(${a});`),t.props.length>0)if(!t.svg&&t.props.every(v))for(let s of t.props)o.push(be(i,s));else{e.add("spread");let s=t.svg?", isSVG: true":"";o.push(`spread({ element: ${i}, props: ${Se(t.props,null,e)}${s} });`)}for(let s of t.children){e.add("insert");let l=k(s,e,n),c=s.kind==="expr"&&s.reactive||s.kind==="component"||s.kind==="control";o.push(c?`insert(${i}, ${l}, null);`:`insert(${i}, ${l});`)}return o.push(`return ${i};`),`(() => { ${o.join(" ")} })()`}}}function E(t,e){if(!e||e.length===0)return t;let n=new Map(e.map(r=>[r.id,JSON.stringify(r.html)]));return t.replace(/_tmpl\$\d+/g,r=>n.get(r)??r)}var R={name:"imperative",contract:P,emit(t,e){let n=new Set,r=e?.templateClone!==!1?[]:void 0;return K=e?.partialTemplates===!0,{code:k(t,n,r),imports:Array.from(n),templates:r}}};import{types as p,traverse as $e,template as we}from"@babel/core";import Y from"@babel/generator";function ye(t){switch(t.kind){case"event":return"event";case"ref":return"ref";case"spread":return"spread";case"class":case"style":return"class-or-style-directive";case"attr":case"prop":return t.reactive?"reactive-prop":t.expr!==void 0?"expression-prop":void 0;default:return"expression-prop"}}function I(t){let e=[],n=new Map,r=i=>{switch(i.kind){case"text":return!0;case"expr":return!1;case"component":case"control":for(let o of i.children)r(o);return!1;case"fragment":for(let o of i.children)r(o);return!1;case"element":{let o=!0;for(let s of i.children)r(s)||(o=!1);let a;for(let s of i.props)if(a=ye(s),a)break;return!a&&!o&&(a=Ie(i)),i.static=!a,a?n.set(i,a):e.push(i),i.static}default:return!1}};for(let i of Array.isArray(t)?t:[t])r(i);return{staticElements:e,reasons:n}}function Ie(t){for(let e of t.children){if(e.kind==="expr")return"expression-child";if(e.kind==="component")return"component-child";if(e.kind==="control")return"control-child";if(e.kind==="element"&&!e.static||e.kind==="fragment")return"expression-child"}return"expression-child"}function q(t,e=new Set,n={}){let r=Z(t,e,n);return I(r),r}var Te=Y.default??Y;function te(t){return Te(t,{concise:!0}).code}function Ce(t,e){let n=p.cloneNode(t,!0),r=p.file(p.program([p.expressionStatement(n)])),i=!1,o=(a,s,l)=>{for(let c of l)e.add(c);a.replaceWith(we.expression(s,{placeholderPattern:!1,plugins:["typescript"]})()),a.skip(),i=!0};return $e(r,{"JSXElement|JSXFragment"(a){let s=a.node,{code:l,imports:c,templates:u}=R.emit(je(s,e),{});o(a,E(l,u),c)},TaggedTemplateExpression(a){let s=a.node.tag;if(!p.isIdentifier(s)||s.name!=="html"&&s.name!=="svg")return;let l=q(a.node,e,{svg:s.name==="svg"}),{code:c,imports:u,templates:d}=R.emit(l,{});o(a,E(c,d),u)}}),i?r.program.body[0].expression:t}function h(t,e){return te(Ce(t,e))}var Ae=new Set(["svg","path","circle","rect","line","polygon","polyline","ellipse","g","defs","clipPath","text"]),Pe=/^on[A-Z]/,Je=new Set(["click","dblclick","input","change","submit","focus","blur","keydown","keyup","keypress","mousedown","mouseup"]);function Le(t){if(p.isJSXIdentifier(t)){let e=t.name[0]!==t.name[0].toLowerCase();return{tag:t.name,component:e}}return p.isJSXMemberExpression(t)?{tag:te(t),component:!0}:p.isJSXNamespacedName(t)?{tag:`${t.namespace.name}:${t.name.name}`,component:!1}:{tag:"div",component:!1}}function L(t){return p.isJSXIdentifier(t)?t.name==="class"?"className":t.name:p.isJSXNamespacedName(t)?`${t.namespace.name}:${t.name.name}`:"unknown"}function m(t){return p.isCallExpression(t)||p.isOptionalCallExpression(t)?!0:p.isMemberExpression(t)||p.isOptionalMemberExpression(t)?!(!t.computed&&p.isIdentifier(t.property,{name:"children"})):p.isConditionalExpression(t)?m(t.test)||m(t.consequent)||m(t.alternate):p.isLogicalExpression(t)||p.isBinaryExpression(t)?m(t.left)||m(t.right):p.isTemplateLiteral(t)?t.expressions.some(e=>m(e)):p.isObjectExpression(t)?t.properties.some(e=>p.isObjectProperty(e)&&!e.computed&&m(e.value)):p.isArrayExpression(t)?t.elements.some(e=>e!=null&&!p.isSpreadElement(e)&&m(e)):!1}function Xe(t,e){let n=L(t.name),r=Pe.test(n),i=r||n.startsWith("on:")||n==="ref",a={name:n,kind:r?"event":"attr"};r&&(a.event={name:n.slice(2).toLowerCase(),delegated:Je.has(n.slice(2).toLowerCase())});let s=t.value;if(s==null)return a.literal=!0,a;if(p.isStringLiteral(s))return a.literal=s.value,a;if(p.isJSXExpressionContainer(s)&&!p.isJSXEmptyExpression(s.expression)){let l=s.expression;return p.isStringLiteral(l)||p.isNumericLiteral(l)||p.isBooleanLiteral(l)?(a.literal=l.value,a):(a.expr=h(l,e),a.reactive=i?!1:m(l),(p.isJSXElement(l)||p.isJSXFragment(l))&&(a.jsxElement=!0),a)}return a.literal=!0,a}function Q(t,e){let n=t.value;return n==null?null:p.isStringLiteral(n)?JSON.stringify(n.value):p.isJSXExpressionContainer(n)&&!p.isJSXEmptyExpression(n.expression)?h(n.expression,e):null}function De(t,e){let n=[],r=[];for(let i of t){if(p.isJSXSpreadAttribute(i)){n.push({name:"",kind:"spread",expr:h(i.argument,e)});continue}if(!p.isJSXAttribute(i)||T(L(i.name)))continue;let o=p.isJSXNamespacedName(i.name)?i.name.namespace.name:null;if(o==="use"){let a=i.name.name.name;e.add(a);let s=Q(i,e);r.push(s!=null?`[${a}, () => (${s})]`:`[${a}]`);continue}if(o==="oncapture"){let a=i.name.name.name.toLowerCase(),s=Q(i,e)??"undefined";n.push({name:"on:"+a,kind:"attr",expr:`[${s}, { capture: true }]`});continue}n.push(Xe(i,e))}return r.length>0&&n.push({name:"use",kind:"attr",expr:`[${r.join(", ")}]`}),n}function $(t){let e=t.split(/\r\n|\n|\r/),n=0;for(let i=0;i<e.length;i++)/[^ \t]/.test(e[i])&&(n=i);let r="";for(let i=0;i<e.length;i++){let o=e[i].replace(/\t/g," ");i!==0&&(o=o.replace(/^ +/,"")),i!==e.length-1&&(o=o.replace(/ +$/,"")),o&&(i!==n&&(o+=" "),r+=o)}return r}function ee(t,e){let n=[];for(let r of t)if(p.isJSXText(r)){let i=$(r.value);i&&n.push({kind:"text",value:i})}else if(p.isJSXExpressionContainer(r)){if(!p.isJSXEmptyExpression(r.expression)){let i=r.expression;n.push({kind:"expr",code:h(i,e),reactive:m(i)})}}else p.isJSXElement(r)||p.isJSXFragment(r)?n.push(J(r,e)):p.isJSXSpreadChild(r)&&n.push({kind:"expr",code:h(r.expression,e),reactive:!1});return n}function je(t,e=new Set){let n=J(t,e);return I(n),n}function J(t,e){if(p.isJSXFragment(t))return{kind:"fragment",children:ee(t.children,e)};let{tag:n,component:r}=Le(t.openingElement.name),i=De(t.openingElement.attributes,e),o=ee(t.children,e);if(r){let a=Oe(t.openingElement.attributes);return{kind:"component",name:n,props:i,children:o,...a?{load:a}:{}}}return{kind:"element",tag:n,svg:Ae.has(n),props:i,children:o,static:!1}}function Oe(t){for(let e of t){if(!p.isJSXAttribute(e))continue;let n=L(e.name);if(T(n)){if(e.value&&!p.isStringLiteral(e.value))throw new f(`'${n}' needs a literal value, not an expression — the strategy is compile-time.`);return S(n,e.value?e.value.value:null)}}}var Me=ne.default??ne;function Be(t){return Me(t,{concise:!0}).code}var re=new Set(["click","dblclick","input","change","submit","focus","blur","keydown","keyup","keypress","mousedown","mouseup"]);function He(t){return t.replace(/\\/g,"\\\\").replace(/`/g,"\\`").replace(/\$\{/g,"\\${")}function ie(t){return t.charAt(0).toUpperCase()+t.slice(1)}var X=class{constructor(e,n){this.holes=e;this.used=n}hole(e){return this.holes[e]??{node:w.identifier("undefined"),code:"undefined",reactive:!1}}emit(e){let{code:n,imports:r,templates:i}=R.emit(e,{});for(let o of r)this.used.add(o);return E(n,i)}lowerRoot(e){let n=this.lowerChildren(e);return n.length===1?n[0]:{kind:"fragment",children:n}}lowerChildren(e){let n=[];for(let r=0;r<e.length;r++){let i=e[r];if(i.kind==="Element"||i.kind==="Component"){let a=i.attributes.find(s=>s.kind==="IfDirective");if(a&&a.kind==="IfDirective"){let s=r+1;s<e.length&&this.isBlankText(e[s])&&s++;let l=e[s],c=l&&(l.kind==="Element"||l.kind==="Component")&&l.attributes.some(u=>u.kind==="ElseDirective");n.push(this.lowerIf(i,a.hole,c?l:null)),c&&(r=s);continue}if(i.attributes.some(s=>s.kind==="EachDirective")){n.push(this.lowerEach(i));continue}}let o=this.lowerNode(i);o&&n.push(o)}return n}isBlankText(e){return e.kind==="Text"&&!e.raw&&$(e.value)===""}lowerNode(e){switch(e.kind){case"Text":{if(e.raw)return{kind:"text",value:e.value};let n=$(e.value);return n?{kind:"text",value:n}:null}case"Comment":return null;case"Expression":{let n=this.hole(e.hole);return{kind:"expr",code:n.code,reactive:n.reactive}}case"Fragment":return{kind:"fragment",children:this.lowerChildren(e.children)};case"Element":return this.lowerElement(e);case"Component":return this.lowerComponent(e);default:return null}}lowerElement(e){let n=e.attributes.find(r=>r.kind==="Attribute"&&r.name==="is");if(e.tag==="component"&&n&&n.value&&n.value.kind==="hole"){let r=e.attributes.filter(o=>o!==n),i=this.lowerComponent({...e,kind:"Component",tag:"Dynamic",tagHole:null,attributes:r});return i.props.unshift({name:"component",kind:"attr",expr:`() => (${this.hole(n.value.hole).code})`}),i}return{kind:"element",tag:e.tag,svg:e.namespace==="svg",props:this.lowerAttributes(e.attributes),children:this.lowerChildren(e.children),static:!1}}lowerComponent(e){let n=e.tagHole!=null?this.hole(e.tagHole).code:e.tag,r=this.lowerAttributes(e.attributes),{slots:i,rest:o}=this.partitionSlots(e.children);for(let[l,c]of i){let u=c.length===1?c[0]:{kind:"fragment",children:c},d={name:l,kind:"attr",expr:this.emit(u),jsxElement:!0},g=r.findIndex(N=>N.name===l);g>=0?r[g]=d:r.push(d)}let a=e.attributes.find(l=>l.kind==="LoadDirective"),s=a?S(`load:${a.strategy}`,a.modifier):void 0;return{kind:"component",name:n,props:r,children:this.lowerChildren(o),...s?{load:s}:{}}}partitionSlots(e){let n=new Map,r=[];for(let i of e){if(i.kind==="Element"||i.kind==="Component"){let o=i.attributes.find(a=>a.kind==="Attribute"&&a.name==="slot");if(o&&o.value&&o.value.kind==="static"){let a={...i,attributes:i.attributes.filter(c=>c!==o)},s=a.kind==="Element"?this.lowerElement(a):this.lowerComponent(a),l=n.get(o.value.value)??[];l.push(s),n.set(o.value.value,l);continue}}r.push(i)}return{slots:n,rest:r}}lowerIf(e,n,r){let i=this.hole(n),o=[{name:"when",kind:"attr",expr:i.code,reactive:i.reactive}];if(r){let s=this.stripAndLower(r,l=>l.kind==="ElseDirective");o.push({name:"fallback",kind:"attr",expr:this.emit(s),jsxElement:!0})}let a=this.stripAndLower(e,s=>s.kind==="IfDirective");return{kind:"component",name:"Show",props:o,children:[a]}}lowerEach(e){let n=e.attributes.find(l=>l.kind==="EachDirective");if(!n||n.kind!=="EachDirective")return this.lowerNode(e);let r=this.hole(n.hole),i=[{name:"each",kind:"attr",expr:r.code,reactive:r.reactive}];if(n.key){let l="static"in n.key?`(item) => item[${JSON.stringify(n.key.static)}]`:this.hole(n.key.hole).code;i.push({name:"by",kind:"attr",expr:l})}let o=this.itemArrow(e),a;if(o){let l=o.body,c={kind:"expr",code:h(l,this.used),reactive:m(l)},u=this.rebuildWithChildren(e,[c]);a=`(${o.params.map(d=>Be(d)).join(", ")}) => (${this.emit(u)})`}else{let l=this.stripAndLower(e,c=>c.kind==="EachDirective");a=`() => (${this.emit(l)})`}return{kind:"component",name:"For",props:i,children:[{kind:"expr",code:a,reactive:!1}]}}itemArrow(e){let n=e.children.filter(i=>!this.isBlankText(i));if(n.length!==1||n[0].kind!=="Expression")return null;let r=this.hole(n[0].hole).node;return w.isArrowFunctionExpression(r)&&!w.isBlockStatement(r.body)?r:null}stripAndLower(e,n){let r={...e,attributes:e.attributes.filter(i=>!n(i))};return r.kind==="Element"?this.lowerElement(r):this.lowerComponent(r)}rebuildWithChildren(e,n){let r=this.lowerAttributes(e.attributes.filter(i=>i.kind!=="EachDirective"));return e.kind==="Element"?{kind:"element",tag:e.tag,svg:e.namespace==="svg",props:r,children:n,static:!1}:{kind:"component",name:e.tag,props:r,children:n}}lowerAttributes(e){let n=[],r=[],i=!1,o=[],a=!1,s=[];for(let l of e)switch(l.kind){case"IfDirective":case"EachDirective":case"ElseDirective":break;case"Attribute":n.push(this.plainAttr(l));break;case"PropertyBinding":n.push({name:l.name,kind:"prop",expr:this.hole(l.hole).code,reactive:this.hole(l.hole).reactive});break;case"EventBinding":n.push(this.eventProp(l));break;case"RefBinding":n.push({name:"ref",kind:"ref",expr:this.hole(l.hole).code,reactive:this.hole(l.hole).reactive});break;case"Spread":n.push({name:"",kind:"spread",expr:this.hole(l.hole).code});break;case"ClassDirective":{let c=this.hole(l.hole);r.push(`${JSON.stringify(l.name)}: ${c.code}`),i=i||c.reactive;break}case"StyleDirective":{let c=this.hole(l.hole);o.push(`${JSON.stringify(l.name)}: ${c.code}`),a=a||c.reactive;break}case"BindDirective":n.push(...this.bindProps(l.name,this.hole(l.hole).code));break;case"UseDirective":{let c=l.name??(l.hole!=null?this.hole(l.hole).code:null);if(!c)break;s.push(l.name!=null&&l.hole!=null?`[${c}, () => (${this.hole(l.hole).code})]`:`[${c}]`);break}}return r.length>0&&n.push({name:"classList",kind:"attr",expr:`{ ${r.join(", ")} }`,reactive:i}),o.length>0&&n.push({name:"style",kind:"attr",expr:`{ ${o.join(", ")} }`,reactive:a}),s.length>0&&n.push({name:"use",kind:"attr",expr:`[${s.join(", ")}]`}),n}eventProp(e){let n=e.name.toLowerCase(),r=this.hole(e.hole).code;if(!(e.syntax==="colon"||e.modifiers.length>0))return{name:"on"+ie(e.name),kind:"event",event:{name:n,delegated:re.has(n)},expr:r};let o=this.wrapHandler(r,e.modifiers),a=this.eventOptions(e.modifiers),s=a?`[${o}, ${a}]`:o;return{name:"on:"+n,kind:"attr",expr:s}}wrapHandler(e,n){let r=n.includes("self")?"if (e.target !== e.currentTarget) return; ":"",i=[];return n.includes("prevent")&&i.push("e.preventDefault();"),n.includes("stop")&&i.push("e.stopPropagation();"),!r&&i.length===0?e:`(e) => { ${r}${i.join(" ")} return (${e})(e); }`}eventOptions(e){let n=[];return e.includes("capture")&&n.push("capture: true"),e.includes("once")&&n.push("once: true"),e.includes("passive")&&n.push("passive: true"),n.length?`{ ${n.join(", ")} }`:null}bindProps(e,n){let r=e==="checked",i=r?"change":"input",o=r?"checked":"value",a=`(${n})`;return[{name:e,kind:"attr",expr:`${a}[0]()`,reactive:!0},{name:"on"+ie(i),kind:"event",event:{name:i,delegated:re.has(i)},expr:`(e) => ${a}[1](e.target.${o})`}]}plainAttr(e){let n=e.value,r=e.name;e.name==="class"?r=n&&n.kind==="hole"&&w.isObjectExpression(this.hole(n.hole).node)?"classList":"className":e.name==="html"&&(r="innerHTML");let o={name:r,kind:"attr"};if(n==null)return o.literal=!0,o;if(n.kind==="static")return o.literal=n.value,o;if(n.kind==="hole"){let l=this.hole(n.hole);return o.expr=l.code,o.reactive=l.reactive,o}let a=!1,s=n.parts.map(l=>{if("text"in l)return He(l.text);let c=this.hole(l.hole);return a=a||c.reactive,"${"+c.code+"}"}).join("");return o.expr="`"+s+"`",o.reactive=a,o}};function Z(t,e,n={}){let r=t.quasi,i=r.expressions.map(s=>{let l=s;return{node:l,code:h(l,e),reactive:m(l)}}),o=Fe(r),{root:a}=_e(o,{svg:n.svg});return new X(i,e).lowerRoot(a.children)}function Fe(t){let e=[];return t.quasis.forEach((n,r)=>{let i=n.value.cooked??n.value.raw;if(e.push({kind:"static",text:i,start:n.start??0}),r<t.expressions.length){let o=t.expressions[r];e.push({kind:"hole",index:r,start:o.start??0,end:o.end??0})}}),e}export{Z as lowerLitTemplate};
1
+ import{types as M}from"@babel/core";import ue from"@babel/generator";import{parseTemplate as Je}from"@fluixi/template-parser";var me={kind:"eager"},fe=["pointerdown","focusin","keydown"],B=new Set(["eager","idle","visible","interaction","media","never"]),m=class extends Error{};function P(e){return e.startsWith("load:")}function I(e,t){let n=e.slice(5);if(!B.has(n))throw new m(`Unknown load strategy 'load:${n}'. Expected one of ${[...B].join(", ")}.`);switch(n){case"eager":return me;case"idle":return{kind:"idle"};case"never":return{kind:"never"};case"visible":return t?{kind:"visible",rootMargin:t}:{kind:"visible"};case"interaction":return{kind:"interaction",events:t?he(t):[...fe]};case"media":if(!t)throw new m(`'load:media' needs a query, e.g. load:media="(min-width: 1024px)".`);return{kind:"media",query:t};default:throw new m(`Unhandled load strategy '${n}'.`)}}function he(e){let t=e.split(/[\s,]+/).map(n=>n.trim()).filter(Boolean);if(t.length===0)throw new m("'load:interaction' was given no event names.");return t}var ge=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),F={className:"class",htmlFor:"for"},ve=new Set(["innerHTML","outerHTML","innerText","textContent","value","checked","selected","muted","defaultValue","defaultChecked","children","ref"]),ke=new Set(["script","style","textarea","title"]);function A(e){return ke.has(e)}function z(e){return F[e]??e}function f(e){return e.kind!=="attr"||e.expr!==void 0||e.name.includes(":")?!1:!ve.has(e.name)}function J(e){if(!e.static||A(e.tag))return!1;for(let t of e.props)if(!f(t))return!1;for(let t of e.children)if(t.kind!=="text"&&!(t.kind==="element"&&J(t)))return!1;return!0}function h(e){let t=e.props.map(ye).filter(Boolean).join(""),n=`<${e.tag}${t}>`;return ge.has(e.tag)?n:`${n}${e.children.map(xe).join("")}</${e.tag}>`}function xe(e){if(e.kind==="text")return Ee(e.value);if(e.kind!=="element")throw new Error(`serializeStatic: unexpected ${e.kind}`);return h(e)}function ye(e){let t=F[e.name]??e.name,n=e.literal;return n===!0||n===void 0?` ${t}`:n===!1||n===null?"":` ${t}="${Ne(String(n))}"`}function Ne(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function Ee(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}var Re="<!--fx-->",be="<!--fx/-->";function w(e){return e.kind==="expr"||e.kind==="component"||e.kind==="control"}function Se(e){return e.kind==="text"||e.kind==="element"&&V(e)}function V(e){return e.svg||A(e.tag)||!e.props.every(t=>f(t))?!1:e.children.every(t=>Se(t)||w(t))}function $(e){if(w(e))return!0;let t=e.children;return t?t.some($):!1}function G(e){for(let t=0;t<e.children.length;t++){let n=e.children[t];if(n.kind==="text"&&(n.value===""||e.children[t+1]?.kind==="text"))return!1}return e.children.every(t=>t.kind!=="element"||G(t))}function W(e){if(!V(e)||!G(e)||!e.children.some($))return null;let t=[],n=[],r=0,i=l=>{let s=`_n$${r++}`;return t.push({ref:s,expr:l}),s};return o(e,"_el$"),{html:Ie(e),tag:e.tag,steps:t,holes:n};function o(l,s){let a=-1;l.children.forEach((p,d)=>{$(p)&&(a=d)});let c=null;for(let p=0;p<=a;p++){let d=l.children[p],u=c?`${c}.nextSibling`:`${s}.firstChild`;if(w(d)){let H=i(u),_=i(`holeEnd(${H})`);n.push({parentRef:s,startRef:H,endRef:_,node:d}),c=_;continue}let S=i(u);d.kind==="element"&&$(d)&&o(d,S),c=S}}}function Ie(e){return h(q(e)).split(U).join(Re+be)}function q(e){return{...e,children:e.children.map(t=>w(t)?{kind:"text",value:U}:t.kind==="element"?q(t):t)}}var U="\0fx-hole\0";var L={version:1,module:"@fluixi/dom",symbols:["createNativeElement","insert","spread","setAttribute","delegateEvents","createComponent","createMemo","untrack","Show","For","Index","Switch","Match","Dynamic","ErrorBoundary"]},st={version:2,module:"@fluixi/dom",symbols:[...L.symbols,"template","cloneTemplate","walk"]};var $e={show:"Show",for:"For",index:"Index",switch:"Switch",match:"Match",dynamic:"Dynamic",errorBoundary:"ErrorBoundary",suspense:"Suspense"};function we(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function Z(e){return we(e)?e:JSON.stringify(e)}function Te(e){return e.expr!==void 0?e.reactive?`() => (${e.expr})`:`(${e.expr})`:JSON.stringify(e.literal??!0)}function Ce(e){return e.expr!==void 0?`(${e.expr})`:JSON.stringify(e.literal??!0)}function Pe(e,t,n){let r=e.filter(s=>s.kind==="spread"),o=e.filter(s=>s.kind!=="spread").map(s=>`${Z(s.name)}: ${Te(s)}`);t!=null&&o.push(`children: ${t}`);let l=`{ ${o.join(", ")} }`;return r.length>0?(n.add("mergeProps"),`mergeProps(${r.map(s=>s.expr).join(", ")}, ${l})`):l}function Y(e,t,n){return e.length===1?g(e[0],t,n):`[${e.map(r=>g(r,t,n)).join(", ")}]`}function K(e,t,n,r,i){r.add("createMemo"),r.add("createComponent");let o=t.filter(c=>c.kind==="spread"),s=t.filter(c=>c.kind!=="spread").map(c=>`get ${Z(c.name)}() { return ${Ce(c)}; }`);n.length>0&&s.push(`get children() { return ${Y(n,r,i)}; }`);let a=`{ ${s.join(", ")} }`;return o.length>0&&(r.add("mergeProps"),a=`mergeProps(${o.map(c=>c.expr).join(", ")}, ${a})`),`createMemo(() => createComponent(${e}, ${a}))`}function Ae(e,t){let n=z(t.name),r=t.literal;return r===!0||r===void 0?`${e}.setAttribute(${JSON.stringify(n)}, "");`:r===!1||r===null?"":`${e}.setAttribute(${JSON.stringify(n)}, ${JSON.stringify(String(r))});`}var Q=!1;function g(e,t,n){switch(e.kind){case"text":return JSON.stringify(e.value);case"expr":return e.reactive?`() => (${e.code})`:`(${e.code})`;case"fragment":return e.children.length===0?"null":Y(e.children,t,n);case"component":return K(e.name,e.props,e.children,t,n);case"control":{let r=$e[e.control]??e.control;return t.add(r),K(r,e.props,e.children,t,n)}case"element":{if(n&&e.static&&!e.svg&&J(e)){t.add("templateNode");let s=`_tmpl$${n.length}`;return n.push({id:s,html:h(e),tag:e.tag,svg:!1}),`templateNode(${s}, ${JSON.stringify(e.tag)})`}if(n&&Q){let s=W(e);if(s){t.add("templateNode"),t.add("insert"),t.add("holeEnd"),t.add("holeContent"),t.add("holeScope");let a=`_tmpl$${n.length}`;n.push({id:a,html:s.html,tag:s.tag,svg:!1});let c=[`const _el$ = templateNode(${a}, ${JSON.stringify(s.tag)}, true);`];for(let p of s.steps)c.push(`const ${p.ref} = ${p.expr};`);for(let p of s.holes)c.push(`insert(${p.parentRef}, holeScope(${p.startRef}, () => (${g(p.node,t,n)})), ${p.endRef}, holeContent(${p.startRef}, ${p.endRef}));`);return c.push("return _el$;"),`(() => { ${c.join(" ")} })()`}}t.add("createNativeElement");let r=JSON.stringify(e.tag),i="_el$",o=[],l=e.svg?`${r}, true`:r;if(o.push(`const ${i} = createNativeElement(${l});`),e.props.length>0)if(!e.svg&&e.props.every(f))for(let s of e.props)o.push(Ae(i,s));else{t.add("spread");let s=e.svg?", isSVG: true":"";o.push(`spread({ element: ${i}, props: ${Pe(e.props,null,t)}${s} });`)}for(let s of e.children){t.add("insert");let a=g(s,t,n),c=s.kind==="expr"&&s.reactive||s.kind==="component"||s.kind==="control";o.push(c?`insert(${i}, ${a}, null);`:`insert(${i}, ${a});`)}return o.push(`return ${i};`),`(() => { ${o.join(" ")} })()`}}}function v(e,t){if(!t||t.length===0)return e;let n=new Map(t.map(r=>[r.id,JSON.stringify(r.html)]));return e.replace(/_tmpl\$\d+/g,r=>n.get(r)??r)}var k={name:"imperative",contract:L,emit(e,t){let n=new Set,r=t?.templateClone!==!1?[]:void 0;return Q=t?.partialTemplates===!0,{code:g(e,n,r),imports:Array.from(n),templates:r}}};function x(e){let t=e.split(/\r\n|\n|\r/),n=0;for(let i=0;i<t.length;i++)/[^ \t]/.test(t[i])&&(n=i);let r="";for(let i=0;i<t.length;i++){let o=t[i].replace(/\t/g," ");i!==0&&(o=o.replace(/^ +/,"")),i!==t.length-1&&(o=o.replace(/ +$/,"")),o&&(i!==n&&(o+=" "),r+=o)}return r}var ee=new Set(["click","dblclick","input","change","submit","focus","blur","keydown","keyup","keypress","mousedown","mouseup"]);function Le(e){return e.replace(/\\/g,"\\\\").replace(/`/g,"\\`").replace(/\$\{/g,"\\${")}function te(e){return e.charAt(0).toUpperCase()+e.slice(1)}var D=class{constructor(t,n){this.holes=t;this.used=n}hole(t){return this.holes[t]??{code:"undefined",reactive:!1}}emit(t){let{code:n,imports:r,templates:i}=k.emit(t,{});for(let o of r)this.used.add(o);return v(n,i)}lowerRoot(t){let n=this.lowerChildren(t);return n.length===1?n[0]:{kind:"fragment",children:n}}lowerChildren(t){let n=[];for(let r=0;r<t.length;r++){let i=t[r];if(i.kind==="Element"||i.kind==="Component"){let l=i.attributes.find(s=>s.kind==="IfDirective");if(l&&l.kind==="IfDirective"){let s=r+1;s<t.length&&this.isBlankText(t[s])&&s++;let a=t[s],c=a&&(a.kind==="Element"||a.kind==="Component")&&a.attributes.some(p=>p.kind==="ElseDirective");n.push(this.lowerIf(i,l.hole,c?a:null)),c&&(r=s);continue}if(i.attributes.some(s=>s.kind==="EachDirective")){n.push(this.lowerEach(i));continue}}let o=this.lowerNode(i);o&&n.push(o)}return n}isBlankText(t){return t.kind==="Text"&&!t.raw&&x(t.value)===""}lowerNode(t){switch(t.kind){case"Text":{if(t.raw)return{kind:"text",value:t.value};let n=x(t.value);return n?{kind:"text",value:n}:null}case"Comment":return null;case"Expression":{let n=this.hole(t.hole);return{kind:"expr",code:n.code,reactive:n.reactive}}case"Fragment":return{kind:"fragment",children:this.lowerChildren(t.children)};case"Element":return this.lowerElement(t);case"Component":return this.lowerComponent(t);default:return null}}lowerElement(t){let n=t.attributes.find(r=>r.kind==="Attribute"&&r.name==="is");if(t.tag==="component"&&n&&n.value&&n.value.kind==="hole"){let r=t.attributes.filter(o=>o!==n),i=this.lowerComponent({...t,kind:"Component",tag:"Dynamic",tagHole:null,attributes:r});return i.props.unshift({name:"component",kind:"attr",expr:`() => (${this.hole(n.value.hole).code})`}),i}return{kind:"element",tag:t.tag,svg:t.namespace==="svg",props:this.lowerAttributes(t.attributes),children:this.lowerChildren(t.children),static:!1}}lowerComponent(t){let n=t.tagHole!=null?this.hole(t.tagHole).code:t.tag,r=this.lowerAttributes(t.attributes),{slots:i,rest:o}=this.partitionSlots(t.children);for(let[a,c]of i){let p=c.length===1?c[0]:{kind:"fragment",children:c},d={name:a,kind:"attr",expr:this.emit(p),jsxElement:!0},u=r.findIndex(S=>S.name===a);u>=0?r[u]=d:r.push(d)}let l=t.attributes.find(a=>a.kind==="LoadDirective"),s=l?I(`load:${l.strategy}`,l.modifier):void 0;return{kind:"component",name:n,props:r,children:this.lowerChildren(o),...s?{load:s}:{}}}partitionSlots(t){let n=new Map,r=[];for(let i of t){if(i.kind==="Element"||i.kind==="Component"){let o=i.attributes.find(l=>l.kind==="Attribute"&&l.name==="slot");if(o&&o.value&&o.value.kind==="static"){let l={...i,attributes:i.attributes.filter(c=>c!==o)},s=l.kind==="Element"?this.lowerElement(l):this.lowerComponent(l),a=n.get(o.value.value)??[];a.push(s),n.set(o.value.value,a);continue}}r.push(i)}return{slots:n,rest:r}}lowerIf(t,n,r){let i=this.hole(n),o=[{name:"when",kind:"attr",expr:i.code,reactive:i.reactive}];if(r){let s=this.stripAndLower(r,a=>a.kind==="ElseDirective");o.push({name:"fallback",kind:"attr",expr:this.emit(s),jsxElement:!0})}let l=this.stripAndLower(t,s=>s.kind==="IfDirective");return{kind:"component",name:"Show",props:o,children:[l]}}lowerEach(t){let n=t.attributes.find(a=>a.kind==="EachDirective");if(!n||n.kind!=="EachDirective")return this.lowerNode(t);let r=this.hole(n.hole),i=[{name:"each",kind:"attr",expr:r.code,reactive:r.reactive}];if(n.key){let a="static"in n.key?`(item) => item[${JSON.stringify(n.key.static)}]`:this.hole(n.key.hole).code;i.push({name:"by",kind:"attr",expr:a})}let o=this.itemArrow(t),l;if(o){let a={kind:"expr",code:o.body,reactive:o.bodyReactive},c=this.rebuildWithChildren(t,[a]);l=`(${o.params.join(", ")}) => (${this.emit(c)})`}else{let a=this.stripAndLower(t,c=>c.kind==="EachDirective");l=`() => (${this.emit(a)})`}return{kind:"component",name:"For",props:i,children:[{kind:"expr",code:l,reactive:!1}]}}itemArrow(t){let n=t.children.filter(r=>!this.isBlankText(r));return n.length!==1||n[0].kind!=="Expression"?null:this.hole(n[0].hole).arrow??null}stripAndLower(t,n){let r={...t,attributes:t.attributes.filter(i=>!n(i))};return r.kind==="Element"?this.lowerElement(r):this.lowerComponent(r)}rebuildWithChildren(t,n){let r=this.lowerAttributes(t.attributes.filter(i=>i.kind!=="EachDirective"));return t.kind==="Element"?{kind:"element",tag:t.tag,svg:t.namespace==="svg",props:r,children:n,static:!1}:{kind:"component",name:t.tag,props:r,children:n}}lowerAttributes(t){let n=[],r=[],i=!1,o=[],l=!1,s=[];for(let a of t)switch(a.kind){case"IfDirective":case"EachDirective":case"ElseDirective":break;case"Attribute":n.push(this.plainAttr(a));break;case"PropertyBinding":n.push({name:a.name,kind:"prop",expr:this.hole(a.hole).code,reactive:this.hole(a.hole).reactive});break;case"EventBinding":n.push(this.eventProp(a));break;case"RefBinding":n.push({name:"ref",kind:"ref",expr:this.hole(a.hole).code,reactive:this.hole(a.hole).reactive});break;case"Spread":n.push({name:"",kind:"spread",expr:this.hole(a.hole).code});break;case"ClassDirective":{let c=this.hole(a.hole);r.push(`${JSON.stringify(a.name)}: ${c.code}`),i=i||c.reactive;break}case"StyleDirective":{let c=this.hole(a.hole);o.push(`${JSON.stringify(a.name)}: ${c.code}`),l=l||c.reactive;break}case"BindDirective":n.push(...this.bindProps(a.name,this.hole(a.hole).code));break;case"UseDirective":{let c=a.name??(a.hole!=null?this.hole(a.hole).code:null);if(!c)break;s.push(a.name!=null&&a.hole!=null?`[${c}, () => (${this.hole(a.hole).code})]`:`[${c}]`);break}}return r.length>0&&n.push({name:"classList",kind:"attr",expr:`{ ${r.join(", ")} }`,reactive:i}),o.length>0&&n.push({name:"style",kind:"attr",expr:`{ ${o.join(", ")} }`,reactive:l}),s.length>0&&n.push({name:"use",kind:"attr",expr:`[${s.join(", ")}]`}),n}eventProp(t){let n=t.name.toLowerCase(),r=this.hole(t.hole).code;if(!(t.syntax==="colon"||t.modifiers.length>0))return{name:"on"+te(t.name),kind:"event",event:{name:n,delegated:ee.has(n)},expr:r};let o=this.wrapHandler(r,t.modifiers),l=this.eventOptions(t.modifiers),s=l?`[${o}, ${l}]`:o;return{name:"on:"+n,kind:"attr",expr:s}}wrapHandler(t,n){let r=n.includes("self")?"if (e.target !== e.currentTarget) return; ":"",i=[];return n.includes("prevent")&&i.push("e.preventDefault();"),n.includes("stop")&&i.push("e.stopPropagation();"),!r&&i.length===0?t:`(e) => { ${r}${i.join(" ")} return (${t})(e); }`}eventOptions(t){let n=[];return t.includes("capture")&&n.push("capture: true"),t.includes("once")&&n.push("once: true"),t.includes("passive")&&n.push("passive: true"),n.length?`{ ${n.join(", ")} }`:null}bindProps(t,n){let r=t==="checked",i=r?"change":"input",o=r?"checked":"value",l=`(${n})`;return[{name:t,kind:"attr",expr:`${l}[0]()`,reactive:!0},{name:"on"+te(i),kind:"event",event:{name:i,delegated:ee.has(i)},expr:`(e) => ${l}[1](e.target.${o})`}]}plainAttr(t){let n=t.value,r=t.name;t.name==="class"?r=n&&n.kind==="hole"&&this.hole(n.hole).object?"classList":"className":t.name==="html"&&(r="innerHTML");let o={name:r,kind:"attr"};if(n==null)return o.literal=!0,o;if(n.kind==="static")return o.literal=n.value,o;if(n.kind==="hole"){let a=this.hole(n.hole);return o.expr=a.code,o.reactive=a.reactive,o}let l=!1,s=n.parts.map(a=>{if("text"in a)return Le(a.text);let c=this.hole(a.hole);return l=l||c.reactive,"${"+c.code+"}"}).join("");return o.expr="`"+s+"`",o.reactive=l,o}};function ne(e,t,n,r={}){let{root:i}=Je(e,{svg:r.svg});return new D(t,n).lowerRoot(i.children)}import{types as b,traverse as We,template as qe}from"@babel/core";import pe from"@babel/generator";function De(e){switch(e.kind){case"event":return"event";case"ref":return"ref";case"spread":return"spread";case"class":case"style":return"class-or-style-directive";case"attr":case"prop":return e.reactive?"reactive-prop":e.expr!==void 0?"expression-prop":void 0;default:return"expression-prop"}}function T(e){let t=[],n=new Map,r=i=>{switch(i.kind){case"text":return!0;case"expr":return!1;case"component":case"control":for(let o of i.children)r(o);return!1;case"fragment":for(let o of i.children)r(o);return!1;case"element":{let o=!0;for(let s of i.children)r(s)||(o=!1);let l;for(let s of i.props)if(l=De(s),l)break;return!l&&!o&&(l=je(i)),i.static=!l,l?n.set(i,l):t.push(i),i.static}default:return!1}};for(let i of Array.isArray(e)?e:[e])r(i);return{staticElements:t,reasons:n}}function je(e){for(let t of e.children){if(t.kind==="expr")return"expression-child";if(t.kind==="component")return"component-child";if(t.kind==="control")return"control-child";if(t.kind==="element"&&!t.static||t.kind==="fragment")return"expression-child"}return"expression-child"}function re(e,t=new Set,n={}){let r=ie(e,t,n);return T(r),r}var Oe="children";function y(e){switch(e.kind){case"call":return!0;case"member":return e.property!==Oe;case"compound":return e.parts.some(y);case"opaque":return!1}}var Xe=new Set(["CallExpression","OptionalCallExpression"]),Me=new Set(["MemberExpression","OptionalMemberExpression"]);function E(e){if(!e)return{kind:"opaque"};if(Xe.has(e.type))return{kind:"call"};if(Me.has(e.type)){let t=e.property;return{kind:"member",property:!(e.computed===!0)&&t?.type==="Identifier"?t.name:null}}return e.type==="ConditionalExpression"?{kind:"compound",parts:[e.test,e.consequent,e.alternate].map(N)}:e.type==="LogicalExpression"||e.type==="BinaryExpression"?{kind:"compound",parts:[e.left,e.right].map(N)}:e.type==="TemplateLiteral"?{kind:"compound",parts:e.expressions.map(N)}:e.type==="ObjectExpression"?{kind:"compound",parts:e.properties.filter(n=>(n.type==="ObjectProperty"||n.type==="Property")&&n.computed!==!0).map(n=>N(n.value))}:e.type==="ArrayExpression"?{kind:"compound",parts:e.elements.filter(n=>n!=null&&n.type!=="SpreadElement").map(N)}:{kind:"opaque"}}var N=e=>E(e);var He=new Set(["svg","path","circle","rect","line","polygon","polyline","ellipse","g","defs","clipPath","text"]),_e=/^on[A-Z]/,Be=new Set(["click","dblclick","input","change","submit","focus","blur","keydown","keyup","keypress","mousedown","mouseup"]),ae=e=>y(E(e));function R(e){if(e.type==="StringLiteral"||e.type==="NumericLiteral"||e.type==="BooleanLiteral"||e.type==="Literal"&&(typeof e.value=="string"||typeof e.value=="number"||typeof e.value=="boolean"))return e.value}var j=e=>!!e&&typeof R(e)=="string";function Fe(e,t){return e.type==="JSXIdentifier"?{tag:e.name,component:e.name[0]!==e.name[0].toLowerCase()}:e.type==="JSXMemberExpression"?{tag:t.code(e),component:!0}:e.type==="JSXNamespacedName"?{tag:`${e.namespace.name}:${e.name.name}`,component:!1}:{tag:"div",component:!1}}function O(e){return e.type==="JSXIdentifier"?e.name==="class"?"className":e.name:e.type==="JSXNamespacedName"?`${e.namespace.name}:${e.name.name}`:"unknown"}function ze(e,t){let n=O(e.name),r=_e.test(n),i=r||n.startsWith("on:")||n==="ref",l={name:n,kind:r?"event":"attr"};if(r){let a=n.slice(2).toLowerCase();l.event={name:a,delegated:Be.has(a)}}let s=e.value;if(s==null)return l.literal=!0,l;if(j(s))return l.literal=R(s),l;if(s.type==="JSXExpressionContainer"&&s.expression?.type!=="JSXEmptyExpression"){let a=s.expression,c=R(a);return c!==void 0?(l.literal=c,l):(l.expr=t.code(a),l.reactive=i?!1:ae(a),(a.type==="JSXElement"||a.type==="JSXFragment")&&(l.jsxElement=!0),l)}return l.literal=!0,l}function oe(e,t){let n=e.value;return n==null?null:j(n)?JSON.stringify(R(n)):n.type==="JSXExpressionContainer"&&n.expression?.type!=="JSXEmptyExpression"?t.code(n.expression):null}function Ve(e,t){let n=[],r=[];for(let i of e){if(i.type==="JSXSpreadAttribute"){n.push({name:"",kind:"spread",expr:t.code(i.argument)});continue}if(i.type!=="JSXAttribute"||P(O(i.name)))continue;let o=i.name.type==="JSXNamespacedName"?i.name.namespace.name:null;if(o==="use"){let l=i.name.name.name;t.used.add(l);let s=oe(i,t);r.push(s!=null?`[${l}, () => (${s})]`:`[${l}]`);continue}if(o==="oncapture"){let l=i.name.name.name.toLowerCase(),s=oe(i,t)??"undefined";n.push({name:"on:"+l,kind:"attr",expr:`[${s}, { capture: true }]`});continue}n.push(ze(i,t))}return r.length>0&&n.push({name:"use",kind:"attr",expr:`[${r.join(", ")}]`}),n}function se(e,t){let n=[];for(let r of e)if(r.type==="JSXText"){let i=x(r.value);i&&n.push({kind:"text",value:i})}else if(r.type==="JSXExpressionContainer"){if(r.expression?.type!=="JSXEmptyExpression"){let i=r.expression;n.push({kind:"expr",code:t.code(i),reactive:ae(i)})}}else r.type==="JSXElement"||r.type==="JSXFragment"?n.push(le(r,t)):r.type==="JSXSpreadChild"&&n.push({kind:"expr",code:t.code(r.expression),reactive:!1});return n}function Ge(e){for(let t of e){if(t.type!=="JSXAttribute")continue;let n=O(t.name);if(P(n)){if(t.value&&!j(t.value))throw new m(`'${n}' needs a literal value, not an expression — the strategy is compile-time.`);return I(n,t.value?R(t.value):null)}}}function le(e,t){if(e.type==="JSXFragment")return{kind:"fragment",children:se(e.children,t)};let{tag:n,component:r}=Fe(e.openingElement.name,t),i=Ve(e.openingElement.attributes,t),o=se(e.children,t);if(r){let l=Ge(e.openingElement.attributes);return{kind:"component",name:n,props:i,children:o,...l?{load:l}:{}}}return{kind:"element",tag:n,svg:He.has(n),props:i,children:o,static:!1}}function ce(e,t){let n=le(e,t);return T(n),n}var Ue=pe.default??pe;function de(e){return Ue(e,{concise:!0}).code}function Ke(e,t,n){let r=b.cloneNode(e,!0),i=b.file(b.program([b.expressionStatement(r)])),o=!1,l=(s,a,c)=>{for(let p of c)t.add(p);s.replaceWith(qe.expression(a,{placeholderPattern:!1,plugins:["typescript"]})()),s.skip(),o=!0};return We(i,{"JSXElement|JSXFragment"(s){let a=s.node,c=Ze(a,t,n);n?.(c);let{code:p,imports:d,templates:u}=k.emit(c,{});l(s,v(p,u),d)},TaggedTemplateExpression(s){let a=s.node.tag;if(!b.isIdentifier(a)||a.name!=="html"&&a.name!=="svg")return;let c=re(s.node,t,{svg:a.name==="svg",onNested:n});n?.(c);let{code:p,imports:d,templates:u}=k.emit(c,{});l(s,v(p,u),d)}}),o?i.program.body[0].expression:e}function C(e,t,n){return de(Ke(e,t,n))}function X(e){return y(E(e))}function Ze(e,t=new Set,n){return ce(e,{code:i=>i.type==="JSXMemberExpression"?de(i):C(i,t,n),used:t})}var Ye=ue.default??ue;function Qe(e){return Ye(e,{concise:!0}).code}function et(e,t,n){let r={code:C(e,t,n),reactive:X(e)};if(M.isArrowFunctionExpression(e)&&!M.isBlockStatement(e.body)){let i=e.body;r.arrow={params:e.params.map(o=>Qe(o)),body:C(i,t,n),bodyReactive:X(i)}}return M.isObjectExpression(e)&&(r.object=!0),r}function ie(e,t,n={}){let r=e.quasi,i=r.expressions.map(o=>et(o,t,n.onNested));return ne(tt(r),i,t,n)}function tt(e){let t=[];return e.quasis.forEach((n,r)=>{let i=n.value.cooked??n.value.raw;if(t.push({kind:"static",text:i,start:n.start??0}),r<e.expressions.length){let o=e.expressions[r];t.push({kind:"hole",index:r,start:o.start??0,end:o.end??0})}}),t}export{ie as lowerLitTemplate};