@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
@@ -949,10 +949,64 @@ function isHole(node) {
949
949
  function isTemplateChild(node) {
950
950
  return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
951
951
  }
952
+ var PROPERTY_BINDS = /* @__PURE__ */ new Set(["indeterminate"]);
953
+ function disposition(prop) {
954
+ if (prop.kind === "spread") return null;
955
+ if (prop.name === "ref") return "ref";
956
+ if (prop.name === "use") return "use";
957
+ if (prop.kind === "event") return prop.event ? "event" : null;
958
+ if (prop.kind === "prop") return "property";
959
+ if (prop.kind !== "attr") return null;
960
+ const name = prop.name;
961
+ if (name.startsWith("on:")) return "nativeEvent";
962
+ if (name.startsWith("prop:")) return "property";
963
+ if (name.startsWith("attr:")) return "attr";
964
+ if (name.startsWith("bool:")) return "boolAttr";
965
+ if (name === "className" || name === "class") {
966
+ return isPlainLiteralAttr(prop) ? "serialize" : "class";
967
+ }
968
+ if (name === "classList") {
969
+ if (isPlainLiteralAttr(prop)) return "serialize";
970
+ return prop.reactive ? "classListDynamic" : "classList";
971
+ }
972
+ if (name === "style") {
973
+ if (isPlainLiteralAttr(prop)) return "serialize";
974
+ return prop.reactive ? "styleDynamic" : "style";
975
+ }
976
+ if (name.includes(":")) return null;
977
+ if (PROPERTY_ONLY.has(name)) return null;
978
+ if (PROPERTY_BINDS.has(name)) return "property";
979
+ if (prop.expr === void 0) return isPlainLiteralAttr(prop) ? "serialize" : null;
980
+ return "attr";
981
+ }
982
+ function effectiveProps(el) {
983
+ const order = [];
984
+ const byName = /* @__PURE__ */ new Map();
985
+ for (const prop of el.props) {
986
+ if (!byName.has(prop.name)) order.push(prop.name);
987
+ byName.set(prop.name, prop);
988
+ }
989
+ return order.map((name) => byName.get(name));
990
+ }
991
+ function propPlan(el) {
992
+ const custom = el.tag.includes("-");
993
+ const plan = { serialize: [], bindings: [] };
994
+ for (const prop of effectiveProps(el)) {
995
+ const kind = disposition(prop);
996
+ if (kind === null) return null;
997
+ if (kind === "serialize") {
998
+ plan.serialize.push(prop);
999
+ continue;
1000
+ }
1001
+ if (custom) return null;
1002
+ plan.bindings.push({ prop, kind });
1003
+ }
1004
+ return plan;
1005
+ }
952
1006
  function isTemplateElement(node) {
953
1007
  if (node.svg) return false;
954
1008
  if (isRawTextElement(node.tag)) return false;
955
- if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
1009
+ if (!propPlan(node)) return false;
956
1010
  return node.children.every((c) => isTemplateChild(c) || isHole(c));
957
1011
  }
958
1012
  function containsHole(node) {
@@ -960,6 +1014,15 @@ function containsHole(node) {
960
1014
  const children = node.children;
961
1015
  return children ? children.some(containsHole) : false;
962
1016
  }
1017
+ function containsBinding(node) {
1018
+ if (node.kind !== "element") return false;
1019
+ const plan = propPlan(node);
1020
+ if (plan && plan.bindings.length > 0) return true;
1021
+ return node.children.some(containsBinding);
1022
+ }
1023
+ function interesting(node) {
1024
+ return containsHole(node) || containsBinding(node);
1025
+ }
963
1026
  function addressable(el) {
964
1027
  for (let i = 0; i < el.children.length; i++) {
965
1028
  const child = el.children[i];
@@ -973,9 +1036,10 @@ function addressable(el) {
973
1036
  function planPartialTemplate(root) {
974
1037
  if (!isTemplateElement(root)) return null;
975
1038
  if (!addressable(root)) return null;
976
- if (!root.children.some(containsHole)) return null;
1039
+ if (!interesting(root)) return null;
977
1040
  const steps = [];
978
1041
  const holes = [];
1042
+ const bindings = [];
979
1043
  let refCount = 0;
980
1044
  const declare = (expr) => {
981
1045
  const ref = `_n$${refCount++}`;
@@ -983,11 +1047,17 @@ function planPartialTemplate(root) {
983
1047
  return ref;
984
1048
  };
985
1049
  walk8(root, "_el$");
986
- return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
1050
+ return { html: serializeWithMarkers(root), tag: root.tag, steps, holes, bindings };
987
1051
  function walk8(el, elementRef) {
1052
+ const plan = propPlan(el);
1053
+ if (plan) {
1054
+ for (const binding of plan.bindings) {
1055
+ bindings.push({ ref: elementRef, prop: binding.prop, kind: binding.kind });
1056
+ }
1057
+ }
988
1058
  let last = -1;
989
1059
  el.children.forEach((child, i) => {
990
- if (containsHole(child)) last = i;
1060
+ if (interesting(child)) last = i;
991
1061
  });
992
1062
  let previous = null;
993
1063
  for (let i = 0; i <= last; i++) {
@@ -1001,19 +1071,21 @@ function planPartialTemplate(root) {
1001
1071
  continue;
1002
1072
  }
1003
1073
  const ref = declare(expr);
1004
- if (child.kind === "element" && containsHole(child)) walk8(child, ref);
1074
+ if (child.kind === "element" && interesting(child)) walk8(child, ref);
1005
1075
  previous = ref;
1006
1076
  }
1007
1077
  }
1008
1078
  }
1009
1079
  function serializeWithMarkers(el) {
1010
- return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
1080
+ return serializeStatic(templateTree(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
1011
1081
  }
1012
- function withSentinels(el) {
1082
+ function templateTree(el) {
1083
+ const plan = propPlan(el);
1013
1084
  return {
1014
1085
  ...el,
1086
+ props: plan ? plan.serialize : [],
1015
1087
  children: el.children.map(
1016
- (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
1088
+ (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? templateTree(child) : child
1017
1089
  )
1018
1090
  };
1019
1091
  }
@@ -1644,6 +1716,55 @@ function emitComponent(name, props, children, used, templates, at) {
1644
1716
  const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
1645
1717
  return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
1646
1718
  }
1719
+ function bindingTarget(binding) {
1720
+ const name = binding.prop.name;
1721
+ if (binding.kind === "boolAttr") return name.slice("bool:".length);
1722
+ if (name.startsWith("prop:")) return name.slice("prop:".length);
1723
+ if (name.startsWith("attr:")) return name.slice("attr:".length);
1724
+ return htmlAttrName(name);
1725
+ }
1726
+ function bindingStatement(binding, used) {
1727
+ const { ref, prop, kind } = binding;
1728
+ const value = propValue(prop);
1729
+ switch (kind) {
1730
+ case "class":
1731
+ used.add("setClassName");
1732
+ return `setClassName(${ref}, ${value});`;
1733
+ case "classList":
1734
+ used.add("setClassList");
1735
+ return `setClassList(${ref}, ${value}, []);`;
1736
+ case "classListDynamic":
1737
+ used.add("setDynamicClassList");
1738
+ return `setDynamicClassList(${ref}, ${value});`;
1739
+ case "style":
1740
+ used.add("setStyle");
1741
+ return `setStyle(${ref}, ${value}, []);`;
1742
+ case "styleDynamic":
1743
+ used.add("setDynamicStyle");
1744
+ return `setDynamicStyle(${ref}, ${value});`;
1745
+ case "attr":
1746
+ used.add("setDynamicAttribute");
1747
+ return `setDynamicAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
1748
+ case "property":
1749
+ used.add("setDynamicProperty");
1750
+ return `setDynamicProperty(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
1751
+ case "boolAttr":
1752
+ used.add("setDynamicBoolAttribute");
1753
+ return `setDynamicBoolAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
1754
+ case "event":
1755
+ used.add("addDelegatedEventListener");
1756
+ return `addDelegatedEventListener(${ref}, ${JSON.stringify(prop.event.name)}, ${value});`;
1757
+ case "nativeEvent":
1758
+ used.add("addNativeEventListener");
1759
+ return `addNativeEventListener(${ref}, ${JSON.stringify(prop.name.slice(3))}, ${value});`;
1760
+ case "ref":
1761
+ used.add("handleRef");
1762
+ return `handleRef(${value}, ${ref});`;
1763
+ case "use":
1764
+ used.add("applyUse");
1765
+ return `applyUse(${ref}, ${value});`;
1766
+ }
1767
+ }
1647
1768
  function staticAttrAssignment(el, prop) {
1648
1769
  const name = htmlAttrName(prop.name);
1649
1770
  const value = prop.literal;
@@ -1694,6 +1815,7 @@ function emitNode(node, used, templates) {
1694
1815
  `const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
1695
1816
  ];
1696
1817
  for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
1818
+ for (const binding of plan.bindings) lines.push(bindingStatement(binding, used));
1697
1819
  for (const hole of plan.holes) {
1698
1820
  lines.push(
1699
1821
  `insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`
@@ -3634,11 +3756,8 @@ function transformTemplates(code, id, options = {}) {
3634
3756
  const hoisted = /* @__PURE__ */ new Map();
3635
3757
  const edits = [...props.edits, ...intrinsics.edits, ...sources.edits, ...styles?.edits ?? []];
3636
3758
  for (const node of found) {
3637
- const nested = found.some(
3638
- (o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
3639
- );
3640
3759
  if (isJsx(node)) {
3641
- edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName, styles) });
3760
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, used, needs, hoisted, options, sourceName, styles) });
3642
3761
  continue;
3643
3762
  }
3644
3763
  const holes = node.quasi.expressions.map(
@@ -3665,7 +3784,7 @@ function transformTemplates(code, id, options = {}) {
3665
3784
  ...options.sourceLocations === true ? { sourceFile: sourceName, positionAt: positionsIn(code) } : {},
3666
3785
  // Same defaults as the plugin, so moving a build over is not a rendering change.
3667
3786
  templateClone: options.templateClone ?? true,
3668
- partialTemplates: nested ? false : options.partialTemplates ?? true,
3787
+ partialTemplates: options.partialTemplates ?? true,
3669
3788
  svg: templateTags.get(node.tag.name) === "svg"
3670
3789
  });
3671
3790
  for (const symbol of result.imports) used.add(symbol);
@@ -3737,7 +3856,7 @@ function transformTemplates(code, id, options = {}) {
3737
3856
  ...styles?.references.length ? { styleReferences: styles.references } : {}
3738
3857
  };
3739
3858
  }
3740
- function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile, styles) {
3859
+ function compileJsx(code, node, edits, used, needs, hoisted, options, sourceFile, styles) {
3741
3860
  const ir = buildJsxIR(node, {
3742
3861
  code: (n) => slice(code, n.start, n.end, edits),
3743
3862
  used,
@@ -3762,7 +3881,7 @@ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, so
3762
3881
  collapseStrategies(ir);
3763
3882
  const emitted = imperativeBackend.emit(ir, {
3764
3883
  templateClone: options.templateClone ?? true,
3765
- partialTemplates: nested ? false : options.partialTemplates ?? true
3884
+ partialTemplates: options.partialTemplates ?? true
3766
3885
  });
3767
3886
  for (const symbol of emitted.imports) used.add(symbol);
3768
3887
  collectNeeds(ir, needs);
@@ -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,EAAgE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEzH,OAAO,EAAqC,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAkB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAmBrL,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D;;;;OAIG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,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;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;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;IAC/C,+FAA+F;IAC/F,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,6FAA6F;IAC7F,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,8EAA8E;IAC9E,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;CACpC;AAoTD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,gBAAqB,GAC7B,eAAe,GAAG,IAAI,CAuPxB"}
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;AAEzH,OAAO,EAAqC,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAkB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAmBrL,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D;;;;OAIG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,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;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;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;IAC/C,+FAA+F;IAC/F,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,6FAA6F;IAC7F,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,8EAA8E;IAC9E,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;CACpC;AAoTD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,gBAAqB,GAC7B,eAAe,GAAG,IAAI,CAiPxB"}
@@ -377,12 +377,8 @@ export function transformTemplates(code, id, options = {}) {
377
377
  const hoisted = new Map();
378
378
  const edits = [...props.edits, ...intrinsics.edits, ...sources.edits, ...(styles?.edits ?? [])];
379
379
  for (const node of found) {
380
- // A root inside another root's hole is emitted without partial templates,
381
- // matching what the plugin does for nested emits. Marker layout has to agree
382
- // between server and client, so this is not the place to change it.
383
- const nested = found.some((o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start);
384
380
  if (isJsx(node)) {
385
- edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName, styles) });
381
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, used, needs, hoisted, options, sourceName, styles) });
386
382
  continue;
387
383
  }
388
384
  const holes = node.quasi.expressions.map((e) => bindHole(code, e, edits, options.sourceLocations === true));
@@ -411,7 +407,7 @@ export function transformTemplates(code, id, options = {}) {
411
407
  : {}),
412
408
  // Same defaults as the plugin, so moving a build over is not a rendering change.
413
409
  templateClone: options.templateClone ?? true,
414
- partialTemplates: nested ? false : options.partialTemplates ?? true,
410
+ partialTemplates: options.partialTemplates ?? true,
415
411
  svg: templateTags.get(node.tag.name) === 'svg',
416
412
  });
417
413
  for (const symbol of result.imports)
@@ -518,7 +514,7 @@ export function transformTemplates(code, id, options = {}) {
518
514
  * with anything already compiled inside them folded in, so nested JSX and nested
519
515
  * `` html`` `` both come along for free.
520
516
  */
521
- function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile, styles) {
517
+ function compileJsx(code, node, edits, used, needs, hoisted, options, sourceFile, styles) {
522
518
  const ir = buildJsxIR(node, {
523
519
  code: (n) => slice(code, n.start, n.end, edits),
524
520
  used,
@@ -544,7 +540,7 @@ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, so
544
540
  collapseStrategies(ir);
545
541
  const emitted = imperativeBackend.emit(ir, {
546
542
  templateClone: options.templateClone ?? true,
547
- partialTemplates: nested ? false : options.partialTemplates ?? true,
543
+ partialTemplates: options.partialTemplates ?? true,
548
544
  });
549
545
  for (const symbol of emitted.imports)
550
546
  used.add(symbol);
@@ -1991,10 +1991,64 @@ function isHole(node) {
1991
1991
  function isTemplateChild(node) {
1992
1992
  return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
1993
1993
  }
1994
+ var PROPERTY_BINDS = /* @__PURE__ */ new Set(["indeterminate"]);
1995
+ function disposition(prop) {
1996
+ if (prop.kind === "spread") return null;
1997
+ if (prop.name === "ref") return "ref";
1998
+ if (prop.name === "use") return "use";
1999
+ if (prop.kind === "event") return prop.event ? "event" : null;
2000
+ if (prop.kind === "prop") return "property";
2001
+ if (prop.kind !== "attr") return null;
2002
+ const name = prop.name;
2003
+ if (name.startsWith("on:")) return "nativeEvent";
2004
+ if (name.startsWith("prop:")) return "property";
2005
+ if (name.startsWith("attr:")) return "attr";
2006
+ if (name.startsWith("bool:")) return "boolAttr";
2007
+ if (name === "className" || name === "class") {
2008
+ return isPlainLiteralAttr(prop) ? "serialize" : "class";
2009
+ }
2010
+ if (name === "classList") {
2011
+ if (isPlainLiteralAttr(prop)) return "serialize";
2012
+ return prop.reactive ? "classListDynamic" : "classList";
2013
+ }
2014
+ if (name === "style") {
2015
+ if (isPlainLiteralAttr(prop)) return "serialize";
2016
+ return prop.reactive ? "styleDynamic" : "style";
2017
+ }
2018
+ if (name.includes(":")) return null;
2019
+ if (PROPERTY_ONLY.has(name)) return null;
2020
+ if (PROPERTY_BINDS.has(name)) return "property";
2021
+ if (prop.expr === void 0) return isPlainLiteralAttr(prop) ? "serialize" : null;
2022
+ return "attr";
2023
+ }
2024
+ function effectiveProps(el) {
2025
+ const order = [];
2026
+ const byName = /* @__PURE__ */ new Map();
2027
+ for (const prop of el.props) {
2028
+ if (!byName.has(prop.name)) order.push(prop.name);
2029
+ byName.set(prop.name, prop);
2030
+ }
2031
+ return order.map((name) => byName.get(name));
2032
+ }
2033
+ function propPlan(el) {
2034
+ const custom = el.tag.includes("-");
2035
+ const plan = { serialize: [], bindings: [] };
2036
+ for (const prop of effectiveProps(el)) {
2037
+ const kind = disposition(prop);
2038
+ if (kind === null) return null;
2039
+ if (kind === "serialize") {
2040
+ plan.serialize.push(prop);
2041
+ continue;
2042
+ }
2043
+ if (custom) return null;
2044
+ plan.bindings.push({ prop, kind });
2045
+ }
2046
+ return plan;
2047
+ }
1994
2048
  function isTemplateElement(node) {
1995
2049
  if (node.svg) return false;
1996
2050
  if (isRawTextElement(node.tag)) return false;
1997
- if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
2051
+ if (!propPlan(node)) return false;
1998
2052
  return node.children.every((c) => isTemplateChild(c) || isHole(c));
1999
2053
  }
2000
2054
  function containsHole(node) {
@@ -2002,6 +2056,15 @@ function containsHole(node) {
2002
2056
  const children = node.children;
2003
2057
  return children ? children.some(containsHole) : false;
2004
2058
  }
2059
+ function containsBinding(node) {
2060
+ if (node.kind !== "element") return false;
2061
+ const plan = propPlan(node);
2062
+ if (plan && plan.bindings.length > 0) return true;
2063
+ return node.children.some(containsBinding);
2064
+ }
2065
+ function interesting(node) {
2066
+ return containsHole(node) || containsBinding(node);
2067
+ }
2005
2068
  function addressable(el) {
2006
2069
  for (let i = 0; i < el.children.length; i++) {
2007
2070
  const child = el.children[i];
@@ -2015,9 +2078,10 @@ function addressable(el) {
2015
2078
  function planPartialTemplate(root) {
2016
2079
  if (!isTemplateElement(root)) return null;
2017
2080
  if (!addressable(root)) return null;
2018
- if (!root.children.some(containsHole)) return null;
2081
+ if (!interesting(root)) return null;
2019
2082
  const steps = [];
2020
2083
  const holes = [];
2084
+ const bindings = [];
2021
2085
  let refCount = 0;
2022
2086
  const declare = (expr) => {
2023
2087
  const ref = `_n$${refCount++}`;
@@ -2025,11 +2089,17 @@ function planPartialTemplate(root) {
2025
2089
  return ref;
2026
2090
  };
2027
2091
  walk8(root, "_el$");
2028
- return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
2092
+ return { html: serializeWithMarkers(root), tag: root.tag, steps, holes, bindings };
2029
2093
  function walk8(el, elementRef) {
2094
+ const plan = propPlan(el);
2095
+ if (plan) {
2096
+ for (const binding of plan.bindings) {
2097
+ bindings.push({ ref: elementRef, prop: binding.prop, kind: binding.kind });
2098
+ }
2099
+ }
2030
2100
  let last = -1;
2031
2101
  el.children.forEach((child, i) => {
2032
- if (containsHole(child)) last = i;
2102
+ if (interesting(child)) last = i;
2033
2103
  });
2034
2104
  let previous = null;
2035
2105
  for (let i = 0; i <= last; i++) {
@@ -2043,19 +2113,21 @@ function planPartialTemplate(root) {
2043
2113
  continue;
2044
2114
  }
2045
2115
  const ref = declare(expr);
2046
- if (child.kind === "element" && containsHole(child)) walk8(child, ref);
2116
+ if (child.kind === "element" && interesting(child)) walk8(child, ref);
2047
2117
  previous = ref;
2048
2118
  }
2049
2119
  }
2050
2120
  }
2051
2121
  function serializeWithMarkers(el) {
2052
- return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
2122
+ return serializeStatic(templateTree(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
2053
2123
  }
2054
- function withSentinels(el) {
2124
+ function templateTree(el) {
2125
+ const plan = propPlan(el);
2055
2126
  return {
2056
2127
  ...el,
2128
+ props: plan ? plan.serialize : [],
2057
2129
  children: el.children.map(
2058
- (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
2130
+ (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? templateTree(child) : child
2059
2131
  )
2060
2132
  };
2061
2133
  }
@@ -2686,6 +2758,55 @@ function emitComponent(name, props, children, used, templates, at) {
2686
2758
  const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
2687
2759
  return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
2688
2760
  }
2761
+ function bindingTarget(binding) {
2762
+ const name = binding.prop.name;
2763
+ if (binding.kind === "boolAttr") return name.slice("bool:".length);
2764
+ if (name.startsWith("prop:")) return name.slice("prop:".length);
2765
+ if (name.startsWith("attr:")) return name.slice("attr:".length);
2766
+ return htmlAttrName(name);
2767
+ }
2768
+ function bindingStatement(binding, used) {
2769
+ const { ref, prop, kind } = binding;
2770
+ const value = propValue(prop);
2771
+ switch (kind) {
2772
+ case "class":
2773
+ used.add("setClassName");
2774
+ return `setClassName(${ref}, ${value});`;
2775
+ case "classList":
2776
+ used.add("setClassList");
2777
+ return `setClassList(${ref}, ${value}, []);`;
2778
+ case "classListDynamic":
2779
+ used.add("setDynamicClassList");
2780
+ return `setDynamicClassList(${ref}, ${value});`;
2781
+ case "style":
2782
+ used.add("setStyle");
2783
+ return `setStyle(${ref}, ${value}, []);`;
2784
+ case "styleDynamic":
2785
+ used.add("setDynamicStyle");
2786
+ return `setDynamicStyle(${ref}, ${value});`;
2787
+ case "attr":
2788
+ used.add("setDynamicAttribute");
2789
+ return `setDynamicAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
2790
+ case "property":
2791
+ used.add("setDynamicProperty");
2792
+ return `setDynamicProperty(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
2793
+ case "boolAttr":
2794
+ used.add("setDynamicBoolAttribute");
2795
+ return `setDynamicBoolAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
2796
+ case "event":
2797
+ used.add("addDelegatedEventListener");
2798
+ return `addDelegatedEventListener(${ref}, ${JSON.stringify(prop.event.name)}, ${value});`;
2799
+ case "nativeEvent":
2800
+ used.add("addNativeEventListener");
2801
+ return `addNativeEventListener(${ref}, ${JSON.stringify(prop.name.slice(3))}, ${value});`;
2802
+ case "ref":
2803
+ used.add("handleRef");
2804
+ return `handleRef(${value}, ${ref});`;
2805
+ case "use":
2806
+ used.add("applyUse");
2807
+ return `applyUse(${ref}, ${value});`;
2808
+ }
2809
+ }
2689
2810
  function staticAttrAssignment(el, prop) {
2690
2811
  const name = htmlAttrName(prop.name);
2691
2812
  const value = prop.literal;
@@ -2736,6 +2857,7 @@ function emitNode(node, used, templates) {
2736
2857
  `const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
2737
2858
  ];
2738
2859
  for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
2860
+ for (const binding of plan.bindings) lines.push(bindingStatement(binding, used));
2739
2861
  for (const hole of plan.holes) {
2740
2862
  lines.push(
2741
2863
  `insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`
@@ -4677,11 +4799,8 @@ function transformTemplates(code, id, options = {}) {
4677
4799
  const hoisted = /* @__PURE__ */ new Map();
4678
4800
  const edits = [...props.edits, ...intrinsics.edits, ...sources.edits, ...styles?.edits ?? []];
4679
4801
  for (const node of found) {
4680
- const nested = found.some(
4681
- (o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
4682
- );
4683
4802
  if (isJsx(node)) {
4684
- edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName, styles) });
4803
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, used, needs, hoisted, options, sourceName, styles) });
4685
4804
  continue;
4686
4805
  }
4687
4806
  const holes = node.quasi.expressions.map(
@@ -4708,7 +4827,7 @@ function transformTemplates(code, id, options = {}) {
4708
4827
  ...options.sourceLocations === true ? { sourceFile: sourceName, positionAt: positionsIn(code) } : {},
4709
4828
  // Same defaults as the plugin, so moving a build over is not a rendering change.
4710
4829
  templateClone: options.templateClone ?? true,
4711
- partialTemplates: nested ? false : options.partialTemplates ?? true,
4830
+ partialTemplates: options.partialTemplates ?? true,
4712
4831
  svg: templateTags.get(node.tag.name) === "svg"
4713
4832
  });
4714
4833
  for (const symbol of result.imports) used.add(symbol);
@@ -4780,7 +4899,7 @@ function transformTemplates(code, id, options = {}) {
4780
4899
  ...styles?.references.length ? { styleReferences: styles.references } : {}
4781
4900
  };
4782
4901
  }
4783
- function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile, styles) {
4902
+ function compileJsx(code, node, edits, used, needs, hoisted, options, sourceFile, styles) {
4784
4903
  const ir = buildJsxIR(node, {
4785
4904
  code: (n2) => slice(code, n2.start, n2.end, edits),
4786
4905
  used,
@@ -4805,7 +4924,7 @@ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, so
4805
4924
  collapseStrategies(ir);
4806
4925
  const emitted = imperativeBackend.emit(ir, {
4807
4926
  templateClone: options.templateClone ?? true,
4808
- partialTemplates: nested ? false : options.partialTemplates ?? true
4927
+ partialTemplates: options.partialTemplates ?? true
4809
4928
  });
4810
4929
  for (const symbol of emitted.imports) used.add(symbol);
4811
4930
  collectNeeds(ir, needs);
@@ -1,9 +1,9 @@
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
  applyTemplateStyles,
4
4
  collectStyles,
5
5
  finishShadowStyles
6
- } from "./chunk-ZDZKJQ5N.mjs";
6
+ } from "./chunk-W7DYOMXJ.mjs";
7
7
  import {
8
8
  analyzeStatic,
9
9
  buildJsxIR,
@@ -19,7 +19,7 @@ import {
19
19
  resolveComponentSources,
20
20
  resolveReactiveBindings,
21
21
  shapeOf
22
- } from "./chunk-NUET3BJB.mjs";
22
+ } from "./chunk-LCQHL2VQ.mjs";
23
23
  import {
24
24
  CORE_CONTROL_FLOW,
25
25
  DOM_CONTROL_FLOW,
@@ -29,12 +29,12 @@ import {
29
29
  isIntrinsicName,
30
30
  mayHaveIntrinsic,
31
31
  tagIntrinsics
32
- } from "./chunk-RBIYCE6M.mjs";
32
+ } from "./chunk-TDN5MYWI.mjs";
33
33
  import {
34
34
  MagicString
35
- } from "./chunk-2O2YW5ZO.mjs";
36
- import "./chunk-FMQPBKTW.mjs";
37
- import "./chunk-NWF66YTU.mjs";
35
+ } from "./chunk-LGUZRHYN.mjs";
36
+ import "./chunk-JUFI6IR3.mjs";
37
+ import "./chunk-4XEOMQ57.mjs";
38
38
 
39
39
  // src/transform/templates.ts
40
40
  import { parse as parse2 } from "@babel/parser";
@@ -767,11 +767,8 @@ function transformTemplates(code, id, options = {}) {
767
767
  const hoisted = /* @__PURE__ */ new Map();
768
768
  const edits = [...props.edits, ...intrinsics.edits, ...sources.edits, ...styles?.edits ?? []];
769
769
  for (const node of found) {
770
- const nested = found.some(
771
- (o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
772
- );
773
770
  if (isJsx(node)) {
774
- edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName, styles) });
771
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, used, needs, hoisted, options, sourceName, styles) });
775
772
  continue;
776
773
  }
777
774
  const holes = node.quasi.expressions.map(
@@ -798,7 +795,7 @@ function transformTemplates(code, id, options = {}) {
798
795
  ...options.sourceLocations === true ? { sourceFile: sourceName, positionAt: positionsIn(code) } : {},
799
796
  // Same defaults as the plugin, so moving a build over is not a rendering change.
800
797
  templateClone: options.templateClone ?? true,
801
- partialTemplates: nested ? false : options.partialTemplates ?? true,
798
+ partialTemplates: options.partialTemplates ?? true,
802
799
  svg: templateTags.get(node.tag.name) === "svg"
803
800
  });
804
801
  for (const symbol of result.imports) used.add(symbol);
@@ -870,7 +867,7 @@ function transformTemplates(code, id, options = {}) {
870
867
  ...styles?.references.length ? { styleReferences: styles.references } : {}
871
868
  };
872
869
  }
873
- function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile, styles) {
870
+ function compileJsx(code, node, edits, used, needs, hoisted, options, sourceFile, styles) {
874
871
  const ir = buildJsxIR(node, {
875
872
  code: (n) => slice(code, n.start, n.end, edits),
876
873
  used,
@@ -895,7 +892,7 @@ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, so
895
892
  collapseStrategies(ir);
896
893
  const emitted = imperativeBackend.emit(ir, {
897
894
  templateClone: options.templateClone ?? true,
898
- partialTemplates: nested ? false : options.partialTemplates ?? true
895
+ partialTemplates: options.partialTemplates ?? true
899
896
  });
900
897
  for (const symbol of emitted.imports) used.add(symbol);
901
898
  collectNeeds(ir, needs);