@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
@@ -1519,6 +1519,7 @@ var INTRINSICS = {
1519
1519
  $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
1520
1520
  $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
1521
1521
  $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
1522
+ $cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
1522
1523
  // No short runtime form for these yet, so the intrinsic stands for the `create*`
1523
1524
  // name. Still worth having: no import to write, and when a shorter form is
1524
1525
  // designed, the change is this line rather than a compiler pass.
@@ -1528,7 +1529,22 @@ var INTRINSICS = {
1528
1529
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
1529
1530
  // dependency analysis must not guess at.
1530
1531
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
1531
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
1532
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
1533
+ // Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
1534
+ // no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
1535
+ $batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
1536
+ $cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
1537
+ $root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
1538
+ $context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
1539
+ $renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
1540
+ $computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
1541
+ // Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
1542
+ // handle as far as reads go: the same accessor with `set` on it.
1543
+ $storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
1544
+ $asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
1545
+ $persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
1546
+ // An environment variable, public or server-only; the browser build refuses a secret.
1547
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
1532
1548
  };
1533
1549
  var RUNTIME_PRIMITIVES = {
1534
1550
  signal: "signal-handle",
@@ -1539,8 +1555,11 @@ var RUNTIME_PRIMITIVES = {
1539
1555
  createMemo: "memo-accessor",
1540
1556
  createEffect: "effect",
1541
1557
  createRenderEffect: "effect",
1558
+ renderEffect: "effect",
1559
+ computed: "effect",
1542
1560
  createStore: "reactive-object",
1543
1561
  resource: "resource-handle",
1562
+ cachedResource: "resource-handle",
1544
1563
  createResource: "reactive-object",
1545
1564
  createSelector: "memo-accessor",
1546
1565
  createDeferred: "memo-accessor"
@@ -1549,6 +1568,7 @@ var PRIMITIVE_MODULES = [
1549
1568
  "@fluixi/reactive",
1550
1569
  "@fluixi/reactive/signal",
1551
1570
  "@fluixi/reactive/store",
1571
+ "@fluixi/reactive/cached-resource",
1552
1572
  "@fluixi/core"
1553
1573
  ];
1554
1574
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n2) => n2.slice(1)).join("|")})\\s*\\(`);
@@ -1684,6 +1704,7 @@ function resolveReactiveBindings(program) {
1684
1704
  // src/transform/source-locations.ts
1685
1705
  var SOURCE_MARKER = "__fx_source";
1686
1706
  var COMPONENT_MARKER = "__fx_component";
1707
+ var CLASS_MARKER = "__fx_class";
1687
1708
  var HOLE_MARKER = "__fx_hole";
1688
1709
  var markHole = (accessor, line, column, name) => `(globalThis.${HOLE_MARKER} ?? ((f) => f))(${accessor},${line},${column}${name === void 0 ? "" : `,${JSON.stringify(name)}`})`;
1689
1710
  var PROPS_MARKER = "__fx_props";
@@ -1701,11 +1722,12 @@ var RUNTIME_PRIMITIVES2 = /* @__PURE__ */ new Set([
1701
1722
  "createStore",
1702
1723
  "createResource"
1703
1724
  ]);
1704
- function mayHaveReactiveCall(code) {
1725
+ function mayHaveSourceMarks(code) {
1705
1726
  for (const name of RUNTIME_PRIMITIVES2) {
1706
1727
  if (code.includes(name)) return true;
1707
1728
  }
1708
- return code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store");
1729
+ if (code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store")) return true;
1730
+ return /\bclass\b[^{;]*\bextends\b/.test(code);
1709
1731
  }
1710
1732
  var SINGLE_STATEMENT_PARENTS = /* @__PURE__ */ new Set([
1711
1733
  "IfStatement",
@@ -1724,6 +1746,7 @@ function isLoneBranch(statement, parent) {
1724
1746
  function isExport(node) {
1725
1747
  return node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration";
1726
1748
  }
1749
+ var CLASS_FIELDS = /* @__PURE__ */ new Set(["PropertyDefinition", "ClassProperty", "ClassPrivateProperty", "AccessorProperty"]);
1727
1750
  function isStatement(node) {
1728
1751
  return node.type.endsWith("Statement") || node.type === "VariableDeclaration";
1729
1752
  }
@@ -1744,6 +1767,14 @@ function walk3(node, visit, stack = []) {
1744
1767
  }
1745
1768
  function nameFor(stack) {
1746
1769
  const declarator = stack[stack.length - 1];
1770
+ if (declarator && CLASS_FIELDS.has(declarator.type)) {
1771
+ const key = declarator.key;
1772
+ if (key?.type === "Identifier" || key?.type === "PrivateIdentifier" || key?.type === "PrivateName") {
1773
+ const name = key.name ?? key.id?.name;
1774
+ return name;
1775
+ }
1776
+ return void 0;
1777
+ }
1747
1778
  if (declarator?.type !== "VariableDeclarator") return void 0;
1748
1779
  const id = declarator.id;
1749
1780
  if (id?.type === "Identifier") return id.name;
@@ -1792,6 +1823,17 @@ function collectSourceEdits(program, filename) {
1792
1823
  });
1793
1824
  }
1794
1825
  }
1826
+ if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.superClass && !node.declare) {
1827
+ const at = node.loc?.start;
1828
+ const body = node.body;
1829
+ if (at && body) {
1830
+ edits.push({
1831
+ start: body.start + 1,
1832
+ end: body.start + 1,
1833
+ code: `static{globalThis.${CLASS_MARKER}?.(this,${JSON.stringify(filename)},${at.line},${at.column});}`
1834
+ });
1835
+ }
1836
+ }
1795
1837
  if (node.type !== "CallExpression") return;
1796
1838
  const callee = node.callee;
1797
1839
  if (callee?.type !== "Identifier") return;
@@ -1801,6 +1843,26 @@ function collectSourceEdits(program, filename) {
1801
1843
  if (!intrinsic && !imported) return;
1802
1844
  const position = node.loc?.start;
1803
1845
  if (!position) return;
1846
+ for (let i = stack.length - 1; i >= 0; i--) {
1847
+ const up = stack[i];
1848
+ if (isStatement(up)) break;
1849
+ if (CLASS_FIELDS.has(up.type)) {
1850
+ if (claimed.has(node.start)) return;
1851
+ claimed.add(node.start);
1852
+ const label2 = nameFor(stack);
1853
+ const own = !up.static;
1854
+ const args2 = [
1855
+ JSON.stringify(filename),
1856
+ String(position.line),
1857
+ String(position.column),
1858
+ label2 ? JSON.stringify(label2) : own ? "undefined" : void 0,
1859
+ own ? "this" : void 0
1860
+ ].filter((a) => a !== void 0).join(",");
1861
+ edits.push({ start: node.start, end: node.start, code: `(globalThis.${SOURCE_MARKER}?.(${args2}),` });
1862
+ edits.push({ start: node.end, end: node.end, code: ")" });
1863
+ return;
1864
+ }
1865
+ }
1804
1866
  let statement;
1805
1867
  let parent;
1806
1868
  let index = -1;
@@ -2006,13 +2068,16 @@ function emitComponent(name, props, children, used, templates, at) {
2006
2068
  used.add("createComponent");
2007
2069
  const spreads = props.filter((p) => p.kind === "spread");
2008
2070
  const normal = props.filter((p) => p.kind !== "spread");
2009
- const entries = normal.map(
2010
- (p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
2011
- );
2071
+ const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
2012
2072
  if (children.length > 0) {
2013
- entries.push(`get children() { return ${emitChildren(children, used, templates)}; }`);
2073
+ bodies.push(["children", emitChildren(children, used, templates)]);
2074
+ }
2075
+ let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
2076
+ if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
2077
+ const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => ${body}`);
2078
+ const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
2079
+ obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
2014
2080
  }
