@fluixi/compiler 1.0.0-alpha.92 → 1.0.0-alpha.94

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 (102) hide show
  1. package/dist/analyze/intrinsics.cjs +31 -1
  2. package/dist/analyze/intrinsics.d.cts +14 -0
  3. package/dist/analyze/intrinsics.d.ts +14 -0
  4. package/dist/analyze/intrinsics.d.ts.map +1 -1
  5. package/dist/analyze/intrinsics.js +35 -0
  6. package/dist/analyze/intrinsics.mjs +31 -1
  7. package/dist/analyze/reactive-bindings.cjs +18 -0
  8. package/dist/analyze/reactive-bindings.mjs +18 -0
  9. package/dist/analyze/static-graph.cjs +22 -4
  10. package/dist/analyze/static-graph.d.ts.map +1 -1
  11. package/dist/analyze/static-graph.js +6 -4
  12. package/dist/analyze/static-graph.mjs +22 -4
  13. package/dist/{babel-GI375YZ2.mjs → babel-RJFQVFJW.mjs} +4 -4
  14. package/dist/{chunk-QZ4CJPYP.mjs → chunk-DP2QDWWH.mjs} +1 -1
  15. package/dist/{chunk-DWNWN5RH.mjs → chunk-E2RWTIYE.mjs} +21 -15
  16. package/dist/{chunk-XJ5H2MXY.mjs → chunk-HCCBEJEZ.mjs} +31 -1
  17. package/dist/{chunk-VOUI6XPV.mjs → chunk-HIZU7WI2.mjs} +1 -1
  18. package/dist/{chunk-VC6X44FS.mjs → chunk-ZR2QHTEX.mjs} +505 -68
  19. package/dist/codegen/backends/imperative.cjs +24 -6
  20. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  21. package/dist/codegen/backends/imperative.js +20 -4
  22. package/dist/codegen/backends/imperative.mjs +24 -6
  23. package/dist/frontend/babel/build-ir-lit.cjs +470 -63
  24. package/dist/frontend/babel/build-ir-lit.mjs +470 -63
  25. package/dist/frontend/babel/build-ir.cjs +470 -63
  26. package/dist/frontend/babel/build-ir.mjs +470 -63
  27. package/dist/frontend/babel/index.cjs +471 -64
  28. package/dist/frontend/babel/index.mjs +471 -64
  29. package/dist/frontend/babel/lower-template.cjs +470 -63
  30. package/dist/frontend/babel/lower-template.mjs +470 -63
  31. package/dist/frontend/babel/plugin.cjs +470 -63
  32. package/dist/frontend/babel/plugin.mjs +470 -63
  33. package/dist/index.cjs +360 -58
  34. package/dist/index.mjs +372 -58
  35. package/dist/integrations.cjs +1347 -98
  36. package/dist/integrations.d.ts.map +1 -1
  37. package/dist/integrations.js +44 -2
  38. package/dist/integrations.mjs +205 -19
  39. package/dist/lower/compile-template.cjs +354 -57
  40. package/dist/lower/compile-template.d.cts +13 -0
  41. package/dist/lower/compile-template.d.ts +13 -0
  42. package/dist/lower/compile-template.d.ts.map +1 -1
  43. package/dist/lower/compile-template.js +3 -0
  44. package/dist/lower/compile-template.mjs +366 -57
  45. package/dist/lower/entities.cjs +288 -0
  46. package/dist/lower/entities.d.cts +1 -0
  47. package/dist/lower/entities.d.ts +2 -0
  48. package/dist/lower/entities.d.ts.map +1 -0
  49. package/dist/lower/entities.js +54 -0
  50. package/dist/lower/entities.mjs +267 -0
  51. package/dist/lower/jsx.cjs +567 -7
  52. package/dist/lower/jsx.d.cts +8 -0
  53. package/dist/lower/jsx.d.ts +8 -0
  54. package/dist/lower/jsx.d.ts.map +1 -1
  55. package/dist/lower/jsx.js +205 -7
  56. package/dist/lower/jsx.mjs +567 -7
  57. package/dist/lower/template.cjs +332 -56
  58. package/dist/lower/template.d.ts.map +1 -1
  59. package/dist/lower/template.js +57 -49
  60. package/dist/lower/template.mjs +332 -56
  61. package/dist/resolve/builtins.cjs +1 -1
  62. package/dist/resolve/builtins.mjs +1 -1
  63. package/dist/resolve/component-globals.cjs +20 -1
  64. package/dist/resolve/component-globals.js +2 -2
  65. package/dist/resolve/component-globals.mjs +20 -1
  66. package/dist/resolve/write-globals.cjs +20 -1
  67. package/dist/resolve/write-globals.mjs +20 -1
  68. package/dist/{server-fns-BBZRZUPP.mjs → server-fns-JLSTKWPS.mjs} +4 -4
  69. package/dist/{server-functions-VEGLIFCE.mjs → server-functions-BGY3RD4R.mjs} +3 -3
  70. package/dist/transform/index.cjs +1123 -77
  71. package/dist/transform/index.mjs +1141 -91
  72. package/dist/transform/intrinsics.cjs +18 -0
  73. package/dist/transform/intrinsics.mjs +18 -0
  74. package/dist/transform/props.mjs +19 -14
  75. package/dist/transform/server-fns.mjs +19 -14
  76. package/dist/transform/source-locations.cjs +64 -3
  77. package/dist/transform/source-locations.d.cts +7 -2
  78. package/dist/transform/source-locations.d.ts +7 -2
  79. package/dist/transform/source-locations.d.ts.map +1 -1
  80. package/dist/transform/source-locations.js +68 -3
  81. package/dist/transform/source-locations.mjs +64 -3
  82. package/dist/transform/styles.cjs +588 -0
  83. package/dist/transform/styles.d.cts +211 -0
  84. package/dist/transform/styles.d.ts +212 -0
  85. package/dist/transform/styles.d.ts.map +1 -0
  86. package/dist/transform/styles.js +714 -0
  87. package/dist/transform/styles.mjs +653 -0
  88. package/dist/transform/templates.cjs +1122 -76
  89. package/dist/transform/templates.d.cts +13 -0
  90. package/dist/transform/templates.d.ts +13 -0
  91. package/dist/transform/templates.d.ts.map +1 -1
  92. package/dist/transform/templates.js +51 -14
  93. package/dist/transform/templates.mjs +1140 -90
  94. package/dist/{transform-UWZ7ZGJ2.mjs → transform-GBP6Y4UI.mjs} +603 -19
  95. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  96. package/dist/vite-styles.cjs +180 -0
  97. package/dist/vite-styles.d.cts +59 -0
  98. package/dist/vite-styles.d.ts +60 -0
  99. package/dist/vite-styles.d.ts.map +1 -0
  100. package/dist/vite-styles.js +198 -0
  101. package/dist/vite-styles.mjs +159 -0
  102. package/package.json +10 -3
