@fluixi/compiler 1.0.0-alpha.105 → 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-USPHNEJF.mjs → babel-HJY4RVAV.mjs} +33 -20
  4. package/dist/{chunk-OQYQ7UTD.mjs → chunk-4XEOMQ57.mjs} +1 -1
  5. package/dist/{chunk-EK4OMGTU.mjs → chunk-JUFI6IR3.mjs} +1 -1
  6. package/dist/{chunk-5GAYDAAC.mjs → chunk-LCQHL2VQ.mjs} +132 -10
  7. package/dist/{chunk-XBAQME2V.mjs → chunk-LGUZRHYN.mjs} +2 -2
  8. package/dist/{chunk-O6OBEV4V.mjs → chunk-TDN5MYWI.mjs} +1 -1
  9. package/dist/{chunk-EQIIWIEU.mjs → chunk-W7DYOMXJ.mjs} +2 -2
  10. package/dist/{chunk-FMIIK5UM.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-7Y25MR3B.mjs → server-fns-WZJK4BJE.mjs} +5 -5
  62. package/dist/{server-functions-43CFKXY3.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-YUDW7K4J.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.105 | (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 __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -957,10 +957,64 @@ function isHole(node) {
957
957
  function isTemplateChild(node) {
958
958
  return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
959
959
  }
960
+ var PROPERTY_BINDS = /* @__PURE__ */ new Set(["indeterminate"]);
961
+ function disposition(prop) {
962
+ if (prop.kind === "spread") return null;
963
+ if (prop.name === "ref") return "ref";
964
+ if (prop.name === "use") return "use";
965
+ if (prop.kind === "event") return prop.event ? "event" : null;
966
+ if (prop.kind === "prop") return "property";
967
+ if (prop.kind !== "attr") return null;
968
+ const name = prop.name;
969
+ if (name.startsWith("on:")) return "nativeEvent";
970
+ if (name.startsWith("prop:")) return "property";
971
+ if (name.startsWith("attr:")) return "attr";
972
+ if (name.startsWith("bool:")) return "boolAttr";
973
+ if (name === "className" || name === "class") {
974
+ return isPlainLiteralAttr(prop) ? "serialize" : "class";
975
+ }
976
+ if (name === "classList") {
977
+ if (isPlainLiteralAttr(prop)) return "serialize";
978
+ return prop.reactive ? "classListDynamic" : "classList";
979
+ }
980
+ if (name === "style") {
981
+ if (isPlainLiteralAttr(prop)) return "serialize";
982
+ return prop.reactive ? "styleDynamic" : "style";
983
+ }
984
+ if (name.includes(":")) return null;
985
+ if (PROPERTY_ONLY.has(name)) return null;
986
+ if (PROPERTY_BINDS.has(name)) return "property";
987
+ if (prop.expr === void 0) return isPlainLiteralAttr(prop) ? "serialize" : null;
988
+ return "attr";
989
+ }
990
+ function effectiveProps(el) {
991
+ const order = [];
992
+ const byName = /* @__PURE__ */ new Map();
993
+ for (const prop of el.props) {
994
+ if (!byName.has(prop.name)) order.push(prop.name);
995
+ byName.set(prop.name, prop);
996
+ }
997
+ return order.map((name) => byName.get(name));
998
+ }
999
+ function propPlan(el) {
1000
+ const custom = el.tag.includes("-");
1001
+ const plan = { serialize: [], bindings: [] };
1002
+ for (const prop of effectiveProps(el)) {
1003
+ const kind = disposition(prop);
1004
+ if (kind === null) return null;
1005
+ if (kind === "serialize") {
1006
+ plan.serialize.push(prop);
1007
+ continue;
1008
+ }
1009
+ if (custom) return null;
1010
+ plan.bindings.push({ prop, kind });
1011
+ }
1012
+ return plan;
1013
+ }
960
1014
  function isTemplateElement(node) {
961
1015
  if (node.svg) return false;
962
1016
  if (isRawTextElement(node.tag)) return false;
963
- if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
1017
+ if (!propPlan(node)) return false;
964
1018
  return node.children.every((c) => isTemplateChild(c) || isHole(c));
965
1019
  }
966
1020
  function containsHole(node) {
@@ -968,6 +1022,15 @@ function containsHole(node) {
968
1022
  const children = node.children;
969
1023
  return children ? children.some(containsHole) : false;
970
1024
  }
1025
+ function containsBinding(node) {
1026
+ if (node.kind !== "element") return false;
1027
+ const plan = propPlan(node);
1028
+ if (plan && plan.bindings.length > 0) return true;
1029
+ return node.children.some(containsBinding);
1030
+ }
1031
+ function interesting(node) {
1032
+ return containsHole(node) || containsBinding(node);
1033
+ }
971
1034
  function addressable(el) {
972
1035
  for (let i = 0; i < el.children.length; i++) {
973
1036
  const child = el.children[i];
@@ -981,9 +1044,10 @@ function addressable(el) {
981
1044
  function planPartialTemplate(root) {
982
1045
  if (!isTemplateElement(root)) return null;
983
1046
  if (!addressable(root)) return null;
984
- if (!root.children.some(containsHole)) return null;
1047
+ if (!interesting(root)) return null;
985
1048
  const steps = [];
986
1049
  const holes = [];
1050
+ const bindings = [];
987
1051
  let refCount = 0;
988
1052
  const declare = (expr) => {
989
1053
  const ref = `_n$${refCount++}`;
@@ -991,11 +1055,17 @@ function planPartialTemplate(root) {
991
1055
  return ref;
992
1056
  };
993
1057
  walk8(root, "_el$");
994
- return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
1058
+ return { html: serializeWithMarkers(root), tag: root.tag, steps, holes, bindings };
995
1059
  function walk8(el, elementRef) {
1060
+ const plan = propPlan(el);
1061
+ if (plan) {
1062
+ for (const binding of plan.bindings) {
1063
+ bindings.push({ ref: elementRef, prop: binding.prop, kind: binding.kind });
1064
+ }
1065
+ }
996
1066
  let last = -1;
997
1067
  el.children.forEach((child, i) => {
998
- if (containsHole(child)) last = i;
1068
+ if (interesting(child)) last = i;
999
1069
  });
1000
1070
  let previous = null;
1001
1071
  for (let i = 0; i <= last; i++) {
@@ -1009,19 +1079,21 @@ function planPartialTemplate(root) {
1009
1079
  continue;
1010
1080
  }
1011
1081
  const ref = declare(expr);
1012
- if (child.kind === "element" && containsHole(child)) walk8(child, ref);
1082
+ if (child.kind === "element" && interesting(child)) walk8(child, ref);
1013
1083
  previous = ref;
1014
1084
  }
1015
1085
  }
1016
1086
  }
1017
1087
  function serializeWithMarkers(el) {
1018
- return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
1088
+ return serializeStatic(templateTree(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
1019
1089
  }
1020
- function withSentinels(el) {
1090
+ function templateTree(el) {
1091
+ const plan = propPlan(el);
1021
1092
  return {
1022
1093
  ...el,
1094
+ props: plan ? plan.serialize : [],
1023
1095
  children: el.children.map(
1024
- (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
1096
+ (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? templateTree(child) : child
1025
1097
  )
1026
1098
  };
1027
1099
  }
@@ -1652,6 +1724,55 @@ function emitComponent(name, props, children, used, templates, at) {
1652
1724
  const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
1653
1725
  return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
1654
1726
  }
1727
+ function bindingTarget(binding) {
1728
+ const name = binding.prop.name;
1729
+ if (binding.kind === "boolAttr") return name.slice("bool:".length);
1730
+ if (name.startsWith("prop:")) return name.slice("prop:".length);
1731
+ if (name.startsWith("attr:")) return name.slice("attr:".length);
1732
+ return htmlAttrName(name);
1733
+ }
1734
+ function bindingStatement(binding, used) {
1735
+ const { ref, prop, kind } = binding;
1736
+ const value = propValue(prop);
1737
+ switch (kind) {
1738
+ case "class":
1739
+ used.add("setClassName");
1740
+ return `setClassName(${ref}, ${value});`;
1741
+ case "classList":
1742
+ used.add("setClassList");
1743
+ return `setClassList(${ref}, ${value}, []);`;
1744
+ case "classListDynamic":
1745
+ used.add("setDynamicClassList");
1746
+ return `setDynamicClassList(${ref}, ${value});`;
1747
+ case "style":
1748
+ used.add("setStyle");
1749
+ return `setStyle(${ref}, ${value}, []);`;
1750
+ case "styleDynamic":
1751
+ used.add("setDynamicStyle");
1752
+ return `setDynamicStyle(${ref}, ${value});`;
1753
+ case "attr":
1754
+ used.add("setDynamicAttribute");
1755
+ return `setDynamicAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
1756
+ case "property":
1757
+ used.add("setDynamicProperty");
1758
+ return `setDynamicProperty(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
1759
+ case "boolAttr":
1760
+ used.add("setDynamicBoolAttribute");
1761
+ return `setDynamicBoolAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
1762
+ case "event":
1763
+ used.add("addDelegatedEventListener");
1764
+ return `addDelegatedEventListener(${ref}, ${JSON.stringify(prop.event.name)}, ${value});`;
1765
+ case "nativeEvent":
1766
+ used.add("addNativeEventListener");
1767
+ return `addNativeEventListener(${ref}, ${JSON.stringify(prop.name.slice(3))}, ${value});`;
1768
+ case "ref":
1769
+ used.add("handleRef");
1770
+ return `handleRef(${value}, ${ref});`;
1771
+ case "use":
1772
+ used.add("applyUse");
1773
+ return `applyUse(${ref}, ${value});`;
1774
+ }
1775
+ }
1655
1776
  function staticAttrAssignment(el, prop) {
1656
1777
  const name = htmlAttrName(prop.name);
1657
1778
  const value = prop.literal;
@@ -1702,6 +1823,7 @@ function emitNode(node, used, templates) {
1702
1823
  `const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
1703
1824
  ];
1704
1825
  for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
1826
+ for (const binding of plan.bindings) lines.push(bindingStatement(binding, used));
1705
1827
  for (const hole of plan.holes) {
1706
1828
  lines.push(
1707
1829
  `insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`
@@ -3665,11 +3787,8 @@ function transformTemplates(code, id, options = {}) {
3665
3787
  const hoisted = /* @__PURE__ */ new Map();
3666
3788
  const edits = [...props.edits, ...intrinsics.edits, ...sources.edits, ...styles?.edits ?? []];
3667
3789
  for (const node of found) {
3668
- const nested = found.some(
3669
- (o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
3670
- );
3671
3790
  if (isJsx(node)) {
3672
- edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName, styles) });
3791
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, used, needs, hoisted, options, sourceName, styles) });
3673
3792
  continue;
3674
3793
  }
3675
3794
  const holes = node.quasi.expressions.map(
@@ -3696,7 +3815,7 @@ function transformTemplates(code, id, options = {}) {
3696
3815
  ...options.sourceLocations === true ? { sourceFile: sourceName, positionAt: positionsIn(code) } : {},
3697
3816
  // Same defaults as the plugin, so moving a build over is not a rendering change.
3698
3817
  templateClone: options.templateClone ?? true,
3699
- partialTemplates: nested ? false : options.partialTemplates ?? true,
3818
+ partialTemplates: options.partialTemplates ?? true,
3700
3819
  svg: templateTags.get(node.tag.name) === "svg"
3701
3820
  });
3702
3821
  for (const symbol of result.imports) used.add(symbol);
@@ -3768,7 +3887,7 @@ function transformTemplates(code, id, options = {}) {
3768
3887
  ...styles?.references.length ? { styleReferences: styles.references } : {}
3769
3888
  };
3770
3889
  }
3771
- function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile, styles) {
3890
+ function compileJsx(code, node, edits, used, needs, hoisted, options, sourceFile, styles) {
3772
3891
  const ir = buildJsxIR(node, {
3773
3892
  code: (n) => slice(code, n.start, n.end, edits),
3774
3893
  used,
@@ -3793,7 +3912,7 @@ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, so
3793
3912
  collapseStrategies(ir);
3794
3913
  const emitted = imperativeBackend.emit(ir, {
3795
3914
  templateClone: options.templateClone ?? true,
3796
- partialTemplates: nested ? false : options.partialTemplates ?? true
3915
+ partialTemplates: options.partialTemplates ?? true
3797
3916
  });
3798
3917
  for (const symbol of emitted.imports) used.add(symbol);
3799
3918
  collectNeeds(ir, needs);
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.105 | (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/templates.ts
4
4
  import { parse as parse2 } from "@babel/parser";
@@ -1993,10 +1993,64 @@ function isHole(node) {
1993
1993
  function isTemplateChild(node) {
1994
1994
  return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
1995
1995
  }
1996
+ var PROPERTY_BINDS = /* @__PURE__ */ new Set(["indeterminate"]);
1997
+ function disposition(prop) {
1998
+ if (prop.kind === "spread") return null;
1999
+ if (prop.name === "ref") return "ref";
2000
+ if (prop.name === "use") return "use";
2001
+ if (prop.kind === "event") return prop.event ? "event" : null;
2002
+ if (prop.kind === "prop") return "property";
2003
+ if (prop.kind !== "attr") return null;
2004
+ const name = prop.name;
2005
+ if (name.startsWith("on:")) return "nativeEvent";
2006
+ if (name.startsWith("prop:")) return "property";
2007
+ if (name.startsWith("attr:")) return "attr";
2008
+ if (name.startsWith("bool:")) return "boolAttr";
2009
+ if (name === "className" || name === "class") {
2010
+ return isPlainLiteralAttr(prop) ? "serialize" : "class";
2011
+ }
2012
+ if (name === "classList") {
2013
+ if (isPlainLiteralAttr(prop)) return "serialize";
2014
+ return prop.reactive ? "classListDynamic" : "classList";
2015
+ }
2016
+ if (name === "style") {
2017
+ if (isPlainLiteralAttr(prop)) return "serialize";
2018
+ return prop.reactive ? "styleDynamic" : "style";
2019
+ }
2020
+ if (name.includes(":")) return null;
2021
+ if (PROPERTY_ONLY.has(name)) return null;
2022
+ if (PROPERTY_BINDS.has(name)) return "property";
2023
+ if (prop.expr === void 0) return isPlainLiteralAttr(prop) ? "serialize" : null;
2024
+ return "attr";
2025
+ }
2026
+ function effectiveProps(el) {
2027
+ const order = [];
2028
+ const byName = /* @__PURE__ */ new Map();
2029
+ for (const prop of el.props) {
2030
+ if (!byName.has(prop.name)) order.push(prop.name);
2031
+ byName.set(prop.name, prop);
2032
+ }
2033
+ return order.map((name) => byName.get(name));
2034
+ }
2035
+ function propPlan(el) {
2036
+ const custom = el.tag.includes("-");
2037
+ const plan = { serialize: [], bindings: [] };
2038
+ for (const prop of effectiveProps(el)) {
2039
+ const kind = disposition(prop);
2040
+ if (kind === null) return null;
2041
+ if (kind === "serialize") {
2042
+ plan.serialize.push(prop);
2043
+ continue;
2044
+ }
2045
+ if (custom) return null;
2046
+ plan.bindings.push({ prop, kind });
2047
+ }
2048
+ return plan;
2049
+ }
1996
2050
  function isTemplateElement(node) {
1997
2051
  if (node.svg) return false;
1998
2052
  if (isRawTextElement(node.tag)) return false;
1999
- if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
2053
+ if (!propPlan(node)) return false;
2000
2054
  return node.children.every((c) => isTemplateChild(c) || isHole(c));
2001
2055
  }
2002
2056
  function containsHole(node) {
@@ -2004,6 +2058,15 @@ function containsHole(node) {
2004
2058
  const children = node.children;
2005
2059
  return children ? children.some(containsHole) : false;
2006
2060
  }
2061
+ function containsBinding(node) {
2062
+ if (node.kind !== "element") return false;
2063
+ const plan = propPlan(node);
2064
+ if (plan && plan.bindings.length > 0) return true;
2065
+ return node.children.some(containsBinding);
2066
+ }
2067
+ function interesting(node) {
2068
+ return containsHole(node) || containsBinding(node);
2069
+ }
2007
2070
  function addressable(el) {
2008
2071
  for (let i = 0; i < el.children.length; i++) {
2009
2072
  const child = el.children[i];
@@ -2017,9 +2080,10 @@ function addressable(el) {
2017
2080
  function planPartialTemplate(root) {
2018
2081
  if (!isTemplateElement(root)) return null;
2019
2082
  if (!addressable(root)) return null;
2020
- if (!root.children.some(containsHole)) return null;
2083
+ if (!interesting(root)) return null;
2021
2084
  const steps = [];
2022
2085
  const holes = [];
2086
+ const bindings = [];
2023
2087
  let refCount = 0;
2024
2088
  const declare = (expr) => {
2025
2089
  const ref = `_n$${refCount++}`;
@@ -2027,11 +2091,17 @@ function planPartialTemplate(root) {
2027
2091
  return ref;
2028
2092
  };
2029
2093
  walk8(root, "_el$");
2030
- return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
2094
+ return { html: serializeWithMarkers(root), tag: root.tag, steps, holes, bindings };
2031
2095
  function walk8(el, elementRef) {
2096
+ const plan = propPlan(el);
2097
+ if (plan) {
2098
+ for (const binding of plan.bindings) {
2099
+ bindings.push({ ref: elementRef, prop: binding.prop, kind: binding.kind });
2100
+ }
2101
+ }
2032
2102
  let last = -1;
2033
2103
  el.children.forEach((child, i) => {
2034
- if (containsHole(child)) last = i;
2104
+ if (interesting(child)) last = i;
2035
2105
  });
2036
2106
  let previous = null;
2037
2107
  for (let i = 0; i <= last; i++) {
@@ -2045,19 +2115,21 @@ function planPartialTemplate(root) {
2045
2115
  continue;
2046
2116
  }
2047
2117
  const ref = declare(expr);
2048
- if (child.kind === "element" && containsHole(child)) walk8(child, ref);
2118
+ if (child.kind === "element" && interesting(child)) walk8(child, ref);
2049
2119
  previous = ref;
2050
2120
  }
2051
2121
  }
2052
2122
  }
2053
2123
  function serializeWithMarkers(el) {
2054
- return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
2124
+ return serializeStatic(templateTree(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
2055
2125
  }
2056
- function withSentinels(el) {
2126
+ function templateTree(el) {
2127
+ const plan = propPlan(el);
2057
2128
  return {
2058
2129
  ...el,
2130
+ props: plan ? plan.serialize : [],
2059
2131
  children: el.children.map(
2060
- (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
2132
+ (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? templateTree(child) : child
2061
2133
  )
2062
2134
  };
2063
2135
  }
@@ -2688,6 +2760,55 @@ function emitComponent(name, props, children, used, templates, at) {
2688
2760
  const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
2689
2761
  return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
2690
2762
  }
2763
+ function bindingTarget(binding) {
2764
+ const name = binding.prop.name;
2765
+ if (binding.kind === "boolAttr") return name.slice("bool:".length);
2766
+ if (name.startsWith("prop:")) return name.slice("prop:".length);
2767
+ if (name.startsWith("attr:")) return name.slice("attr:".length);
2768
+ return htmlAttrName(name);
2769
+ }
2770
+ function bindingStatement(binding, used) {
2771
+ const { ref, prop, kind } = binding;
2772
+ const value = propValue(prop);
2773
+ switch (kind) {
2774
+ case "class":
2775
+ used.add("setClassName");
2776
+ return `setClassName(${ref}, ${value});`;
2777
+ case "classList":
2778
+ used.add("setClassList");
2779
+ return `setClassList(${ref}, ${value}, []);`;
2780
+ case "classListDynamic":
2781
+ used.add("setDynamicClassList");
2782
+ return `setDynamicClassList(${ref}, ${value});`;
2783
+ case "style":
2784
+ used.add("setStyle");
2785
+ return `setStyle(${ref}, ${value}, []);`;
2786
+ case "styleDynamic":
2787
+ used.add("setDynamicStyle");
2788
+ return `setDynamicStyle(${ref}, ${value});`;
2789
+ case "attr":
2790
+ used.add("setDynamicAttribute");
2791
+ return `setDynamicAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
2792
+ case "property":
2793
+ used.add("setDynamicProperty");
2794
+ return `setDynamicProperty(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
2795
+ case "boolAttr":
2796
+ used.add("setDynamicBoolAttribute");
2797
+ return `setDynamicBoolAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
2798
+ case "event":
2799
+ used.add("addDelegatedEventListener");
2800
+ return `addDelegatedEventListener(${ref}, ${JSON.stringify(prop.event.name)}, ${value});`;
2801
+ case "nativeEvent":
2802
+ used.add("addNativeEventListener");
2803
+ return `addNativeEventListener(${ref}, ${JSON.stringify(prop.name.slice(3))}, ${value});`;
2804
+ case "ref":
2805
+ used.add("handleRef");
2806
+ return `handleRef(${value}, ${ref});`;
2807
+ case "use":
2808
+ used.add("applyUse");
2809
+ return `applyUse(${ref}, ${value});`;
2810
+ }
2811
+ }
2691
2812
  function staticAttrAssignment(el, prop) {
2692
2813
  const name = htmlAttrName(prop.name);
2693
2814
  const value = prop.literal;
@@ -2738,6 +2859,7 @@ function emitNode(node, used, templates) {
2738
2859
  `const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
2739
2860
  ];
2740
2861
  for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
2862
+ for (const binding of plan.bindings) lines.push(bindingStatement(binding, used));
2741
2863
  for (const hole of plan.holes) {
2742
2864
  lines.push(
2743
2865
  `insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`
@@ -4702,11 +4824,8 @@ function transformTemplates(code, id, options = {}) {
4702
4824
  const hoisted = /* @__PURE__ */ new Map();
4703
4825
  const edits = [...props.edits, ...intrinsics.edits, ...sources.edits, ...styles?.edits ?? []];
4704
4826
  for (const node of found) {
4705
- const nested = found.some(
4706
- (o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
4707
- );
4708
4827
  if (isJsx(node)) {
4709
- edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName, styles) });
4828
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, used, needs, hoisted, options, sourceName, styles) });
4710
4829
  continue;
4711
4830
  }
4712
4831
  const holes = node.quasi.expressions.map(
@@ -4733,7 +4852,7 @@ function transformTemplates(code, id, options = {}) {
4733
4852
  ...options.sourceLocations === true ? { sourceFile: sourceName, positionAt: positionsIn(code) } : {},
4734
4853
  // Same defaults as the plugin, so moving a build over is not a rendering change.
4735
4854
  templateClone: options.templateClone ?? true,
4736
- partialTemplates: nested ? false : options.partialTemplates ?? true,
4855
+ partialTemplates: options.partialTemplates ?? true,
4737
4856
  svg: templateTags.get(node.tag.name) === "svg"
4738
4857
  });
4739
4858
  for (const symbol of result.imports) used.add(symbol);
@@ -4805,7 +4924,7 @@ function transformTemplates(code, id, options = {}) {
4805
4924
  ...styles?.references.length ? { styleReferences: styles.references } : {}
4806
4925
  };
4807
4926
  }
4808
- function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile, styles) {
4927
+ function compileJsx(code, node, edits, used, needs, hoisted, options, sourceFile, styles) {
4809
4928
  const ir = buildJsxIR(node, {
4810
4929
  code: (n2) => slice(code, n2.start, n2.end, edits),
4811
4930
  used,
@@ -4830,7 +4949,7 @@ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, so
4830
4949
  collapseStrategies(ir);
4831
4950
  const emitted = imperativeBackend.emit(ir, {
4832
4951
  templateClone: options.templateClone ?? true,
4833
- partialTemplates: nested ? false : options.partialTemplates ?? true
4952
+ partialTemplates: options.partialTemplates ?? true
4834
4953
  });
4835
4954
  for (const symbol of emitted.imports) used.add(symbol);
4836
4955
  collectNeeds(ir, needs);