2015
- let obj = `{ ${entries.join(", ")} }`;
2016
2081
  if (spreads.length > 0) {
2017
2082
  used.add("mergeProps");
2018
2083
  obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
@@ -2094,7 +2159,8 @@ function emitNode(node, used, templates) {
2094
2159
  } else {
2095
2160
  used.add("spread");
2096
2161
  const svgFlag = node.svg ? ", isSVG: true" : "";
2097
- const customFlag = node.tag.includes("-") ? ", isCustomElement: true" : "";
2162
+ const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
2163
+ const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
2098
2164
  parts.push(
2099
2165
  `spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
2100
2166
  );
@@ -2227,6 +2293,7 @@ var DELEGATED = /* @__PURE__ */ new Set([
2227
2293
  function escapeTemplate(s) {
2228
2294
  return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
2229
2295
  }
2296
+ var CONTAINER = "container";
2230
2297
  function capitalize(s) {
2231
2298
  return s.charAt(0).toUpperCase() + s.slice(1);
2232
2299
  }
@@ -2281,10 +2348,6 @@ var Lowerer = class {
2281
2348
  if (hasElse) i = elseIdx;
2282
2349
  continue;
2283
2350
  }
2284
- if (child.attributes.some((a) => a.kind === "EachDirective")) {
2285
- out.push(this.lowerEach(child));
2286
- continue;
2287
- }
2288
2351
  }
2289
2352
  const node = this.lowerNode(child);
2290
2353
  if (node) out.push(node);
@@ -2326,13 +2389,16 @@ var Lowerer = class {
2326
2389
  node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
2327
2390
  return node;
2328
2391
  }
2392
+ const each = this.lowerEach(el);
2393
+ const children = each ? [each] : this.lowerChildren(el.children);
2394
+ if (el.tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
2329
2395
  const at = this.tagAt(el);
2330
2396
  return {
2331
2397
  kind: "element",
2332
2398
  tag: el.tag,
2333
2399
  svg: el.namespace === "svg",
2334
2400
  props: this.lowerAttributes(el.attributes),
2335
- children: this.lowerChildren(el.children),
2401
+ children,
2336
2402
  static: false,
2337
2403
  ...at ? { at } : {}
2338
2404
  };
@@ -2404,10 +2470,14 @@ var Lowerer = class {
2404
2470
  const at = this.tagAt(el);
2405
2471
  return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
2406
2472
  }
2407
- /** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
2473
+ /**
2474
+ * `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
2475
+ * content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
2476
+ * it is. Null when the element has no `each`.
2477
+ */
2408
2478
  lowerEach(el) {
2409
2479
  const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
2410
- if (!eachDir || eachDir.kind !== "EachDirective") return this.lowerNode(el);
2480
+ if (!eachDir || eachDir.kind !== "EachDirective") return null;
2411
2481
  const each = this.hole(eachDir.hole);
2412
2482
  const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
2413
2483
  if (eachDir.key) {
@@ -2417,12 +2487,12 @@ var Lowerer = class {
2417
2487
  const arrow = this.itemArrow(el);
2418
2488
  let childrenCode;
2419
2489
  if (arrow) {
2420
- const bodyIR = { kind: "expr", code: arrow.body, reactive: arrow.bodyReactive };
2421
- const repeated = this.rebuildWithChildren(el, [bodyIR]);
2422
- childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
2490
+ const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
2491
+ childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
2423
2492
  } else {
2424
- const repeated = this.stripAndLower(el, (a) => a.kind === "EachDirective");
2425
- childrenCode = `() => ${paren(this.emit(repeated), "arrowBody")}`;
2493
+ const content = this.lowerChildren(el.children);
2494
+ const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
2495
+ childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
2426
2496
  }
2427
2497
  const children = [{ kind: "expr", code: childrenCode, reactive: false }];
2428
2498
  const at = this.tagAt(el);
@@ -2439,25 +2509,6 @@ var Lowerer = class {
2439
2509
  const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
2440
2510
  return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
2441
2511
  }
2442
- /** Same element (minus each/key) but with explicit IR children. */
2443
- rebuildWithChildren(el, children) {
2444
- const props = this.lowerAttributes(
2445
- el.attributes.filter((a) => a.kind !== "EachDirective")
2446
- );
2447
- if (el.kind === "Element") {
2448
- const at = this.tagAt(el);
2449
- return {
2450
- kind: "element",
2451
- tag: el.tag,
2452
- svg: el.namespace === "svg",
2453
- props,
2454
- children,
2455
- static: false,
2456
- ...at ? { at } : {}
2457
- };
2458
- }
2459
- return { kind: "component", name: el.tag, props, children };
2460
- }
2461
2512
  // --- attributes ---------------------------------------------------------
2462
2513
  lowerAttributes(attrs) {
2463
2514
  const props = [];
@@ -2776,6 +2827,22 @@ var DELEGATED2 = /* @__PURE__ */ new Set([
2776
2827
  "mouseup"
2777
2828
  ]);
2778
2829
  var isReactive = (node) => isReactiveShape(shapeOf(node));
2830
+ var CONTAINER2 = "container";
2831
+ function directive(node, name) {
2832
+ if (node.type !== "JSXElement") return void 0;
2833
+ const opening = node.openingElement;
2834
+ if (opening.name.type !== "JSXIdentifier" || opening.name.name[0] !== opening.name.name[0].toLowerCase()) return void 0;
2835
+ return opening.attributes.find((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === name);
2836
+ }
2837
+ function directiveExpr(attr) {
2838
+ const v = attr.value;
2839
+ return v?.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression" ? v.expression : void 0;
2840
+ }
2841
+ function emitIR(ir, ctx) {
2842
+ const { code, imports, templates } = imperativeBackend.emit(ir, {});
2843
+ for (const s of imports) ctx.used.add(s);
2844
+ return inlineTemplates(code, templates);
2845
+ }
2779
2846
  var posOf = (node, ctx) => {
2780
2847
  if (!ctx.sourceFile) return void 0;
2781
2848
  const at = node.loc?.start;
@@ -2884,7 +2951,16 @@ function buildProps(attrs, ctx) {
2884
2951
  }
2885
2952
  function buildChildren(children, ctx) {
2886
2953
  const out = [];
2887
- for (const child of children) {
2954
+ for (let i = 0; i < children.length; i++) {
2955
+ const child = children[i];
2956
+ if (directive(child, "if")) {
2957
+ let next = i + 1;
2958
+ while (next < children.length && children[next].type === "JSXText" && !cleanTemplateText(children[next].value)) next++;
2959
+ const fallback = directive(children[next], "else") ? children[next] : null;
2960
+ out.push(buildIf(child, fallback, ctx));
2961
+ if (fallback) i = next;
2962
+ continue;
2963
+ }
2888
2964
  if (child.type === "JSXText") {
2889
2965
  const text = cleanTemplateText(child.value);
2890
2966
  if (text) out.push({ kind: "text", value: text });
@@ -2921,19 +2997,68 @@ function readLoad(attrs) {
2921
2997
  }
2922
2998
  return void 0;
2923
2999
  }
3000
+ function buildIf(node, fallback, ctx) {
3001
+ const cond = directiveExpr(directive(node, "if"));
3002
+ const props = [
3003
+ cond ? { name: "when", kind: "attr", expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) } : { name: "when", kind: "attr", literal: true }
3004
+ ];
3005
+ if (fallback) {
3006
+ props.push({ name: "fallback", kind: "attr", expr: emitIR(buildElement(fallback, ctx, ["else"]), ctx), jsxElement: true });
3007
+ }
3008
+ return { kind: "component", name: "Show", props, children: [buildElement(node, ctx, ["if"])] };
3009
+ }
3010
+ function buildEach(node, ctx) {
3011
+ const attr = directive(node, "each");
3012
+ if (!attr) return null;
3013
+ const list = directiveExpr(attr);
3014
+ const props = [
3015
+ list ? { name: "each", kind: "attr", expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) } : { name: "each", kind: "attr", expr: "[]" }
3016
+ ];
3017
+ const key = directive(node, "key");
3018
+ if (key) {
3019
+ const keyExpr = directiveExpr(key);
3020
+ const by = isString(key.value) ? `(item) => item[${JSON.stringify(literalOf(key.value))}]` : keyExpr ? ctx.code(keyExpr) : void 0;
3021
+ if (by) props.push({ name: "by", kind: "attr", expr: by });
3022
+ }
3023
+ const content = node.children.filter((c) => !(c.type === "JSXText" && !cleanTemplateText(c.value)));
3024
+ const only = content.length === 1 && content[0].type === "JSXExpressionContainer" ? content[0].expression : null;
3025
+ let render;
3026
+ if (only && (only.type === "ArrowFunctionExpression" || only.type === "FunctionExpression")) {
3027
+ const fn = ctx.code(only);
3028
+ const live = only.type === "ArrowFunctionExpression" && only.body.type !== "BlockStatement" && isReactive(only.body);
3029
+ render = live ? `(...args) => () => (${fn})(...args)` : fn;
3030
+ } else {
3031
+ const built = buildChildren(node.children, ctx);
3032
+ const ir = built.length === 1 ? built[0] : { kind: "fragment", children: built };
3033
+ render = `() => ${paren(emitIR(ir, ctx), "arrowBody")}`;
3034
+ }
3035
+ return { kind: "component", name: "For", props, children: [{ kind: "expr", code: render, reactive: false }] };
3036
+ }
3037
+ function buildElement(node, ctx, handled) {
3038
+ const skip = new Set(handled);
3039
+ const directives = /* @__PURE__ */ new Set(["if", "else", "each", ...directive(node, "each") ? ["key"] : []]);
3040
+ const attributes = node.openingElement.attributes.filter(
3041
+ (a) => !(a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && (skip.has(a.name.name) || directives.has(a.name.name)))
3042
+ );
3043
+ const { tag } = tagInfo(node.openingElement.name, ctx);
3044
+ const each = buildEach(node, ctx);
3045
+ const children = each ? [each] : buildChildren(node.children, ctx);
3046
+ if (tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
3047
+ const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
3048
+ return { kind: "element", tag, svg: SVG_TAGS.has(tag), props: buildProps(attributes, ctx), children, static: false, ...at ? { at } : {} };
3049
+ }
2924
3050
  function buildNode(node, ctx) {
2925
3051
  if (node.type === "JSXFragment") {
2926
3052
  return { kind: "fragment", children: buildChildren(node.children, ctx) };
2927
3053
  }
3054
+ if (directive(node, "if")) return buildIf(node, null, ctx);
2928
3055
  const { tag, component } = tagInfo(node.openingElement.name, ctx);
3056
+ if (!component) return buildElement(node, ctx, []);
2929
3057
  const props = buildProps(node.openingElement.attributes, ctx);
2930
3058
  const children = buildChildren(node.children, ctx);
2931
3059
  const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
2932
- if (component) {
2933
- const load = readLoad(node.openingElement.attributes);
2934
- return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
2935
- }
2936
- return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
3060
+ const load = readLoad(node.openingElement.attributes);
3061
+ return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
2937
3062
  }
2938
3063
  function buildJsxIR(node, ctx) {
2939
3064
  const ir = buildNode(node, ctx);
@@ -3366,10 +3491,34 @@ function collectIntrinsicEdits(program) {
3366
3491
  });
3367
3492
  return { edits, diagnostics, imports };
3368
3493
  }
3494
+ function avoidBindingClashes(program, result, bound) {
3495
+ const importedAsIs = /* @__PURE__ */ new Set();
3496
+ for (const stmt of program.body ?? []) {
3497
+ if (stmt.type !== "ImportDeclaration") continue;
3498
+ const module = stmt.source.value;
3499
+ for (const spec of stmt.specifiers ?? []) {
3500
+ if (spec.type !== "ImportSpecifier") continue;
3501
+ const imported = spec.imported.name ?? spec.imported.value;
3502
+ if (imported === spec.local.name && result.imports.get(module)?.has(imported)) {
3503
+ importedAsIs.add(imported);
3504
+ }
3505
+ }
3506
+ }
3507
+ const aliases = /* @__PURE__ */ new Map();
3508
+ for (const names of result.imports.values()) {
3509
+ for (const name of names) if (bound.has(name) && !importedAsIs.has(name)) aliases.set(name, `__fx_${name}`);
3510
+ }
3511
+ if (!aliases.size) return;
3512
+ for (const edit of result.edits) {
3513
+ const alias = aliases.get(edit.code);
3514
+ if (alias) edit.code = alias;
3515
+ }
3516
+ result.aliases = aliases;
3517
+ }
3369
3518
  function intrinsicImports(result, bound) {
3370
3519
  const lines = [];
3371
3520
  for (const [module, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
3372
- const wanted = [...names].filter((name) => !bound.has(name)).sort();
3521
+ 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);
3373
3522
  if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module)};`);
3374
3523
  }
3375
3524
  return lines.length ? `${lines.join("\n")}
@@ -3554,7 +3703,7 @@ function transformTemplates(code, id, options = {}) {
3554
3703
  const wantsJsx = format !== "lit";
3555
3704
  const mayHaveTemplate = wantsLit && (code.includes(`${litTag}\``) || code.includes("svg`"));
3556
3705
  const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
3557
- const wantsSources = options.sourceLocations === true && mayHaveReactiveCall(code);
3706
+ const wantsSources = options.sourceLocations === true && mayHaveSourceMarks(code);
3558
3707
  const sourceName = relativeToRoot(id, options.sourceRoot);
3559
3708
  if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources) return null;
3560
3709
  const ast = parse2(code, {
@@ -3569,6 +3718,7 @@ function transformTemplates(code, id, options = {}) {
3569
3718
  });
3570
3719
  const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
3571
3720
  const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
3721
+ if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
3572
3722
  const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
3573
3723
  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;
3574
3724
  if (silent) return null;
@@ -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
  import {
3
3
  analyzeStatic,
4
4
  buildJsxIR,
@@ -10,11 +10,11 @@ import {
10
10
  isDeferred,
11
11
  isReactiveShape,
12
12
  lowerTemplate,
13
- mayHaveReactiveCall,
13
+ mayHaveSourceMarks,
14
14
  resolveComponentSources,
15
15
  resolveReactiveBindings,
16
16
  shapeOf
17
- } from "./chunk-3JWMCK4A.mjs";
17
+ } from "./chunk-U7HCFLZ2.mjs";
18
18
  import {
19
19
  CORE_CONTROL_FLOW,
20
20
  DOM_CONTROL_FLOW,
@@ -23,11 +23,11 @@ import {
23
23
  createComponentResolver,
24
24
  isIntrinsicName,
25
25
  mayHaveIntrinsic
26
- } from "./chunk-S4J4OCWK.mjs";
26
+ } from "./chunk-OD53TMER.mjs";
27
27
  import {
28
28
  MagicString
29
- } from "./chunk-TWDJUXWZ.mjs";
30
- import "./chunk-QX6Y3OAR.mjs";
29
+ } from "./chunk-R7PPFBCL.mjs";
30
+ import "./chunk-TJIH7TLX.mjs";
31
31
 
32
32
  // src/transform/templates.ts
33
33
  import { parse as parse2 } from "@babel/parser";
@@ -508,10 +508,34 @@ function collectIntrinsicEdits(program) {
508
508
  });
509
509
  return { edits, diagnostics, imports };
510
510
  }
511
+ function avoidBindingClashes(program, result, bound) {
512
+ const importedAsIs = /* @__PURE__ */ new Set();
513
+ for (const stmt of program.body ?? []) {
514
+ if (stmt.type !== "ImportDeclaration") continue;
515
+ const module = stmt.source.value;
516
+ for (const spec of stmt.specifiers ?? []) {
517
+ if (spec.type !== "ImportSpecifier") continue;
518
+ const imported = spec.imported.name ?? spec.imported.value;
519
+ if (imported === spec.local.name && result.imports.get(module)?.has(imported)) {
520
+ importedAsIs.add(imported);
521
+ }
522
+ }
523
+ }
524
+ const aliases = /* @__PURE__ */ new Map();
525
+ for (const names of result.imports.values()) {
526
+ for (const name of names) if (bound.has(name) && !importedAsIs.has(name)) aliases.set(name, `__fx_${name}`);
527
+ }
528
+ if (!aliases.size) return;
529
+ for (const edit of result.edits) {
530
+ const alias = aliases.get(edit.code);
531
+ if (alias) edit.code = alias;
532
+ }
533
+ result.aliases = aliases;
534
+ }
511
535
  function intrinsicImports(result, bound) {
512
536
  const lines = [];
513
537
  for (const [module, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
514
- const wanted = [...names].filter((name) => !bound.has(name)).sort();
538
+ 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);
515
539
  if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module)};`);
516
540
  }
517
541
  return lines.length ? `${lines.join("\n")}
@@ -696,7 +720,7 @@ function transformTemplates(code, id, options = {}) {
696
720
  const wantsJsx = format !== "lit";
697
721
  const mayHaveTemplate = wantsLit && (code.includes(`${litTag}\``) || code.includes("svg`"));
698
722
  const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
699
- const wantsSources = options.sourceLocations === true && mayHaveReactiveCall(code);
723
+ const wantsSources = options.sourceLocations === true && mayHaveSourceMarks(code);
700
724
  const sourceName = relativeToRoot(id, options.sourceRoot);
701
725
  if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources) return null;
702
726
  const ast = parse2(code, {
@@ -711,6 +735,7 @@ function transformTemplates(code, id, options = {}) {
711
735
  });
712
736
  const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
713
737
  const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
738
+ if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
714
739
  const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
715
740
  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;
716
741
  if (silent) return null;