@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
@@ -481,6 +481,7 @@ var INTRINSICS = {
481
481
  $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
482
482
  $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
483
483
  $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
484
+ $cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
484
485
  // No short runtime form for these yet, so the intrinsic stands for the `create*`
485
486
  // name. Still worth having: no import to write, and when a shorter form is
486
487
  // designed, the change is this line rather than a compiler pass.
@@ -490,7 +491,22 @@ var INTRINSICS = {
490
491
  // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
491
492
  // dependency analysis must not guess at.
492
493
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
493
- $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
494
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
495
+ // Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
496
+ // no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
497
+ $batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
498
+ $cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
499
+ $root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
500
+ $context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
501
+ $renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
502
+ $computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
503
+ // Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
504
+ // handle as far as reads go: the same accessor with `set` on it.
505
+ $storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
506
+ $asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
507
+ $persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
508
+ // An environment variable, public or server-only; the browser build refuses a secret.
509
+ $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
494
510
  };
495
511
  var RUNTIME_PRIMITIVES = {
496
512
  signal: "signal-handle",
@@ -501,8 +517,11 @@ var RUNTIME_PRIMITIVES = {
501
517
  createMemo: "memo-accessor",
502
518
  createEffect: "effect",
503
519
  createRenderEffect: "effect",
520
+ renderEffect: "effect",
521
+ computed: "effect",
504
522
  createStore: "reactive-object",
505
523
  resource: "resource-handle",
524
+ cachedResource: "resource-handle",
506
525
  createResource: "reactive-object",
507
526
  createSelector: "memo-accessor",
508
527
  createDeferred: "memo-accessor"
@@ -511,6 +530,7 @@ var PRIMITIVE_MODULES = [
511
530
  "@fluixi/reactive",
512
531
  "@fluixi/reactive/signal",
513
532
  "@fluixi/reactive/store",
533
+ "@fluixi/reactive/cached-resource",
514
534
  "@fluixi/core"
515
535
  ];
516
536
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
@@ -646,6 +666,7 @@ function resolveReactiveBindings(program) {
646
666
  // src/transform/source-locations.ts
647
667
  var SOURCE_MARKER = "__fx_source";
648
668
  var COMPONENT_MARKER = "__fx_component";
669
+ var CLASS_MARKER = "__fx_class";
649
670
  var HOLE_MARKER = "__fx_hole";
650
671
  var markHole = (accessor, line, column, name) => `(globalThis.${HOLE_MARKER} ?? ((f) => f))(${accessor},${line},${column}${name === void 0 ? "" : `,${JSON.stringify(name)}`})`;
651
672
  var PROPS_MARKER = "__fx_props";
@@ -663,11 +684,12 @@ var RUNTIME_PRIMITIVES2 = /* @__PURE__ */ new Set([
663
684
  "createStore",
664
685
  "createResource"
665
686
  ]);
666
- function mayHaveReactiveCall(code) {
687
+ function mayHaveSourceMarks(code) {
667
688
  for (const name of RUNTIME_PRIMITIVES2) {
668
689
  if (code.includes(name)) return true;
669
690
  }
670
- return code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store");
691
+ if (code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store")) return true;
692
+ return /\bclass\b[^{;]*\bextends\b/.test(code);
671
693
  }
672
694
  var SINGLE_STATEMENT_PARENTS = /* @__PURE__ */ new Set([
673
695
  "IfStatement",
@@ -686,6 +708,7 @@ function isLoneBranch(statement, parent) {
686
708
  function isExport(node) {
687
709
  return node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration";
688
710
  }
711
+ var CLASS_FIELDS = /* @__PURE__ */ new Set(["PropertyDefinition", "ClassProperty", "ClassPrivateProperty", "AccessorProperty"]);
689
712
  function isStatement(node) {
690
713
  return node.type.endsWith("Statement") || node.type === "VariableDeclaration";
691
714
  }
@@ -706,6 +729,14 @@ function walk3(node, visit, stack = []) {
706
729
  }
707
730
  function nameFor(stack) {
708
731
  const declarator = stack[stack.length - 1];
732
+ if (declarator && CLASS_FIELDS.has(declarator.type)) {
733
+ const key = declarator.key;
734
+ if (key?.type === "Identifier" || key?.type === "PrivateIdentifier" || key?.type === "PrivateName") {
735
+ const name = key.name ?? key.id?.name;
736
+ return name;
737
+ }
738
+ return void 0;
739
+ }
709
740
  if (declarator?.type !== "VariableDeclarator") return void 0;
710
741
  const id = declarator.id;
711
742
  if (id?.type === "Identifier") return id.name;
@@ -754,6 +785,17 @@ function collectSourceEdits(program, filename) {
754
785
  });
755
786
  }
756
787
  }
788
+ if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.superClass && !node.declare) {
789
+ const at = node.loc?.start;
790
+ const body = node.body;
791
+ if (at && body) {
792
+ edits.push({
793
+ start: body.start + 1,
794
+ end: body.start + 1,
795
+ code: `static{globalThis.${CLASS_MARKER}?.(this,${JSON.stringify(filename)},${at.line},${at.column});}`
796
+ });
797
+ }
798
+ }
757
799
  if (node.type !== "CallExpression") return;
758
800
  const callee = node.callee;
759
801
  if (callee?.type !== "Identifier") return;
@@ -763,6 +805,26 @@ function collectSourceEdits(program, filename) {
763
805
  if (!intrinsic && !imported) return;
764
806
  const position = node.loc?.start;
765
807
  if (!position) return;
808
+ for (let i = stack.length - 1; i >= 0; i--) {
809
+ const up = stack[i];
810
+ if (isStatement(up)) break;
811
+ if (CLASS_FIELDS.has(up.type)) {
812
+ if (claimed.has(node.start)) return;
813
+ claimed.add(node.start);
814
+ const label2 = nameFor(stack);
815
+ const own = !up.static;
816
+ const args2 = [
817
+ JSON.stringify(filename),
818
+ String(position.line),
819
+ String(position.column),
820
+ label2 ? JSON.stringify(label2) : own ? "undefined" : void 0,
821
+ own ? "this" : void 0
822
+ ].filter((a) => a !== void 0).join(",");
823
+ edits.push({ start: node.start, end: node.start, code: `(globalThis.${SOURCE_MARKER}?.(${args2}),` });
824
+ edits.push({ start: node.end, end: node.end, code: ")" });
825
+ return;
826
+ }
827
+ }
766
828
  let statement;
767
829
  let parent;
768
830
  let index = -1;
@@ -968,13 +1030,16 @@ function emitComponent(name, props, children, used, templates, at) {
968
1030
  used.add("createComponent");
969
1031
  const spreads = props.filter((p) => p.kind === "spread");
970
1032
  const normal = props.filter((p) => p.kind !== "spread");
971
- const entries = normal.map(
972
- (p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
973
- );
1033
+ const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
974
1034
  if (children.length > 0) {
975
- entries.push(`get children() { return ${emitChildren(children, used, templates)}; }`);
1035
+ bodies.push(["children", emitChildren(children, used, templates)]);
1036
+ }
1037
+ let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
1038
+ if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
1039
+ const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => ${body}`);
1040
+ const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
1041
+ obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
976
1042
  }
977
- let obj = `{ ${entries.join(", ")} }`;
978
1043
  if (spreads.length > 0) {
979
1044
  used.add("mergeProps");
980
1045
  obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
@@ -1056,7 +1121,8 @@ function emitNode(node, used, templates) {
1056
1121
  } else {
1057
1122
  used.add("spread");
1058
1123
  const svgFlag = node.svg ? ", isSVG: true" : "";
1059
- const customFlag = node.tag.includes("-") ? ", isCustomElement: true" : "";
1124
+ const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
1125
+ const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
1060
1126
  parts.push(
1061
1127
  `spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
1062
1128
  );
@@ -1187,6 +1253,7 @@ var DELEGATED = /* @__PURE__ */ new Set([
1187
1253
  function escapeTemplate(s) {
1188
1254
  return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
1189
1255
  }
1256
+ var CONTAINER = "container";
1190
1257
  function capitalize(s) {
1191
1258
  return s.charAt(0).toUpperCase() + s.slice(1);
1192
1259
  }
@@ -1241,10 +1308,6 @@ var Lowerer = class {
1241
1308
  if (hasElse) i = elseIdx;
1242
1309
  continue;
1243
1310
  }
1244
- if (child.attributes.some((a) => a.kind === "EachDirective")) {
1245
- out.push(this.lowerEach(child));
1246
- continue;
1247
- }
1248
1311
  }
1249
1312
  const node = this.lowerNode(child);
1250
1313
  if (node) out.push(node);
@@ -1286,13 +1349,16 @@ var Lowerer = class {
1286
1349
  node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
1287
1350
  return node;
1288
1351
  }
1352
+ const each = this.lowerEach(el);
1353
+ const children = each ? [each] : this.lowerChildren(el.children);
1354
+ if (el.tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
1289
1355
  const at = this.tagAt(el);
1290
1356
  return {
1291
1357
  kind: "element",
1292
1358
  tag: el.tag,
1293
1359
  svg: el.namespace === "svg",
1294
1360
  props: this.lowerAttributes(el.attributes),
1295
- children: this.lowerChildren(el.children),
1361
+ children,
1296
1362
  static: false,
1297
1363
  ...at ? { at } : {}
1298
1364
  };
@@ -1364,10 +1430,14 @@ var Lowerer = class {
1364
1430
  const at = this.tagAt(el);
1365
1431
  return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
1366
1432
  }
1367
- /** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
1433
+ /**
1434
+ * `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
1435
+ * content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
1436
+ * it is. Null when the element has no `each`.
1437
+ */
1368
1438
  lowerEach(el) {
1369
1439
  const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
1370
- if (!eachDir || eachDir.kind !== "EachDirective") return this.lowerNode(el);
1440
+ if (!eachDir || eachDir.kind !== "EachDirective") return null;
1371
1441
  const each = this.hole(eachDir.hole);
1372
1442
  const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
1373
1443
  if (eachDir.key) {
@@ -1377,12 +1447,12 @@ var Lowerer = class {
1377
1447
  const arrow = this.itemArrow(el);
1378
1448
  let childrenCode;
1379
1449
  if (arrow) {
1380
- const bodyIR = { kind: "expr", code: arrow.body, reactive: arrow.bodyReactive };
1381
- const repeated = this.rebuildWithChildren(el, [bodyIR]);
1382
- childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
1450
+ const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
1451
+ childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
1383
1452
  } else {
1384
- const repeated = this.stripAndLower(el, (a) => a.kind === "EachDirective");
1385
- childrenCode = `() => ${paren(this.emit(repeated), "arrowBody")}`;
1453
+ const content = this.lowerChildren(el.children);
1454
+ const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
1455
+ childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
1386
1456
  }
1387
1457
  const children = [{ kind: "expr", code: childrenCode, reactive: false }];
1388
1458
  const at = this.tagAt(el);
@@ -1399,25 +1469,6 @@ var Lowerer = class {
1399
1469
  const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
1400
1470
  return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
1401
1471
  }
1402
- /** Same element (minus each/key) but with explicit IR children. */
1403
- rebuildWithChildren(el, children) {
1404
- const props = this.lowerAttributes(
1405
- el.attributes.filter((a) => a.kind !== "EachDirective")
1406
- );
1407
- if (el.kind === "Element") {
1408
- const at = this.tagAt(el);
1409
- return {
1410
- kind: "element",
1411
- tag: el.tag,
1412
- svg: el.namespace === "svg",
1413
- props,
1414
- children,
1415
- static: false,
1416
- ...at ? { at } : {}
1417
- };
1418
- }
1419
- return { kind: "component", name: el.tag, props, children };
1420
- }
1421
1472
  // --- attributes ---------------------------------------------------------
1422
1473
  lowerAttributes(attrs) {
1423
1474
  const props = [];
@@ -1736,6 +1787,22 @@ var DELEGATED2 = /* @__PURE__ */ new Set([
1736
1787
  "mouseup"
1737
1788
  ]);
1738
1789
  var isReactive = (node) => isReactiveShape(shapeOf(node));
1790
+ var CONTAINER2 = "container";
1791
+ function directive(node, name) {
1792
+ if (node.type !== "JSXElement") return void 0;
1793
+ const opening = node.openingElement;
1794
+ if (opening.name.type !== "JSXIdentifier" || opening.name.name[0] !== opening.name.name[0].toLowerCase()) return void 0;
1795
+ return opening.attributes.find((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === name);
1796
+ }
1797
+ function directiveExpr(attr) {
1798
+ const v = attr.value;
1799
+ return v?.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression" ? v.expression : void 0;
1800
+ }
1801
+ function emitIR(ir, ctx) {
1802
+ const { code, imports, templates } = imperativeBackend.emit(ir, {});
1803
+ for (const s of imports) ctx.used.add(s);
1804
+ return inlineTemplates(code, templates);
1805
+ }
1739
1806
  var posOf = (node, ctx) => {
1740
1807
  if (!ctx.sourceFile) return void 0;
1741
1808
  const at = node.loc?.start;
@@ -1844,7 +1911,16 @@ function buildProps(attrs, ctx) {
1844
1911
  }
1845
1912
  function buildChildren(children, ctx) {
1846
1913
  const out = [];
1847
- for (const child of children) {
1914
+ for (let i = 0; i < children.length; i++) {
1915
+ const child = children[i];
1916
+ if (directive(child, "if")) {
1917
+ let next = i + 1;
1918
+ while (next < children.length && children[next].type === "JSXText" && !cleanTemplateText(children[next].value)) next++;
1919
+ const fallback = directive(children[next], "else") ? children[next] : null;
1920
+ out.push(buildIf(child, fallback, ctx));
1921
+ if (fallback) i = next;
1922
+ continue;
1923
+ }
1848
1924
  if (child.type === "JSXText") {
1849
1925
  const text = cleanTemplateText(child.value);
1850
1926
  if (text) out.push({ kind: "text", value: text });
@@ -1881,19 +1957,68 @@ function readLoad(attrs) {
1881
1957
  }
1882
1958
  return void 0;
1883
1959
  }
1960
+ function buildIf(node, fallback, ctx) {
1961
+ const cond = directiveExpr(directive(node, "if"));
1962
+ const props = [
1963
+ cond ? { name: "when", kind: "attr", expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) } : { name: "when", kind: "attr", literal: true }
1964
+ ];
1965
+ if (fallback) {
1966
+ props.push({ name: "fallback", kind: "attr", expr: emitIR(buildElement(fallback, ctx, ["else"]), ctx), jsxElement: true });
1967
+ }
1968
+ return { kind: "component", name: "Show", props, children: [buildElement(node, ctx, ["if"])] };
1969
+ }
1970
+ function buildEach(node, ctx) {
1971
+ const attr = directive(node, "each");
1972
+ if (!attr) return null;
1973
+ const list = directiveExpr(attr);
1974
+ const props = [
1975
+ list ? { name: "each", kind: "attr", expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) } : { name: "each", kind: "attr", expr: "[]" }
1976
+ ];
1977
+ const key = directive(node, "key");
1978
+ if (key) {
1979
+ const keyExpr = directiveExpr(key);
1980
+ const by = isString(key.value) ? `(item) => item[${JSON.stringify(literalOf(key.value))}]` : keyExpr ? ctx.code(keyExpr) : void 0;
1981
+ if (by) props.push({ name: "by", kind: "attr", expr: by });
1982
+ }
1983
+ const content = node.children.filter((c) => !(c.type === "JSXText" && !cleanTemplateText(c.value)));
1984
+ const only = content.length === 1 && content[0].type === "JSXExpressionContainer" ? content[0].expression : null;
1985
+ let render;
1986
+ if (only && (only.type === "ArrowFunctionExpression" || only.type === "FunctionExpression")) {
1987
+ const fn = ctx.code(only);
1988
+ const live = only.type === "ArrowFunctionExpression" && only.body.type !== "BlockStatement" && isReactive(only.body);
1989
+ render = live ? `(...args) => () => (${fn})(...args)` : fn;
1990
+ } else {
1991
+ const built = buildChildren(node.children, ctx);
1992
+ const ir = built.length === 1 ? built[0] : { kind: "fragment", children: built };
1993
+ render = `() => ${paren(emitIR(ir, ctx), "arrowBody")}`;
1994
+ }
1995
+ return { kind: "component", name: "For", props, children: [{ kind: "expr", code: render, reactive: false }] };
1996
+ }
1997
+ function buildElement(node, ctx, handled) {
1998
+ const skip = new Set(handled);
1999
+ const directives = /* @__PURE__ */ new Set(["if", "else", "each", ...directive(node, "each") ? ["key"] : []]);
2000
+ const attributes = node.openingElement.attributes.filter(
2001
+ (a) => !(a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && (skip.has(a.name.name) || directives.has(a.name.name)))
2002
+ );
2003
+ const { tag } = tagInfo(node.openingElement.name, ctx);
2004
+ const each = buildEach(node, ctx);
2005
+ const children = each ? [each] : buildChildren(node.children, ctx);
2006
+ if (tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
2007
+ const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
2008
+ return { kind: "element", tag, svg: SVG_TAGS.has(tag), props: buildProps(attributes, ctx), children, static: false, ...at ? { at } : {} };
2009
+ }
1884
2010
  function buildNode(node, ctx) {
1885
2011
  if (node.type === "JSXFragment") {
1886
2012
  return { kind: "fragment", children: buildChildren(node.children, ctx) };
1887
2013
  }
2014
+ if (directive(node, "if")) return buildIf(node, null, ctx);
1888
2015
  const { tag, component } = tagInfo(node.openingElement.name, ctx);
2016
+ if (!component) return buildElement(node, ctx, []);
1889
2017
  const props = buildProps(node.openingElement.attributes, ctx);
1890
2018
  const children = buildChildren(node.children, ctx);
1891
2019
  const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
1892
- if (component) {
1893
- const load = readLoad(node.openingElement.attributes);
1894
- return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
1895
- }
1896
- return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
2020
+ const load = readLoad(node.openingElement.attributes);
2021
+ return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
1897
2022
  }
1898
2023
  function buildJsxIR(node, ctx) {
1899
2024
  const ir = buildNode(node, ctx);
@@ -2327,10 +2452,34 @@ function collectIntrinsicEdits(program) {
2327
2452
  });
2328
2453
  return { edits, diagnostics, imports };
2329
2454
  }
2455
+ function avoidBindingClashes(program, result, bound) {
2456
+ const importedAsIs = /* @__PURE__ */ new Set();
2457
+ for (const stmt of program.body ?? []) {
2458
+ if (stmt.type !== "ImportDeclaration") continue;
2459
+ const module2 = stmt.source.value;
2460
+ for (const spec of stmt.specifiers ?? []) {
2461
+ if (spec.type !== "ImportSpecifier") continue;
2462
+ const imported = spec.imported.name ?? spec.imported.value;
2463
+ if (imported === spec.local.name && result.imports.get(module2)?.has(imported)) {
2464
+ importedAsIs.add(imported);
2465
+ }
2466
+ }
2467
+ }
2468
+ const aliases = /* @__PURE__ */ new Map();
2469
+ for (const names of result.imports.values()) {
2470
+ for (const name of names) if (bound.has(name) && !importedAsIs.has(name)) aliases.set(name, `__fx_${name}`);
2471
+ }
2472
+ if (!aliases.size) return;
2473
+ for (const edit of result.edits) {
2474
+ const alias = aliases.get(edit.code);
2475
+ if (alias) edit.code = alias;
2476
+ }
2477
+ result.aliases = aliases;
2478
+ }
2330
2479
  function intrinsicImports(result, bound) {
2331
2480
  const lines = [];
2332
2481
  for (const [module2, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
2333
- const wanted = [...names].filter((name) => !bound.has(name)).sort();
2482
+ 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);
2334
2483
  if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module2)};`);
2335
2484
  }
2336
2485
  return lines.length ? `${lines.join("\n")}
@@ -2515,7 +2664,7 @@ function transformTemplates(code, id, options = {}) {
2515
2664
  const wantsJsx = format !== "lit";
2516
2665
  const mayHaveTemplate = wantsLit && (code.includes(`${litTag}\``) || code.includes("svg`"));
2517
2666
  const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
2518
- const wantsSources = options.sourceLocations === true && mayHaveReactiveCall(code);
2667
+ const wantsSources = options.sourceLocations === true && mayHaveSourceMarks(code);
2519
2668
  const sourceName = relativeToRoot(id, options.sourceRoot);
2520
2669
  if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources) return null;
2521
2670
  const ast = (0, import_parser2.parse)(code, {
@@ -2530,6 +2679,7 @@ function transformTemplates(code, id, options = {}) {
2530
2679
  });
2531
2680
  const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
2532
2681
  const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
2682
+ if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
2533
2683
  const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
2534
2684
  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;
2535
2685
  if (silent) return null;
@@ -1 +1 @@
1
- {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/transform/templates.ts"],"names":[],"mappings":"AASA,OAAO,WAAW,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAiB,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAG1F,OAAO,KAAK,EAAqB,cAAc,EAAU,MAAM,gBAAgB,CAAC;AAWhF,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAA2C,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAoBpG,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D;;;;OAIG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAChC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;IAC5C,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,wEAAwE;IACxE,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC7C,8DAA8D;IAC9D,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAChD;AAwTD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,gBAAqB,GAC7B,eAAe,GAAG,IAAI,CAiNxB"}
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/transform/templates.ts"],"names":[],"mappings":"AASA,OAAO,WAAW,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAiB,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAG1F,OAAO,KAAK,EAAqB,cAAc,EAAU,MAAM,gBAAgB,CAAC;AAWhF,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAgE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAoBzH,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D;;;;OAIG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAChC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;IAC5C,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,wEAAwE;IACxE,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC7C,8DAA8D;IAC9D,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAChD;AAwTD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,gBAAqB,GAC7B,eAAe,GAAG,IAAI,CAkNxB"}
@@ -20,8 +20,8 @@ import { createComponentResolver } from '../resolve/component-resolver.js';
20
20
  import { imperativeBackend } from '../codegen/backends/imperative.js';
21
21
  import { moduleBindings } from './bindings.js';
22
22
  import { collectPropsEdits } from './props.js';
23
- import { collectIntrinsicEdits, intrinsicImports } from './intrinsics.js';
24
- import { collectSourceEdits, mayHaveReactiveCall } from './source-locations.js';
23
+ import { avoidBindingClashes, collectIntrinsicEdits, intrinsicImports } from './intrinsics.js';
24
+ import { collectSourceEdits, mayHaveSourceMarks } from './source-locations.js';
25
25
  import { mayHaveIntrinsic } from '../analyze/intrinsics.js';
26
26
  import { declaredNames } from '../analyze/reactive-bindings.js';
27
27
  import { DOM_CONTROL_FLOW, CORE_CONTROL_FLOW, ROUTER_COMPONENTS } from '../resolve/builtins.js';
@@ -303,7 +303,7 @@ export function transformTemplates(code, id, options = {}) {
303
303
  const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
304
304
  // A module can be nothing but reactive calls and still need marking, so the skip check
305
305
  // has to look for those too when source locations are wanted.
306
- const wantsSources = options.sourceLocations === true && mayHaveReactiveCall(code);
306
+ const wantsSources = options.sourceLocations === true && mayHaveSourceMarks(code);
307
307
  // What a mark calls this file. The declaration marks and the usage marks are read back by
308
308
  // name, so both passes have to spell it the same way.
309
309
  const sourceName = relativeToRoot(id, options.sourceRoot);
@@ -331,6 +331,8 @@ export function transformTemplates(code, id, options = {}) {
331
331
  const intrinsics = options.intrinsics === false
332
332
  ? { edits: [], diagnostics: [], imports: new Map() }
333
333
  : collectIntrinsicEdits(ast.program);
334
+ if (intrinsics.edits.length)
335
+ avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
334
336
  // Where each reactive primitive was created, for the devtools graph. Off unless asked
335
337
  // for: it is development tooling, and production should carry none of it.
336
338
  // `wantsSources` only decides whether a module with nothing else in it is worth parsing.