@fluixi/compiler 1.0.0-alpha.104 → 1.0.0-alpha.106

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 (71) hide show
  1. package/dist/analyze/static-graph.cjs +1 -1
  2. package/dist/analyze/static-graph.mjs +1 -1
  3. package/dist/{babel-5SX36G76.mjs → babel-HJY4RVAV.mjs} +33 -20
  4. package/dist/{chunk-NWF66YTU.mjs → chunk-4XEOMQ57.mjs} +1 -1
  5. package/dist/{chunk-FMQPBKTW.mjs → chunk-JUFI6IR3.mjs} +1 -1
  6. package/dist/{chunk-NUET3BJB.mjs → chunk-LCQHL2VQ.mjs} +132 -10
  7. package/dist/{chunk-2O2YW5ZO.mjs → chunk-LGUZRHYN.mjs} +2 -2
  8. package/dist/{chunk-RBIYCE6M.mjs → chunk-TDN5MYWI.mjs} +1 -1
  9. package/dist/{chunk-ZDZKJQ5N.mjs → chunk-W7DYOMXJ.mjs} +2 -2
  10. package/dist/{chunk-DN33T5GJ.mjs → chunk-WHEDRMNR.mjs} +1 -1
  11. package/dist/codegen/backends/imperative.cjs +130 -8
  12. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  13. package/dist/codegen/backends/imperative.js +62 -0
  14. package/dist/codegen/backends/imperative.mjs +130 -8
  15. package/dist/codegen/partial-template.cjs +80 -8
  16. package/dist/codegen/partial-template.d.cts +21 -4
  17. package/dist/codegen/partial-template.d.ts +21 -4
  18. package/dist/codegen/partial-template.d.ts.map +1 -1
  19. package/dist/codegen/partial-template.js +0 -0
  20. package/dist/codegen/partial-template.mjs +80 -8
  21. package/dist/codegen/serialize-static.cjs +1 -0
  22. package/dist/codegen/serialize-static.d.cts +8 -0
  23. package/dist/codegen/serialize-static.d.ts +8 -0
  24. package/dist/codegen/serialize-static.d.ts.map +1 -1
  25. package/dist/codegen/serialize-static.js +1 -1
  26. package/dist/codegen/serialize-static.mjs +1 -0
  27. package/dist/frontend/babel/build-ir-html.cjs +149 -21
  28. package/dist/frontend/babel/build-ir-html.d.cts +3 -1
  29. package/dist/frontend/babel/build-ir-html.d.ts +3 -1
  30. package/dist/frontend/babel/build-ir-html.d.ts.map +1 -1
  31. package/dist/frontend/babel/build-ir-html.mjs +149 -21
  32. package/dist/frontend/babel/build-ir.cjs +149 -21
  33. package/dist/frontend/babel/build-ir.d.cts +11 -2
  34. package/dist/frontend/babel/build-ir.d.ts +11 -2
  35. package/dist/frontend/babel/build-ir.d.ts.map +1 -1
  36. package/dist/frontend/babel/build-ir.js +15 -9
  37. package/dist/frontend/babel/build-ir.mjs +149 -21
  38. package/dist/frontend/babel/index.cjs +160 -25
  39. package/dist/frontend/babel/index.mjs +160 -25
  40. package/dist/frontend/babel/lower-template.cjs +149 -21
  41. package/dist/frontend/babel/lower-template.d.cts +2 -1
  42. package/dist/frontend/babel/lower-template.d.ts +2 -1
  43. package/dist/frontend/babel/lower-template.d.ts.map +1 -1
  44. package/dist/frontend/babel/lower-template.js +4 -4
  45. package/dist/frontend/babel/lower-template.mjs +149 -21
  46. package/dist/frontend/babel/plugin.cjs +158 -23
  47. package/dist/frontend/babel/plugin.js +9 -2
  48. package/dist/frontend/babel/plugin.mjs +158 -23
  49. package/dist/index.cjs +131 -9
  50. package/dist/index.mjs +131 -9
  51. package/dist/integrations.cjs +165 -33
  52. package/dist/integrations.mjs +11 -11
  53. package/dist/lower/compile-template.cjs +131 -9
  54. package/dist/lower/compile-template.mjs +131 -9
  55. package/dist/lower/jsx.cjs +130 -8
  56. package/dist/lower/jsx.mjs +130 -8
  57. package/dist/lower/template.cjs +130 -8
  58. package/dist/lower/template.mjs +130 -8
  59. package/dist/resolve/builtins.cjs +1 -1
  60. package/dist/resolve/builtins.mjs +1 -1
  61. package/dist/{server-fns-3Z3ZKJLB.mjs → server-fns-WZJK4BJE.mjs} +5 -5
  62. package/dist/{server-functions-DB7AHWE6.mjs → server-functions-4KTFFEO3.mjs} +3 -3
  63. package/dist/transform/index.cjs +135 -16
  64. package/dist/transform/index.mjs +135 -16
  65. package/dist/transform/templates.cjs +134 -15
  66. package/dist/transform/templates.d.ts.map +1 -1
  67. package/dist/transform/templates.js +4 -8
  68. package/dist/transform/templates.mjs +134 -15
  69. package/dist/{transform-VMK2URDB.mjs → transform-NO46NFQH.mjs} +11 -14
  70. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  71. package/package.json +4 -4
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/analyze/static-graph.ts
4
4
  import { parse } from "@babel/parser";
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  analyzeStatic,
4
4
  buildJsxIR,
