@fluixi/compiler 1.0.0-alpha.92 → 1.0.0-alpha.94

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 (102) hide show
  1. package/dist/analyze/intrinsics.cjs +31 -1
  2. package/dist/analyze/intrinsics.d.cts +14 -0
  3. package/dist/analyze/intrinsics.d.ts +14 -0
  4. package/dist/analyze/intrinsics.d.ts.map +1 -1
  5. package/dist/analyze/intrinsics.js +35 -0
  6. package/dist/analyze/intrinsics.mjs +31 -1
  7. package/dist/analyze/reactive-bindings.cjs +18 -0
  8. package/dist/analyze/reactive-bindings.mjs +18 -0
  9. package/dist/analyze/static-graph.cjs +22 -4
  10. package/dist/analyze/static-graph.d.ts.map +1 -1
  11. package/dist/analyze/static-graph.js +6 -4
  12. package/dist/analyze/static-graph.mjs +22 -4
  13. package/dist/{babel-GI375YZ2.mjs → babel-RJFQVFJW.mjs} +4 -4
  14. package/dist/{chunk-QZ4CJPYP.mjs → chunk-DP2QDWWH.mjs} +1 -1
  15. package/dist/{chunk-DWNWN5RH.mjs → chunk-E2RWTIYE.mjs} +21 -15
  16. package/dist/{chunk-XJ5H2MXY.mjs → chunk-HCCBEJEZ.mjs} +31 -1
  17. package/dist/{chunk-VOUI6XPV.mjs → chunk-HIZU7WI2.mjs} +1 -1
  18. package/dist/{chunk-VC6X44FS.mjs → chunk-ZR2QHTEX.mjs} +505 -68
  19. package/dist/codegen/backends/imperative.cjs +24 -6
  20. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  21. package/dist/codegen/backends/imperative.js +20 -4
  22. package/dist/codegen/backends/imperative.mjs +24 -6
  23. package/dist/frontend/babel/build-ir-lit.cjs +470 -63
  24. package/dist/frontend/babel/build-ir-lit.mjs +470 -63
  25. package/dist/frontend/babel/build-ir.cjs +470 -63
  26. package/dist/frontend/babel/build-ir.mjs +470 -63
  27. package/dist/frontend/babel/index.cjs +471 -64
  28. package/dist/frontend/babel/index.mjs +471 -64
  29. package/dist/frontend/babel/lower-template.cjs +470 -63
  30. package/dist/frontend/babel/lower-template.mjs +470 -63
  31. package/dist/frontend/babel/plugin.cjs +470 -63
  32. package/dist/frontend/babel/plugin.mjs +470 -63
  33. package/dist/index.cjs +360 -58
  34. package/dist/index.mjs +372 -58
  35. package/dist/integrations.cjs +1347 -98
  36. package/dist/integrations.d.ts.map +1 -1
  37. package/dist/integrations.js +44 -2
  38. package/dist/integrations.mjs +205 -19
  39. package/dist/lower/compile-template.cjs +354 -57
  40. package/dist/lower/compile-template.d.cts +13 -0
  41. package/dist/lower/compile-template.d.ts +13 -0
  42. package/dist/lower/compile-template.d.ts.map +1 -1
  43. package/dist/lower/compile-template.js +3 -0
  44. package/dist/lower/compile-template.mjs +366 -57
  45. package/dist/lower/entities.cjs +288 -0
  46. package/dist/lower/entities.d.cts +1 -0
  47. package/dist/lower/entities.d.ts +2 -0
  48. package/dist/lower/entities.d.ts.map +1 -0
  49. package/dist/lower/entities.js +54 -0
  50. package/dist/lower/entities.mjs +267 -0
  51. package/dist/lower/jsx.cjs +567 -7
  52. package/dist/lower/jsx.d.cts +8 -0
  53. package/dist/lower/jsx.d.ts +8 -0
  54. package/dist/lower/jsx.d.ts.map +1 -1
  55. package/dist/lower/jsx.js +205 -7
  56. package/dist/lower/jsx.mjs +567 -7
  57. package/dist/lower/template.cjs +332 -56
  58. package/dist/lower/template.d.ts.map +1 -1
  59. package/dist/lower/template.js +57 -49
  60. package/dist/lower/template.mjs +332 -56
  61. package/dist/resolve/builtins.cjs +1 -1
  62. package/dist/resolve/builtins.mjs +1 -1
  63. package/dist/resolve/component-globals.cjs +20 -1
  64. package/dist/resolve/component-globals.js +2 -2
  65. package/dist/resolve/component-globals.mjs +20 -1
  66. package/dist/resolve/write-globals.cjs +20 -1
  67. package/dist/resolve/write-globals.mjs +20 -1
  68. package/dist/{server-fns-BBZRZUPP.mjs → server-fns-JLSTKWPS.mjs} +4 -4
  69. package/dist/{server-functions-VEGLIFCE.mjs → server-functions-BGY3RD4R.mjs} +3 -3
  70. package/dist/transform/index.cjs +1123 -77
  71. package/dist/transform/index.mjs +1141 -91
  72. package/dist/transform/intrinsics.cjs +18 -0
  73. package/dist/transform/intrinsics.mjs +18 -0
  74. package/dist/transform/props.mjs +19 -14
  75. package/dist/transform/server-fns.mjs +19 -14
  76. package/dist/transform/source-locations.cjs +64 -3
  77. package/dist/transform/source-locations.d.cts +7 -2
  78. package/dist/transform/source-locations.d.ts +7 -2
  79. package/dist/transform/source-locations.d.ts.map +1 -1
  80. package/dist/transform/source-locations.js +68 -3
  81. package/dist/transform/source-locations.mjs +64 -3
  82. package/dist/transform/styles.cjs +588 -0
  83. package/dist/transform/styles.d.cts +211 -0
  84. package/dist/transform/styles.d.ts +212 -0
  85. package/dist/transform/styles.d.ts.map +1 -0
  86. package/dist/transform/styles.js +714 -0
  87. package/dist/transform/styles.mjs +653 -0
  88. package/dist/transform/templates.cjs +1122 -76
  89. package/dist/transform/templates.d.cts +13 -0
  90. package/dist/transform/templates.d.ts +13 -0
  91. package/dist/transform/templates.d.ts.map +1 -1
  92. package/dist/transform/templates.js +51 -14
  93. package/dist/transform/templates.mjs +1140 -90
  94. package/dist/{transform-UWZ7ZGJ2.mjs → transform-GBP6Y4UI.mjs} +603 -19
  95. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  96. package/dist/vite-styles.cjs +180 -0
  97. package/dist/vite-styles.d.cts +59 -0
  98. package/dist/vite-styles.d.ts +60 -0
  99. package/dist/vite-styles.d.ts.map +1 -0
  100. package/dist/vite-styles.js +198 -0
  101. package/dist/vite-styles.mjs +159 -0
  102. package/package.json +10 -3
@@ -36,6 +36,563 @@ module.exports = __toCommonJS(templates_exports);
36
36
  var import_parser2 = require("@babel/parser");
37
37
  var import_magic_string2 = __toESM(require("magic-string"), 1);
38
38
 
