@fluixi/compiler 1.0.0-alpha.91 → 1.0.0-alpha.93

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 (81) hide show
  1. package/dist/analyze/intrinsics.cjs +21 -1
  2. package/dist/analyze/intrinsics.d.ts.map +1 -1
  3. package/dist/analyze/intrinsics.js +20 -0
  4. package/dist/analyze/intrinsics.mjs +21 -1
  5. package/dist/analyze/reactive-bindings.cjs +21 -1
  6. package/dist/analyze/reactive-bindings.mjs +21 -1
  7. package/dist/analyze/static-graph.cjs +25 -5
  8. package/dist/analyze/static-graph.d.ts.map +1 -1
  9. package/dist/analyze/static-graph.js +6 -4
  10. package/dist/analyze/static-graph.mjs +25 -5
  11. package/dist/{babel-VBLQRHQ2.mjs → babel-RJHJQVEM.mjs} +4 -4
  12. package/dist/{chunk-D53J7ICY.mjs → chunk-56QSOVVL.mjs} +1 -1
  13. package/dist/{chunk-S4J4OCWK.mjs → chunk-OD53TMER.mjs} +22 -2
  14. package/dist/{chunk-TWDJUXWZ.mjs → chunk-R7PPFBCL.mjs} +1 -1
  15. package/dist/{chunk-QX6Y3OAR.mjs → chunk-TJIH7TLX.mjs} +1 -1
  16. package/dist/{chunk-3JWMCK4A.mjs → chunk-U7HCFLZ2.mjs} +153 -48
  17. package/dist/codegen/backends/imperative.cjs +27 -7
  18. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  19. package/dist/codegen/backends/imperative.js +19 -4
  20. package/dist/codegen/backends/imperative.mjs +27 -7
  21. package/dist/frontend/babel/build-ir-lit.cjs +123 -44
  22. package/dist/frontend/babel/build-ir-lit.mjs +123 -44
  23. package/dist/frontend/babel/build-ir.cjs +123 -44
  24. package/dist/frontend/babel/build-ir.mjs +123 -44
  25. package/dist/frontend/babel/index.cjs +124 -45
  26. package/dist/frontend/babel/index.mjs +124 -45
  27. package/dist/frontend/babel/lower-template.cjs +123 -44
  28. package/dist/frontend/babel/lower-template.mjs +123 -44
  29. package/dist/frontend/babel/plugin.cjs +123 -44
  30. package/dist/frontend/babel/plugin.mjs +123 -44
  31. package/dist/index.cjs +86 -46
  32. package/dist/index.mjs +88 -48
  33. package/dist/integrations.cjs +246 -61
  34. package/dist/integrations.mjs +53 -19
  35. package/dist/lower/compile-template.cjs +44 -39
  36. package/dist/lower/compile-template.mjs +44 -39
  37. package/dist/lower/jsx.cjs +509 -6
  38. package/dist/lower/jsx.d.ts.map +1 -1
  39. package/dist/lower/jsx.js +114 -6
  40. package/dist/lower/jsx.mjs +509 -6
  41. package/dist/lower/template.cjs +43 -38
  42. package/dist/lower/template.d.ts.map +1 -1
  43. package/dist/lower/template.js +22 -30
  44. package/dist/lower/template.mjs +43 -38
  45. package/dist/resolve/builtins.cjs +1 -1
  46. package/dist/resolve/builtins.mjs +1 -1
  47. package/dist/resolve/component-globals.cjs +33 -8
  48. package/dist/resolve/component-globals.d.cts +8 -0
  49. package/dist/resolve/component-globals.d.ts +8 -0
  50. package/dist/resolve/component-globals.d.ts.map +1 -1
  51. package/dist/resolve/component-globals.js +21 -12
  52. package/dist/resolve/component-globals.mjs +33 -8
  53. package/dist/resolve/write-globals.cjs +59 -8
  54. package/dist/resolve/write-globals.d.cts +6 -0
  55. package/dist/resolve/write-globals.d.ts +6 -0
  56. package/dist/resolve/write-globals.d.ts.map +1 -1
  57. package/dist/resolve/write-globals.js +35 -2
  58. package/dist/resolve/write-globals.mjs +61 -10
  59. package/dist/{server-fns-J56G3PFP.mjs → server-fns-ZFRDIQ2X.mjs} +4 -4
  60. package/dist/{server-functions-7PUFLRGF.mjs → server-functions-CTDXX67X.mjs} +3 -3
  61. package/dist/transform/index.cjs +199 -49
  62. package/dist/transform/index.mjs +199 -49
  63. package/dist/transform/intrinsics.cjs +47 -2
  64. package/dist/transform/intrinsics.d.cts +12 -0
  65. package/dist/transform/intrinsics.d.ts +12 -0
  66. package/dist/transform/intrinsics.d.ts.map +1 -1
  67. package/dist/transform/intrinsics.js +43 -1
  68. package/dist/transform/intrinsics.mjs +47 -2
  69. package/dist/transform/source-locations.cjs +67 -4
  70. package/dist/transform/source-locations.d.cts +7 -2
  71. package/dist/transform/source-locations.d.ts +7 -2
  72. package/dist/transform/source-locations.d.ts.map +1 -1
  73. package/dist/transform/source-locations.js +68 -3
  74. package/dist/transform/source-locations.mjs +67 -4
  75. package/dist/transform/templates.cjs +198 -48
  76. package/dist/transform/templates.d.ts.map +1 -1
  77. package/dist/transform/templates.js +5 -3
  78. package/dist/transform/templates.mjs +198 -48
  79. package/dist/{transform-D536WXGM.mjs → transform-QWWQDCXE.mjs} +33 -8
  80. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  81. package/package.json +9 -3
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.91 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.93 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -489,6 +489,7 @@ var INTRINSICS = {
489
489
  $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
490
490
  $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
491
491
  $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
492
+ $cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
492
493
  // No short runtime form for these yet, so the intrinsic stands for the `create*`
493
494
  // name. Still worth having: no import to write, and when a shorter form is
494
495
  // designed, the change is this line rather than a compiler pass.
@@ -498,7 +499,22 @@ var INTRINSICS = {
498
499
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
499
500
  // dependency analysis must not guess at.
500
501
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
501
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
502
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
503
+ // Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
504
+ // no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
505
+ $batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
506
+ $cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
507
+ $root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
508
+ $context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
509
+ $renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
510
+ $computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
511
+ // Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
512
+ // handle as far as reads go: the same accessor with `set` on it.
513
+ $storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
514
+ $asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
515
+ $persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
516
+ // An environment variable, public or server-only; the browser build refuses a secret.
517
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
502
518
  };
503
519
  var RUNTIME_PRIMITIVES = {
504
520
  signal: "signal-handle",
@@ -509,8 +525,11 @@ var RUNTIME_PRIMITIVES = {
509
525
  createMemo: "memo-accessor",
510
526
  createEffect: "effect",
511
527
  createRenderEffect: "effect",
528
+ renderEffect: "effect",
529
+ computed: "effect",
512
530
  createStore: "reactive-object",
513
531
  resource: "resource-handle",
532
+ cachedResource: "resource-handle",
514
533
  createResource: "reactive-object",
515
534
  createSelector: "memo-accessor",
516
535
  createDeferred: "memo-accessor"
@@ -519,6 +538,7 @@ var PRIMITIVE_MODULES = [
519
538
  "@fluixi/reactive",
520
539
  "@fluixi/reactive/signal",
521
540
  "@fluixi/reactive/store",
541
+ "@fluixi/reactive/cached-resource",
522
542
  "@fluixi/core"
523
543
  ];
524
544
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
@@ -654,6 +674,7 @@ function resolveReactiveBindings(program) {
654
674
  // src/transform/source-locations.ts
655
675
  var SOURCE_MARKER = "__fx_source";
656
676
  var COMPONENT_MARKER = "__fx_component";
677
+ var CLASS_MARKER = "__fx_class";
657
678
  var HOLE_MARKER = "__fx_hole";
658
679
  var markHole = (accessor, line, column, name) => `(globalThis.${HOLE_MARKER} ?? ((f) => f))(${accessor},${line},${column}${name === void 0 ? "" : `,${JSON.stringify(name)}`})`;
659
680
  var PROPS_MARKER = "__fx_props";
@@ -671,11 +692,12 @@ var RUNTIME_PRIMITIVES2 = /* @__PURE__ */ new Set([
671
692
  "createStore",
672
693
  "createResource"
673
694
  ]);
674
- function mayHaveReactiveCall(code) {
695
+ function mayHaveSourceMarks(code) {
675
696
  for (const name of RUNTIME_PRIMITIVES2) {
676
697
  if (code.includes(name)) return true;
677
698
  }
678
- return code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store");
699
+ if (code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store")) return true;
700
+ return /\bclass\b[^{;]*\bextends\b/.test(code);
679
701
  }
680
702
  var SINGLE_STATEMENT_PARENTS = /* @__PURE__ */ new Set([
681
703
  "IfStatement",
@@ -694,6 +716,7 @@ function isLoneBranch(statement, parent) {
694
716
  function isExport(node) {
695
717
  return node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration";
696
718
  }
719
+ var CLASS_FIELDS = /* @__PURE__ */ new Set(["PropertyDefinition", "ClassProperty", "ClassPrivateProperty", "AccessorProperty"]);
697
720
  function isStatement(node) {
698
721
  return node.type.endsWith("Statement") || node.type === "VariableDeclaration";
699
722
  }
@@ -714,6 +737,14 @@ function walk3(node, visit, stack = []) {
714
737
  }
715
738
  function nameFor(stack) {
716
739
  const declarator = stack[stack.length - 1];
740
+ if (declarator && CLASS_FIELDS.has(declarator.type)) {
741
+ const key = declarator.key;
742
+ if (key?.type === "Identifier" || key?.type === "PrivateIdentifier" || key?.type === "PrivateName") {
743
+ const name = key.name ?? key.id?.name;
744
+ return name;
745
+ }
746
+ return void 0;
747
+ }
717
748
  if (declarator?.type !== "VariableDeclarator") return void 0;
718
749
  const id = declarator.id;
719
750
  if (id?.type === "Identifier") return id.name;
@@ -762,6 +793,17 @@ function collectSourceEdits(program, filename) {
762
793
  });
763
794
  }
764
795
  }
796
+ if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.superClass && !node.declare) {
797
+ const at = node.loc?.start;
798
+ const body = node.body;
799
+ if (at && body) {
800
+ edits.push({
801
+ start: body.start + 1,
802
+ end: body.start + 1,
803
+ code: `static{globalThis.${CLASS_MARKER}?.(this,${JSON.stringify(filename)},${at.line},${at.column});}`
804
+ });
805
+ }
806
+ }
765
807
  if (node.type !== "CallExpression") return;
766
808
  const callee = node.callee;
767
809
  if (callee?.type !== "Identifier") return;
@@ -771,6 +813,26 @@ function collectSourceEdits(program, filename) {
771
813
  if (!intrinsic && !imported) return;
772
814
  const position = node.loc?.start;
773
815
  if (!position) return;
816
+ for (let i = stack.length - 1; i >= 0; i--) {
817
+ const up = stack[i];
818
+ if (isStatement(up)) break;
819
+ if (CLASS_FIELDS.has(up.type)) {
820
+ if (claimed.has(node.start)) return;
821
+ claimed.add(node.start);
822
+ const label2 = nameFor(stack);
823
+ const own = !up.static;
824
+ const args2 = [
825
+ JSON.stringify(filename),
826
+ String(position.line),
827
+ String(position.column),
828
+ label2 ? JSON.stringify(label2) : own ? "undefined" : void 0,
829
+ own ? "this" : void 0
830
+ ].filter((a) => a !== void 0).join(",");
831
+ edits.push({ start: node.start, end: node.start, code: `(globalThis.${SOURCE_MARKER}?.(${args2}),` });
832
+ edits.push({ start: node.end, end: node.end, code: ")" });
833
+ return;
834
+ }
835
+ }
774
836
  let statement;
775
837
  let parent;
776
838
  let index = -1;
@@ -976,13 +1038,16 @@ function emitComponent(name, props, children, used, templates, at) {
976
1038
  used.add("createComponent");
977
1039
  const spreads = props.filter((p) => p.kind === "spread");
978
1040
  const normal = props.filter((p) => p.kind !== "spread");
979
- const entries = normal.map(
980
- (p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
981
- );
1041
+ const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
982
1042
  if (children.length > 0) {
983
- entries.push(`get children() { return ${emitChildren(children, used, templates)}; }`);
1043
+ bodies.push(["children", emitChildren(children, used, templates)]);
1044
+ }
1045
+ let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
1046
+ if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
1047
+ const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => ${body}`);
1048
+ const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
1049
+ obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
984
1050
  }
985
- let obj = `{ ${entries.join(", ")} }`;
986
1051
  if (spreads.length > 0) {
987
1052
  used.add("mergeProps");
988
1053
  obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
@@ -1064,7 +1129,8 @@ function emitNode(node, used, templates) {
1064
1129
  } else {
1065
1130
  used.add("spread");
1066
1131
  const svgFlag = node.svg ? ", isSVG: true" : "";
1067
- const customFlag = node.tag.includes("-") ? ", isCustomElement: true" : "";
1132
+ const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
1133
+ const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
1068
1134
  parts.push(
1069
1135
  `spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
1070
1136
  );
@@ -1195,6 +1261,7 @@ var DELEGATED = /* @__PURE__ */ new Set([
1195
1261
  function escapeTemplate(s) {
1196
1262
  return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
1197
1263
  }
1264
+ var CONTAINER = "container";
1198
1265
  function capitalize(s) {
1199
1266
  return s.charAt(0).toUpperCase() + s.slice(1);
1200
1267
  }
@@ -1249,10 +1316,6 @@ var Lowerer = class {
1249
1316
  if (hasElse) i = elseIdx;
1250
1317
  continue;
1251
1318
  }
1252
- if (child.attributes.some((a) => a.kind === "EachDirective")) {
1253
- out.push(this.lowerEach(child));
1254
- continue;
1255
- }
1256
1319
  }
1257
1320
  const node = this.lowerNode(child);
1258
1321
  if (node) out.push(node);
@@ -1294,13 +1357,16 @@ var Lowerer = class {
1294
1357
  node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
1295
1358
  return node;
1296
1359
  }
1360
+ const each = this.lowerEach(el);
1361
+ const children = each ? [each] : this.lowerChildren(el.children);
1362
+ if (el.tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
1297
1363
  const at = this.tagAt(el);
1298
1364
  return {
1299
1365
  kind: "element",
1300
1366
  tag: el.tag,
1301
1367
  svg: el.namespace === "svg",
1302
1368
  props: this.lowerAttributes(el.attributes),
1303
- children: this.lowerChildren(el.children),
1369
+ children,
1304
1370
  static: false,
1305
1371
  ...at ? { at } : {}
1306
1372
  };
@@ -1372,10 +1438,14 @@ var Lowerer = class {
1372
1438
  const at = this.tagAt(el);
1373
1439
  return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
1374
1440
  }
1375
- /** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
1441
+ /**
1442
+ * `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
1443
+ * content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
1444
+ * it is. Null when the element has no `each`.
1445
+ */
1376
1446
  lowerEach(el) {
1377
1447
  const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
1378
- if (!eachDir || eachDir.kind !== "EachDirective") return this.lowerNode(el);
1448
+ if (!eachDir || eachDir.kind !== "EachDirective") return null;
1379
1449
  const each = this.hole(eachDir.hole);
1380
1450
  const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
1381
1451
  if (eachDir.key) {
@@ -1385,12 +1455,12 @@ var Lowerer = class {
1385
1455
  const arrow = this.itemArrow(el);
1386
1456
  let childrenCode;
1387
1457
  if (arrow) {
1388
- const bodyIR = { kind: "expr", code: arrow.body, reactive: arrow.bodyReactive };
1389
- const repeated = this.rebuildWithChildren(el, [bodyIR]);
1390
- childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
1458
+ const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
1459
+ childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
1391
1460
  } else {
1392
- const repeated = this.stripAndLower(el, (a) => a.kind === "EachDirective");
1393
- childrenCode = `() => ${paren(this.emit(repeated), "arrowBody")}`;
1461
+ const content = this.lowerChildren(el.children);
1462
+ const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
1463
+ childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
1394
1464
  }
1395
1465
  const children = [{ kind: "expr", code: childrenCode, reactive: false }];
1396
1466
  const at = this.tagAt(el);
@@ -1407,25 +1477,6 @@ var Lowerer = class {
1407
1477
  const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
1408
1478
  return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
1409
1479
  }
1410
- /** Same element (minus each/key) but with explicit IR children. */
1411
- rebuildWithChildren(el, children) {
1412
- const props = this.lowerAttributes(
1413
- el.attributes.filter((a) => a.kind !== "EachDirective")
1414
- );
1415
- if (el.kind === "Element") {
1416
- const at = this.tagAt(el);
1417
- return {
1418
- kind: "element",
1419
- tag: el.tag,
1420
- svg: el.namespace === "svg",
1421
- props,
1422
- children,
1423
- static: false,
1424
- ...at ? { at } : {}
1425
- };
1426
- }
1427
- return { kind: "component", name: el.tag, props, children };
1428
- }
1429
1480
  // --- attributes ---------------------------------------------------------
1430
1481
  lowerAttributes(attrs) {
1431
1482
  const props = [];
@@ -1744,6 +1795,22 @@ var DELEGATED2 = /* @__PURE__ */ new Set([
1744
1795
  "mouseup"
1745
1796
  ]);
1746
1797
  var isReactive = (node) => isReactiveShape(shapeOf(node));
1798
+ var CONTAINER2 = "container";
1799
+ function directive(node, name) {
1800
+ if (node.type !== "JSXElement") return void 0;
1801
+ const opening = node.openingElement;
1802
+ if (opening.name.type !== "JSXIdentifier" || opening.name.name[0] !== opening.name.name[0].toLowerCase()) return void 0;
1803
+ return opening.attributes.find((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === name);
1804
+ }
1805
+ function directiveExpr(attr) {
1806
+ const v = attr.value;
1807
+ return v?.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression" ? v.expression : void 0;
1808
+ }
1809
+ function emitIR(ir, ctx) {
1810
+ const { code, imports, templates } = imperativeBackend.emit(ir, {});
1811
+ for (const s of imports) ctx.used.add(s);
1812
+ return inlineTemplates(code, templates);
1813
+ }
1747
1814
  var posOf = (node, ctx) => {
1748
1815
  if (!ctx.sourceFile) return void 0;
1749
1816
  const at = node.loc?.start;
@@ -1852,7 +1919,16 @@ function buildProps(attrs, ctx) {
1852
1919
  }
1853
1920
  function buildChildren(children, ctx) {
1854
1921
  const out = [];
1855
- for (const child of children) {
1922
+ for (let i = 0; i < children.length; i++) {
1923
+ const child = children[i];
1924
+ if (directive(child, "if")) {
1925
+ let next = i + 1;
1926
+ while (next < children.length && children[next].type === "JSXText" && !cleanTemplateText(children[next].value)) next++;
1927
+ const fallback = directive(children[next], "else") ? children[next] : null;
1928
+ out.push(buildIf(child, fallback, ctx));
1929
+ if (fallback) i = next;
1930
+ continue;
1931
+ }
1856
1932
  if (child.type === "JSXText") {
1857
1933
  const text = cleanTemplateText(child.value);
1858
1934
  if (text) out.push({ kind: "text", value: text });
@@ -1889,19 +1965,68 @@ function readLoad(attrs) {
1889
1965
  }
1890
1966
  return void 0;
1891
1967
  }
1968
+ function buildIf(node, fallback, ctx) {
1969
+ const cond = directiveExpr(directive(node, "if"));
1970
+ const props = [
1971
+ cond ? { name: "when", kind: "attr", expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) } : { name: "when", kind: "attr", literal: true }
1972
+ ];
1973
+ if (fallback) {
1974
+ props.push({ name: "fallback", kind: "attr", expr: emitIR(buildElement(fallback, ctx, ["else"]), ctx), jsxElement: true });
1975
+ }
1976
+ return { kind: "component", name: "Show", props, children: [buildElement(node, ctx, ["if"])] };
1977
+ }
1978
+ function buildEach(node, ctx) {
1979
+ const attr = directive(node, "each");
1980
+ if (!attr) return null;
1981
+ const list = directiveExpr(attr);
1982
+ const props = [
1983
+ list ? { name: "each", kind: "attr", expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) } : { name: "each", kind: "attr", expr: "[]" }
1984
+ ];
1985
+ const key = directive(node, "key");
1986
+ if (key) {
1987
+ const keyExpr = directiveExpr(key);
1988
+ const by = isString(key.value) ? `(item) => item[${JSON.stringify(literalOf(key.value))}]` : keyExpr ? ctx.code(keyExpr) : void 0;
1989
+ if (by) props.push({ name: "by", kind: "attr", expr: by });
1990
+ }
1991
+ const content = node.children.filter((c) => !(c.type === "JSXText" && !cleanTemplateText(c.value)));
1992
+ const only = content.length === 1 && content[0].type === "JSXExpressionContainer" ? content[0].expression : null;
1993
+ let render;
1994
+ if (only && (only.type === "ArrowFunctionExpression" || only.type === "FunctionExpression")) {
1995
+ const fn = ctx.code(only);
1996
+ const live = only.type === "ArrowFunctionExpression" && only.body.type !== "BlockStatement" && isReactive(only.body);
1997
+ render = live ? `(...args) => () => (${fn})(...args)` : fn;
1998
+ } else {
1999
+ const built = buildChildren(node.children, ctx);
2000
+ const ir = built.length === 1 ? built[0] : { kind: "fragment", children: built };
2001
+ render = `() => ${paren(emitIR(ir, ctx), "arrowBody")}`;
2002
+ }
2003
+ return { kind: "component", name: "For", props, children: [{ kind: "expr", code: render, reactive: false }] };
2004
+ }
2005
+ function buildElement(node, ctx, handled) {
2006
+ const skip = new Set(handled);
2007
+ const directives = /* @__PURE__ */ new Set(["if", "else", "each", ...directive(node, "each") ? ["key"] : []]);
2008
+ const attributes = node.openingElement.attributes.filter(
2009
+ (a) => !(a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && (skip.has(a.name.name) || directives.has(a.name.name)))
2010
+ );
2011
+ const { tag } = tagInfo(node.openingElement.name, ctx);
2012
+ const each = buildEach(node, ctx);
2013
+ const children = each ? [each] : buildChildren(node.children, ctx);
2014
+ if (tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
2015
+ const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
2016
+ return { kind: "element", tag, svg: SVG_TAGS.has(tag), props: buildProps(attributes, ctx), children, static: false, ...at ? { at } : {} };
2017
+ }
1892
2018
  function buildNode(node, ctx) {
1893
2019
  if (node.type === "JSXFragment") {
1894
2020
  return { kind: "fragment", children: buildChildren(node.children, ctx) };
1895
2021
  }
2022
+ if (directive(node, "if")) return buildIf(node, null, ctx);
1896
2023
  const { tag, component } = tagInfo(node.openingElement.name, ctx);
2024
+ if (!component) return buildElement(node, ctx, []);
1897
2025
  const props = buildProps(node.openingElement.attributes, ctx);
1898
2026
  const children = buildChildren(node.children, ctx);
1899
2027
  const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
1900
- if (component) {
1901
- const load = readLoad(node.openingElement.attributes);
1902
- return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
1903
- }
1904
- return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
2028
+ const load = readLoad(node.openingElement.attributes);
2029
+ return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
1905
2030
  }
1906
2031
  function buildJsxIR(node, ctx) {
1907
2032
  const ir = buildNode(node, ctx);
@@ -2358,10 +2483,34 @@ function collectIntrinsicEdits(program) {
2358
2483
  });
2359
2484
  return { edits, diagnostics, imports };
2360
2485
  }
2486
+ function avoidBindingClashes(program, result, bound) {
2487
+ const importedAsIs = /* @__PURE__ */ new Set();
2488
+ for (const stmt of program.body ?? []) {
2489
+ if (stmt.type !== "ImportDeclaration") continue;
2490
+ const module2 = stmt.source.value;
2491
+ for (const spec of stmt.specifiers ?? []) {
2492
+ if (spec.type !== "ImportSpecifier") continue;
2493
+ const imported = spec.imported.name ?? spec.imported.value;
2494
+ if (imported === spec.local.name && result.imports.get(module2)?.has(imported)) {
2495
+ importedAsIs.add(imported);
2496
+ }
2497
+ }
2498
+ }
2499
+ const aliases = /* @__PURE__ */ new Map();
2500
+ for (const names of result.imports.values()) {
2501
+ for (const name of names) if (bound.has(name) && !importedAsIs.has(name)) aliases.set(name, `__fx_${name}`);
2502
+ }
2503
+ if (!aliases.size) return;
2504
+ for (const edit of result.edits) {
2505
+ const alias = aliases.get(edit.code);
2506
+ if (alias) edit.code = alias;
2507
+ }
2508
+ result.aliases = aliases;
2509
+ }
2361
2510
  function intrinsicImports(result, bound) {
2362
2511
  const lines = [];
2363
2512
  for (const [module2, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
2364
- const wanted = [...names].filter((name) => !bound.has(name)).sort();
2513
+ const wanted = [...names].filter((name) => result.aliases?.has(name) || !bound.has(name)).sort().map((name) => result.aliases?.has(name) ? `${name} as ${result.aliases.get(name)}` : name);
2365
2514
  if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module2)};`);
2366
2515
  }
2367
2516
  return lines.length ? `${lines.join("\n")}
@@ -2546,7 +2695,7 @@ function transformTemplates(code, id, options = {}) {
2546
2695
  const wantsJsx = format !== "lit";
2547
2696
  const mayHaveTemplate = wantsLit && (code.includes(`${litTag}\``) || code.includes("svg`"));
2548
2697
  const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
2549
- const wantsSources = options.sourceLocations === true && mayHaveReactiveCall(code);
2698
+ const wantsSources = options.sourceLocations === true && mayHaveSourceMarks(code);
2550
2699
  const sourceName = relativeToRoot(id, options.sourceRoot);
2551
2700
  if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources) return null;
2552
2701
  const ast = (0, import_parser2.parse)(code, {
@@ -2561,6 +2710,7 @@ function transformTemplates(code, id, options = {}) {
2561
2710
  });
2562
2711
  const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
2563
2712
  const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
2713
+ if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
2564
2714
  const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
2565
2715
  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;
2566
2716
  if (silent) return null;