@@ -10,13 +10,13 @@ import {
10
10
  lowerTemplate,
11
11
  resolveComponentSources,
12
12
  shapeOf
13
- } from "./chunk-NUET3BJB.mjs";
13
+ } from "./chunk-LCQHL2VQ.mjs";
14
14
  import {
15
15
  CORE_CONTROL_FLOW,
16
16
  ROUTER_COMPONENTS,
17
17
  createComponentResolver
18
- } from "./chunk-RBIYCE6M.mjs";
19
- import "./chunk-NWF66YTU.mjs";
18
+ } from "./chunk-TDN5MYWI.mjs";
19
+ import "./chunk-4XEOMQ57.mjs";
20
20
 
21
21
  // src/frontend/babel/plugin.ts
22
22
  import { declare } from "@babel/helper-plugin-utils";
@@ -33,16 +33,16 @@ var generate = _generate.default ?? _generate;
33
33
  function gen(node) {
34
34
  return generate(node, { concise: true }).code;
35
35
  }
36
- function bindHole(expr, used, onNested) {
36
+ function bindHole(expr, used, onNested, emit) {
37
37
  const hole = {
38
- code: genExpr(expr, used, onNested),
38
+ code: genExpr(expr, used, onNested, emit),
39
39
  reactive: isReactiveExpr(expr)
40
40
  };
41
41
  if (t.isArrowFunctionExpression(expr) && !t.isBlockStatement(expr.body)) {
42
42
  const body = expr.body;
43
43
  hole.arrow = {
44
44
  params: expr.params.map((p) => gen(p)),
45
- body: genExpr(body, used, onNested),
45
+ body: genExpr(body, used, onNested, emit),
46
46
  bodyReactive: isReactiveExpr(body)
47
47
  };
48
48
  }
@@ -51,7 +51,7 @@ function bindHole(expr, used, onNested) {
51
51
  }
52
52
  function lowerHtmlTemplate(node, used, opts = {}) {
53
53
  const quasi = node.quasi;
54
- const holes = quasi.expressions.map((e) => bindHole(e, used, opts.onNested));
54
+ const holes = quasi.expressions.map((e) => bindHole(e, used, opts.onNested, opts.emit));
55
55
  return lowerTemplate(buildPieces(quasi), holes, used, opts);
56
56
  }
57
57
  function buildPieces(quasi) {
@@ -79,7 +79,7 @@ var generate2 = _generate2.default ?? _generate2;
79
79
  function gen2(node) {
80
80
  return generate2(node, { concise: true }).code;
81
81
  }
82
- function transformNestedJSX(node, used, onNested) {
82
+ function transformNestedJSX(node, used, onNested, emit) {
83
83
  const clone = t2.cloneNode(node, true);
84
84
  const file = t2.file(t2.program([t2.expressionStatement(clone)]));
85
85
  let changed = false;
@@ -92,9 +92,12 @@ function transformNestedJSX(node, used, onNested) {
92
92
  traverse(file, {
93
93
  "JSXElement|JSXFragment"(path) {
94
94
  const jsx = path.node;
95
- const nestedIR = buildIR(jsx, used, onNested);
95
+ const nestedIR = buildIR(jsx, used, onNested, emit);
96
96
  onNested?.(nestedIR);
97
- const { code, imports, templates } = imperativeBackend.emit(nestedIR, {});
97
+ const { code, imports, templates } = imperativeBackend.emit(nestedIR, {
98
+ templateClone: emit?.templateClone,
99
+ partialTemplates: emit?.partialTemplates ?? true
100
+ });
98
101
  emitInto(path, inlineTemplates(code, templates), imports);
99
102
  },
100
103
  // Nested html templates compose: ${cond ? html`...` : html`...`},
@@ -102,26 +105,29 @@ function transformNestedJSX(node, used, onNested) {
102
105
  TaggedTemplateExpression(path) {
103
106
  const tag = path.node.tag;
104
107
  if (!t2.isIdentifier(tag) || tag.name !== "html" && tag.name !== "svg") return;
105
- const ir = buildIRFromHtml(path.node, used, { svg: tag.name === "svg", onNested });
108
+ const ir = buildIRFromHtml(path.node, used, { svg: tag.name === "svg", onNested, emit });
106
109
  onNested?.(ir);
107
- const { code, imports, templates } = imperativeBackend.emit(ir, {});
110
+ const { code, imports, templates } = imperativeBackend.emit(ir, {
111
+ templateClone: emit?.templateClone,
112
+ partialTemplates: emit?.partialTemplates ?? true
113
+ });
108
114
  emitInto(path, inlineTemplates(code, templates), imports);
109
115
  }
110
116
  });
111
117
  return changed ? file.program.body[0].expression : node;
112
118
  }
113
- function genExpr(node, used, onNested) {
114
- return gen2(transformNestedJSX(node, used, onNested));
119
+ function genExpr(node, used, onNested, emit) {
120
+ return gen2(transformNestedJSX(node, used, onNested, emit));
115
121
  }
116
122
  function isReactiveExpr(node) {
117
123
  return isReactiveShape(shapeOf(node));
118
124
  }
119
- function buildIR(node, used = /* @__PURE__ */ new Set(), onNested) {
125
+ function buildIR(node, used = /* @__PURE__ */ new Set(), onNested, emit) {
120
126
  const ir = buildJsxIR(node, {
121
127
  code: (n) => (
122
128
  // A member-expression tag (`<ns.Foo/>`) is not an Expression, so it cannot go
123
129
  // through the nested-JSX compile: it only ever needs printing.
124
- n.type === "JSXMemberExpression" ? gen2(n) : genExpr(n, used, onNested)
130
+ n.type === "JSXMemberExpression" ? gen2(n) : genExpr(n, used, onNested, emit)
125
131
  ),
126
132
  used
127
133
  });
@@ -456,7 +462,10 @@ function adoptTemplates(code, templates, state) {
456
462
  }
457
463
  function emitViaIR(node, state) {
458
464
  const used = /* @__PURE__ */ new Set();
459
- const ir = buildIR(node, used, nestedHook(state));
465
+ const ir = buildIR(node, used, nestedHook(state), {
466
+ partialTemplates: state.partialTemplates,
467
+ templateClone: state.templateClone
468
+ });
460
469
  resolveComponentSources(ir, {
461
470
  resolver: state.componentResolver,
462
471
  modules: {
@@ -505,7 +514,11 @@ function dedupeImports(imports) {
505
514
  function emitHtmlViaIR(node, state) {
506
515
  const used = /* @__PURE__ */ new Set();
507
516
  const svg = t3.isIdentifier(node.tag) && node.tag.name === "svg";
508
- const ir = buildIRFromHtml(node, used, { svg, onNested: nestedHook(state) });
517
+ const ir = buildIRFromHtml(node, used, {
518
+ svg,
519
+ onNested: nestedHook(state),
520
+ emit: { partialTemplates: state.partialTemplates, templateClone: state.templateClone }
521
+ });
509
522
  resolveComponentSources(ir, {
510
523
  resolver: state.componentResolver,
511
524
  modules: {
@@ -594,7 +607,7 @@ function createPreset(options = {}) {
594
607
  {
595
608
  runtime: "automatic",
596
609
  importSource: "@fluixi/jsx",
597
- development: false,
610
+ development: process.env.NODE_ENV === "development",
598
611
  detectReactivity: true,
599
612
  useHtmlTag: true,
600
613
  hoistStatics: true,
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
3
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
4
  }) : x)(function(x) {
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.6.0/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
4
4
  var comma = ",".charCodeAt(0);
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  INTRINSICS,
4
4
  RESERVED_COMPONENTS,
@@ -7,7 +7,7 @@ import {
7
7
  builtinComponentMap,
8
8
  isIntrinsicName,
9
9
  isPrimitiveModule
10
- } from "./chunk-RBIYCE6M.mjs";
10
+ } from "./chunk-TDN5MYWI.mjs";
11
11
 
12
12
  // src/analyze/expr-shape.ts
13
13
  var CALL = /* @__PURE__ */ new Set(["CallExpression", "OptionalCallExpression"]);
@@ -598,10 +598,64 @@ function isHole(node) {
598
598
  function isTemplateChild(node) {
599
599
  return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
600
600
  }
601
+ var PROPERTY_BINDS = /* @__PURE__ */ new Set(["indeterminate"]);
602
+ function disposition(prop) {
603
+ if (prop.kind === "spread") return null;
604
+ if (prop.name === "ref") return "ref";
605
+ if (prop.name === "use") return "use";
606
+ if (prop.kind === "event") return prop.event ? "event" : null;
607
+ if (prop.kind === "prop") return "property";
608
+ if (prop.kind !== "attr") return null;
609
+ const name = prop.name;
610
+ if (name.startsWith("on:")) return "nativeEvent";
611
+ if (name.startsWith("prop:")) return "property";
612
+ if (name.startsWith("attr:")) return "attr";
613
+ if (name.startsWith("bool:")) return "boolAttr";
614
+ if (name === "className" || name === "class") {
615
+ return isPlainLiteralAttr(prop) ? "serialize" : "class";
616
+ }
617
+ if (name === "classList") {
618
+ if (isPlainLiteralAttr(prop)) return "serialize";
619
+ return prop.reactive ? "classListDynamic" : "classList";
620
+ }
621
+ if (name === "style") {
622
+ if (isPlainLiteralAttr(prop)) return "serialize";
623
+ return prop.reactive ? "styleDynamic" : "style";
624
+ }
625
+ if (name.includes(":")) return null;
626
+ if (PROPERTY_ONLY.has(name)) return null;
627
+ if (PROPERTY_BINDS.has(name)) return "property";
628
+ if (prop.expr === void 0) return isPlainLiteralAttr(prop) ? "serialize" : null;
629
+ return "attr";
630
+ }
631
+ function effectiveProps(el) {
632
+ const order = [];
633
+ const byName = /* @__PURE__ */ new Map();
634
+ for (const prop of el.props) {
635
+ if (!byName.has(prop.name)) order.push(prop.name);
636
+ byName.set(prop.name, prop);
637
+ }
638
+ return order.map((name) => byName.get(name));
639
+ }
640
+ function propPlan(el) {
641
+ const custom = el.tag.includes("-");
642
+ const plan = { serialize: [], bindings: [] };
643
+ for (const prop of effectiveProps(el)) {
644
+ const kind = disposition(prop);
645
+ if (kind === null) return null;
646
+ if (kind === "serialize") {
647
+ plan.serialize.push(prop);
648
+ continue;
649
+ }
650
+ if (custom) return null;
651
+ plan.bindings.push({ prop, kind });
652
+ }
653
+ return plan;
654
+ }
601
655
  function isTemplateElement(node) {
602
656
  if (node.svg) return false;
603
657
  if (isRawTextElement(node.tag)) return false;
604
- if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
658
+ if (!propPlan(node)) return false;
605
659
  return node.children.every((c) => isTemplateChild(c) || isHole(c));
606
660
  }
607
661
  function containsHole(node) {
@@ -609,6 +663,15 @@ function containsHole(node) {
609
663
  const children = node.children;
610
664
  return children ? children.some(containsHole) : false;
611
665
  }
666
+ function containsBinding(node) {
667
+ if (node.kind !== "element") return false;
668
+ const plan = propPlan(node);
669
+ if (plan && plan.bindings.length > 0) return true;
670
+ return node.children.some(containsBinding);
671
+ }
672
+ function interesting(node) {
673
+ return containsHole(node) || containsBinding(node);
674
+ }
612
675
  function addressable(el) {
613
676
  for (let i = 0; i < el.children.length; i++) {
614
677
  const child = el.children[i];
@@ -622,9 +685,10 @@ function addressable(el) {
622
685
  function planPartialTemplate(root) {
623
686
  if (!isTemplateElement(root)) return null;
624
687
  if (!addressable(root)) return null;
625
- if (!root.children.some(containsHole)) return null;
688
+ if (!interesting(root)) return null;
626
689
  const steps = [];
627
690
  const holes = [];
691
+ const bindings = [];
628
692
  let refCount = 0;
629
693
  const declare = (expr) => {
630
694
  const ref = `_n$${refCount++}`;
@@ -632,11 +696,17 @@ function planPartialTemplate(root) {
632
696
  return ref;
633
697
  };
634
698
  walk4(root, "_el$");
635
- return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
699
+ return { html: serializeWithMarkers(root), tag: root.tag, steps, holes, bindings };
636
700
  function walk4(el, elementRef) {
701
+ const plan = propPlan(el);
702
+ if (plan) {
703
+ for (const binding of plan.bindings) {
704
+ bindings.push({ ref: elementRef, prop: binding.prop, kind: binding.kind });
705
+ }
706
+ }
637
707
  let last = -1;
638
708
  el.children.forEach((child, i) => {
639
- if (containsHole(child)) last = i;
709
+ if (interesting(child)) last = i;
640
710
  });
641
711
  let previous = null;
642
712
  for (let i = 0; i <= last; i++) {
@@ -650,19 +720,21 @@ function planPartialTemplate(root) {
650
720
  continue;
651
721
  }
652
722
  const ref = declare(expr);
653
- if (child.kind === "element" && containsHole(child)) walk4(child, ref);
723
+ if (child.kind === "element" && interesting(child)) walk4(child, ref);
654
724
  previous = ref;
655
725
  }
656
726
  }
657
727
  }
658
728
  function serializeWithMarkers(el) {
659
- return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
729
+ return serializeStatic(templateTree(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
660
730
  }
661
- function withSentinels(el) {
731
+ function templateTree(el) {
732
+ const plan = propPlan(el);
662
733
  return {
663
734
  ...el,
735
+ props: plan ? plan.serialize : [],
664
736
  children: el.children.map(
665
- (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
737
+ (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? templateTree(child) : child
666
738
  )
667
739
  };
668
740
  }
@@ -891,6 +963,55 @@ function emitComponent(name, props, children, used, templates, at) {
891
963
  const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
892
964
  return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
893
965
  }
966
+ function bindingTarget(binding) {
967
+ const name = binding.prop.name;
968
+ if (binding.kind === "boolAttr") return name.slice("bool:".length);
969
+ if (name.startsWith("prop:")) return name.slice("prop:".length);
970
+ if (name.startsWith("attr:")) return name.slice("attr:".length);
971
+ return htmlAttrName(name);
972
+ }
973
+ function bindingStatement(binding, used) {
974
+ const { ref, prop, kind } = binding;
975
+ const value = propValue(prop);
976
+ switch (kind) {
977
+ case "class":
978
+ used.add("setClassName");
979
+ return `setClassName(${ref}, ${value});`;
980
+ case "classList":
981
+ used.add("setClassList");
982
+ return `setClassList(${ref}, ${value}, []);`;
983
+ case "classListDynamic":
984
+ used.add("setDynamicClassList");
985
+ return `setDynamicClassList(${ref}, ${value});`;
986
+ case "style":
987
+ used.add("setStyle");
988
+ return `setStyle(${ref}, ${value}, []);`;
989
+ case "styleDynamic":
990
+ used.add("setDynamicStyle");
991
+ return `setDynamicStyle(${ref}, ${value});`;
992
+ case "attr":
993
+ used.add("setDynamicAttribute");
994
+ return `setDynamicAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
995
+ case "property":
996
+ used.add("setDynamicProperty");
997
+ return `setDynamicProperty(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
998
+ case "boolAttr":
999
+ used.add("setDynamicBoolAttribute");
1000
+ return `setDynamicBoolAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
1001
+ case "event":
1002
+ used.add("addDelegatedEventListener");
1003
+ return `addDelegatedEventListener(${ref}, ${JSON.stringify(prop.event.name)}, ${value});`;
1004
+ case "nativeEvent":
1005
+ used.add("addNativeEventListener");
1006
+ return `addNativeEventListener(${ref}, ${JSON.stringify(prop.name.slice(3))}, ${value});`;
1007
+ case "ref":
1008
+ used.add("handleRef");
1009
+ return `handleRef(${value}, ${ref});`;
1010
+ case "use":
1011
+ used.add("applyUse");
1012
+ return `applyUse(${ref}, ${value});`;
1013
+ }
1014
+ }
894
1015
  function staticAttrAssignment(el, prop) {
895
1016
  const name = htmlAttrName(prop.name);
896
1017
  const value = prop.literal;
@@ -941,6 +1062,7 @@ function emitNode(node, used, templates) {
941
1062
  `const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
942
1063
  ];
943
1064
  for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
1065
+ for (const binding of plan.bindings) lines.push(bindingStatement(binding, used));
944
1066
  for (const hole of plan.holes) {
945
1067
  lines.push(
946
1068
  `insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`
@@ -1,7 +1,7 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  encode
4
- } from "./chunk-FMQPBKTW.mjs";
4
+ } from "./chunk-JUFI6IR3.mjs";
5
5
 
6
6
  // ../../node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.mjs
7
7
  var BitSet = class _BitSet {
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/resolve/component-resolver.ts
4
4
  var isMapRule = (rule) => "components" in rule;
@@ -1,7 +1,7 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  encode
4
- } from "./chunk-FMQPBKTW.mjs";
4
+ } from "./chunk-JUFI6IR3.mjs";
5
5
 
6
6
  // src/transform/styles.ts
7
7
  var SCOPE_ATTR = "data-fx-s";
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/transform/server-fn-id.ts
4
4
  function hash(s) {
@@ -131,10 +131,64 @@ function isHole(node) {
131
131
  function isTemplateChild(node) {
132
132
  return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
133
133
  }
134
+ var PROPERTY_BINDS = /* @__PURE__ */ new Set(["indeterminate"]);
135
+ function disposition(prop) {
136
+ if (prop.kind === "spread") return null;
137
+ if (prop.name === "ref") return "ref";
138
+ if (prop.name === "use") return "use";
139
+ if (prop.kind === "event") return prop.event ? "event" : null;
140
+ if (prop.kind === "prop") return "property";
141
+ if (prop.kind !== "attr") return null;
142
+ const name = prop.name;
143
+ if (name.startsWith("on:")) return "nativeEvent";
144
+ if (name.startsWith("prop:")) return "property";
145
+ if (name.startsWith("attr:")) return "attr";
146
+ if (name.startsWith("bool:")) return "boolAttr";
147
+ if (name === "className" || name === "class") {
148
+ return isPlainLiteralAttr(prop) ? "serialize" : "class";
149
+ }
150
+ if (name === "classList") {
151
+ if (isPlainLiteralAttr(prop)) return "serialize";
152
+ return prop.reactive ? "classListDynamic" : "classList";
153
+ }
154
+ if (name === "style") {
155
+ if (isPlainLiteralAttr(prop)) return "serialize";
156
+ return prop.reactive ? "styleDynamic" : "style";
157
+ }
158
+ if (name.includes(":")) return null;
159
+ if (PROPERTY_ONLY.has(name)) return null;
160
+ if (PROPERTY_BINDS.has(name)) return "property";
161
+ if (prop.expr === void 0) return isPlainLiteralAttr(prop) ? "serialize" : null;
162
+ return "attr";
163
+ }
164
+ function effectiveProps(el) {
165
+ const order = [];
166
+ const byName = /* @__PURE__ */ new Map();
167
+ for (const prop of el.props) {
168
+ if (!byName.has(prop.name)) order.push(prop.name);
169
+ byName.set(prop.name, prop);
170
+ }
171
+ return order.map((name) => byName.get(name));
172
+ }
173
+ function propPlan(el) {
174
+ const custom = el.tag.includes("-");
175
+ const plan = { serialize: [], bindings: [] };
176
+ for (const prop of effectiveProps(el)) {
177
+ const kind = disposition(prop);
178
+ if (kind === null) return null;
179
+ if (kind === "serialize") {
180
+ plan.serialize.push(prop);
181
+ continue;
182
+ }
183
+ if (custom) return null;
184
+ plan.bindings.push({ prop, kind });
185
+ }
186
+ return plan;
187
+ }
134
188
  function isTemplateElement(node) {
135
189
  if (node.svg) return false;
136
190
  if (isRawTextElement(node.tag)) return false;
137
- if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
191
+ if (!propPlan(node)) return false;
138
192
  return node.children.every((c) => isTemplateChild(c) || isHole(c));
139
193
  }
140
194
  function containsHole(node) {
@@ -142,6 +196,15 @@ function containsHole(node) {
142
196
  const children = node.children;
143
197
  return children ? children.some(containsHole) : false;
144
198
  }
199
+ function containsBinding(node) {
200
+ if (node.kind !== "element") return false;
201
+ const plan = propPlan(node);
202
+ if (plan && plan.bindings.length > 0) return true;
203
+ return node.children.some(containsBinding);
204
+ }
205
+ function interesting(node) {
206
+ return containsHole(node) || containsBinding(node);
207
+ }
145
208
  function addressable(el) {
146
209
  for (let i = 0; i < el.children.length; i++) {
147
210
  const child = el.children[i];
@@ -155,9 +218,10 @@ function addressable(el) {
155
218
  function planPartialTemplate(root) {
156
219
  if (!isTemplateElement(root)) return null;
157
220
  if (!addressable(root)) return null;
158
- if (!root.children.some(containsHole)) return null;
221
+ if (!interesting(root)) return null;
159
222
  const steps = [];
160
223
  const holes = [];
224
+ const bindings = [];
161
225
  let refCount = 0;
162
226
  const declare = (expr) => {
163
227
  const ref = `_n$${refCount++}`;
@@ -165,11 +229,17 @@ function planPartialTemplate(root) {
165
229
  return ref;
166
230
  };
167
231
  walk(root, "_el$");
168
- return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
232
+ return { html: serializeWithMarkers(root), tag: root.tag, steps, holes, bindings };
169
233
  function walk(el, elementRef) {
234
+ const plan = propPlan(el);
235
+ if (plan) {
236
+ for (const binding of plan.bindings) {
237
+ bindings.push({ ref: elementRef, prop: binding.prop, kind: binding.kind });
238
+ }
239
+ }
170
240
  let last = -1;
171
241
  el.children.forEach((child, i) => {
172
- if (containsHole(child)) last = i;
242
+ if (interesting(child)) last = i;
173
243
  });
174
244
  let previous = null;
175
245
  for (let i = 0; i <= last; i++) {
@@ -183,19 +253,21 @@ function planPartialTemplate(root) {
183
253
  continue;
184
254
  }
185
255
  const ref = declare(expr);
186
- if (child.kind === "element" && containsHole(child)) walk(child, ref);
256
+ if (child.kind === "element" && interesting(child)) walk(child, ref);
187
257
  previous = ref;
188
258
  }
189
259
  }
190
260
  }
191
261
  function serializeWithMarkers(el) {
192
- return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
262
+ return serializeStatic(templateTree(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
193
263
  }
194
- function withSentinels(el) {
264
+ function templateTree(el) {
265
+ const plan = propPlan(el);
195
266
  return {
196
267
  ...el,
268
+ props: plan ? plan.serialize : [],
197
269
  children: el.children.map(
198
- (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
270
+ (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? templateTree(child) : child
199
271
  )
200
272
  };
201
273
  }
@@ -468,6 +540,55 @@ function emitComponent(name, props, children, used, templates, at) {
468
540
  const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
469
541
  return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
470
542
  }
543
+ function bindingTarget(binding) {
544
+ const name = binding.prop.name;
545
+ if (binding.kind === "boolAttr") return name.slice("bool:".length);
546
+ if (name.startsWith("prop:")) return name.slice("prop:".length);
547
+ if (name.startsWith("attr:")) return name.slice("attr:".length);
548
+ return htmlAttrName(name);
549
+ }
550
+ function bindingStatement(binding, used) {
551
+ const { ref, prop, kind } = binding;
552
+ const value = propValue(prop);
553
+ switch (kind) {
554
+ case "class":
555
+ used.add("setClassName");
556
+ return `setClassName(${ref}, ${value});`;
557
+ case "classList":
558
+ used.add("setClassList");
559
+ return `setClassList(${ref}, ${value}, []);`;
560
+ case "classListDynamic":
561
+ used.add("setDynamicClassList");
562
+ return `setDynamicClassList(${ref}, ${value});`;
563
+ case "style":
564
+ used.add("setStyle");
565
+ return `setStyle(${ref}, ${value}, []);`;
566
+ case "styleDynamic":
567
+ used.add("setDynamicStyle");
568
+ return `setDynamicStyle(${ref}, ${value});`;
569
+ case "attr":
570
+ used.add("setDynamicAttribute");
571
+ return `setDynamicAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
572
+ case "property":
573
+ used.add("setDynamicProperty");
574
+ return `setDynamicProperty(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
575
+ case "boolAttr":
576
+ used.add("setDynamicBoolAttribute");
577
+ return `setDynamicBoolAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
578
+ case "event":
579
+ used.add("addDelegatedEventListener");
580
+ return `addDelegatedEventListener(${ref}, ${JSON.stringify(prop.event.name)}, ${value});`;
581
+ case "nativeEvent":
582
+ used.add("addNativeEventListener");
583
+ return `addNativeEventListener(${ref}, ${JSON.stringify(prop.name.slice(3))}, ${value});`;
584
+ case "ref":
585
+ used.add("handleRef");
586
+ return `handleRef(${value}, ${ref});`;
587
+ case "use":
588
+ used.add("applyUse");
589
+ return `applyUse(${ref}, ${value});`;
590
+ }
591
+ }
471
592
  function staticAttrAssignment(el, prop) {
472
593
  const name = htmlAttrName(prop.name);
473
594
  const value = prop.literal;
@@ -518,6 +639,7 @@ function emitNode(node, used, templates) {
518
639
  `const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
519
640
  ];
520
641
  for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
642
+ for (const binding of plan.bindings) lines.push(bindingStatement(binding, used));
521
643
  for (const hole of plan.holes) {
522
644
  lines.push(
523
645
  `insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`
@@ -1 +1 @@
1
- {"version":3,"file":"imperative.d.ts","sourceRoot":"","sources":["../../../src/codegen/backends/imperative.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAiB,cAAc,EAAE,MAAM,eAAe,CAAC;AA0WnF;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,SAAS,GAAG,MAAM,CAK7F;AAED,eAAO,MAAM,iBAAiB,EAAE,cAgB/B,CAAC"}
1
+ {"version":3,"file":"imperative.d.ts","sourceRoot":"","sources":["../../../src/codegen/backends/imperative.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAiB,cAAc,EAAE,MAAM,eAAe,CAAC;AAsanF;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,SAAS,GAAG,MAAM,CAK7F;AAED,eAAO,MAAM,iBAAiB,EAAE,cAgB/B,CAAC"}