39
+ // src/transform/styles.ts
40
+ var import_sourcemap_codec = require("@jridgewell/sourcemap-codec");
41
+ var SCOPE_ATTR = "data-fx-s";
42
+ var FUNCTIONS = /* @__PURE__ */ new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression", "ObjectMethod", "ClassMethod"]);
43
+ function collectStyles(program, sourceName, options, tags = { html: /* @__PURE__ */ new Map([["html", "html"]]) }, module2) {
44
+ const plan = {
45
+ scopes: [],
46
+ templateOwners: /* @__PURE__ */ new Map(),
47
+ drop: /* @__PURE__ */ new Set(),
48
+ styles: [],
49
+ diagnostics: [],
50
+ edits: [],
51
+ literals: [],
52
+ references: [],
53
+ shadowClasses: /* @__PURE__ */ new Map()
54
+ };
55
+ if (!options) return plan;
56
+ const literalsOf = findLiterals(program, options.cssModules ?? ["@fluixi/core", "@fluixi/dom"], plan, tags.css ?? []);
57
+ plan.names = literalsOf;
58
+ const classOf = /* @__PURE__ */ new Map();
59
+ const shadowOf = (owner) => {
60
+ const cls = classOf.get(owner);
61
+ return cls ? plan.shadowClasses.get(cls) : void 0;
62
+ };
63
+ const resolved = /* @__PURE__ */ new Map();
64
+ const piecesToNodes = (quasis, expressions, at, stack) => {
65
+ const out = [];
66
+ for (let i = 0; i < quasis.length; i++) {
67
+ const text = quasis[i].value.cooked ?? quasis[i].value.raw;
68
+ if (text.trim()) {
69
+ try {
70
+ const start = quasis[i].loc?.start;
71
+ out.push(...options.process(text, sourceName).map((n) => start ? shiftLoc(n, sourceName, start) : n));
72
+ } catch (error) {
73
+ plan.diagnostics.push({ ...at, message: `CSS could not be processed: ${error.message}` });
74
+ return null;
75
+ }
76
+ }
77
+ const expr = expressions[i];
78
+ if (!expr) continue;
79
+ const value = expr.type === "Identifier" ? resolveLiteral(expr.name, at, stack) : void 0;
80
+ if (value === void 0) {
81
+ plan.diagnostics.push({
82
+ ...at,
83
+ 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))."
84
+ });
85
+ return null;
86
+ }
87
+ if (value === null) return null;
88
+ out.push(...value);
89
+ }
90
+ return out;
91
+ };
92
+ function resolveLiteral(name, at, stack) {
93
+ const imported = literalsOf.imports.get(name);
94
+ if (imported) {
95
+ const nodes = options?.imported?.get(`${imported.source}#${imported.name}`);
96
+ if (nodes) return nodes.map(dropLoc);
97
+ plan.references.push({ name: imported.name, source: imported.source, ...at });
98
+ plan.diagnostics.push({
99
+ ...at,
100
+ 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.`
101
+ });
102
+ return null;
103
+ }
104
+ const literal = literalsOf.literals.get(name);
105
+ if (!literal) return void 0;
106
+ if (stack.includes(name)) {
107
+ plan.diagnostics.push({ ...at, message: `css\`\` values include each other: ${[...stack, name].join(" → ")}.` });
108
+ return null;
109
+ }
110
+ if (!resolved.has(name)) {
111
+ resolved.set(name, piecesToNodes(literal.quasi.quasis, literal.quasi.expressions, at, [...stack, name]));
112
+ }
113
+ return resolved.get(name);
114
+ }
115
+ for (const [name, literal] of literalsOf.literals) {
116
+ const at = { line: literal.loc?.start.line ?? 0, column: literal.loc?.start.column ?? 0 };
117
+ const nodes = resolveLiteral(name, at, []);
118
+ const id = hash(`${sourceName}:css:${name}`);
119
+ plan.edits.push({ start: literal.start, end: literal.end, code: `({ $fxStyle: ${JSON.stringify(id)} })` });
120
+ if (nodes) plan.literals.push({ id, name, css: printStyle(nodes, options.minify) });
121
+ }
122
+ const scopeOf = /* @__PURE__ */ new Map();
123
+ const names = /* @__PURE__ */ new Map();
124
+ const named = /* @__PURE__ */ new Map();
125
+ const visit = (node, owners) => {
126
+ if (!node || typeof node !== "object") return;
127
+ if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.init && FUNCTIONS.has(node.init.type)) {
128
+ named.set(node.init, node.id.name);
129
+ }
130
+ if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.id) {
131
+ for (const member of node.body.body) if (member.type === "ClassMethod") named.set(member, node.id.name);
132
+ }
133
+ if (node.type === "ClassDeclaration" || node.type === "ClassExpression") {
134
+ for (const member of node.body.body) if (member.type === "ClassMethod") classOf.set(member, node);
135
+ const shadow = staticMember(node, "shadow");
136
+ if (shadow?.value && !(shadow.value.type === "BooleanLiteral" && shadow.value.value === false)) {
137
+ plan.shadowClasses.set(node, { node, styles: staticMember(node, "styles"), indexes: [] });
138
+ }
139
+ }
140
+ if (node.type === "TaggedTemplateExpression" && node.tag.type === "Identifier" && tags.html.get(node.tag.name) === "html") {
141
+ const text = node.quasi.quasis.map((q) => q.value.raw).join("");
142
+ if (/<style[\s>]/.test(text)) {
143
+ const at = { line: node.loc?.start.line ?? 0, column: node.loc?.start.column ?? 0 };
144
+ const owner = owners[0];
145
+ if (!owner) plan.diagnostics.push({ ...at, message: "<style> has to be written inside a component." });
146
+ else {
147
+ const id = idFor(owner);
148
+ const shadow = shadowOf(owner);
149
+ plan.templateOwners.set(node.start, { id, component: functionName(owner, named) });
150
+ for (const block of templateBlocks(node.quasi)) compileBlock(block, block.scoped, owner, at);
151
+ }
152
+ }
153
+ }
154
+ const inner = FUNCTIONS.has(node.type) ? [...owners, node] : owners;
155
+ if (node.type === "JSXElement" && isStyle(node)) {
156
+ handle(node, owners);
157
+ return;
158
+ }
159
+ for (const key of Object.keys(node)) {
160
+ if (key === "loc" || key === "leadingComments" || key === "trailingComments" || key === "innerComments") continue;
161
+ const value = node[key];
162
+ if (Array.isArray(value)) for (const v of value) visit(v, inner);
163
+ else if (value && typeof value === "object" && "type" in value) visit(value, inner);
164
+ }
165
+ };
166
+ const handle = (node, owners) => {
167
+ const at = { line: node.loc?.start.line ?? 0, column: node.loc?.start.column ?? 0 };
168
+ const pieces = blockPieces(node);
169
+ if (pieces === null) {
170
+ plan.diagnostics.push({
171
+ ...at,
172
+ message: "<style> needs its CSS as one template literal, <style>{`...`}</style>: JSX reads a bare `{` as an expression."
173
+ });
174
+ return;
175
+ }
176
+ const owner = owners[0];
177
+ if (!owner) {
178
+ plan.diagnostics.push({ ...at, message: "<style> has to be written inside a component." });
179
+ return;
180
+ }
181
+ compileBlock(pieces, isScoped(node), owner, at);
182
+ plan.drop.add(node.start);
183
+ };
184
+ const compileBlock = (pieces, scoped, owner, at) => {
185
+ const component = functionName(owner, named);
186
+ const id = idFor(owner);
187
+ const processed = piecesToNodes(pieces.quasis, pieces.expressions, at, []);
188
+ if (!processed) return;
189
+ let nodes = processed;
190
+ const shadow = shadowOf(owner);
191
+ if (scoped && !shadow) {
192
+ if (!plan.scopes.some((s) => s.value === id)) plan.scopes.push({ start: owner.start, end: owner.end, value: id });
193
+ nodes = scopeNodes(nodes, id, (message) => plan.diagnostics.push({ ...at, message }));
194
+ }
195
+ const printed = module2 ? printStyleWithMap(nodes, options.minify, sourceName, module2) : { css: printStyle(nodes, options.minify) };
196
+ plan.styles.push({ id, scoped: scoped && !shadow, component, ...printed, ...shadow ? { shadow: true } : {}, ...at });
197
+ if (shadow) shadow.indexes.push(plan.styles.length - 1);
198
+ };
199
+ function idFor(owner) {
200
+ let id = scopeOf.get(owner);
201
+ if (!id) {
202
+ const component = functionName(owner, named);
203
+ const seen = names.get(component) ?? 0;
204
+ names.set(component, seen + 1);
205
+ id = hash(`${sourceName}:${component}${seen ? ":" + seen : ""}`);
206
+ scopeOf.set(owner, id);
207
+ }
208
+ return id;
209
+ }
210
+ visit(program, []);
211
+ return plan;
212
+ }
213
+ function applyTemplateStyles(ir, t) {
214
+ const walk8 = (node) => {
215
+ const children = node.children;
216
+ if (children) {
217
+ for (let i = children.length - 1; i >= 0; i--) {
218
+ const child = children[i];
219
+ if (child.kind === "element" && child.tag === "style" && t.owner) children.splice(i, 1);
220
+ else walk8(child);
221
+ }
222
+ }
223
+ if (t.scope && node.kind === "element" && node.tag !== "style" && node.props && !node.props.some((p) => p.name === SCOPE_ATTR)) {
224
+ node.props.unshift({ name: SCOPE_ATTR, kind: "attr", literal: t.scope });
225
+ }
226
+ };
227
+ walk8(ir);
228
+ }
229
+ function staticMember(cls, name) {
230
+ return cls.body.body.find(
231
+ (m) => m.type === "ClassProperty" && m.static && (m.key.type === "Identifier" && m.key.name === name || m.key.type === "StringLiteral" && m.key.value === name)
232
+ );
233
+ }
234
+ function finishShadowStyles(plan, code, moduleId) {
235
+ const edits = [];
236
+ const imports = [];
237
+ let next = 0;
238
+ const importOf = (specifier) => {
239
+ const local = `__fxShadow${next++}`;
240
+ imports.push(`import ${local} from ${JSON.stringify(specifier)};
241
+ `);
242
+ return local;
243
+ };
244
+ for (const shadow of plan.shadowClasses.values()) {
245
+ const blocks = shadow.indexes.map((i) => importOf(`${moduleId}?fx-style&index=${i}&inline&lang.css`));
246
+ let value;
247
+ const prop = shadow.styles;
248
+ if (prop?.value) {
249
+ const start = prop.value.start;
250
+ let text = code.slice(start, prop.value.end);
251
+ const replacements = [];
252
+ walkIdentifiers(prop.value, (id) => {
253
+ const local = plan.names?.literals.has(id.name) ? importOf(`${moduleId}?fx-literal=${id.name}&inline&lang.css`) : plan.names?.imports.has(id.name) && !/\.css(\?|$)/.test(plan.names.imports.get(id.name).source) ? importOf(`${plan.names.imports.get(id.name).source}?fx-literal=${plan.names.imports.get(id.name).name}&inline&lang.css`) : void 0;
254
+ if (local) replacements.push({ at: id.start - start, length: id.name.length, with: local });
255
+ });
256
+ 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);
257
+ value = text;
258
+ }
259
+ if (!blocks.length && value === void 0) continue;
260
+ if (prop?.value) {
261
+ const merged = blocks.length ? `[${value}, ${blocks.join(", ")}]` : value;
262
+ edits.push({ start: prop.value.start, end: prop.value.end, code: merged });
263
+ } else if (blocks.length) {
264
+ const open = shadow.node.body.start + 1;
265
+ edits.push({ start: open, end: open, code: ` static styles = [${blocks.join(", ")}];` });
266
+ }
267
+ }
268
+ if (imports.length) edits.push({ start: 0, end: 0, code: imports.join("") });
269
+ return edits;
270
+ }
271
+ function walkIdentifiers(node, visit) {
272
+ if (!node || typeof node !== "object") return;
273
+ if (node.type === "Identifier") return visit(node);
274
+ if (node.type === "MemberExpression") return walkIdentifiers(node.object, visit);
275
+ if (node.type === "ObjectProperty") return walkIdentifiers(node.value, visit);
276
+ for (const key of Object.keys(node)) {
277
+ if (key === "loc") continue;
278
+ const value = node[key];
279
+ if (Array.isArray(value)) for (const v of value) walkIdentifiers(v, visit);
280
+ else if (value && typeof value === "object" && "type" in value) walkIdentifiers(value, visit);
281
+ }
282
+ }
283
+ function isStyle(node) {
284
+ const name = node.openingElement.name;
285
+ return name.type === "JSXIdentifier" && name.name === "style";
286
+ }
287
+ function isScoped(node) {
288
+ return node.openingElement.attributes.some((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === "scoped");
289
+ }
290
+ function templateBlocks(quasi) {
291
+ const blocks = [];
292
+ let open = null;
293
+ quasi.quasis.forEach((q, i) => {
294
+ const raw = q.value.raw;
295
+ let from = 0;
296
+ while (from <= raw.length) {
297
+ if (!open) {
298
+ const tag = /<style\b([^>]*)>/g;
299
+ tag.lastIndex = from;
300
+ const m = tag.exec(raw);
301
+ if (!m) break;
302
+ open = { quasis: [], expressions: [], scoped: /\bscoped\b/.test(m[1]) };
303
+ from = m.index + m[0].length;
304
+ }
305
+ const close = raw.indexOf("</style", from);
306
+ open.quasis.push(slicePiece(q, raw, from, close === -1 ? raw.length : close));
307
+ if (close === -1) break;
308
+ blocks.push(open);
309
+ open = null;
310
+ from = close;
311
+ }
312
+ const expr = quasi.expressions[i];
313
+ if (open && expr) open.expressions.push(expr);
314
+ });
315
+ return blocks;
316
+ }
317
+ function slicePiece(q, raw, from, to) {
318
+ const text = raw.slice(from, to);
319
+ const start = q.loc?.start;
320
+ if (!start) return { type: "TemplateElement", value: { raw: text, cooked: text } };
321
+ const before = raw.slice(0, from).split("\n");
322
+ const line = start.line + before.length - 1;
323
+ const column = before.length > 1 ? before[before.length - 1].length : start.column + from;
324
+ return { type: "TemplateElement", value: { raw: text, cooked: text }, loc: { start: { line, column } } };
325
+ }
326
+ function blockPieces(node) {
327
+ const meaningful = node.children.filter((c) => !(c.type === "JSXText" && !c.value.trim()));
328
+ if (meaningful.length === 0) return { quasis: [], expressions: [] };
329
+ if (meaningful.length !== 1) return null;
330
+ const only = meaningful[0];
331
+ if (only.type !== "JSXExpressionContainer") return null;
332
+ const expr = only.expression;
333
+ if (expr.type === "StringLiteral") return { quasis: [{ type: "TemplateElement", value: { raw: expr.value, cooked: expr.value } }], expressions: [] };
334
+ if (expr.type === "TemplateLiteral") return { quasis: expr.quasis, expressions: expr.expressions };
335
+ return null;
336
+ }
337
+ function findLiterals(program, modules, plan, intrinsic) {
338
+ const literals = /* @__PURE__ */ new Map();
339
+ const imports = /* @__PURE__ */ new Map();
340
+ const tags = new Set(intrinsic);
341
+ for (const statement of program.body ?? []) {
342
+ if (statement.type !== "ImportDeclaration") continue;
343
+ const source = statement.source.value;
344
+ const specifiers = statement.specifiers;
345
+ for (const sp of specifiers) {
346
+ if (sp.type === "ImportSpecifier") imports.set(sp.local.name, { source, name: sp.imported.name ?? sp.imported.value });
347
+ }
348
+ if (!modules.includes(source)) continue;
349
+ const css = specifiers.find((sp) => sp.type === "ImportSpecifier" && (sp.imported.name ?? sp.imported.value) === "css");
350
+ if (!css) continue;
351
+ const local = css.local.name;
352
+ tags.add(local);
353
+ imports.delete(local);
354
+ plan.edits.push({ start: statement.start, end: statement.end, code: importWithout(statement, css) });
355
+ }
356
+ if (tags.size === 0) return { literals, imports };
357
+ const visit = (node) => {
358
+ if (!node || typeof node !== "object") return;
359
+ if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.init?.type === "TaggedTemplateExpression" && node.init.tag.type === "Identifier" && tags.has(node.init.tag.name)) {
360
+ literals.set(node.id.name, node.init);
361
+ }
362
+ for (const key of Object.keys(node)) {
363
+ if (key === "loc") continue;
364
+ const value = node[key];
365
+ if (Array.isArray(value)) for (const v of value) visit(v);
366
+ else if (value && typeof value === "object" && "type" in value) visit(value);
367
+ }
368
+ };
369
+ visit(program);
370
+ return { literals, imports };
371
+ }
372
+ function importWithout(statement, removed) {
373
+ const rest = statement.specifiers.filter((sp) => sp !== removed);
374
+ const source = JSON.stringify(statement.source.value);
375
+ if (rest.length === 0) return "";
376
+ const def = rest.find((sp) => sp.type === "ImportDefaultSpecifier");
377
+ const ns = rest.find((sp) => sp.type === "ImportNamespaceSpecifier");
378
+ const named = rest.filter((sp) => sp.type === "ImportSpecifier").map((sp) => {
379
+ const imported = sp.imported.name ?? JSON.stringify(sp.imported.value);
380
+ return imported === sp.local.name ? imported : `${imported} as ${sp.local.name}`;
381
+ });
382
+ const parts = [def?.local.name, ns ? `* as ${ns.local.name}` : void 0, named.length ? `{ ${named.join(", ")} }` : void 0].filter(Boolean);
383
+ return `import ${parts.join(", ")} from ${source};`;
384
+ }
385
+ function functionName(fn, named) {
386
+ if ((fn.type === "FunctionDeclaration" || fn.type === "FunctionExpression") && fn.id) return fn.id.name;
387
+ return named.get(fn) ?? "anonymous";
388
+ }
389
+ function hash(text) {
390
+ let h = 2166136261;
391
+ for (let i = 0; i < text.length; i++) {
392
+ h ^= text.charCodeAt(i);
393
+ h = Math.imul(h, 16777619);
394
+ }
395
+ return (h >>> 0).toString(36);
396
+ }
397
+ var OPAQUE = /(^|-)keyframes$|^font-face$|^property$|^counter-style$|^page$|^font-feature-values$/;
398
+ function scopeNodes(nodes, id, warn = () => {
399
+ }) {
400
+ return nodes.map((node) => {
401
+ if (node.kind === "rule") return { ...node, selector: scopeSelector(node.selector, id, warn) };
402
+ if (node.kind === "at-rule" && !OPAQUE.test(node.name)) return { ...node, nodes: scopeNodes(node.nodes, id, warn) };
403
+ return node;
404
+ });
405
+ }
406
+ function scopeSelector(selector, id, warn = () => {
407
+ }) {
408
+ return splitTop(selector, ",").map((complex) => scopeComplex(complex.trim(), `[${SCOPE_ATTR}="${id}"]`, warn)).join(", ");
409
+ }
410
+ function scopeComplex(selector, attr, warn) {
411
+ if (/:host\b|::slotted\(/.test(selector)) {
412
+ warn(`\`${selector}\` only means something in a shadow root; in a light-DOM component it is left as written.`);
413
+ return selector;
414
+ }
415
+ const parts = compounds(selector);
416
+ const deep = parts.findIndex((p) => p.text.startsWith(":deep("));
417
+ if (deep !== -1) {
418
+ const inner = unwrap(parts[deep].text, ":deep(");
419
+ const before = parts.slice(0, deep);
420
+ if (before.length === 0) return `${attr} ${inner}`;
421
+ const scopedBefore = scopeAt(before, before.length - 1, attr);
422
+ return `${join(scopedBefore)} ${inner}`;
423
+ }
424
+ let target = -1;
425
+ for (let i = parts.length - 1; i >= 0; i--) {
426
+ if (!parts[i].text.startsWith(":global(")) {
427
+ target = i;
428
+ break;
429
+ }
430
+ }
431
+ const out = target === -1 ? parts : scopeAt(parts, target, attr);
432
+ return join(out.map((p) => p.text.startsWith(":global(") ? { ...p, text: unwrap(p.text, ":global(") } : p));
433
+ }
434
+ function scopeAt(parts, index, attr) {
435
+ return parts.map((p, i) => i === index ? { ...p, text: insertAttr(p.text, attr) } : p);
436
+ }
437
+ function insertAttr(compound, attr) {
438
+ let depth = 0;
439
+ let quote = "";
440
+ for (let i = 0; i < compound.length; i++) {
441
+ const c = compound[i];
442
+ if (quote) {
443
+ if (c === "\\") i++;
444
+ else if (c === quote) quote = "";
445
+ continue;
446
+ }
447
+ if (c === "\\") {
448
+ i++;
449
+ continue;
450
+ }
451
+ if (c === '"' || c === "'") quote = c;
452
+ else if (c === "(" || c === "[") depth++;
453
+ else if (c === ")" || c === "]") depth--;
454
+ else if (c === ":" && depth === 0 && i > 0) return compound.slice(0, i) + attr + compound.slice(i);
455
+ }
456
+ return compound + attr;
457
+ }
458
+ function compounds(selector) {
459
+ const out = [];
460
+ let depth = 0;
461
+ let quote = "";
462
+ let current = "";
463
+ let combinator = "";
464
+ const push = () => {
465
+ if (current.trim()) out.push({ combinator: out.length ? combinator || " " : "", text: current.trim() });
466
+ current = "";
467
+ combinator = "";
468
+ };
469
+ for (let i = 0; i < selector.length; i++) {
470
+ const c = selector[i];
471
+ if (quote) {
472
+ current += c;
473
+ if (c === "\\") current += selector[++i] ?? "";
474
+ else if (c === quote) quote = "";
475
+ continue;
476
+ }
477
+ if (c === "\\") {
478
+ current += c + (selector[++i] ?? "");
479
+ continue;
480
+ }
481
+ if (c === '"' || c === "'") quote = c;
482
+ if (c === "(" || c === "[") depth++;
483
+ if (c === ")" || c === "]") depth--;
484
+ if (depth === 0 && (c === ">" || c === "+" || c === "~")) {
485
+ push();
486
+ combinator = c;
487
+ continue;
488
+ }
489
+ if (depth === 0 && /\s/.test(c)) {
490
+ if (current.trim()) {
491
+ const keep = combinator;
492
+ push();
493
+ combinator = keep;
494
+ }
495
+ continue;
496
+ }
497
+ current += c;
498
+ }
499
+ push();
500
+ return out;
501
+ }
502
+ function join(parts) {
503
+ return parts.map((p, i) => i === 0 ? p.text : p.combinator === " " ? ` ${p.text}` : ` ${p.combinator} ${p.text}`).join("");
504
+ }
505
+ function unwrap(text, prefix) {
506
+ return text.slice(prefix.length, text.lastIndexOf(")")).trim() + text.slice(text.lastIndexOf(")") + 1);
507
+ }
508
+ function splitTop(selector, separator) {
509
+ const parts = [];
510
+ let depth = 0;
511
+ let quote = "";
512
+ let start = 0;
513
+ for (let i = 0; i < selector.length; i++) {
514
+ const c = selector[i];
515
+ if (quote) {
516
+ if (c === "\\") i++;
517
+ else if (c === quote) quote = "";
518
+ } else if (c === '"' || c === "'") quote = c;
519
+ else if (c === "\\") i++;
520
+ else if (c === "(" || c === "[") depth++;
521
+ else if (c === ")" || c === "]") depth--;
522
+ else if (c === separator && depth === 0) {
523
+ parts.push(selector.slice(start, i));
524
+ start = i + 1;
525
+ }
526
+ }
527
+ parts.push(selector.slice(start));
528
+ return parts.filter((p) => p.trim());
529
+ }
530
+ function shiftLoc(node, source, start) {
531
+ 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;
532
+ if (node.kind === "rule" || node.kind === "at-rule") return { ...node, loc, nodes: node.nodes.map((n) => shiftLoc(n, source, start)) };
533
+ return { ...node, loc };
534
+ }
535
+ function dropLoc(node) {
536
+ const { loc: _loc, ...rest } = node;
537
+ if (rest.kind === "rule" || rest.kind === "at-rule") return { ...rest, nodes: rest.nodes.map(dropLoc) };
538
+ return rest;
539
+ }
540
+ function printStyleWithMap(nodes, minify, sourceName, module2) {
541
+ const lines = [[]];
542
+ let css = "";
543
+ let column = 0;
544
+ const emit = (text) => {
545
+ for (const ch of text) {
546
+ css += ch;
547
+ if (ch === "\n") {
548
+ lines.push([]);
549
+ column = 0;
550
+ } else column++;
551
+ }
552
+ };
553
+ const mark = (loc) => {
554
+ if (loc && loc.source === sourceName) lines[lines.length - 1].push([column, 0, loc.line - 1, loc.column]);
555
+ };
556
+ const write = (node, depth) => {
557
+ const pad = minify ? "" : " ".repeat(depth);
558
+ const nl = minify ? "" : "\n";
559
+ const sp = minify ? "" : " ";
560
+ emit(pad);
561
+ mark(node.loc);
562
+ if (node.kind === "declaration") {
563
+ emit(`${node.property}:${sp}${node.value}${node.important ? `${sp}!important` : ""};${nl}`);
564
+ } else if (node.kind === "raw") {
565
+ emit(`${node.text}${nl}`);
566
+ } else {
567
+ emit(`${node.kind === "rule" ? node.selector : `@${node.name}${node.params ? " " + node.params : ""}`}${sp}{${nl}`);
568
+ for (const child of node.nodes) write(child, depth + 1);
569
+ emit(`${pad}}${nl}`);
570
+ }
571
+ };
572
+ for (const node of nodes) write(node, 0);
573
+ return { css, map: { version: 3, sources: [module2.id], sourcesContent: [module2.code], names: [], mappings: (0, import_sourcemap_codec.encode)(lines) } };
574
+ }
575
+ function printStyle(nodes, minify = false) {
576
+ const out = [];
577
+ const write = (node, depth) => {
578
+ const pad = minify ? "" : " ".repeat(depth);
579
+ const nl = minify ? "" : "\n";
580
+ const sp = minify ? "" : " ";
581
+ if (node.kind === "declaration") {
582
+ out.push(`${pad}${node.property}:${sp}${node.value}${node.important ? `${sp}!important` : ""};${nl}`);
583
+ } else if (node.kind === "raw") {
584
+ out.push(`${pad}${node.text}${nl}`);
585
+ } else {
586
+ const header = node.kind === "rule" ? node.selector : `@${node.name}${node.params ? " " + node.params : ""}`;
587
+ out.push(`${pad}${header}${sp}{${nl}`);
588
+ for (const child of node.nodes) write(child, depth + 1);
589
+ out.push(`${pad}}${nl}`);
590
+ }
591
+ };
592
+ for (const node of nodes) write(node, 0);
593
+ return out.join("");
594
+ }
595
+
39
596
  // src/optimize/analyze-static.ts
40
597
  function propReason(prop) {
41
598
  switch (prop.kind) {
@@ -481,6 +1038,7 @@ var INTRINSICS = {
481
1038
  $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
482
1039
  $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
483
1040
  $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
1041
+ $cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
484
1042
  // No short runtime form for these yet, so the intrinsic stands for the `create*`
485
1043
  // name. Still worth having: no import to write, and when a shorter form is
486
1044
  // designed, the change is this line rather than a compiler pass.
@@ -491,6 +1049,19 @@ var INTRINSICS = {
491
1049
  // dependency analysis must not guess at.
492
1050
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
493
1051
  $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
1052
+ // Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
1053
+ // no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
1054
+ $batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
1055
+ $cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
1056
+ $root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
1057
+ $context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
1058
+ $renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
1059
+ $computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
1060
+ // Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
1061
+ // handle as far as reads go: the same accessor with `set` on it.
1062
+ $storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
1063
+ $asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
1064
+ $persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
494
1065
  // An environment variable, public or server-only; the browser build refuses a secret.
495
1066
  $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
496
1067
  };
@@ -503,8 +1074,11 @@ var RUNTIME_PRIMITIVES = {
503
1074
  createMemo: "memo-accessor",
504
1075
  createEffect: "effect",
505
1076
  createRenderEffect: "effect",
1077
+ renderEffect: "effect",
1078
+ computed: "effect",
506
1079
  createStore: "reactive-object",
507
1080
  resource: "resource-handle",
1081
+ cachedResource: "resource-handle",
508
1082
  createResource: "reactive-object",
509
1083
  createSelector: "memo-accessor",
510
1084
  createDeferred: "memo-accessor"
@@ -513,8 +1087,19 @@ var PRIMITIVE_MODULES = [
513
1087
  "@fluixi/reactive",
514
1088
  "@fluixi/reactive/signal",
515
1089
  "@fluixi/reactive/store",
1090
+ "@fluixi/reactive/cached-resource",
516
1091
  "@fluixi/core"
517
1092
  ];
1093
+ var TAG_INTRINSICS = {
1094
+ $html: { export: "html", module: "@fluixi/core" },
1095
+ $svg: { export: "svg", module: "@fluixi/core" },
1096
+ $css: { export: "css", module: "@fluixi/core" }
1097
+ };
1098
+ function tagIntrinsics(bound) {
1099
+ const tags = /* @__PURE__ */ new Map();
1100
+ for (const [name, tag] of Object.entries(TAG_INTRINSICS)) if (!bound.has(name)) tags.set(name, tag.export);
1101
+ return tags;
1102
+ }
518
1103
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
519
1104
  function mayHaveIntrinsic(code) {
520
1105
  return INTRINSIC_CALL.test(code);
@@ -648,6 +1233,7 @@ function resolveReactiveBindings(program) {
648
1233
  // src/transform/source-locations.ts
649
1234
  var SOURCE_MARKER = "__fx_source";
650
1235
  var COMPONENT_MARKER = "__fx_component";
1236
+ var CLASS_MARKER = "__fx_class";
651
1237
  var HOLE_MARKER = "__fx_hole";
652
1238
  var markHole = (accessor, line, column, name) => `(globalThis.${HOLE_MARKER} ?? ((f) => f))(${accessor},${line},${column}${name === void 0 ? "" : `,${JSON.stringify(name)}`})`;
653
1239
  var PROPS_MARKER = "__fx_props";
@@ -665,11 +1251,12 @@ var RUNTIME_PRIMITIVES2 = /* @__PURE__ */ new Set([
665
1251
  "createStore",
666
1252
  "createResource"
667
1253
  ]);
668
- function mayHaveReactiveCall(code) {
1254
+ function mayHaveSourceMarks(code) {
669
1255
  for (const name of RUNTIME_PRIMITIVES2) {
670
1256
  if (code.includes(name)) return true;
671
1257
  }
672
- return code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store");
1258
+ if (code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store")) return true;
1259
+ return /\bclass\b[^{;]*\bextends\b/.test(code);
673
1260
  }
674
1261
  var SINGLE_STATEMENT_PARENTS = /* @__PURE__ */ new Set([
675
1262
  "IfStatement",
@@ -688,6 +1275,7 @@ function isLoneBranch(statement, parent) {
688
1275
  function isExport(node) {
689
1276
  return node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration";
690
1277
  }
1278
+ var CLASS_FIELDS = /* @__PURE__ */ new Set(["PropertyDefinition", "ClassProperty", "ClassPrivateProperty", "AccessorProperty"]);
691
1279
  function isStatement(node) {
692
1280
  return node.type.endsWith("Statement") || node.type === "VariableDeclaration";
693
1281
  }
@@ -708,6 +1296,14 @@ function walk3(node, visit, stack = []) {
708
1296
  }
709
1297
  function nameFor(stack) {
710
1298
  const declarator = stack[stack.length - 1];
1299
+ if (declarator && CLASS_FIELDS.has(declarator.type)) {
1300
+ const key = declarator.key;
1301
+ if (key?.type === "Identifier" || key?.type === "PrivateIdentifier" || key?.type === "PrivateName") {
1302
+ const name = key.name ?? key.id?.name;
1303
+ return name;
1304
+ }
1305
+ return void 0;
1306
+ }
711
1307
  if (declarator?.type !== "VariableDeclarator") return void 0;
712
1308
  const id = declarator.id;
713
1309
  if (id?.type === "Identifier") return id.name;
@@ -756,6 +1352,17 @@ function collectSourceEdits(program, filename) {
756
1352
  });
757
1353
  }
758
1354
  }
1355
+ if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.superClass && !node.declare) {
1356
+ const at = node.loc?.start;
1357
+ const body = node.body;
1358
+ if (at && body) {
1359
+ edits.push({
1360
+ start: body.start + 1,
1361
+ end: body.start + 1,
1362
+ code: `static{globalThis.${CLASS_MARKER}?.(this,${JSON.stringify(filename)},${at.line},${at.column});}`
1363
+ });
1364
+ }
1365
+ }
759
1366
  if (node.type !== "CallExpression") return;
760
1367
  const callee = node.callee;
761
1368
  if (callee?.type !== "Identifier") return;
@@ -765,6 +1372,26 @@ function collectSourceEdits(program, filename) {
765
1372
  if (!intrinsic && !imported) return;
766
1373
  const position = node.loc?.start;
767
1374
  if (!position) return;
1375
+ for (let i = stack.length - 1; i >= 0; i--) {
1376
+ const up = stack[i];
1377
+ if (isStatement(up)) break;
1378
+ if (CLASS_FIELDS.has(up.type)) {
1379
+ if (claimed.has(node.start)) return;
1380
+ claimed.add(node.start);
1381
+ const label2 = nameFor(stack);
1382
+ const own = !up.static;
1383
+ const args2 = [
1384
+ JSON.stringify(filename),
1385
+ String(position.line),
1386
+ String(position.column),
1387
+ label2 ? JSON.stringify(label2) : own ? "undefined" : void 0,
1388
+ own ? "this" : void 0
1389
+ ].filter((a) => a !== void 0).join(",");
1390
+ edits.push({ start: node.start, end: node.start, code: `(globalThis.${SOURCE_MARKER}?.(${args2}),` });
1391
+ edits.push({ start: node.end, end: node.end, code: ")" });
1392
+ return;
1393
+ }
1394
+ }
768
1395
  let statement;
769
1396
  let parent;
770
1397
  let index = -1;
@@ -970,13 +1597,16 @@ function emitComponent(name, props, children, used, templates, at) {
970
1597
  used.add("createComponent");
971
1598
  const spreads = props.filter((p) => p.kind === "spread");
972
1599
  const normal = props.filter((p) => p.kind !== "spread");
973
- const entries = normal.map(
974
- (p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
975
- );
1600
+ const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
976
1601
  if (children.length > 0) {
977
- entries.push(`get children() { return ${emitChildren(children, used, templates)}; }`);
1602
+ bodies.push(["children", emitChildren(children, used, templates)]);
1603
+ }
1604
+ let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
1605
+ if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
1606
+ const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => (${body})`);
1607
+ const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
1608
+ obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
978
1609
  }
979
- let obj = `{ ${entries.join(", ")} }`;
980
1610
  if (spreads.length > 0) {
981
1611
  used.add("mergeProps");
982
1612
  obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
@@ -1058,7 +1688,8 @@ function emitNode(node, used, templates) {
1058
1688
  } else {
1059
1689
  used.add("spread");
1060
1690
  const svgFlag = node.svg ? ", isSVG: true" : "";
1061
- const customFlag = node.tag.includes("-") ? ", isCustomElement: true" : "";
1691
+ const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
1692
+ const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
1062
1693
  parts.push(
1063
1694
  `spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
1064
1695
  );
@@ -1171,6 +1802,271 @@ function cleanTemplateText(value) {
1171
1802
  return out;
1172
1803
  }
1173
1804
 
1805
+ // src/lower/entities.ts
1806
+ var NAMED = {
1807
+ quot: 34,
1808
+ amp: 38,
1809
+ apos: 39,
1810
+ lt: 60,
1811
+ gt: 62,
1812
+ nbsp: 160,
1813
+ iexcl: 161,
1814
+ cent: 162,
1815
+ pound: 163,
1816
+ curren: 164,
1817
+ yen: 165,
1818
+ brvbar: 166,
1819
+ sect: 167,
1820
+ uml: 168,
1821
+ copy: 169,
1822
+ ordf: 170,
1823
+ laquo: 171,
1824
+ not: 172,
1825
+ shy: 173,
1826
+ reg: 174,
1827
+ macr: 175,
1828
+ deg: 176,
1829
+ plusmn: 177,
1830
+ sup2: 178,
1831
+ sup3: 179,
1832
+ acute: 180,
1833
+ micro: 181,
1834
+ para: 182,
1835
+ middot: 183,
1836
+ cedil: 184,
1837
+ sup1: 185,
1838
+ ordm: 186,
1839
+ raquo: 187,
1840
+ frac14: 188,
1841
+ frac12: 189,
1842
+ frac34: 190,
1843
+ iquest: 191,
1844
+ Agrave: 192,
1845
+ Aacute: 193,
1846
+ Acirc: 194,
1847
+ Atilde: 195,
1848
+ Auml: 196,
1849
+ Aring: 197,
1850
+ AElig: 198,
1851
+ Ccedil: 199,
1852
+ Egrave: 200,
1853
+ Eacute: 201,
1854
+ Ecirc: 202,
1855
+ Euml: 203,
1856
+ Igrave: 204,
1857
+ Iacute: 205,
1858
+ Icirc: 206,
1859
+ Iuml: 207,
1860
+ ETH: 208,
1861
+ Ntilde: 209,
1862
+ Ograve: 210,
1863
+ Oacute: 211,
1864
+ Ocirc: 212,
1865
+ Otilde: 213,
1866
+ Ouml: 214,
1867
+ times: 215,
1868
+ Oslash: 216,
1869
+ Ugrave: 217,
1870
+ Uacute: 218,
1871
+ Ucirc: 219,
1872
+ Uuml: 220,
1873
+ Yacute: 221,
1874
+ THORN: 222,
1875
+ szlig: 223,
1876
+ agrave: 224,
1877
+ aacute: 225,
1878
+ acirc: 226,
1879
+ atilde: 227,
1880
+ auml: 228,
1881
+ aring: 229,
1882
+ aelig: 230,
1883
+ ccedil: 231,
1884
+ egrave: 232,
1885
+ eacute: 233,
1886
+ ecirc: 234,
1887
+ euml: 235,
1888
+ igrave: 236,
1889
+ iacute: 237,
1890
+ icirc: 238,
1891
+ iuml: 239,
1892
+ eth: 240,
1893
+ ntilde: 241,
1894
+ ograve: 242,
1895
+ oacute: 243,
1896
+ ocirc: 244,
1897
+ otilde: 245,
1898
+ ouml: 246,
1899
+ divide: 247,
1900
+ oslash: 248,
1901
+ ugrave: 249,
1902
+ uacute: 250,
1903
+ ucirc: 251,
1904
+ uuml: 252,
1905
+ yacute: 253,
1906
+ thorn: 254,
1907
+ yuml: 255,
1908
+ OElig: 338,
1909
+ oelig: 339,
1910
+ Scaron: 352,
1911
+ scaron: 353,
1912
+ Yuml: 376,
1913
+ fnof: 402,
1914
+ circ: 710,
1915
+ tilde: 732,
1916
+ Alpha: 913,
1917
+ Beta: 914,
1918
+ Gamma: 915,
1919
+ Delta: 916,
1920
+ Epsilon: 917,
1921
+ Zeta: 918,
1922
+ Eta: 919,
1923
+ Theta: 920,
1924
+ Iota: 921,
1925
+ Kappa: 922,
1926
+ Lambda: 923,
1927
+ Mu: 924,
1928
+ Nu: 925,
1929
+ Xi: 926,
1930
+ Omicron: 927,
1931
+ Pi: 928,
1932
+ Rho: 929,
1933
+ Sigma: 931,
1934
+ Tau: 932,
1935
+ Upsilon: 933,
1936
+ Phi: 934,
1937
+ Chi: 935,
1938
+ Psi: 936,
1939
+ Omega: 937,
1940
+ alpha: 945,
1941
+ beta: 946,
1942
+ gamma: 947,
1943
+ delta: 948,
1944
+ epsilon: 949,
1945
+ zeta: 950,
1946
+ eta: 951,
1947
+ theta: 952,
1948
+ iota: 953,
1949
+ kappa: 954,
1950
+ lambda: 955,
1951
+ mu: 956,
1952
+ nu: 957,
1953
+ xi: 958,
1954
+ omicron: 959,
1955
+ pi: 960,
1956
+ rho: 961,
1957
+ sigmaf: 962,
1958
+ sigma: 963,
1959
+ tau: 964,
1960
+ upsilon: 965,
1961
+ phi: 966,
1962
+ chi: 967,
1963
+ psi: 968,
1964
+ omega: 969,
1965
+ thetasym: 977,
1966
+ upsih: 978,
1967
+ piv: 982,
1968
+ ensp: 8194,
1969
+ emsp: 8195,
1970
+ thinsp: 8201,
1971
+ zwnj: 8204,
1972
+ zwj: 8205,
1973
+ lrm: 8206,
1974
+ rlm: 8207,
1975
+ ndash: 8211,
1976
+ mdash: 8212,
1977
+ lsquo: 8216,
1978
+ rsquo: 8217,
1979
+ sbquo: 8218,
1980
+ ldquo: 8220,
1981
+ rdquo: 8221,
1982
+ bdquo: 8222,
1983
+ dagger: 8224,
1984
+ Dagger: 8225,
1985
+ bull: 8226,
1986
+ hellip: 8230,
1987
+ permil: 8240,
1988
+ prime: 8242,
1989
+ Prime: 8243,
1990
+ lsaquo: 8249,
1991
+ rsaquo: 8250,
1992
+ oline: 8254,
1993
+ frasl: 8260,
1994
+ euro: 8364,
1995
+ image: 8465,
1996
+ weierp: 8472,
1997
+ real: 8476,
1998
+ trade: 8482,
1999
+ alefsym: 8501,
2000
+ larr: 8592,
2001
+ uarr: 8593,
2002
+ rarr: 8594,
2003
+ darr: 8595,
2004
+ harr: 8596,
2005
+ crarr: 8629,
2006
+ lArr: 8656,
2007
+ uArr: 8657,
2008
+ rArr: 8658,
2009
+ dArr: 8659,
2010
+ hArr: 8660,
2011
+ forall: 8704,
2012
+ part: 8706,
2013
+ exist: 8707,
2014
+ empty: 8709,
2015
+ nabla: 8711,
2016
+ isin: 8712,
2017
+ notin: 8713,
2018
+ ni: 8715,
2019
+ prod: 8719,
2020
+ sum: 8721,
2021
+ minus: 8722,
2022
+ lowast: 8727,
2023
+ radic: 8730,
2024
+ prop: 8733,
2025
+ infin: 8734,
2026
+ ang: 8736,
2027
+ and: 8743,
2028
+ or: 8744,
2029
+ cap: 8745,
2030
+ cup: 8746,
2031
+ int: 8747,
2032
+ there4: 8756,
2033
+ sim: 8764,
2034
+ cong: 8773,
2035
+ asymp: 8776,
2036
+ ne: 8800,
2037
+ equiv: 8801,
2038
+ le: 8804,
2039
+ ge: 8805,
2040
+ sub: 8834,
2041
+ sup: 8835,
2042
+ nsub: 8836,
2043
+ sube: 8838,
2044
+ supe: 8839,
2045
+ oplus: 8853,
2046
+ otimes: 8855,
2047
+ perp: 8869,
2048
+ sdot: 8901,
2049
+ lceil: 8968,
2050
+ rceil: 8969,
2051
+ lfloor: 8970,
2052
+ rfloor: 8971,
2053
+ lang: 9001,
2054
+ rang: 9002,
2055
+ loz: 9674,
2056
+ spades: 9824,
2057
+ clubs: 9827,
2058
+ hearts: 9829,
2059
+ diams: 9830
2060
+ };
2061
+ var REFERENCE = /&(?:#[xX]([0-9a-fA-F]{1,6})|#([0-9]{1,7})|([a-zA-Z][a-zA-Z0-9]{1,31}));/g;
2062
+ function decodeEntities(value) {
2063
+ if (!value.includes("&")) return value;
2064
+ return value.replace(REFERENCE, (match, hex, dec, name) => {
2065
+ const code = hex ? parseInt(hex, 16) : dec ? parseInt(dec, 10) : Object.prototype.hasOwnProperty.call(NAMED, name) ? NAMED[name] : void 0;
2066
+ return code !== void 0 && code <= 1114111 ? String.fromCodePoint(code) : match;
2067
+ });
2068
+ }
2069
+
1174
2070
  // src/lower/template.ts
1175
2071
  var DELEGATED = /* @__PURE__ */ new Set([
1176
2072
  "click",
@@ -1189,6 +2085,7 @@ var DELEGATED = /* @__PURE__ */ new Set([
1189
2085
  function escapeTemplate(s) {
1190
2086
  return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
1191
2087
  }
2088
+ var CONTAINER = "container";
1192
2089
  function capitalize(s) {
1193
2090
  return s.charAt(0).toUpperCase() + s.slice(1);
1194
2091
  }
@@ -1243,10 +2140,6 @@ var Lowerer = class {
1243
2140
  if (hasElse) i = elseIdx;
1244
2141
  continue;
1245
2142
  }
1246
- if (child.attributes.some((a) => a.kind === "EachDirective")) {
1247
- out.push(this.lowerEach(child));
1248
- continue;
1249
- }
1250
2143
  }
1251
2144
  const node = this.lowerNode(child);
1252
2145
  if (node) out.push(node);
@@ -1260,7 +2153,7 @@ var Lowerer = class {
1260
2153
  switch (node.kind) {
1261
2154
  case "Text": {
1262
2155
  if (node.raw) return { kind: "text", value: node.value };
1263
- const cleaned = cleanTemplateText(node.value);
2156
+ const cleaned = decodeEntities(cleanTemplateText(node.value));
1264
2157
  return cleaned ? { kind: "text", value: cleaned } : null;
1265
2158
  }
1266
2159
  case "Comment":
@@ -1288,13 +2181,16 @@ var Lowerer = class {
1288
2181
  node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
1289
2182
  return node;
1290
2183
  }
2184
+ const each = this.lowerEach(el);
2185
+ const children = each ? [each] : this.lowerChildren(el.children);
2186
+ if (el.tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
1291
2187
  const at = this.tagAt(el);
1292
2188
  return {
1293
2189
  kind: "element",
1294
2190
  tag: el.tag,
1295
2191
  svg: el.namespace === "svg",
1296
- props: this.lowerAttributes(el.attributes),
1297
- children: this.lowerChildren(el.children),
2192
+ props: this.lowerAttributes(el.attributes, true),
2193
+ children,
1298
2194
  static: false,
1299
2195
  ...at ? { at } : {}
1300
2196
  };
@@ -1366,10 +2262,14 @@ var Lowerer = class {
1366
2262
  const at = this.tagAt(el);
1367
2263
  return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
1368
2264
  }
1369
- /** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
2265
+ /**
2266
+ * `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
2267
+ * content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
2268
+ * it is. Null when the element has no `each`.
2269
+ */
1370
2270
  lowerEach(el) {
1371
2271
  const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
1372
- if (!eachDir || eachDir.kind !== "EachDirective") return this.lowerNode(el);
2272
+ if (!eachDir || eachDir.kind !== "EachDirective") return null;
1373
2273
  const each = this.hole(eachDir.hole);
1374
2274
  const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
1375
2275
  if (eachDir.key) {
@@ -1379,12 +2279,12 @@ var Lowerer = class {
1379
2279
  const arrow = this.itemArrow(el);
1380
2280
  let childrenCode;
1381
2281
  if (arrow) {
1382
- const bodyIR = { kind: "expr", code: arrow.body, reactive: arrow.bodyReactive };
1383
- const repeated = this.rebuildWithChildren(el, [bodyIR]);
1384
- childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
2282
+ const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
2283
+ childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
1385
2284
  } else {
1386
- const repeated = this.stripAndLower(el, (a) => a.kind === "EachDirective");
1387
- childrenCode = `() => ${paren(this.emit(repeated), "arrowBody")}`;
2285
+ const content = this.lowerChildren(el.children);
2286
+ const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
2287
+ childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
1388
2288
  }
1389
2289
  const children = [{ kind: "expr", code: childrenCode, reactive: false }];
1390
2290
  const at = this.tagAt(el);
@@ -1401,33 +2301,23 @@ var Lowerer = class {
1401
2301
  const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
1402
2302
  return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
1403
2303
  }
1404
- /** Same element (minus each/key) but with explicit IR children. */
1405
- rebuildWithChildren(el, children) {
1406
- const props = this.lowerAttributes(
1407
- el.attributes.filter((a) => a.kind !== "EachDirective")
1408
- );
1409
- if (el.kind === "Element") {
1410
- const at = this.tagAt(el);
1411
- return {
1412
- kind: "element",
1413
- tag: el.tag,
1414
- svg: el.namespace === "svg",
1415
- props,
1416
- children,
1417
- static: false,
1418
- ...at ? { at } : {}
1419
- };
1420
- }
1421
- return { kind: "component", name: el.tag, props, children };
1422
- }
1423
2304
  // --- attributes ---------------------------------------------------------
1424
- lowerAttributes(attrs) {
2305
+ /**
2306
+ * `element`: a DOM element, where each class:/style: value that moves is its own accessor.
2307
+ * A component gets the object as before, rebuilt whole when any value moves.
2308
+ */
2309
+ lowerAttributes(attrs, element = false) {
2310
+ let anyReactive = false;
2311
+ const entry = (name, h) => {
2312
+ anyReactive ||= h.reactive;
2313
+ if (!element || !h.reactive) return `${JSON.stringify(name)}: ${h.code}`;
2314
+ const accessor = `() => ${paren(h.code, "arrowBody")}`;
2315
+ return `${JSON.stringify(name)}: ${h.at ? markHole(accessor, h.at.line, h.at.column) : accessor}`;
2316
+ };
1425
2317
  const props = [];
1426
2318
  const classEntries = [];
1427
- let classReactive = false;
1428
2319
  let classAt;
1429
2320
  const styleEntries = [];
1430
- let styleReactive = false;
1431
2321
  let styleAt;
1432
2322
  const usePairs = [];
1433
2323
  for (const a of attrs) {
@@ -1467,15 +2357,13 @@ var Lowerer = class {
1467
2357
  break;
1468
2358
  case "ClassDirective": {
1469
2359
  const h = this.hole(a.hole);
1470
- classEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
1471
- classReactive = classReactive || h.reactive;
2360
+ classEntries.push(entry(a.name, h));
1472
2361
  classAt ??= h.at;
1473
2362
  break;
1474
2363
  }
1475
2364
  case "StyleDirective": {
1476
2365
  const h = this.hole(a.hole);
1477
- styleEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
1478
- styleReactive = styleReactive || h.reactive;
2366
+ styleEntries.push(entry(a.name, h));
1479
2367
  styleAt ??= h.at;
1480
2368
  break;
1481
2369
  }
@@ -1495,18 +2383,19 @@ var Lowerer = class {
1495
2383
  name: "classList",
1496
2384
  kind: "attr",
1497
2385
  expr: `{ ${classEntries.join(", ")} }`,
1498
- reactive: classReactive,
2386
+ reactive: !element && anyReactive,
1499
2387
  ...classAt ? { at: classAt } : {}
1500
2388
  });
1501
2389
  }
1502
2390
  if (styleEntries.length > 0) {
1503
- props.push({
1504
- name: "style",
1505
- kind: "attr",
1506
- expr: `{ ${styleEntries.join(", ")} }`,
1507
- reactive: styleReactive,
1508
- ...styleAt ? { at: styleAt } : {}
1509
- });
2391
+ const entries = `{ ${styleEntries.join(", ")} }`;
2392
+ const base = props.findIndex((p) => p.name === "style");
2393
+ if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: !element && anyReactive, ...styleAt ? { at: styleAt } : {} });
2394
+ else {
2395
+ const prop = props[base];
2396
+ const value = prop.expr === void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
2397
+ props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
2398
+ }
1510
2399
  }
1511
2400
  if (usePairs.length > 0) {
1512
2401
  props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
@@ -1595,7 +2484,7 @@ var Lowerer = class {
1595
2484
  return base;
1596
2485
  }
1597
2486
  if (v.kind === "static") {
1598
- base.literal = v.value;
2487
+ base.literal = decodeEntities(v.value);
1599
2488
  return base;
1600
2489
  }
1601
2490
  if (v.kind === "hole") {
@@ -1608,7 +2497,7 @@ var Lowerer = class {
1608
2497
  let reactive = false;
1609
2498
  let at;
1610
2499
  const body = v.parts.map((p) => {
1611
- if ("text" in p) return escapeTemplate(p.text);
2500
+ if ("text" in p) return escapeTemplate(decodeEntities(p.text));
1612
2501
  const h = this.hole(p.hole);
1613
2502
  reactive = reactive || h.reactive;
1614
2503
  at ??= h.at;
@@ -1633,6 +2522,7 @@ function compilePieces(pieces, holes, options = {}) {
1633
2522
  ...options.sourceFile ? { sourceFile: options.sourceFile } : {},
1634
2523
  ...options.positionAt ? { positionAt: options.positionAt } : {}
1635
2524
  });
2525
+ if (options.templateStyles) applyTemplateStyles(ir, options.templateStyles);
1636
2526
  analyzeStatic(ir);
1637
2527
  resolveComponentSources(ir, {
1638
2528
  resolver: createComponentResolver(options.resolve ?? []),
@@ -1738,6 +2628,22 @@ var DELEGATED2 = /* @__PURE__ */ new Set([
1738
2628
  "mouseup"
1739
2629
  ]);
1740
2630
  var isReactive = (node) => isReactiveShape(shapeOf(node));
2631
+ var CONTAINER2 = "container";
2632
+ function directive(node, name) {
2633
+ if (node.type !== "JSXElement") return void 0;
2634
+ const opening = node.openingElement;
2635
+ if (opening.name.type !== "JSXIdentifier" || opening.name.name[0] !== opening.name.name[0].toLowerCase()) return void 0;
2636
+ return opening.attributes.find((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === name);
2637
+ }
2638
+ function directiveExpr(attr) {
2639
+ const v = attr.value;
2640
+ return v?.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression" ? v.expression : void 0;
2641
+ }
2642
+ function emitIR(ir, ctx) {
2643
+ const { code, imports, templates } = imperativeBackend.emit(ir, {});
2644
+ for (const s of imports) ctx.used.add(s);
2645
+ return inlineTemplates(code, templates);
2646
+ }
1741
2647
  var posOf = (node, ctx) => {
1742
2648
  if (!ctx.sourceFile) return void 0;
1743
2649
  const at = node.loc?.start;
@@ -1815,9 +2721,12 @@ function attrExprCode(attr, ctx) {
1815
2721
  }
1816
2722
  return null;
1817
2723
  }
1818
- function buildProps(attrs, ctx) {
2724
+ function buildProps(attrs, ctx, element = false) {
1819
2725
  const props = [];
1820
2726
  const usePairs = [];
2727
+ const classEntries = [];
2728
+ const styleEntries = [];
2729
+ let styleAt;
1821
2730
  for (const a of attrs) {
1822
2731
  if (a.type === "JSXSpreadAttribute") {
1823
2732
  props.push({ name: "", kind: "spread", expr: ctx.code(a.argument) });
@@ -1833,6 +2742,27 @@ function buildProps(attrs, ctx) {
1833
2742
  usePairs.push(opts != null ? `[${dir}, () => ${paren(opts, "arrowBody")}]` : `[${dir}]`);
1834
2743
  continue;
1835
2744
  }
2745
+ if (element && (ns === "class" || ns === "style")) {
2746
+ const key = JSON.stringify(a.name.name.name);
2747
+ const v = a.value;
2748
+ let value;
2749
+ if (v == null) value = "true";
2750
+ else if (isString(v)) value = JSON.stringify(literalOf(v));
2751
+ else if (v.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression") {
2752
+ value = keyValue(v.expression, ctx);
2753
+ if (ns === "style") styleAt ??= posOf(v.expression, ctx);
2754
+ } else continue;
2755
+ (ns === "class" ? classEntries : styleEntries).push(`${key}: ${value}`);
2756
+ continue;
2757
+ }
2758
+ if (element && a.name.type === "JSXIdentifier" && a.name.name === "style" && a.value?.type === "JSXExpressionContainer") {
2759
+ const entries = objectEntries(a.value.expression, ctx);
2760
+ if (entries) {
2761
+ styleEntries.unshift(...entries);
2762
+ styleAt = posOf(a.value.expression, ctx);
2763
+ continue;
2764
+ }
2765
+ }
1836
2766
  if (ns === "oncapture") {
1837
2767
  const evt = a.name.name.name.toLowerCase();
1838
2768
  const h = attrExprCode(a, ctx) ?? "undefined";
@@ -1841,12 +2771,49 @@ function buildProps(attrs, ctx) {
1841
2771
  }
1842
2772
  props.push(buildAttr(a, ctx));
1843
2773
  }
2774
+ if (classEntries.length > 0) props.push({ name: "classList", kind: "attr", expr: `{ ${classEntries.join(", ")} }`, reactive: false });
2775
+ if (styleEntries.length > 0) {
2776
+ const entries = `{ ${styleEntries.join(", ")} }`;
2777
+ const base = props.findIndex((p) => p.name === "style" && p.kind === "attr");
2778
+ if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: false, ...styleAt ? { at: styleAt } : {} });
2779
+ else {
2780
+ const prop = props[base];
2781
+ const value = prop.literal !== void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
2782
+ props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
2783
+ }
2784
+ }
1844
2785
  if (usePairs.length > 0) props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
1845
2786
  return props;
1846
2787
  }
2788
+ function keyValue(expr, ctx) {
2789
+ const code = ctx.code(expr);
2790
+ if (!isReactive(expr)) return code;
2791
+ const accessor = `() => ${paren(code, "arrowBody")}`;
2792
+ const at = posOf(expr, ctx);
2793
+ return at ? markHole(accessor, at.line, at.column) : accessor;
2794
+ }
2795
+ function objectEntries(expr, ctx) {
2796
+ if (expr?.type !== "ObjectExpression") return null;
2797
+ const entries = [];
2798
+ for (const p of expr.properties) {
2799
+ if (p.type !== "ObjectProperty") return null;
2800
+ const key = p.computed ? `[${ctx.code(p.key)}]` : p.key.type === "Identifier" ? JSON.stringify(p.key.name) : JSON.stringify(String(p.key.value));
2801
+ entries.push(`${key}: ${keyValue(p.value, ctx)}`);
2802
+ }
2803
+ return entries;
2804
+ }
1847
2805
  function buildChildren(children, ctx) {
1848
2806
  const out = [];
1849
- for (const child of children) {
2807
+ for (let i = 0; i < children.length; i++) {
2808
+ const child = children[i];
2809
+ if (directive(child, "if")) {
2810
+ let next = i + 1;
2811
+ while (next < children.length && children[next].type === "JSXText" && !cleanTemplateText(children[next].value)) next++;
2812
+ const fallback = directive(children[next], "else") ? children[next] : null;
2813
+ out.push(buildIf(child, fallback, ctx));
2814
+ if (fallback) i = next;
2815
+ continue;
2816
+ }
1850
2817
  if (child.type === "JSXText") {
1851
2818
  const text = cleanTemplateText(child.value);
1852
2819
  if (text) out.push({ kind: "text", value: text });
@@ -1862,6 +2829,7 @@ function buildChildren(children, ctx) {
1862
2829
  });
1863
2830
  }
1864
2831
  } else if (child.type === "JSXElement" || child.type === "JSXFragment") {
2832
+ if (ctx.dropStyles?.has(child.start)) continue;
1865
2833
  out.push(buildNode(child, ctx));
1866
2834
  } else if (child.type === "JSXSpreadChild") {
1867
2835
  out.push({ kind: "expr", code: ctx.code(child.expression), reactive: false });
@@ -1883,19 +2851,72 @@ function readLoad(attrs) {
1883
2851
  }
1884
2852
  return void 0;
1885
2853
  }
2854
+ function buildIf(node, fallback, ctx) {
2855
+ const cond = directiveExpr(directive(node, "if"));
2856
+ const props = [
2857
+ cond ? { name: "when", kind: "attr", expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) } : { name: "when", kind: "attr", literal: true }
2858
+ ];
2859
+ if (fallback) {
2860
+ props.push({ name: "fallback", kind: "attr", expr: emitIR(buildElement(fallback, ctx, ["else"]), ctx), jsxElement: true });
2861
+ }
2862
+ return { kind: "component", name: "Show", props, children: [buildElement(node, ctx, ["if"])] };
2863
+ }
2864
+ function buildEach(node, ctx) {
2865
+ const attr = directive(node, "each");
2866
+ if (!attr) return null;
2867
+ const list = directiveExpr(attr);
2868
+ const props = [
2869
+ list ? { name: "each", kind: "attr", expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) } : { name: "each", kind: "attr", expr: "[]" }
2870
+ ];
2871
+ const key = directive(node, "key");
2872
+ if (key) {
2873
+ const keyExpr = directiveExpr(key);
2874
+ const by = isString(key.value) ? `(item) => item[${JSON.stringify(literalOf(key.value))}]` : keyExpr ? ctx.code(keyExpr) : void 0;
2875
+ if (by) props.push({ name: "by", kind: "attr", expr: by });
2876
+ }
2877
+ const content = node.children.filter((c) => !(c.type === "JSXText" && !cleanTemplateText(c.value)));
2878
+ const only = content.length === 1 && content[0].type === "JSXExpressionContainer" ? content[0].expression : null;
2879
+ let render;
2880
+ if (only && (only.type === "ArrowFunctionExpression" || only.type === "FunctionExpression")) {
2881
+ const fn = ctx.code(only);
2882
+ const live = only.type === "ArrowFunctionExpression" && only.body.type !== "BlockStatement" && isReactive(only.body);
2883
+ render = live ? `(...args) => () => (${fn})(...args)` : fn;
2884
+ } else {
2885
+ const built = buildChildren(node.children, ctx);
2886
+ const ir = built.length === 1 ? built[0] : { kind: "fragment", children: built };
2887
+ render = `() => ${paren(emitIR(ir, ctx), "arrowBody")}`;
2888
+ }
2889
+ return { kind: "component", name: "For", props, children: [{ kind: "expr", code: render, reactive: false }] };
2890
+ }
2891
+ function buildElement(node, ctx, handled) {
2892
+ const skip = new Set(handled);
2893
+ const directives = /* @__PURE__ */ new Set(["if", "else", "each", ...directive(node, "each") ? ["key"] : []]);
2894
+ const attributes = node.openingElement.attributes.filter(
2895
+ (a) => !(a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && (skip.has(a.name.name) || directives.has(a.name.name)))
2896
+ );
2897
+ const { tag } = tagInfo(node.openingElement.name, ctx);
2898
+ const each = buildEach(node, ctx);
2899
+ const children = each ? [each] : buildChildren(node.children, ctx);
2900
+ if (tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
2901
+ const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
2902
+ const props = buildProps(attributes, ctx, true);
2903
+ const scope = ctx.scopes?.find((s) => node.start >= s.start && node.end <= s.end);
2904
+ if (scope) props.unshift({ name: "data-fx-s", kind: "attr", literal: scope.value });
2905
+ return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
2906
+ }
1886
2907
  function buildNode(node, ctx) {
1887
2908
  if (node.type === "JSXFragment") {
1888
2909
  return { kind: "fragment", children: buildChildren(node.children, ctx) };
1889
2910
  }
2911
+ if (directive(node, "if")) return buildIf(node, null, ctx);
2912
+ if (ctx.dropStyles?.has(node.start)) return { kind: "fragment", children: [] };
1890
2913
  const { tag, component } = tagInfo(node.openingElement.name, ctx);
2914
+ if (!component) return buildElement(node, ctx, []);
1891
2915
  const props = buildProps(node.openingElement.attributes, ctx);
1892
2916
  const children = buildChildren(node.children, ctx);
1893
2917
  const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
1894
- if (component) {
1895
- const load = readLoad(node.openingElement.attributes);
1896
- return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
1897
- }
1898
- return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
2918
+ const load = readLoad(node.openingElement.attributes);
2919
+ return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
1899
2920
  }
1900
2921
  function buildJsxIR(node, ctx) {
1901
2922
  const ir = buildNode(node, ctx);
@@ -2394,8 +3415,8 @@ function isJsxRoot(node, parent, key) {
2394
3415
  if (!isJsx(node)) return false;
2395
3416
  return !(parent && isJsx(parent) && key === "children");
2396
3417
  }
2397
- function isTemplateTag(node, litTag) {
2398
- return node.type === "TaggedTemplateExpression" && node.tag?.type === "Identifier" && (node.tag.name === litTag || node.tag.name === "svg");
3418
+ function isTemplateTag(node, tags) {
3419
+ return node.type === "TaggedTemplateExpression" && node.tag?.type === "Identifier" && tags.has(node.tag.name);
2399
3420
  }
2400
3421
  function outermost(list) {
2401
3422
  return list.filter(
@@ -2541,24 +3562,30 @@ function transformTemplates(code, id, options = {}) {
2541
3562
  const wantsJsx = format !== "lit";
2542
3563
  const mayHaveTemplate = wantsLit && (code.includes(`${litTag}\``) || code.includes("svg`"));
2543
3564
  const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
2544
- const wantsSources = options.sourceLocations === true && mayHaveReactiveCall(code);
3565
+ const wantsSources = options.sourceLocations === true && mayHaveSourceMarks(code);
2545
3566
  const sourceName = relativeToRoot(id, options.sourceRoot);
2546
- if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources) return null;
3567
+ const wantsStyles = options.styles !== void 0 && (code.includes("<style") || code.includes("css`"));
3568
+ if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources && !wantsStyles) return null;
2547
3569
  const ast = (0, import_parser2.parse)(code, {
2548
3570
  sourceType: "module",
2549
3571
  plugins: ["jsx", "typescript"],
2550
3572
  errorRecovery: true
2551
3573
  });
3574
+ const intrinsicTags = options.intrinsics === false ? /* @__PURE__ */ new Map() : tagIntrinsics(moduleBindings(ast.program));
3575
+ const templateTags = /* @__PURE__ */ new Map([[litTag, "html"], ["svg", "svg"]]);
3576
+ for (const [name, tag] of intrinsicTags) if (tag !== "css") templateTags.set(name, tag);
3577
+ const cssTags = [...intrinsicTags].filter(([, tag]) => tag === "css").map(([name]) => name);
2552
3578
  const found = [];
2553
3579
  walk7(ast.program, (n, parent, key) => {
2554
- if (wantsLit && isTemplateTag(n, litTag)) found.push(n);
3580
+ if (wantsLit && isTemplateTag(n, templateTags)) found.push(n);
2555
3581
  else if (wantsJsx && isJsxRoot(n, parent, key)) found.push(n);
2556
3582
  });
2557
3583
  const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
2558
3584
  const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
2559
3585
  if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
2560
3586
  const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
2561
- 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;
3587
+ const styles = wantsStyles ? collectStyles(ast.program, sourceName, options.styles, { html: templateTags, css: cssTags }, { id, code }) : void 0;
3588
+ 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;
2562
3589
  if (silent) return null;
2563
3590
  found.sort((a, b) => b.start - a.start || a.end - b.end);
2564
3591
  const used = new Set(props.used);
@@ -2572,20 +3599,32 @@ function transformTemplates(code, id, options = {}) {
2572
3599
  declared: declaredNames(ast.program)
2573
3600
  };
2574
3601
  const hoisted = /* @__PURE__ */ new Map();
2575
- const edits = [...props.edits, ...intrinsics.edits, ...sources.edits];
3602
+ const edits = [...props.edits, ...intrinsics.edits, ...sources.edits, ...styles?.edits ?? []];
2576
3603
  for (const node of found) {
2577
3604
  const nested = found.some(
2578
3605
  (o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
2579
3606
  );
2580
3607
  if (isJsx(node)) {
2581
- edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName) });
3608
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName, styles) });
2582
3609
  continue;
2583
3610
  }
2584
3611
  const holes = node.quasi.expressions.map(
2585
3612
  (e) => bindHole(code, e, edits, options.sourceLocations === true)
2586
3613
  );
3614
+ const scope = styles?.scopes.find((s) => node.start >= s.start && node.end <= s.end)?.value;
3615
+ const owner = styles?.templateOwners.get(node.start);
3616
+ const templateStyles = options.styles && styles && (scope || owner) ? {
3617
+ options: options.styles,
3618
+ ...scope ? { scope } : {},
3619
+ ...owner ? { owner } : {},
3620
+ line: node.loc?.start.line ?? 0,
3621
+ column: node.loc?.start.column ?? 0,
3622
+ styles: styles.styles,
3623
+ diagnostics: styles.diagnostics
3624
+ } : void 0;
2587
3625
  const result = compilePieces(toPieces(node), holes, {
2588
3626
  ...options,
3627
+ ...templateStyles ? { templateStyles } : {},
2589
3628
  hoistTemplates: true,
2590
3629
  // A tag inside a template gets the same mark a JSX tag does. Without one, the nodes it
2591
3630
  // makes are the only ones in the module carrying no mark, and they take whichever was
@@ -2594,12 +3633,13 @@ function transformTemplates(code, id, options = {}) {
2594
3633
  // Same defaults as the plugin, so moving a build over is not a rendering change.
2595
3634
  templateClone: options.templateClone ?? true,
2596
3635
  partialTemplates: nested ? false : options.partialTemplates ?? true,
2597
- svg: node.tag.name === "svg"
3636
+ svg: templateTags.get(node.tag.name) === "svg"
2598
3637
  });
2599
3638
  for (const symbol of result.imports) used.add(symbol);
2600
3639
  collectNeeds(result.ir, needs);
2601
3640
  edits.push({ start: node.start, end: node.end, code: adoptTemplates(result.code, result.templates, hoisted) });
2602
3641
  }
3642
+ if (styles && options.styles) edits.push(...finishShadowStyles(styles, code, id));
2603
3643
  const out = new import_magic_string2.default(code);
2604
3644
  for (const e of outermost(edits)) {
2605
3645
  if (e.start === e.end) out.appendLeft(e.start, e.code);
@@ -2657,13 +3697,19 @@ function transformTemplates(code, id, options = {}) {
2657
3697
  ...loadDiagnostics.length ? { loadDiagnostics } : {},
2658
3698
  ...unresolvedDiagnostics.length ? { unresolvedDiagnostics } : {},
2659
3699
  ...props.diagnostics.length ? { propsDiagnostics: props.diagnostics } : {},
2660
- ...intrinsics.diagnostics.length ? { intrinsicDiagnostics: intrinsics.diagnostics } : {}
3700
+ ...intrinsics.diagnostics.length ? { intrinsicDiagnostics: intrinsics.diagnostics } : {},
3701
+ ...styles?.styles.length ? { styles: styles.styles } : {},
3702
+ ...styles?.diagnostics.length ? { styleDiagnostics: styles.diagnostics } : {},
3703
+ ...styles?.literals.length ? { styleLiterals: styles.literals } : {},
3704
+ ...styles?.references.length ? { styleReferences: styles.references } : {}
2661
3705
  };
2662
3706
  }
2663
- function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile) {
3707
+ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile, styles) {
2664
3708
  const ir = buildJsxIR(node, {
2665
3709
  code: (n) => slice(code, n.start, n.end, edits),
2666
3710
  used,
3711
+ ...styles?.scopes.length ? { scopes: styles.scopes } : {},
3712
+ ...styles?.drop.size ? { dropStyles: styles.drop } : {},
2667
3713
  ...options.sourceLocations === true && sourceFile ? { sourceFile } : {}
2668
3714
  });
2669
3715
  analyzeStatic(ir);