@@ -469,6 +469,7 @@ var INTRINSICS = {
469
469
  $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
470
470
  $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
471
471
  $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
472
+ $cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
472
473
  // No short runtime form for these yet, so the intrinsic stands for the `create*`
473
474
  // name. Still worth having: no import to write, and when a shorter form is
474
475
  // designed, the change is this line rather than a compiler pass.
@@ -479,6 +480,19 @@ var INTRINSICS = {
479
480
  // dependency analysis must not guess at.
480
481
  $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
481
482
  $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
483
+ // Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
484
+ // no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
485
+ $batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
486
+ $cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
487
+ $root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
488
+ $context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
489
+ $renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
490
+ $computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
491
+ // Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
492
+ // handle as far as reads go: the same accessor with `set` on it.
493
+ $storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
494
+ $asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
495
+ $persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
482
496
  // An environment variable, public or server-only; the browser build refuses a secret.
483
497
  $env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
484
498
  };
@@ -656,13 +670,16 @@ function emitComponent(name, props, children, used, templates, at) {
656
670
  used.add("createComponent");
657
671
  const spreads = props.filter((p) => p.kind === "spread");
658
672
  const normal = props.filter((p) => p.kind !== "spread");
659
- const entries = normal.map(
660
- (p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
661
- );
673
+ const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
662
674
  if (children.length > 0) {
663
- entries.push(`get children() { return ${emitChildren(children, used, templates)}; }`);
675
+ bodies.push(["children", emitChildren(children, used, templates)]);
676
+ }
677
+ let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
678
+ if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
679
+ const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => (${body})`);
680
+ const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
681
+ obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
664
682
  }
665
- let obj = `{ ${entries.join(", ")} }`;
666
683
  if (spreads.length > 0) {
667
684
  used.add("mergeProps");
668
685
  obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
@@ -744,7 +761,8 @@ function emitNode(node, used, templates) {
744
761
  } else {
745
762
  used.add("spread");
746
763
  const svgFlag = node.svg ? ", isSVG: true" : "";
747
- const customFlag = node.tag.includes("-") ? ", isCustomElement: true" : "";
764
+ const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
765
+ const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
748
766
  parts.push(
749
767
  `spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
750
768
  );
@@ -804,6 +822,271 @@ function cleanTemplateText(value) {
804
822
  return out;
805
823
  }
806
824
 
825
+ // src/lower/entities.ts
826
+ var NAMED = {
827
+ quot: 34,
828
+ amp: 38,
829
+ apos: 39,
830
+ lt: 60,
831
+ gt: 62,
832
+ nbsp: 160,
833
+ iexcl: 161,
834
+ cent: 162,
835
+ pound: 163,
836
+ curren: 164,
837
+ yen: 165,
838
+ brvbar: 166,
839
+ sect: 167,
840
+ uml: 168,
841
+ copy: 169,
842
+ ordf: 170,
843
+ laquo: 171,
844
+ not: 172,
845
+ shy: 173,
846
+ reg: 174,
847
+ macr: 175,
848
+ deg: 176,
849
+ plusmn: 177,
850
+ sup2: 178,
851
+ sup3: 179,
852
+ acute: 180,
853
+ micro: 181,
854
+ para: 182,
855
+ middot: 183,
856
+ cedil: 184,
857
+ sup1: 185,
858
+ ordm: 186,
859
+ raquo: 187,
860
+ frac14: 188,
861
+ frac12: 189,
862
+ frac34: 190,
863
+ iquest: 191,
864
+ Agrave: 192,
865
+ Aacute: 193,
866
+ Acirc: 194,
867
+ Atilde: 195,
868
+ Auml: 196,
869
+ Aring: 197,
870
+ AElig: 198,
871
+ Ccedil: 199,
872
+ Egrave: 200,
873
+ Eacute: 201,
874
+ Ecirc: 202,
875
+ Euml: 203,
876
+ Igrave: 204,
877
+ Iacute: 205,
878
+ Icirc: 206,
879
+ Iuml: 207,
880
+ ETH: 208,
881
+ Ntilde: 209,
882
+ Ograve: 210,
883
+ Oacute: 211,
884
+ Ocirc: 212,
885
+ Otilde: 213,
886
+ Ouml: 214,
887
+ times: 215,
888
+ Oslash: 216,
889
+ Ugrave: 217,
890
+ Uacute: 218,
891
+ Ucirc: 219,
892
+ Uuml: 220,
893
+ Yacute: 221,
894
+ THORN: 222,
895
+ szlig: 223,
896
+ agrave: 224,
897
+ aacute: 225,
898
+ acirc: 226,
899
+ atilde: 227,
900
+ auml: 228,
901
+ aring: 229,
902
+ aelig: 230,
903
+ ccedil: 231,
904
+ egrave: 232,
905
+ eacute: 233,
906
+ ecirc: 234,
907
+ euml: 235,
908
+ igrave: 236,
909
+ iacute: 237,
910
+ icirc: 238,
911
+ iuml: 239,
912
+ eth: 240,
913
+ ntilde: 241,
914
+ ograve: 242,
915
+ oacute: 243,
916
+ ocirc: 244,
917
+ otilde: 245,
918
+ ouml: 246,
919
+ divide: 247,
920
+ oslash: 248,
921
+ ugrave: 249,
922
+ uacute: 250,
923
+ ucirc: 251,
924
+ uuml: 252,
925
+ yacute: 253,
926
+ thorn: 254,
927
+ yuml: 255,
928
+ OElig: 338,
929
+ oelig: 339,
930
+ Scaron: 352,
931
+ scaron: 353,
932
+ Yuml: 376,
933
+ fnof: 402,
934
+ circ: 710,
935
+ tilde: 732,
936
+ Alpha: 913,
937
+ Beta: 914,
938
+ Gamma: 915,
939
+ Delta: 916,
940
+ Epsilon: 917,
941
+ Zeta: 918,
942
+ Eta: 919,
943
+ Theta: 920,
944
+ Iota: 921,
945
+ Kappa: 922,
946
+ Lambda: 923,
947
+ Mu: 924,
948
+ Nu: 925,
949
+ Xi: 926,
950
+ Omicron: 927,
951
+ Pi: 928,
952
+ Rho: 929,
953
+ Sigma: 931,
954
+ Tau: 932,
955
+ Upsilon: 933,
956
+ Phi: 934,
957
+ Chi: 935,
958
+ Psi: 936,
959
+ Omega: 937,
960
+ alpha: 945,
961
+ beta: 946,
962
+ gamma: 947,
963
+ delta: 948,
964
+ epsilon: 949,
965
+ zeta: 950,
966
+ eta: 951,
967
+ theta: 952,
968
+ iota: 953,
969
+ kappa: 954,
970
+ lambda: 955,
971
+ mu: 956,
972
+ nu: 957,
973
+ xi: 958,
974
+ omicron: 959,
975
+ pi: 960,
976
+ rho: 961,
977
+ sigmaf: 962,
978
+ sigma: 963,
979
+ tau: 964,
980
+ upsilon: 965,
981
+ phi: 966,
982
+ chi: 967,
983
+ psi: 968,
984
+ omega: 969,
985
+ thetasym: 977,
986
+ upsih: 978,
987
+ piv: 982,
988
+ ensp: 8194,
989
+ emsp: 8195,
990
+ thinsp: 8201,
991
+ zwnj: 8204,
992
+ zwj: 8205,
993
+ lrm: 8206,
994
+ rlm: 8207,
995
+ ndash: 8211,
996
+ mdash: 8212,
997
+ lsquo: 8216,
998
+ rsquo: 8217,
999
+ sbquo: 8218,
1000
+ ldquo: 8220,
1001
+ rdquo: 8221,
1002
+ bdquo: 8222,
1003
+ dagger: 8224,
1004
+ Dagger: 8225,
1005
+ bull: 8226,
1006
+ hellip: 8230,
1007
+ permil: 8240,
1008
+ prime: 8242,
1009
+ Prime: 8243,
1010
+ lsaquo: 8249,
1011
+ rsaquo: 8250,
1012
+ oline: 8254,
1013
+ frasl: 8260,
1014
+ euro: 8364,
1015
+ image: 8465,
1016
+ weierp: 8472,
1017
+ real: 8476,
1018
+ trade: 8482,
1019
+ alefsym: 8501,
1020
+ larr: 8592,
1021
+ uarr: 8593,
1022
+ rarr: 8594,
1023
+ darr: 8595,
1024
+ harr: 8596,
1025
+ crarr: 8629,
1026
+ lArr: 8656,
1027
+ uArr: 8657,
1028
+ rArr: 8658,
1029
+ dArr: 8659,
1030
+ hArr: 8660,
1031
+ forall: 8704,
1032
+ part: 8706,
1033
+ exist: 8707,
1034
+ empty: 8709,
1035
+ nabla: 8711,
1036
+ isin: 8712,
1037
+ notin: 8713,
1038
+ ni: 8715,
1039
+ prod: 8719,
1040
+ sum: 8721,
1041
+ minus: 8722,
1042
+ lowast: 8727,
1043
+ radic: 8730,
1044
+ prop: 8733,
1045
+ infin: 8734,
1046
+ ang: 8736,
1047
+ and: 8743,
1048
+ or: 8744,
1049
+ cap: 8745,
1050
+ cup: 8746,
1051
+ int: 8747,
1052
+ there4: 8756,
1053
+ sim: 8764,
1054
+ cong: 8773,
1055
+ asymp: 8776,
1056
+ ne: 8800,
1057
+ equiv: 8801,
1058
+ le: 8804,
1059
+ ge: 8805,
1060
+ sub: 8834,
1061
+ sup: 8835,
1062
+ nsub: 8836,
1063
+ sube: 8838,
1064
+ supe: 8839,
1065
+ oplus: 8853,
1066
+ otimes: 8855,
1067
+ perp: 8869,
1068
+ sdot: 8901,
1069
+ lceil: 8968,
1070
+ rceil: 8969,
1071
+ lfloor: 8970,
1072
+ rfloor: 8971,
1073
+ lang: 9001,
1074
+ rang: 9002,
1075
+ loz: 9674,
1076
+ spades: 9824,
1077
+ clubs: 9827,
1078
+ hearts: 9829,
1079
+ diams: 9830
1080
+ };
1081
+ var REFERENCE = /&(?:#[xX]([0-9a-fA-F]{1,6})|#([0-9]{1,7})|([a-zA-Z][a-zA-Z0-9]{1,31}));/g;
1082
+ function decodeEntities(value) {
1083
+ if (!value.includes("&")) return value;
1084
+ return value.replace(REFERENCE, (match, hex, dec, name) => {
1085
+ const code = hex ? parseInt(hex, 16) : dec ? parseInt(dec, 10) : Object.prototype.hasOwnProperty.call(NAMED, name) ? NAMED[name] : void 0;
1086
+ return code !== void 0 && code <= 1114111 ? String.fromCodePoint(code) : match;
1087
+ });
1088
+ }
1089
+
807
1090
  // src/lower/template.ts
808
1091
  var DELEGATED = /* @__PURE__ */ new Set([
809
1092
  "click",
@@ -822,6 +1105,7 @@ var DELEGATED = /* @__PURE__ */ new Set([
822
1105
  function escapeTemplate(s) {
823
1106
  return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
824
1107
  }
1108
+ var CONTAINER = "container";
825
1109
  function capitalize(s) {
826
1110
  return s.charAt(0).toUpperCase() + s.slice(1);
827
1111
  }
@@ -876,10 +1160,6 @@ var Lowerer = class {
876
1160
  if (hasElse) i = elseIdx;
877
1161
  continue;
878
1162
  }
879
- if (child.attributes.some((a) => a.kind === "EachDirective")) {
880
- out.push(this.lowerEach(child));
881
- continue;
882
- }
883
1163
  }
884
1164
  const node = this.lowerNode(child);
885
1165
  if (node) out.push(node);
@@ -893,7 +1173,7 @@ var Lowerer = class {
893
1173
  switch (node.kind) {
894
1174
  case "Text": {
895
1175
  if (node.raw) return { kind: "text", value: node.value };
896
- const cleaned = cleanTemplateText(node.value);
1176
+ const cleaned = decodeEntities(cleanTemplateText(node.value));
897
1177
  return cleaned ? { kind: "text", value: cleaned } : null;
898
1178
  }
899
1179
  case "Comment":
@@ -921,13 +1201,16 @@ var Lowerer = class {
921
1201
  node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
922
1202
  return node;
923
1203
  }
1204
+ const each = this.lowerEach(el);
1205
+ const children = each ? [each] : this.lowerChildren(el.children);
1206
+ if (el.tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
924
1207
  const at = this.tagAt(el);
925
1208
  return {
926
1209
  kind: "element",
927
1210
  tag: el.tag,
928
1211
  svg: el.namespace === "svg",
929
- props: this.lowerAttributes(el.attributes),
930
- children: this.lowerChildren(el.children),
1212
+ props: this.lowerAttributes(el.attributes, true),
1213
+ children,
931
1214
  static: false,
932
1215
  ...at ? { at } : {}
933
1216
  };
@@ -999,10 +1282,14 @@ var Lowerer = class {
999
1282
  const at = this.tagAt(el);
1000
1283
  return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
1001
1284
  }
1002
- /** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
1285
+ /**
1286
+ * `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
1287
+ * content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
1288
+ * it is. Null when the element has no `each`.
1289
+ */
1003
1290
  lowerEach(el) {
1004
1291
  const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
1005
- if (!eachDir || eachDir.kind !== "EachDirective") return this.lowerNode(el);
1292
+ if (!eachDir || eachDir.kind !== "EachDirective") return null;
1006
1293
  const each = this.hole(eachDir.hole);
1007
1294
  const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
1008
1295
  if (eachDir.key) {
@@ -1012,12 +1299,12 @@ var Lowerer = class {
1012
1299
  const arrow = this.itemArrow(el);
1013
1300
  let childrenCode;
1014
1301
  if (arrow) {
1015
- const bodyIR = { kind: "expr", code: arrow.body, reactive: arrow.bodyReactive };
1016
- const repeated = this.rebuildWithChildren(el, [bodyIR]);
1017
- childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
1302
+ const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
1303
+ childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
1018
1304
  } else {
1019
- const repeated = this.stripAndLower(el, (a) => a.kind === "EachDirective");
1020
- childrenCode = `() => ${paren(this.emit(repeated), "arrowBody")}`;
1305
+ const content = this.lowerChildren(el.children);
1306
+ const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
1307
+ childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
1021
1308
  }
1022
1309
  const children = [{ kind: "expr", code: childrenCode, reactive: false }];
1023
1310
  const at = this.tagAt(el);
@@ -1034,33 +1321,23 @@ var Lowerer = class {
1034
1321
  const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
1035
1322
  return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
1036
1323
  }
1037
- /** Same element (minus each/key) but with explicit IR children. */
1038
- rebuildWithChildren(el, children) {
1039
- const props = this.lowerAttributes(
1040
- el.attributes.filter((a) => a.kind !== "EachDirective")
1041
- );
1042
- if (el.kind === "Element") {
1043
- const at = this.tagAt(el);
1044
- return {
1045
- kind: "element",
1046
- tag: el.tag,
1047
- svg: el.namespace === "svg",
1048
- props,
1049
- children,
1050
- static: false,
1051
- ...at ? { at } : {}
1052
- };
1053
- }
1054
- return { kind: "component", name: el.tag, props, children };
1055
- }
1056
1324
  // --- attributes ---------------------------------------------------------
1057
- lowerAttributes(attrs) {
1325
+ /**
1326
+ * `element`: a DOM element, where each class:/style: value that moves is its own accessor.
1327
+ * A component gets the object as before, rebuilt whole when any value moves.
1328
+ */
1329
+ lowerAttributes(attrs, element = false) {
1330
+ let anyReactive = false;
1331
+ const entry = (name, h) => {
1332
+ anyReactive ||= h.reactive;
1333
+ if (!element || !h.reactive) return `${JSON.stringify(name)}: ${h.code}`;
1334
+ const accessor = `() => ${paren(h.code, "arrowBody")}`;
1335
+ return `${JSON.stringify(name)}: ${h.at ? markHole(accessor, h.at.line, h.at.column) : accessor}`;
1336
+ };
1058
1337
  const props = [];
1059
1338
  const classEntries = [];
1060
- let classReactive = false;
1061
1339
  let classAt;
1062
1340
  const styleEntries = [];
1063
- let styleReactive = false;
1064
1341
  let styleAt;
1065
1342
  const usePairs = [];
1066
1343
  for (const a of attrs) {
@@ -1100,15 +1377,13 @@ var Lowerer = class {
1100
1377
  break;
1101
1378
  case "ClassDirective": {
1102
1379
  const h = this.hole(a.hole);
1103
- classEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
1104
- classReactive = classReactive || h.reactive;
1380
+ classEntries.push(entry(a.name, h));
1105
1381
  classAt ??= h.at;
1106
1382
  break;
1107
1383
  }
1108
1384
  case "StyleDirective": {
1109
1385
  const h = this.hole(a.hole);
1110
- styleEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
1111
- styleReactive = styleReactive || h.reactive;
1386
+ styleEntries.push(entry(a.name, h));
1112
1387
  styleAt ??= h.at;
1113
1388
  break;
1114
1389
  }
@@ -1128,18 +1403,19 @@ var Lowerer = class {
1128
1403
  name: "classList",
1129
1404
  kind: "attr",
1130
1405
  expr: `{ ${classEntries.join(", ")} }`,
1131
- reactive: classReactive,
1406
+ reactive: !element && anyReactive,
1132
1407
  ...classAt ? { at: classAt } : {}
1133
1408
  });
1134
1409
  }
1135
1410
  if (styleEntries.length > 0) {
1136
- props.push({
1137
- name: "style",
1138
- kind: "attr",
1139
- expr: `{ ${styleEntries.join(", ")} }`,
1140
- reactive: styleReactive,
1141
- ...styleAt ? { at: styleAt } : {}
1142
- });
1411
+ const entries = `{ ${styleEntries.join(", ")} }`;
1412
+ const base = props.findIndex((p) => p.name === "style");
1413
+ if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: !element && anyReactive, ...styleAt ? { at: styleAt } : {} });
1414
+ else {
1415
+ const prop = props[base];
1416
+ const value = prop.expr === void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
1417
+ props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
1418
+ }
1143
1419
  }
1144
1420
  if (usePairs.length > 0) {
1145
1421
  props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
@@ -1228,7 +1504,7 @@ var Lowerer = class {
1228
1504
  return base;
1229
1505
  }
1230
1506
  if (v.kind === "static") {
1231
- base.literal = v.value;
1507
+ base.literal = decodeEntities(v.value);
1232
1508
  return base;
1233
1509
  }
1234
1510
  if (v.kind === "hole") {
@@ -1241,7 +1517,7 @@ var Lowerer = class {
1241
1517
  let reactive = false;
1242
1518
  let at;
1243
1519
  const body = v.parts.map((p) => {
1244
- if ("text" in p) return escapeTemplate(p.text);
1520
+ if ("text" in p) return escapeTemplate(decodeEntities(p.text));
1245
1521
  const h = this.hole(p.hole);
1246
1522
  reactive = reactive || h.reactive;
1247
1523
  at ??= h.at;
@@ -1464,6 +1740,22 @@ var DELEGATED2 = /* @__PURE__ */ new Set([
1464
1740
  "mouseup"
1465
1741
  ]);
1466
1742
  var isReactive = (node) => isReactiveShape(shapeOf(node));
1743
+ var CONTAINER2 = "container";
1744
+ function directive(node, name) {
1745
+ if (node.type !== "JSXElement") return void 0;
1746
+ const opening = node.openingElement;
1747
+ if (opening.name.type !== "JSXIdentifier" || opening.name.name[0] !== opening.name.name[0].toLowerCase()) return void 0;
1748
+ return opening.attributes.find((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === name);
1749
+ }
1750
+ function directiveExpr(attr) {
1751
+ const v = attr.value;
1752
+ return v?.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression" ? v.expression : void 0;
1753
+ }
1754
+ function emitIR(ir, ctx) {
1755
+ const { code, imports, templates } = imperativeBackend.emit(ir, {});
1756
+ for (const s of imports) ctx.used.add(s);
1757
+ return inlineTemplates(code, templates);
1758
+ }
1467
1759
  var posOf = (node, ctx) => {
1468
1760
  if (!ctx.sourceFile) return void 0;
1469
1761
  const at = node.loc?.start;
@@ -1541,9 +1833,12 @@ function attrExprCode(attr, ctx) {
1541
1833
  }
1542
1834
  return null;
1543
1835
  }
1544
- function buildProps(attrs, ctx) {
1836
+ function buildProps(attrs, ctx, element = false) {
1545
1837
  const props = [];
1546
1838
  const usePairs = [];
1839
+ const classEntries = [];
1840
+ const styleEntries = [];
1841
+ let styleAt;
1547
1842
  for (const a of attrs) {
1548
1843
  if (a.type === "JSXSpreadAttribute") {
1549
1844
  props.push({ name: "", kind: "spread", expr: ctx.code(a.argument) });
@@ -1559,6 +1854,27 @@ function buildProps(attrs, ctx) {
1559
1854
  usePairs.push(opts != null ? `[${dir}, () => ${paren(opts, "arrowBody")}]` : `[${dir}]`);
1560
1855
  continue;
1561
1856
  }
1857
+ if (element && (ns === "class" || ns === "style")) {
1858
+ const key = JSON.stringify(a.name.name.name);
1859
+ const v = a.value;
1860
+ let value;
1861
+ if (v == null) value = "true";
1862
+ else if (isString(v)) value = JSON.stringify(literalOf(v));
1863
+ else if (v.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression") {
1864
+ value = keyValue(v.expression, ctx);
1865
+ if (ns === "style") styleAt ??= posOf(v.expression, ctx);
1866
+ } else continue;
1867
+ (ns === "class" ? classEntries : styleEntries).push(`${key}: ${value}`);
1868
+ continue;
1869
+ }
1870
+ if (element && a.name.type === "JSXIdentifier" && a.name.name === "style" && a.value?.type === "JSXExpressionContainer") {
1871
+ const entries = objectEntries(a.value.expression, ctx);
1872
+ if (entries) {
1873
+ styleEntries.unshift(...entries);
1874
+ styleAt = posOf(a.value.expression, ctx);
1875
+ continue;
1876
+ }
1877
+ }
1562
1878
  if (ns === "oncapture") {
1563
1879
  const evt = a.name.name.name.toLowerCase();
1564
1880
  const h = attrExprCode(a, ctx) ?? "undefined";
@@ -1567,12 +1883,49 @@ function buildProps(attrs, ctx) {
1567
1883
  }
1568
1884
  props.push(buildAttr(a, ctx));
1569
1885
  }
1886
+ if (classEntries.length > 0) props.push({ name: "classList", kind: "attr", expr: `{ ${classEntries.join(", ")} }`, reactive: false });
1887
+ if (styleEntries.length > 0) {
1888
+ const entries = `{ ${styleEntries.join(", ")} }`;
1889
+ const base = props.findIndex((p) => p.name === "style" && p.kind === "attr");
1890
+ if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: false, ...styleAt ? { at: styleAt } : {} });
1891
+ else {
1892
+ const prop = props[base];
1893
+ const value = prop.literal !== void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
1894
+ props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
1895
+ }
1896
+ }
1570
1897
  if (usePairs.length > 0) props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
1571
1898
  return props;
1572
1899
  }
1900
+ function keyValue(expr, ctx) {
1901
+ const code = ctx.code(expr);
1902
+ if (!isReactive(expr)) return code;
1903
+ const accessor = `() => ${paren(code, "arrowBody")}`;
1904
+ const at = posOf(expr, ctx);
1905
+ return at ? markHole(accessor, at.line, at.column) : accessor;
1906
+ }
1907
+ function objectEntries(expr, ctx) {
1908
+ if (expr?.type !== "ObjectExpression") return null;
1909
+ const entries = [];
1910
+ for (const p of expr.properties) {
1911
+ if (p.type !== "ObjectProperty") return null;
1912
+ const key = p.computed ? `[${ctx.code(p.key)}]` : p.key.type === "Identifier" ? JSON.stringify(p.key.name) : JSON.stringify(String(p.key.value));
1913
+ entries.push(`${key}: ${keyValue(p.value, ctx)}`);
1914
+ }
1915
+ return entries;
1916
+ }
1573
1917
  function buildChildren(children, ctx) {
1574
1918
  const out = [];
1575
- for (const child of children) {
1919
+ for (let i = 0; i < children.length; i++) {
1920
+ const child = children[i];
1921
+ if (directive(child, "if")) {
1922
+ let next = i + 1;
1923
+ while (next < children.length && children[next].type === "JSXText" && !cleanTemplateText(children[next].value)) next++;
1924
+ const fallback = directive(children[next], "else") ? children[next] : null;
1925
+ out.push(buildIf(child, fallback, ctx));
1926
+ if (fallback) i = next;
1927
+ continue;
1928
+ }
1576
1929
  if (child.type === "JSXText") {
1577
1930
  const text = cleanTemplateText(child.value);
1578
1931
  if (text) out.push({ kind: "text", value: text });
@@ -1588,6 +1941,7 @@ function buildChildren(children, ctx) {
1588
1941
  });
1589
1942
  }
1590
1943
  } else if (child.type === "JSXElement" || child.type === "JSXFragment") {
1944
+ if (ctx.dropStyles?.has(child.start)) continue;
1591
1945
  out.push(buildNode(child, ctx));
1592
1946
  } else if (child.type === "JSXSpreadChild") {
1593
1947
  out.push({ kind: "expr", code: ctx.code(child.expression), reactive: false });
@@ -1609,19 +1963,72 @@ function readLoad(attrs) {
1609
1963
  }
1610
1964
  return void 0;
1611
1965
  }
1966
+ function buildIf(node, fallback, ctx) {
1967
+ const cond = directiveExpr(directive(node, "if"));
1968
+ const props = [
1969
+ cond ? { name: "when", kind: "attr", expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) } : { name: "when", kind: "attr", literal: true }
1970
+ ];
1971
+ if (fallback) {
1972
+ props.push({ name: "fallback", kind: "attr", expr: emitIR(buildElement(fallback, ctx, ["else"]), ctx), jsxElement: true });
1973
+ }
1974
+ return { kind: "component", name: "Show", props, children: [buildElement(node, ctx, ["if"])] };
1975
+ }
1976
+ function buildEach(node, ctx) {
1977
+ const attr = directive(node, "each");
1978
+ if (!attr) return null;
1979
+ const list = directiveExpr(attr);
1980
+ const props = [
1981
+ list ? { name: "each", kind: "attr", expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) } : { name: "each", kind: "attr", expr: "[]" }
1982
+ ];
1983
+ const key = directive(node, "key");
1984
+ if (key) {
1985
+ const keyExpr = directiveExpr(key);
1986
+ const by = isString(key.value) ? `(item) => item[${JSON.stringify(literalOf(key.value))}]` : keyExpr ? ctx.code(keyExpr) : void 0;
1987
+ if (by) props.push({ name: "by", kind: "attr", expr: by });
1988
+ }
1989
+ const content = node.children.filter((c) => !(c.type === "JSXText" && !cleanTemplateText(c.value)));
1990
+ const only = content.length === 1 && content[0].type === "JSXExpressionContainer" ? content[0].expression : null;
1991
+ let render;
1992
+ if (only && (only.type === "ArrowFunctionExpression" || only.type === "FunctionExpression")) {
1993
+ const fn = ctx.code(only);
1994
+ const live = only.type === "ArrowFunctionExpression" && only.body.type !== "BlockStatement" && isReactive(only.body);
1995
+ render = live ? `(...args) => () => (${fn})(...args)` : fn;
1996
+ } else {
1997
+ const built = buildChildren(node.children, ctx);
1998
+ const ir = built.length === 1 ? built[0] : { kind: "fragment", children: built };
1999
+ render = `() => ${paren(emitIR(ir, ctx), "arrowBody")}`;
2000
+ }
2001
+ return { kind: "component", name: "For", props, children: [{ kind: "expr", code: render, reactive: false }] };
2002
+ }
2003
+ function buildElement(node, ctx, handled) {
2004
+ const skip = new Set(handled);
2005
+ const directives = /* @__PURE__ */ new Set(["if", "else", "each", ...directive(node, "each") ? ["key"] : []]);
2006
+ const attributes = node.openingElement.attributes.filter(
2007
+ (a) => !(a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && (skip.has(a.name.name) || directives.has(a.name.name)))
2008
+ );
2009
+ const { tag } = tagInfo(node.openingElement.name, ctx);
2010
+ const each = buildEach(node, ctx);
2011
+ const children = each ? [each] : buildChildren(node.children, ctx);
2012
+ if (tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
2013
+ const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
2014
+ const props = buildProps(attributes, ctx, true);
2015
+ const scope = ctx.scopes?.find((s) => node.start >= s.start && node.end <= s.end);
2016
+ if (scope) props.unshift({ name: "data-fx-s", kind: "attr", literal: scope.value });
2017
+ return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
2018
+ }
1612
2019
  function buildNode(node, ctx) {
1613
2020
  if (node.type === "JSXFragment") {
1614
2021
  return { kind: "fragment", children: buildChildren(node.children, ctx) };
1615
2022
  }
2023
+ if (directive(node, "if")) return buildIf(node, null, ctx);
2024
+ if (ctx.dropStyles?.has(node.start)) return { kind: "fragment", children: [] };
1616
2025
  const { tag, component } = tagInfo(node.openingElement.name, ctx);
2026
+ if (!component) return buildElement(node, ctx, []);
1617
2027
  const props = buildProps(node.openingElement.attributes, ctx);
1618
2028
  const children = buildChildren(node.children, ctx);
1619
2029
  const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
1620
- if (component) {
1621
- const load = readLoad(node.openingElement.attributes);
1622
- return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
1623
- }
1624
- return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
2030
+ const load = readLoad(node.openingElement.attributes);
2031
+ return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
1625
2032
  }
1626
2033
  function buildJsxIR(node, ctx) {
1627
2034
  const ir = buildNode(node, ctx);