@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
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.92 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  INTRINSICS,
4
4
  RESERVED_COMPONENTS,
@@ -7,7 +7,7 @@ import {
7
7
  builtinComponentMap,
8
8
  isIntrinsicName,
9
9
  isPrimitiveModule
10
- } from "./chunk-XJ5H2MXY.mjs";
10
+ } from "./chunk-HCCBEJEZ.mjs";
11
11
 
12
12
  // src/analyze/expr-shape.ts
13
13
  var CALL = /* @__PURE__ */ new Set(["CallExpression", "OptionalCallExpression"]);
@@ -293,6 +293,7 @@ function resolveReactiveBindings(program) {
293
293
  // src/transform/source-locations.ts
294
294
  var SOURCE_MARKER = "__fx_source";
295
295
  var COMPONENT_MARKER = "__fx_component";
296
+ var CLASS_MARKER = "__fx_class";
296
297
  var HOLE_MARKER = "__fx_hole";
297
298
  var markHole = (accessor, line, column, name) => `(globalThis.${HOLE_MARKER} ?? ((f) => f))(${accessor},${line},${column}${name === void 0 ? "" : `,${JSON.stringify(name)}`})`;
298
299
  var PROPS_MARKER = "__fx_props";
@@ -310,11 +311,12 @@ var RUNTIME_PRIMITIVES2 = /* @__PURE__ */ new Set([
310
311
  "createStore",
311
312
  "createResource"
312
313
  ]);
313
- function mayHaveReactiveCall(code) {
314
+ function mayHaveSourceMarks(code) {
314
315
  for (const name of RUNTIME_PRIMITIVES2) {
315
316
  if (code.includes(name)) return true;
316
317
  }
317
- return code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store");
318
+ if (code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store")) return true;
319
+ return /\bclass\b[^{;]*\bextends\b/.test(code);
318
320
  }
319
321
  var SINGLE_STATEMENT_PARENTS = /* @__PURE__ */ new Set([
320
322
  "IfStatement",
@@ -333,6 +335,7 @@ function isLoneBranch(statement, parent) {
333
335
  function isExport(node) {
334
336
  return node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration";
335
337
  }
338
+ var CLASS_FIELDS = /* @__PURE__ */ new Set(["PropertyDefinition", "ClassProperty", "ClassPrivateProperty", "AccessorProperty"]);
336
339
  function isStatement(node) {
337
340
  return node.type.endsWith("Statement") || node.type === "VariableDeclaration";
338
341
  }
@@ -353,6 +356,14 @@ function walk3(node, visit, stack = []) {
353
356
  }
354
357
  function nameFor(stack) {
355
358
  const declarator = stack[stack.length - 1];
359
+ if (declarator && CLASS_FIELDS.has(declarator.type)) {
360
+ const key = declarator.key;
361
+ if (key?.type === "Identifier" || key?.type === "PrivateIdentifier" || key?.type === "PrivateName") {
362
+ const name = key.name ?? key.id?.name;
363
+ return name;
364
+ }
365
+ return void 0;
366
+ }
356
367
  if (declarator?.type !== "VariableDeclarator") return void 0;
357
368
  const id = declarator.id;
358
369
  if (id?.type === "Identifier") return id.name;
@@ -401,6 +412,17 @@ function collectSourceEdits(program, filename) {
401
412
  });
402
413
  }
403
414
  }
415
+ if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.superClass && !node.declare) {
416
+ const at = node.loc?.start;
417
+ const body = node.body;
418
+ if (at && body) {
419
+ edits.push({
420
+ start: body.start + 1,
421
+ end: body.start + 1,
422
+ code: `static{globalThis.${CLASS_MARKER}?.(this,${JSON.stringify(filename)},${at.line},${at.column});}`
423
+ });
424
+ }
425
+ }
404
426
  if (node.type !== "CallExpression") return;
405
427
  const callee = node.callee;
406
428
  if (callee?.type !== "Identifier") return;
@@ -410,6 +432,26 @@ function collectSourceEdits(program, filename) {
410
432
  if (!intrinsic && !imported) return;
411
433
  const position = node.loc?.start;
412
434
  if (!position) return;
435
+ for (let i = stack.length - 1; i >= 0; i--) {
436
+ const up = stack[i];
437
+ if (isStatement(up)) break;
438
+ if (CLASS_FIELDS.has(up.type)) {
439
+ if (claimed.has(node.start)) return;
440
+ claimed.add(node.start);
441
+ const label2 = nameFor(stack);
442
+ const own = !up.static;
443
+ const args2 = [
444
+ JSON.stringify(filename),
445
+ String(position.line),
446
+ String(position.column),
447
+ label2 ? JSON.stringify(label2) : own ? "undefined" : void 0,
448
+ own ? "this" : void 0
449
+ ].filter((a) => a !== void 0).join(",");
450
+ edits.push({ start: node.start, end: node.start, code: `(globalThis.${SOURCE_MARKER}?.(${args2}),` });
451
+ edits.push({ start: node.end, end: node.end, code: ")" });
452
+ return;
453
+ }
454
+ }
413
455
  let statement;
414
456
  let parent;
415
457
  let index = -1;
@@ -819,13 +861,16 @@ function emitComponent(name, props, children, used, templates, at) {
819
861
  used.add("createComponent");
820
862
  const spreads = props.filter((p) => p.kind === "spread");
821
863
  const normal = props.filter((p) => p.kind !== "spread");
822
- const entries = normal.map(
823
- (p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
824
- );
864
+ const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
825
865
  if (children.length > 0) {
826
- entries.push(`get children() { return ${emitChildren(children, used, templates)}; }`);
866
+ bodies.push(["children", emitChildren(children, used, templates)]);
867
+ }
868
+ let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
869
+ if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
870
+ const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => (${body})`);
871
+ const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
872
+ obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
827
873
  }
828
- let obj = `{ ${entries.join(", ")} }`;
829
874
  if (spreads.length > 0) {
830
875
  used.add("mergeProps");
831
876
  obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
@@ -907,7 +952,8 @@ function emitNode(node, used, templates) {
907
952
  } else {
908
953
  used.add("spread");
909
954
  const svgFlag = node.svg ? ", isSVG: true" : "";
910
- const customFlag = node.tag.includes("-") ? ", isCustomElement: true" : "";
955
+ const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
956
+ const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
911
957
  parts.push(
912
958
  `spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
913
959
  );
@@ -1081,6 +1127,22 @@ var DELEGATED = /* @__PURE__ */ new Set([
1081
1127
  "mouseup"
1082
1128
  ]);
1083
1129
  var isReactive = (node) => isReactiveShape(shapeOf(node));
1130
+ var CONTAINER = "container";
1131
+ function directive(node, name) {
1132
+ if (node.type !== "JSXElement") return void 0;
1133
+ const opening = node.openingElement;
1134
+ if (opening.name.type !== "JSXIdentifier" || opening.name.name[0] !== opening.name.name[0].toLowerCase()) return void 0;
1135
+ return opening.attributes.find((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === name);
1136
+ }
1137
+ function directiveExpr(attr) {
1138
+ const v = attr.value;
1139
+ return v?.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression" ? v.expression : void 0;
1140
+ }
1141
+ function emitIR(ir, ctx) {
1142
+ const { code, imports, templates } = imperativeBackend.emit(ir, {});
1143
+ for (const s of imports) ctx.used.add(s);
1144
+ return inlineTemplates(code, templates);
1145
+ }
1084
1146
  var posOf = (node, ctx) => {
1085
1147
  if (!ctx.sourceFile) return void 0;
1086
1148
  const at = node.loc?.start;
@@ -1158,9 +1220,12 @@ function attrExprCode(attr, ctx) {
1158
1220
  }
1159
1221
  return null;
1160
1222
  }
1161
- function buildProps(attrs, ctx) {
1223
+ function buildProps(attrs, ctx, element = false) {
1162
1224
  const props = [];
1163
1225
  const usePairs = [];
1226
+ const classEntries = [];
1227
+ const styleEntries = [];
1228
+ let styleAt;
1164
1229
  for (const a of attrs) {
1165
1230
  if (a.type === "JSXSpreadAttribute") {
1166
1231
  props.push({ name: "", kind: "spread", expr: ctx.code(a.argument) });
@@ -1176,6 +1241,27 @@ function buildProps(attrs, ctx) {
1176
1241
  usePairs.push(opts != null ? `[${dir}, () => ${paren(opts, "arrowBody")}]` : `[${dir}]`);
1177
1242
  continue;
1178
1243
  }
1244
+ if (element && (ns === "class" || ns === "style")) {
1245
+ const key = JSON.stringify(a.name.name.name);
1246
+ const v = a.value;
1247
+ let value;
1248
+ if (v == null) value = "true";
1249
+ else if (isString(v)) value = JSON.stringify(literalOf(v));
1250
+ else if (v.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression") {
1251
+ value = keyValue(v.expression, ctx);
1252
+ if (ns === "style") styleAt ??= posOf(v.expression, ctx);
1253
+ } else continue;
1254
+ (ns === "class" ? classEntries : styleEntries).push(`${key}: ${value}`);
1255
+ continue;
1256
+ }
1257
+ if (element && a.name.type === "JSXIdentifier" && a.name.name === "style" && a.value?.type === "JSXExpressionContainer") {
1258
+ const entries = objectEntries(a.value.expression, ctx);
1259
+ if (entries) {
1260
+ styleEntries.unshift(...entries);
1261
+ styleAt = posOf(a.value.expression, ctx);
1262
+ continue;
1263
+ }
1264
+ }
1179
1265
  if (ns === "oncapture") {
1180
1266
  const evt = a.name.name.name.toLowerCase();
1181
1267
  const h = attrExprCode(a, ctx) ?? "undefined";
@@ -1184,12 +1270,49 @@ function buildProps(attrs, ctx) {
1184
1270
  }
1185
1271
  props.push(buildAttr(a, ctx));
1186
1272
  }
1273
+ if (classEntries.length > 0) props.push({ name: "classList", kind: "attr", expr: `{ ${classEntries.join(", ")} }`, reactive: false });
1274
+ if (styleEntries.length > 0) {
1275
+ const entries = `{ ${styleEntries.join(", ")} }`;
1276
+ const base = props.findIndex((p) => p.name === "style" && p.kind === "attr");
1277
+ if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: false, ...styleAt ? { at: styleAt } : {} });
1278
+ else {
1279
+ const prop = props[base];
1280
+ const value = prop.literal !== void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
1281
+ props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
1282
+ }
1283
+ }
1187
1284
  if (usePairs.length > 0) props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
1188
1285
  return props;
1189
1286
  }
1287
+ function keyValue(expr, ctx) {
1288
+ const code = ctx.code(expr);
1289
+ if (!isReactive(expr)) return code;
1290
+ const accessor = `() => ${paren(code, "arrowBody")}`;
1291
+ const at = posOf(expr, ctx);
1292
+ return at ? markHole(accessor, at.line, at.column) : accessor;
1293
+ }
1294
+ function objectEntries(expr, ctx) {
1295
+ if (expr?.type !== "ObjectExpression") return null;
1296
+ const entries = [];
1297
+ for (const p of expr.properties) {
1298
+ if (p.type !== "ObjectProperty") return null;
1299
+ const key = p.computed ? `[${ctx.code(p.key)}]` : p.key.type === "Identifier" ? JSON.stringify(p.key.name) : JSON.stringify(String(p.key.value));
1300
+ entries.push(`${key}: ${keyValue(p.value, ctx)}`);
1301
+ }
1302
+ return entries;
1303
+ }
1190
1304
  function buildChildren(children, ctx) {
1191
1305
  const out = [];
1192
- for (const child of children) {
1306
+ for (let i = 0; i < children.length; i++) {
1307
+ const child = children[i];
1308
+ if (directive(child, "if")) {
1309
+ let next = i + 1;
1310
+ while (next < children.length && children[next].type === "JSXText" && !cleanTemplateText(children[next].value)) next++;
1311
+ const fallback = directive(children[next], "else") ? children[next] : null;
1312
+ out.push(buildIf(child, fallback, ctx));
1313
+ if (fallback) i = next;
1314
+ continue;
1315
+ }
1193
1316
  if (child.type === "JSXText") {
1194
1317
  const text = cleanTemplateText(child.value);
1195
1318
  if (text) out.push({ kind: "text", value: text });
@@ -1205,6 +1328,7 @@ function buildChildren(children, ctx) {
1205
1328
  });
1206
1329
  }
1207
1330
  } else if (child.type === "JSXElement" || child.type === "JSXFragment") {
1331
+ if (ctx.dropStyles?.has(child.start)) continue;
1208
1332
  out.push(buildNode(child, ctx));
1209
1333
  } else if (child.type === "JSXSpreadChild") {
1210
1334
  out.push({ kind: "expr", code: ctx.code(child.expression), reactive: false });
@@ -1226,19 +1350,72 @@ function readLoad(attrs) {
1226
1350
  }
1227
1351
  return void 0;
1228
1352
  }
1353
+ function buildIf(node, fallback, ctx) {
1354
+ const cond = directiveExpr(directive(node, "if"));
1355
+ const props = [
1356
+ cond ? { name: "when", kind: "attr", expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) } : { name: "when", kind: "attr", literal: true }
1357
+ ];
1358
+ if (fallback) {
1359
+ props.push({ name: "fallback", kind: "attr", expr: emitIR(buildElement(fallback, ctx, ["else"]), ctx), jsxElement: true });
1360
+ }
1361
+ return { kind: "component", name: "Show", props, children: [buildElement(node, ctx, ["if"])] };
1362
+ }
1363
+ function buildEach(node, ctx) {
1364
+ const attr = directive(node, "each");
1365
+ if (!attr) return null;
1366
+ const list = directiveExpr(attr);
1367
+ const props = [
1368
+ list ? { name: "each", kind: "attr", expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) } : { name: "each", kind: "attr", expr: "[]" }
1369
+ ];
1370
+ const key = directive(node, "key");
1371
+ if (key) {
1372
+ const keyExpr = directiveExpr(key);
1373
+ const by = isString(key.value) ? `(item) => item[${JSON.stringify(literalOf(key.value))}]` : keyExpr ? ctx.code(keyExpr) : void 0;
1374
+ if (by) props.push({ name: "by", kind: "attr", expr: by });
1375
+ }
1376
+ const content = node.children.filter((c) => !(c.type === "JSXText" && !cleanTemplateText(c.value)));
1377
+ const only = content.length === 1 && content[0].type === "JSXExpressionContainer" ? content[0].expression : null;
1378
+ let render;
1379
+ if (only && (only.type === "ArrowFunctionExpression" || only.type === "FunctionExpression")) {
1380
+ const fn = ctx.code(only);
1381
+ const live = only.type === "ArrowFunctionExpression" && only.body.type !== "BlockStatement" && isReactive(only.body);
1382
+ render = live ? `(...args) => () => (${fn})(...args)` : fn;
1383
+ } else {
1384
+ const built = buildChildren(node.children, ctx);
1385
+ const ir = built.length === 1 ? built[0] : { kind: "fragment", children: built };
1386
+ render = `() => ${paren(emitIR(ir, ctx), "arrowBody")}`;
1387
+ }
1388
+ return { kind: "component", name: "For", props, children: [{ kind: "expr", code: render, reactive: false }] };
1389
+ }
1390
+ function buildElement(node, ctx, handled) {
1391
+ const skip = new Set(handled);
1392
+ const directives = /* @__PURE__ */ new Set(["if", "else", "each", ...directive(node, "each") ? ["key"] : []]);
1393
+ const attributes = node.openingElement.attributes.filter(
1394
+ (a) => !(a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && (skip.has(a.name.name) || directives.has(a.name.name)))
1395
+ );
1396
+ const { tag } = tagInfo(node.openingElement.name, ctx);
1397
+ const each = buildEach(node, ctx);
1398
+ const children = each ? [each] : buildChildren(node.children, ctx);
1399
+ if (tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
1400
+ const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
1401
+ const props = buildProps(attributes, ctx, true);
1402
+ const scope = ctx.scopes?.find((s) => node.start >= s.start && node.end <= s.end);
1403
+ if (scope) props.unshift({ name: "data-fx-s", kind: "attr", literal: scope.value });
1404
+ return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
1405
+ }
1229
1406
  function buildNode(node, ctx) {
1230
1407
  if (node.type === "JSXFragment") {
1231
1408
  return { kind: "fragment", children: buildChildren(node.children, ctx) };
1232
1409
  }
1410
+ if (directive(node, "if")) return buildIf(node, null, ctx);
1411
+ if (ctx.dropStyles?.has(node.start)) return { kind: "fragment", children: [] };
1233
1412
  const { tag, component } = tagInfo(node.openingElement.name, ctx);
1413
+ if (!component) return buildElement(node, ctx, []);
1234
1414
  const props = buildProps(node.openingElement.attributes, ctx);
1235
1415
  const children = buildChildren(node.children, ctx);
1236
1416
  const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
1237
- if (component) {
1238
- const load = readLoad(node.openingElement.attributes);
1239
- return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
1240
- }
1241
- return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
1417
+ const load = readLoad(node.openingElement.attributes);
1418
+ return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
1242
1419
  }
1243
1420
  function buildJsxIR(node, ctx) {
1244
1421
  const ir = buildNode(node, ctx);
@@ -1250,6 +1427,273 @@ function buildJsxIR(node, ctx) {
1250
1427
  import {
1251
1428
  parseTemplate
1252
1429
  } from "@fluixi/template-parser";
1430
+
1431
+ // src/lower/entities.ts
1432
+ var NAMED = {
1433
+ quot: 34,
1434
+ amp: 38,
1435
+ apos: 39,
1436
+ lt: 60,
1437
+ gt: 62,
1438
+ nbsp: 160,
1439
+ iexcl: 161,
1440
+ cent: 162,
1441
+ pound: 163,
1442
+ curren: 164,
1443
+ yen: 165,
1444
+ brvbar: 166,
1445
+ sect: 167,
1446
+ uml: 168,
1447
+ copy: 169,
1448
+ ordf: 170,
1449
+ laquo: 171,
1450
+ not: 172,
1451
+ shy: 173,
1452
+ reg: 174,
1453
+ macr: 175,
1454
+ deg: 176,
1455
+ plusmn: 177,
1456
+ sup2: 178,
1457
+ sup3: 179,
1458
+ acute: 180,
1459
+ micro: 181,
1460
+ para: 182,
1461
+ middot: 183,
1462
+ cedil: 184,
1463
+ sup1: 185,
1464
+ ordm: 186,
1465
+ raquo: 187,
1466
+ frac14: 188,
1467
+ frac12: 189,
1468
+ frac34: 190,
1469
+ iquest: 191,
1470
+ Agrave: 192,
1471
+ Aacute: 193,
1472
+ Acirc: 194,
1473
+ Atilde: 195,
1474
+ Auml: 196,
1475
+ Aring: 197,
1476
+ AElig: 198,
1477
+ Ccedil: 199,
1478
+ Egrave: 200,
1479
+ Eacute: 201,
1480
+ Ecirc: 202,
1481
+ Euml: 203,
1482
+ Igrave: 204,
1483
+ Iacute: 205,
1484
+ Icirc: 206,
1485
+ Iuml: 207,
1486
+ ETH: 208,
1487
+ Ntilde: 209,
1488
+ Ograve: 210,
1489
+ Oacute: 211,
1490
+ Ocirc: 212,
1491
+ Otilde: 213,
1492
+ Ouml: 214,
1493
+ times: 215,
1494
+ Oslash: 216,
1495
+ Ugrave: 217,
1496
+ Uacute: 218,
1497
+ Ucirc: 219,
1498
+ Uuml: 220,
1499
+ Yacute: 221,
1500
+ THORN: 222,
1501
+ szlig: 223,
1502
+ agrave: 224,
1503
+ aacute: 225,
1504
+ acirc: 226,
1505
+ atilde: 227,
1506
+ auml: 228,
1507
+ aring: 229,
1508
+ aelig: 230,
1509
+ ccedil: 231,
1510
+ egrave: 232,
1511
+ eacute: 233,
1512
+ ecirc: 234,
1513
+ euml: 235,
1514
+ igrave: 236,
1515
+ iacute: 237,
1516
+ icirc: 238,
1517
+ iuml: 239,
1518
+ eth: 240,
1519
+ ntilde: 241,
1520
+ ograve: 242,
1521
+ oacute: 243,
1522
+ ocirc: 244,
1523
+ otilde: 245,
1524
+ ouml: 246,
1525
+ divide: 247,
1526
+ oslash: 248,
1527
+ ugrave: 249,
1528
+ uacute: 250,
1529
+ ucirc: 251,
1530
+ uuml: 252,
1531
+ yacute: 253,
1532
+ thorn: 254,
1533
+ yuml: 255,
1534
+ OElig: 338,
1535
+ oelig: 339,
1536
+ Scaron: 352,
1537
+ scaron: 353,
1538
+ Yuml: 376,
1539
+ fnof: 402,
1540
+ circ: 710,
1541
+ tilde: 732,
1542
+ Alpha: 913,
1543
+ Beta: 914,
1544
+ Gamma: 915,
1545
+ Delta: 916,
1546
+ Epsilon: 917,
1547
+ Zeta: 918,
1548
+ Eta: 919,
1549
+ Theta: 920,
1550
+ Iota: 921,
1551
+ Kappa: 922,
1552
+ Lambda: 923,
1553
+ Mu: 924,
1554
+ Nu: 925,
1555
+ Xi: 926,
1556
+ Omicron: 927,
1557
+ Pi: 928,
1558
+ Rho: 929,
1559
+ Sigma: 931,
1560
+ Tau: 932,
1561
+ Upsilon: 933,
1562
+ Phi: 934,
1563
+ Chi: 935,
1564
+ Psi: 936,
1565
+ Omega: 937,
1566
+ alpha: 945,
1567
+ beta: 946,
1568
+ gamma: 947,
1569
+ delta: 948,
1570
+ epsilon: 949,
1571
+ zeta: 950,
1572
+ eta: 951,
1573
+ theta: 952,
1574
+ iota: 953,
1575
+ kappa: 954,
1576
+ lambda: 955,
1577
+ mu: 956,
1578
+ nu: 957,
1579
+ xi: 958,
1580
+ omicron: 959,
1581
+ pi: 960,
1582
+ rho: 961,
1583
+ sigmaf: 962,
1584
+ sigma: 963,
1585
+ tau: 964,
1586
+ upsilon: 965,
1587
+ phi: 966,
1588
+ chi: 967,
1589
+ psi: 968,
1590
+ omega: 969,
1591
+ thetasym: 977,
1592
+ upsih: 978,
1593
+ piv: 982,
1594
+ ensp: 8194,
1595
+ emsp: 8195,
1596
+ thinsp: 8201,
1597
+ zwnj: 8204,
1598
+ zwj: 8205,
1599
+ lrm: 8206,
1600
+ rlm: 8207,
1601
+ ndash: 8211,
1602
+ mdash: 8212,
1603
+ lsquo: 8216,
1604
+ rsquo: 8217,
1605
+ sbquo: 8218,
1606
+ ldquo: 8220,
1607
+ rdquo: 8221,
1608
+ bdquo: 8222,
1609
+ dagger: 8224,
1610
+ Dagger: 8225,
1611
+ bull: 8226,
1612
+ hellip: 8230,
1613
+ permil: 8240,
1614
+ prime: 8242,
1615
+ Prime: 8243,
1616
+ lsaquo: 8249,
1617
+ rsaquo: 8250,
1618
+ oline: 8254,
1619
+ frasl: 8260,
1620
+ euro: 8364,
1621
+ image: 8465,
1622
+ weierp: 8472,
1623
+ real: 8476,
1624
+ trade: 8482,
1625
+ alefsym: 8501,
1626
+ larr: 8592,
1627
+ uarr: 8593,
1628
+ rarr: 8594,
1629
+ darr: 8595,
1630
+ harr: 8596,
1631
+ crarr: 8629,
1632
+ lArr: 8656,
1633
+ uArr: 8657,
1634
+ rArr: 8658,
1635
+ dArr: 8659,
1636
+ hArr: 8660,
1637
+ forall: 8704,
1638
+ part: 8706,
1639
+ exist: 8707,
1640
+ empty: 8709,
1641
+ nabla: 8711,
1642
+ isin: 8712,
1643
+ notin: 8713,
1644
+ ni: 8715,
1645
+ prod: 8719,
1646
+ sum: 8721,
1647
+ minus: 8722,
1648
+ lowast: 8727,
1649
+ radic: 8730,
1650
+ prop: 8733,
1651
+ infin: 8734,
1652
+ ang: 8736,
1653
+ and: 8743,
1654
+ or: 8744,
1655
+ cap: 8745,
1656
+ cup: 8746,
1657
+ int: 8747,
1658
+ there4: 8756,
1659
+ sim: 8764,
1660
+ cong: 8773,
1661
+ asymp: 8776,
1662
+ ne: 8800,
1663
+ equiv: 8801,
1664
+ le: 8804,
1665
+ ge: 8805,
1666
+ sub: 8834,
1667
+ sup: 8835,
1668
+ nsub: 8836,
1669
+ sube: 8838,
1670
+ supe: 8839,
1671
+ oplus: 8853,
1672
+ otimes: 8855,
1673
+ perp: 8869,
1674
+ sdot: 8901,
1675
+ lceil: 8968,
1676
+ rceil: 8969,
1677
+ lfloor: 8970,
1678
+ rfloor: 8971,
1679
+ lang: 9001,
1680
+ rang: 9002,
1681
+ loz: 9674,
1682
+ spades: 9824,
1683
+ clubs: 9827,
1684
+ hearts: 9829,
1685
+ diams: 9830
1686
+ };
1687
+ var REFERENCE = /&(?:#[xX]([0-9a-fA-F]{1,6})|#([0-9]{1,7})|([a-zA-Z][a-zA-Z0-9]{1,31}));/g;
1688
+ function decodeEntities(value) {
1689
+ if (!value.includes("&")) return value;
1690
+ return value.replace(REFERENCE, (match, hex, dec, name) => {
1691
+ const code = hex ? parseInt(hex, 16) : dec ? parseInt(dec, 10) : Object.prototype.hasOwnProperty.call(NAMED, name) ? NAMED[name] : void 0;
1692
+ return code !== void 0 && code <= 1114111 ? String.fromCodePoint(code) : match;
1693
+ });
1694
+ }
1695
+
1696
+ // src/lower/template.ts
1253
1697
  var DELEGATED2 = /* @__PURE__ */ new Set([
1254
1698
  "click",
1255
1699
  "dblclick",
@@ -1267,6 +1711,7 @@ var DELEGATED2 = /* @__PURE__ */ new Set([
1267
1711
  function escapeTemplate(s) {
1268
1712
  return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
1269
1713
  }
1714
+ var CONTAINER2 = "container";
1270
1715
  function capitalize(s) {
1271
1716
  return s.charAt(0).toUpperCase() + s.slice(1);
1272
1717
  }
@@ -1321,10 +1766,6 @@ var Lowerer = class {
1321
1766
  if (hasElse) i = elseIdx;
1322
1767
  continue;
1323
1768
  }
1324
- if (child.attributes.some((a) => a.kind === "EachDirective")) {
1325
- out.push(this.lowerEach(child));
1326
- continue;
1327
- }
1328
1769
  }
1329
1770
  const node = this.lowerNode(child);
1330
1771
  if (node) out.push(node);
@@ -1338,7 +1779,7 @@ var Lowerer = class {
1338
1779
  switch (node.kind) {
1339
1780
  case "Text": {
1340
1781
  if (node.raw) return { kind: "text", value: node.value };
1341
- const cleaned = cleanTemplateText(node.value);
1782
+ const cleaned = decodeEntities(cleanTemplateText(node.value));
1342
1783
  return cleaned ? { kind: "text", value: cleaned } : null;
1343
1784
  }
1344
1785
  case "Comment":
@@ -1366,13 +1807,16 @@ var Lowerer = class {
1366
1807
  node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
1367
1808
  return node;
1368
1809
  }
1810
+ const each = this.lowerEach(el);
1811
+ const children = each ? [each] : this.lowerChildren(el.children);
1812
+ if (el.tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
1369
1813
  const at = this.tagAt(el);
1370
1814
  return {
1371
1815
  kind: "element",
1372
1816
  tag: el.tag,
1373
1817
  svg: el.namespace === "svg",
1374
- props: this.lowerAttributes(el.attributes),
1375
- children: this.lowerChildren(el.children),
1818
+ props: this.lowerAttributes(el.attributes, true),
1819
+ children,
1376
1820
  static: false,
1377
1821
  ...at ? { at } : {}
1378
1822
  };
@@ -1444,10 +1888,14 @@ var Lowerer = class {
1444
1888
  const at = this.tagAt(el);
1445
1889
  return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
1446
1890
  }
1447
- /** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
1891
+ /**
1892
+ * `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
1893
+ * content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
1894
+ * it is. Null when the element has no `each`.
1895
+ */
1448
1896
  lowerEach(el) {
1449
1897
  const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
1450
- if (!eachDir || eachDir.kind !== "EachDirective") return this.lowerNode(el);
1898
+ if (!eachDir || eachDir.kind !== "EachDirective") return null;
1451
1899
  const each = this.hole(eachDir.hole);
1452
1900
  const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
1453
1901
  if (eachDir.key) {
@@ -1457,12 +1905,12 @@ var Lowerer = class {
1457
1905
  const arrow = this.itemArrow(el);
1458
1906
  let childrenCode;
1459
1907
  if (arrow) {
1460
- const bodyIR = { kind: "expr", code: arrow.body, reactive: arrow.bodyReactive };
1461
- const repeated = this.rebuildWithChildren(el, [bodyIR]);
1462
- childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
1908
+ const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
1909
+ childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
1463
1910
  } else {
1464
- const repeated = this.stripAndLower(el, (a) => a.kind === "EachDirective");
1465
- childrenCode = `() => ${paren(this.emit(repeated), "arrowBody")}`;
1911
+ const content = this.lowerChildren(el.children);
1912
+ const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
1913
+ childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
1466
1914
  }
1467
1915
  const children = [{ kind: "expr", code: childrenCode, reactive: false }];
1468
1916
  const at = this.tagAt(el);
@@ -1479,33 +1927,23 @@ var Lowerer = class {
1479
1927
  const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
1480
1928
  return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
1481
1929
  }
1482
- /** Same element (minus each/key) but with explicit IR children. */
1483
- rebuildWithChildren(el, children) {
1484
- const props = this.lowerAttributes(
1485
- el.attributes.filter((a) => a.kind !== "EachDirective")
1486
- );
1487
- if (el.kind === "Element") {
1488
- const at = this.tagAt(el);
1489
- return {
1490
- kind: "element",
1491
- tag: el.tag,
1492
- svg: el.namespace === "svg",
1493
- props,
1494
- children,
1495
- static: false,
1496
- ...at ? { at } : {}
1497
- };
1498
- }
1499
- return { kind: "component", name: el.tag, props, children };
1500
- }
1501
1930
  // --- attributes ---------------------------------------------------------
1502
- lowerAttributes(attrs) {
1931
+ /**
1932
+ * `element`: a DOM element, where each class:/style: value that moves is its own accessor.
1933
+ * A component gets the object as before, rebuilt whole when any value moves.
1934
+ */
1935
+ lowerAttributes(attrs, element = false) {
1936
+ let anyReactive = false;
1937
+ const entry = (name, h) => {
1938
+ anyReactive ||= h.reactive;
1939
+ if (!element || !h.reactive) return `${JSON.stringify(name)}: ${h.code}`;
1940
+ const accessor = `() => ${paren(h.code, "arrowBody")}`;
1941
+ return `${JSON.stringify(name)}: ${h.at ? markHole(accessor, h.at.line, h.at.column) : accessor}`;
1942
+ };
1503
1943
  const props = [];
1504
1944
  const classEntries = [];
1505
- let classReactive = false;
1506
1945
  let classAt;
1507
1946
  const styleEntries = [];
1508
- let styleReactive = false;
1509
1947
  let styleAt;
1510
1948
  const usePairs = [];
1511
1949
  for (const a of attrs) {
@@ -1545,15 +1983,13 @@ var Lowerer = class {
1545
1983
  break;
1546
1984
  case "ClassDirective": {
1547
1985
  const h = this.hole(a.hole);
1548
- classEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
1549
- classReactive = classReactive || h.reactive;
1986
+ classEntries.push(entry(a.name, h));
1550
1987
  classAt ??= h.at;
1551
1988
  break;
1552
1989
  }
1553
1990
  case "StyleDirective": {
1554
1991
  const h = this.hole(a.hole);
1555
- styleEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
1556
- styleReactive = styleReactive || h.reactive;
1992
+ styleEntries.push(entry(a.name, h));
1557
1993
  styleAt ??= h.at;
1558
1994
  break;
1559
1995
  }
@@ -1573,18 +2009,19 @@ var Lowerer = class {
1573
2009
  name: "classList",
1574
2010
  kind: "attr",
1575
2011
  expr: `{ ${classEntries.join(", ")} }`,
1576
- reactive: classReactive,
2012
+ reactive: !element && anyReactive,
1577
2013
  ...classAt ? { at: classAt } : {}
1578
2014
  });
1579
2015
  }
1580
2016
  if (styleEntries.length > 0) {
1581
- props.push({
1582
- name: "style",
1583
- kind: "attr",
1584
- expr: `{ ${styleEntries.join(", ")} }`,
1585
- reactive: styleReactive,
1586
- ...styleAt ? { at: styleAt } : {}
1587
- });
2017
+ const entries = `{ ${styleEntries.join(", ")} }`;
2018
+ const base = props.findIndex((p) => p.name === "style");
2019
+ if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: !element && anyReactive, ...styleAt ? { at: styleAt } : {} });
2020
+ else {
2021
+ const prop = props[base];
2022
+ const value = prop.expr === void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
2023
+ props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
2024
+ }
1588
2025
  }
1589
2026
  if (usePairs.length > 0) {
1590
2027
  props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
@@ -1673,7 +2110,7 @@ var Lowerer = class {
1673
2110
  return base;
1674
2111
  }
1675
2112
  if (v.kind === "static") {
1676
- base.literal = v.value;
2113
+ base.literal = decodeEntities(v.value);
1677
2114
  return base;
1678
2115
  }
1679
2116
  if (v.kind === "hole") {
@@ -1686,7 +2123,7 @@ var Lowerer = class {
1686
2123
  let reactive = false;
1687
2124
  let at;
1688
2125
  const body = v.parts.map((p) => {
1689
- if ("text" in p) return escapeTemplate(p.text);
2126
+ if ("text" in p) return escapeTemplate(decodeEntities(p.text));
1690
2127
  const h = this.hole(p.hole);
1691
2128
  reactive = reactive || h.reactive;
1692
2129
  at ??= h.at;
@@ -1709,7 +2146,7 @@ export {
1709
2146
  collapseStrategies,
1710
2147
  declaredNames,
1711
2148
  resolveReactiveBindings,
1712
- mayHaveReactiveCall,
2149
+ mayHaveSourceMarks,
1713
2150
  collectSourceEdits,
1714
2151
  inlineTemplates,
1715
2152
  imperativeBackend,