@fluixi/compiler 1.0.0-alpha.92 → 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 (68) hide show
  1. package/dist/analyze/intrinsics.cjs +18 -0
  2. package/dist/analyze/intrinsics.d.ts.map +1 -1
  3. package/dist/analyze/intrinsics.js +18 -0
  4. package/dist/analyze/intrinsics.mjs +18 -0
  5. package/dist/analyze/reactive-bindings.cjs +18 -0
  6. package/dist/analyze/reactive-bindings.mjs +18 -0
  7. package/dist/analyze/static-graph.cjs +22 -4
  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 +22 -4
  11. package/dist/{babel-GI375YZ2.mjs → babel-RJHJQVEM.mjs} +4 -4
  12. package/dist/{chunk-QZ4CJPYP.mjs → chunk-56QSOVVL.mjs} +1 -1
  13. package/dist/{chunk-XJ5H2MXY.mjs → chunk-OD53TMER.mjs} +19 -1
  14. package/dist/{chunk-DWNWN5RH.mjs → chunk-R7PPFBCL.mjs} +1 -1
  15. package/dist/{chunk-VOUI6XPV.mjs → chunk-TJIH7TLX.mjs} +1 -1
  16. package/dist/{chunk-VC6X44FS.mjs → chunk-U7HCFLZ2.mjs} +153 -48
  17. package/dist/codegen/backends/imperative.cjs +24 -6
  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 +24 -6
  21. package/dist/frontend/babel/build-ir-lit.cjs +120 -43
  22. package/dist/frontend/babel/build-ir-lit.mjs +120 -43
  23. package/dist/frontend/babel/build-ir.cjs +120 -43
  24. package/dist/frontend/babel/build-ir.mjs +120 -43
  25. package/dist/frontend/babel/index.cjs +121 -44
  26. package/dist/frontend/babel/index.mjs +121 -44
  27. package/dist/frontend/babel/lower-template.cjs +120 -43
  28. package/dist/frontend/babel/lower-template.mjs +120 -43
  29. package/dist/frontend/babel/plugin.cjs +120 -43
  30. package/dist/frontend/babel/plugin.mjs +120 -43
  31. package/dist/index.cjs +41 -38
  32. package/dist/index.mjs +41 -38
  33. package/dist/integrations.cjs +176 -52
  34. package/dist/integrations.mjs +8 -8
  35. package/dist/lower/compile-template.cjs +41 -38
  36. package/dist/lower/compile-template.mjs +41 -38
  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 +40 -37
  42. package/dist/lower/template.d.ts.map +1 -1
  43. package/dist/lower/template.js +22 -30
  44. package/dist/lower/template.mjs +40 -37
  45. package/dist/resolve/builtins.cjs +1 -1
  46. package/dist/resolve/builtins.mjs +1 -1
  47. package/dist/resolve/component-globals.cjs +14 -0
  48. package/dist/resolve/component-globals.mjs +14 -0
  49. package/dist/resolve/write-globals.cjs +14 -0
  50. package/dist/resolve/write-globals.mjs +14 -0
  51. package/dist/{server-fns-BBZRZUPP.mjs → server-fns-ZFRDIQ2X.mjs} +4 -4
  52. package/dist/{server-functions-VEGLIFCE.mjs → server-functions-CTDXX67X.mjs} +3 -3
  53. package/dist/transform/index.cjs +170 -47
  54. package/dist/transform/index.mjs +170 -47
  55. package/dist/transform/intrinsics.cjs +18 -0
  56. package/dist/transform/intrinsics.mjs +18 -0
  57. package/dist/transform/source-locations.cjs +64 -3
  58. package/dist/transform/source-locations.d.cts +7 -2
  59. package/dist/transform/source-locations.d.ts +7 -2
  60. package/dist/transform/source-locations.d.ts.map +1 -1
  61. package/dist/transform/source-locations.js +68 -3
  62. package/dist/transform/source-locations.mjs +64 -3
  63. package/dist/transform/templates.cjs +169 -46
  64. package/dist/transform/templates.js +2 -2
  65. package/dist/transform/templates.mjs +169 -46
  66. package/dist/{transform-UWZ7ZGJ2.mjs → transform-QWWQDCXE.mjs} +7 -7
  67. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  68. package/package.json +9 -3
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.92 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.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;
@@ -156,6 +156,7 @@ var init_intrinsics = __esm({
156
156
  $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
157
157
  $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
158
158
  $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
159
+ $cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
159
160
  // No short runtime form for these yet, so the intrinsic stands for the `create*`
160
161
  // name. Still worth having: no import to write, and when a shorter form is
161
162
  // designed, the change is this line rather than a compiler pass.
@@ -166,6 +167,19 @@ var init_intrinsics = __esm({
166
167
  // dependency analysis must not guess at.
167
168
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
168
169
  $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
170
+ // Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
171
+ // no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
172
+ $batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
173
+ $cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
174
+ $root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
175
+ $context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
176
+ $renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
177
+ $computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
178
+ // Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
179
+ // handle as far as reads go: the same accessor with `set` on it.
180
+ $storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
181
+ $asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
182
+ $persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
169
183
  // An environment variable, public or server-only; the browser build refuses a secret.
170
184
  $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
171
185
  };
@@ -178,8 +192,11 @@ var init_intrinsics = __esm({
178
192
  createMemo: "memo-accessor",
179
193
  createEffect: "effect",
180
194
  createRenderEffect: "effect",
195
+ renderEffect: "effect",
196
+ computed: "effect",
181
197
  createStore: "reactive-object",
182
198
  resource: "resource-handle",
199
+ cachedResource: "resource-handle",
183
200
  createResource: "reactive-object",
184
201
  createSelector: "memo-accessor",
185
202
  createDeferred: "memo-accessor"
@@ -188,6 +205,7 @@ var init_intrinsics = __esm({
188
205
  "@fluixi/reactive",
189
206
  "@fluixi/reactive/signal",
190
207
  "@fluixi/reactive/store",
208
+ "@fluixi/reactive/cached-resource",
191
209
  "@fluixi/core"
192
210
  ];
193
211
  INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
@@ -686,11 +704,12 @@ var init_reactive_bindings = __esm({
686
704
  });
687
705
 
688
706
  // src/transform/source-locations.ts
689
- function mayHaveReactiveCall(code) {
707
+ function mayHaveSourceMarks(code) {
690
708
  for (const name of RUNTIME_PRIMITIVES2) {
691
709
  if (code.includes(name)) return true;
692
710
  }
693
- return code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store");
711
+ if (code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store")) return true;
712
+ return /\bclass\b[^{;]*\bextends\b/.test(code);
694
713
  }
695
714
  function isLoneBranch(statement, parent) {
696
715
  if (!parent || statement.type === "BlockStatement") return false;
@@ -719,6 +738,14 @@ function walk3(node, visit, stack = []) {
719
738
  }
720
739
  function nameFor(stack) {
721
740
  const declarator = stack[stack.length - 1];
741
+ if (declarator && CLASS_FIELDS.has(declarator.type)) {
742
+ const key = declarator.key;
743
+ if (key?.type === "Identifier" || key?.type === "PrivateIdentifier" || key?.type === "PrivateName") {
744
+ const name = key.name ?? key.id?.name;
745
+ return name;
746
+ }
747
+ return void 0;
748
+ }
722
749
  if (declarator?.type !== "VariableDeclarator") return void 0;
723
750
  const id = declarator.id;
724
751
  if (id?.type === "Identifier") return id.name;
@@ -767,6 +794,17 @@ function collectSourceEdits(program, filename) {
767
794
  });
768
795
  }
769
796
  }
797
+ if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.superClass && !node.declare) {
798
+ const at = node.loc?.start;
799
+ const body = node.body;
800
+ if (at && body) {
801
+ edits.push({
802
+ start: body.start + 1,
803
+ end: body.start + 1,
804
+ code: `static{globalThis.${CLASS_MARKER}?.(this,${JSON.stringify(filename)},${at.line},${at.column});}`
805
+ });
806
+ }
807
+ }
770
808
  if (node.type !== "CallExpression") return;
771
809
  const callee = node.callee;
772
810
  if (callee?.type !== "Identifier") return;
@@ -776,6 +814,26 @@ function collectSourceEdits(program, filename) {
776
814
  if (!intrinsic && !imported) return;
777
815
  const position = node.loc?.start;
778
816
  if (!position) return;
817
+ for (let i = stack.length - 1; i >= 0; i--) {
818
+ const up = stack[i];
819
+ if (isStatement(up)) break;
820
+ if (CLASS_FIELDS.has(up.type)) {
821
+ if (claimed.has(node.start)) return;
822
+ claimed.add(node.start);
823
+ const label2 = nameFor(stack);
824
+ const own = !up.static;
825
+ const args2 = [
826
+ JSON.stringify(filename),
827
+ String(position.line),
828
+ String(position.column),
829
+ label2 ? JSON.stringify(label2) : own ? "undefined" : void 0,
830
+ own ? "this" : void 0
831
+ ].filter((a) => a !== void 0).join(",");
832
+ edits.push({ start: node.start, end: node.start, code: `(globalThis.${SOURCE_MARKER}?.(${args2}),` });
833
+ edits.push({ start: node.end, end: node.end, code: ")" });
834
+ return;
835
+ }
836
+ }
779
837
  let statement;
780
838
  let parent;
781
839
  let index = -1;
@@ -815,7 +873,7 @@ function collectSourceEdits(program, filename) {
815
873
  });
816
874
  return { edits, marked: edits.length };
817
875
  }
818
- var SOURCE_MARKER, COMPONENT_MARKER, HOLE_MARKER, markHole, PROPS_MARKER, markProps, RUNTIME_PRIMITIVES2, SINGLE_STATEMENT_PARENTS;
876
+ var SOURCE_MARKER, COMPONENT_MARKER, CLASS_MARKER, HOLE_MARKER, markHole, PROPS_MARKER, markProps, RUNTIME_PRIMITIVES2, SINGLE_STATEMENT_PARENTS, CLASS_FIELDS;
819
877
  var init_source_locations = __esm({
820
878
  "src/transform/source-locations.ts"() {
821
879
  "use strict";
@@ -823,6 +881,7 @@ var init_source_locations = __esm({
823
881
  init_reactive_bindings();
824
882
  SOURCE_MARKER = "__fx_source";
825
883
  COMPONENT_MARKER = "__fx_component";
884
+ CLASS_MARKER = "__fx_class";
826
885
  HOLE_MARKER = "__fx_hole";
827
886
  markHole = (accessor, line, column, name) => `(globalThis.${HOLE_MARKER} ?? ((f) => f))(${accessor},${line},${column}${name === void 0 ? "" : `,${JSON.stringify(name)}`})`;
828
887
  PROPS_MARKER = "__fx_props";
@@ -850,6 +909,7 @@ var init_source_locations = __esm({
850
909
  "LabeledStatement",
851
910
  "WithStatement"
852
911
  ]);
912
+ CLASS_FIELDS = /* @__PURE__ */ new Set(["PropertyDefinition", "ClassProperty", "ClassPrivateProperty", "AccessorProperty"]);
853
913
  }
854
914
  });
855
915
 
@@ -1013,13 +1073,16 @@ function emitComponent(name, props, children, used, templates, at) {
1013
1073
  used.add("createComponent");
1014
1074
  const spreads = props.filter((p) => p.kind === "spread");
1015
1075
  const normal = props.filter((p) => p.kind !== "spread");
1016
- const entries = normal.map(
1017
- (p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
1018
- );
1076
+ const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
1019
1077
  if (children.length > 0) {
1020
- entries.push(`get children() { return ${emitChildren(children, used, templates)}; }`);
1078
+ bodies.push(["children", emitChildren(children, used, templates)]);
1079
+ }
1080
+ let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
1081
+ if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
1082
+ const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => ${body}`);
1083
+ const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
1084
+ obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
1021
1085
  }
1022
- let obj = `{ ${entries.join(", ")} }`;
1023
1086
  if (spreads.length > 0) {
1024
1087
  used.add("mergeProps");
1025
1088
  obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
@@ -1100,7 +1163,8 @@ function emitNode(node, used, templates) {
1100
1163
  } else {
1101
1164
  used.add("spread");
1102
1165
  const svgFlag = node.svg ? ", isSVG: true" : "";
1103
- const customFlag = node.tag.includes("-") ? ", isCustomElement: true" : "";
1166
+ const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
1167
+ const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
1104
1168
  parts.push(
1105
1169
  `spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
1106
1170
  );
@@ -1191,7 +1255,7 @@ function lowerTemplate(pieces, holes, used, opts = {}) {
1191
1255
  const { root } = (0, import_template_parser.parseTemplate)(pieces, { svg: opts.svg });
1192
1256
  return new Lowerer(holes, used, opts.sourceFile, opts.positionAt).lowerRoot(root.children);
1193
1257
  }
1194
- var import_template_parser, DELEGATED, Lowerer;
1258
+ var import_template_parser, DELEGATED, CONTAINER, Lowerer;
1195
1259
  var init_template = __esm({
1196
1260
  "src/lower/template.ts"() {
1197
1261
  "use strict";
@@ -1214,6 +1278,7 @@ var init_template = __esm({
1214
1278
  "mousedown",
1215
1279
  "mouseup"
1216
1280
  ]);
1281
+ CONTAINER = "container";
1217
1282
  Lowerer = class {
1218
1283
  constructor(holes, used, sourceFile, positionAt) {
1219
1284
  this.holes = holes;
@@ -1265,10 +1330,6 @@ var init_template = __esm({
1265
1330
  if (hasElse) i = elseIdx;
1266
1331
  continue;
1267
1332
  }
1268
- if (child.attributes.some((a) => a.kind === "EachDirective")) {
1269
- out.push(this.lowerEach(child));
1270
- continue;
1271
- }
1272
1333
  }
1273
1334
  const node = this.lowerNode(child);
1274
1335
  if (node) out.push(node);
@@ -1310,13 +1371,16 @@ var init_template = __esm({
1310
1371
  node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
1311
1372
  return node;
1312
1373
  }
1374
+ const each = this.lowerEach(el);
1375
+ const children = each ? [each] : this.lowerChildren(el.children);
1376
+ if (el.tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
1313
1377
  const at = this.tagAt(el);
1314
1378
  return {
1315
1379
  kind: "element",
1316
1380
  tag: el.tag,
1317
1381
  svg: el.namespace === "svg",
1318
1382
  props: this.lowerAttributes(el.attributes),
1319
- children: this.lowerChildren(el.children),
1383
+ children,
1320
1384
  static: false,
1321
1385
  ...at ? { at } : {}
1322
1386
  };
@@ -1388,10 +1452,14 @@ var init_template = __esm({
1388
1452
  const at = this.tagAt(el);
1389
1453
  return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
1390
1454
  }
1391
- /** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
1455
+ /**
1456
+ * `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
1457
+ * content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
1458
+ * it is. Null when the element has no `each`.
1459
+ */
1392
1460
  lowerEach(el) {
1393
1461
  const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
1394
- if (!eachDir || eachDir.kind !== "EachDirective") return this.lowerNode(el);
1462
+ if (!eachDir || eachDir.kind !== "EachDirective") return null;
1395
1463
  const each = this.hole(eachDir.hole);
1396
1464
  const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
1397
1465
  if (eachDir.key) {
@@ -1401,12 +1469,12 @@ var init_template = __esm({
1401
1469
  const arrow = this.itemArrow(el);
1402
1470
  let childrenCode;
1403
1471
  if (arrow) {
1404
- const bodyIR = { kind: "expr", code: arrow.body, reactive: arrow.bodyReactive };
1405
- const repeated = this.rebuildWithChildren(el, [bodyIR]);
1406
- childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
1472
+ const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
1473
+ childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
1407
1474
  } else {
1408
- const repeated = this.stripAndLower(el, (a) => a.kind === "EachDirective");
1409
- childrenCode = `() => ${paren(this.emit(repeated), "arrowBody")}`;
1475
+ const content = this.lowerChildren(el.children);
1476
+ const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
1477
+ childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
1410
1478
  }
1411
1479
  const children = [{ kind: "expr", code: childrenCode, reactive: false }];
1412
1480
  const at = this.tagAt(el);
@@ -1423,25 +1491,6 @@ var init_template = __esm({
1423
1491
  const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
1424
1492
  return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
1425
1493
  }
1426
- /** Same element (minus each/key) but with explicit IR children. */
1427
- rebuildWithChildren(el, children) {
1428
- const props = this.lowerAttributes(
1429
- el.attributes.filter((a) => a.kind !== "EachDirective")
1430
- );
1431
- if (el.kind === "Element") {
1432
- const at = this.tagAt(el);
1433
- return {
1434
- kind: "element",
1435
- tag: el.tag,
1436
- svg: el.namespace === "svg",
1437
- props,
1438
- children,
1439
- static: false,
1440
- ...at ? { at } : {}
1441
- };
1442
- }
1443
- return { kind: "component", name: el.tag, props, children };
1444
- }
1445
1494
  // --- attributes ---------------------------------------------------------
1446
1495
  lowerAttributes(attrs) {
1447
1496
  const props = [];
@@ -1855,6 +1904,21 @@ var init_expr_shape = __esm({
1855
1904
  });
1856
1905
 
1857
1906
  // src/lower/jsx.ts
1907
+ function directive(node, name) {
1908
+ if (node.type !== "JSXElement") return void 0;
1909
+ const opening = node.openingElement;
1910
+ if (opening.name.type !== "JSXIdentifier" || opening.name.name[0] !== opening.name.name[0].toLowerCase()) return void 0;
1911
+ return opening.attributes.find((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === name);
1912
+ }
1913
+ function directiveExpr(attr) {
1914
+ const v = attr.value;
1915
+ return v?.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression" ? v.expression : void 0;
1916
+ }
1917
+ function emitIR(ir, ctx) {
1918
+ const { code, imports, templates } = imperativeBackend.emit(ir, {});
1919
+ for (const s of imports) ctx.used.add(s);
1920
+ return inlineTemplates(code, templates);
1921
+ }
1858
1922
  function literalOf(node) {
1859
1923
  if (node.type === "StringLiteral" || node.type === "NumericLiteral" || node.type === "BooleanLiteral") {
1860
1924
  return node.value;
@@ -1957,7 +2021,16 @@ function buildProps(attrs, ctx) {
1957
2021
  }
1958
2022
  function buildChildren(children, ctx) {
1959
2023
  const out = [];
1960
- for (const child of children) {
2024
+ for (let i = 0; i < children.length; i++) {
2025
+ const child = children[i];
2026
+ if (directive(child, "if")) {
2027
+ let next = i + 1;
2028
+ while (next < children.length && children[next].type === "JSXText" && !cleanTemplateText(children[next].value)) next++;
2029
+ const fallback = directive(children[next], "else") ? children[next] : null;
2030
+ out.push(buildIf(child, fallback, ctx));
2031
+ if (fallback) i = next;
2032
+ continue;
2033
+ }
1961
2034
  if (child.type === "JSXText") {
1962
2035
  const text = cleanTemplateText(child.value);
1963
2036
  if (text) out.push({ kind: "text", value: text });
@@ -1994,26 +2067,75 @@ function readLoad(attrs) {
1994
2067
  }
1995
2068
  return void 0;
1996
2069
  }
2070
+ function buildIf(node, fallback, ctx) {
2071
+ const cond = directiveExpr(directive(node, "if"));
2072
+ const props = [
2073
+ cond ? { name: "when", kind: "attr", expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) } : { name: "when", kind: "attr", literal: true }
2074
+ ];
2075
+ if (fallback) {
2076
+ props.push({ name: "fallback", kind: "attr", expr: emitIR(buildElement(fallback, ctx, ["else"]), ctx), jsxElement: true });
2077
+ }
2078
+ return { kind: "component", name: "Show", props, children: [buildElement(node, ctx, ["if"])] };
2079
+ }
2080
+ function buildEach(node, ctx) {
2081
+ const attr = directive(node, "each");
2082
+ if (!attr) return null;
2083
+ const list = directiveExpr(attr);
2084
+ const props = [
2085
+ list ? { name: "each", kind: "attr", expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) } : { name: "each", kind: "attr", expr: "[]" }
2086
+ ];
2087
+ const key = directive(node, "key");
2088
+ if (key) {
2089
+ const keyExpr = directiveExpr(key);
2090
+ const by = isString(key.value) ? `(item) => item[${JSON.stringify(literalOf(key.value))}]` : keyExpr ? ctx.code(keyExpr) : void 0;
2091
+ if (by) props.push({ name: "by", kind: "attr", expr: by });
2092
+ }
2093
+ const content = node.children.filter((c) => !(c.type === "JSXText" && !cleanTemplateText(c.value)));
2094
+ const only = content.length === 1 && content[0].type === "JSXExpressionContainer" ? content[0].expression : null;
2095
+ let render;
2096
+ if (only && (only.type === "ArrowFunctionExpression" || only.type === "FunctionExpression")) {
2097
+ const fn = ctx.code(only);
2098
+ const live = only.type === "ArrowFunctionExpression" && only.body.type !== "BlockStatement" && isReactive(only.body);
2099
+ render = live ? `(...args) => () => (${fn})(...args)` : fn;
2100
+ } else {
2101
+ const built = buildChildren(node.children, ctx);
2102
+ const ir = built.length === 1 ? built[0] : { kind: "fragment", children: built };
2103
+ render = `() => ${paren(emitIR(ir, ctx), "arrowBody")}`;
2104
+ }
2105
+ return { kind: "component", name: "For", props, children: [{ kind: "expr", code: render, reactive: false }] };
2106
+ }
2107
+ function buildElement(node, ctx, handled) {
2108
+ const skip = new Set(handled);
2109
+ const directives = /* @__PURE__ */ new Set(["if", "else", "each", ...directive(node, "each") ? ["key"] : []]);
2110
+ const attributes = node.openingElement.attributes.filter(
2111
+ (a) => !(a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && (skip.has(a.name.name) || directives.has(a.name.name)))
2112
+ );
2113
+ const { tag } = tagInfo(node.openingElement.name, ctx);
2114
+ const each = buildEach(node, ctx);
2115
+ const children = each ? [each] : buildChildren(node.children, ctx);
2116
+ if (tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
2117
+ const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
2118
+ return { kind: "element", tag, svg: SVG_TAGS.has(tag), props: buildProps(attributes, ctx), children, static: false, ...at ? { at } : {} };
2119
+ }
1997
2120
  function buildNode(node, ctx) {
1998
2121
  if (node.type === "JSXFragment") {
1999
2122
  return { kind: "fragment", children: buildChildren(node.children, ctx) };
2000
2123
  }
2124
+ if (directive(node, "if")) return buildIf(node, null, ctx);
2001
2125
  const { tag, component } = tagInfo(node.openingElement.name, ctx);
2126
+ if (!component) return buildElement(node, ctx, []);
2002
2127
  const props = buildProps(node.openingElement.attributes, ctx);
2003
2128
  const children = buildChildren(node.children, ctx);
2004
2129
  const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
2005
- if (component) {
2006
- const load = readLoad(node.openingElement.attributes);
2007
- return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
2008
- }
2009
- return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
2130
+ const load = readLoad(node.openingElement.attributes);
2131
+ return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
2010
2132
  }
2011
2133
  function buildJsxIR(node, ctx) {
2012
2134
  const ir = buildNode(node, ctx);
2013
2135
  analyzeStatic(ir);
2014
2136
  return ir;
2015
2137
  }
2016
- var SVG_TAGS, EVENT_RE, DELEGATED2, isReactive, posOf, isString;
2138
+ var SVG_TAGS, EVENT_RE, DELEGATED2, isReactive, CONTAINER2, posOf, isString;
2017
2139
  var init_jsx = __esm({
2018
2140
  "src/lower/jsx.ts"() {
2019
2141
  "use strict";
@@ -2023,6 +2145,7 @@ var init_jsx = __esm({
2023
2145
  init_analyze_static();
2024
2146
  init_text();
2025
2147
  init_paren();
2148
+ init_imperative();
2026
2149
  SVG_TAGS = /* @__PURE__ */ new Set([
2027
2150
  "svg",
2028
2151
  "path",
@@ -2053,6 +2176,7 @@ var init_jsx = __esm({
2053
2176
  "mouseup"
2054
2177
  ]);
2055
2178
  isReactive = (node) => isReactiveShape(shapeOf(node));
2179
+ CONTAINER2 = "container";
2056
2180
  posOf = (node, ctx) => {
2057
2181
  if (!ctx.sourceFile) return void 0;
2058
2182
  const at = node.loc?.start;
@@ -3378,7 +3502,7 @@ function transformTemplates(code, id, options = {}) {
3378
3502
  const wantsJsx = format !== "lit";
3379
3503
  const mayHaveTemplate = wantsLit && (code.includes(`${litTag}\``) || code.includes("svg`"));
3380
3504
  const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
3381
- const wantsSources = options.sourceLocations === true && mayHaveReactiveCall(code);
3505
+ const wantsSources = options.sourceLocations === true && mayHaveSourceMarks(code);
3382
3506
  const sourceName = relativeToRoot(id, options.sourceRoot);
3383
3507
  if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources) return null;
3384
3508
  const ast = (0, import_parser2.parse)(code, {
@@ -3733,7 +3857,7 @@ var server_fns_exports = {};
3733
3857
  __export(server_fns_exports, {
3734
3858
  transformServerFns: () => transformServerFns
3735
3859
  });
3736
- function directive(node) {
3860
+ function directive2(node) {
3737
3861
  if (!FUNCTION_TYPES.has(node.type)) return null;
3738
3862
  const body = node.body;
3739
3863
  if (!body || body.type !== "BlockStatement") return null;
@@ -3749,7 +3873,7 @@ function findServerFns(node, out) {
3749
3873
  return;
3750
3874
  }
3751
3875
  if (typeof node.type === "string") {
3752
- const found = directive(node);
3876
+ const found = directive2(node);
3753
3877
  if (found) {
3754
3878
  out.push({ fn: node, directive: found });
3755
3879
  return;
@@ -1,12 +1,12 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.92 | (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
  INTRINSICS,
4
4
  builtinComponentMap,
5
5
  createComponentResolver
6
- } from "./chunk-XJ5H2MXY.mjs";
6
+ } from "./chunk-OD53TMER.mjs";
7
7
  import {
8
8
  __require
9
- } from "./chunk-VOUI6XPV.mjs";
9
+ } from "./chunk-TJIH7TLX.mjs";
10
10
 
11
11
  // src/resolve/write-globals.ts
12
12
  import { mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
@@ -238,7 +238,7 @@ import { join as _join } from "node:path";
238
238
  async function createBabelPlugin(options = {}) {
239
239
  let pluginModule = null;
240
240
  try {
241
- pluginModule = await import("./babel-GI375YZ2.mjs");
241
+ pluginModule = await import("./babel-RJHJQVEM.mjs");
242
242
  } catch (e) {
243
243
  console.warn("Could not load the babel front-end:", e);
244
244
  }
@@ -409,7 +409,7 @@ function transformOptions(options, id) {
409
409
  }
410
410
  async function rewriteProps(code, id, options) {
411
411
  if (options.propsDestructure === false) return code;
412
- const { transformProps } = await import("./transform-UWZ7ZGJ2.mjs");
412
+ const { transformProps } = await import("./transform-QWWQDCXE.mjs");
413
413
  const result = transformProps(code, id);
414
414
  reportDiagnostics({ propsDiagnostics: result.diagnostics }, id);
415
415
  return result.rewritten > 0 ? result.code : code;
@@ -432,7 +432,7 @@ function reportDiagnostics(result, id) {
432
432
  }
433
433
  async function compileModule(code, id, options) {
434
434
  if (!options.babel) {
435
- const { transformTemplates } = await import("./transform-UWZ7ZGJ2.mjs");
435
+ const { transformTemplates } = await import("./transform-QWWQDCXE.mjs");
436
436
  const result2 = transformTemplates(code, id, transformOptions(options, id));
437
437
  reportDiagnostics(result2, id);
438
438
  return result2;
@@ -551,10 +551,10 @@ export { isServerFnRequest, handleServerFn } from '@fluixi/start/server-fn';
551
551
  if (!code.includes("use server")) return null;
552
552
  const args = { ssr: !!opts?.ssr, filename: id, root };
553
553
  if (options.babel) {
554
- const { transformServerFunctions } = await import("./server-functions-VEGLIFCE.mjs");
554
+ const { transformServerFunctions } = await import("./server-functions-CTDXX67X.mjs");
555
555
  return transformServerFunctions(code, args);
556
556
  }
557
- const { transformServerFns } = await import("./server-fns-BBZRZUPP.mjs");
557
+ const { transformServerFns } = await import("./server-fns-ZFRDIQ2X.mjs");
558
558
  return transformServerFns(code, args);
559
559
  }
560
560
  };