@farm.js/react 0.1.0-beta.3 → 0.1.0-beta.5

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.
package/dist/vite.cjs CHANGED
@@ -6,6 +6,96 @@ var promises = require('fs/promises');
6
6
  var path = require('path');
7
7
 
8
8
  // src/vite.ts
9
+ var DELEGATABLE_KEYED_ROW_EVENTS = /* @__PURE__ */ new Set([
10
+ "onBeforeInput",
11
+ "onBlur",
12
+ "onChange",
13
+ "onClick",
14
+ "onCompositionEnd",
15
+ "onCompositionStart",
16
+ "onCompositionUpdate",
17
+ "onContextMenu",
18
+ "onCopy",
19
+ "onCut",
20
+ "onDoubleClick",
21
+ "onDrag",
22
+ "onDragEnd",
23
+ "onDragEnter",
24
+ "onDragExit",
25
+ "onDragLeave",
26
+ "onDragOver",
27
+ "onDragStart",
28
+ "onDrop",
29
+ "onFocus",
30
+ "onInput",
31
+ "onKeyDown",
32
+ "onKeyPress",
33
+ "onKeyUp",
34
+ "onMouseDown",
35
+ "onMouseMove",
36
+ "onMouseOut",
37
+ "onMouseOver",
38
+ "onMouseUp",
39
+ "onPaste",
40
+ "onPointerCancel",
41
+ "onPointerDown",
42
+ "onPointerMove",
43
+ "onPointerOut",
44
+ "onPointerOver",
45
+ "onPointerUp",
46
+ "onReset",
47
+ "onSubmit",
48
+ "onTouchCancel",
49
+ "onTouchEnd",
50
+ "onTouchMove",
51
+ "onTouchStart",
52
+ "onWheel"
53
+ ]);
54
+ function canDelegateKeyedRowEvents(plan) {
55
+ if (plan.events.length === 0 || plan.conditionals.length > 0) return false;
56
+ if (plan.source.openingElement.attributes.some(
57
+ (attribute) => core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && /^on[A-Z]/.test(attribute.name.name)
58
+ )) {
59
+ return false;
60
+ }
61
+ return plan.events.every(
62
+ (event) => DELEGATABLE_KEYED_ROW_EVENTS.has(event.name.replace(/Capture$/, ""))
63
+ );
64
+ }
65
+ var COMPILER_RUNTIME_FEATURE_EXPORTS = {
66
+ conditional: "conditionalRuntimeFeature",
67
+ "host-conditional": "hostConditionalRuntimeFeature",
68
+ "conditional-ranges": "conditionalRangesRuntimeFeature",
69
+ "keyed-list": "keyedListRuntimeFeature",
70
+ "keyed-rows": "keyedRowsRuntimeFeature",
71
+ "keyed-rows-conditional": "keyedRowsConditionalRuntimeFeature",
72
+ "keyed-rows-host": "keyedRowsHostRuntimeFeature",
73
+ "keyed-rows-complete": "keyedRowsCompleteRuntimeFeature",
74
+ "keyed-ranges": "keyedRangesRuntimeFeature",
75
+ "mixed-ranges": "mixedRangesRuntimeFeature",
76
+ component: "componentRuntimeFeature"
77
+ };
78
+ function runtimeFeaturesForPlans(plans) {
79
+ const features = /* @__PURE__ */ new Set();
80
+ let keyedRowsHaveConditionals = false;
81
+ let keyedRowsHaveHostBlocks = false;
82
+ for (const plan of plans) {
83
+ if (plan.kind === "keyed-rows") {
84
+ keyedRowsHaveConditionals || (keyedRowsHaveConditionals = plan.conditionals.length > 0);
85
+ keyedRowsHaveHostBlocks || (keyedRowsHaveHostBlocks = Boolean(plan.descriptorBlocks?.size));
86
+ continue;
87
+ }
88
+ if (plan.kind in COMPILER_RUNTIME_FEATURE_EXPORTS) {
89
+ features.add(plan.kind);
90
+ }
91
+ }
92
+ if (plans.some((plan) => plan.kind === "keyed-rows")) {
93
+ features.add(
94
+ keyedRowsHaveConditionals && keyedRowsHaveHostBlocks ? "keyed-rows-complete" : keyedRowsHaveConditionals ? "keyed-rows-conditional" : keyedRowsHaveHostBlocks ? "keyed-rows-host" : "keyed-rows"
95
+ );
96
+ }
97
+ return [...features].sort();
98
+ }
9
99
  var SAFE_GLOBAL_CALLS = /* @__PURE__ */ new Set(["Boolean", "Number", "String"]);
10
100
  var SAFE_MATH_CALLS = /* @__PURE__ */ new Set(["abs", "ceil", "floor", "max", "min", "round", "sign", "trunc"]);
11
101
  function isComponentName(name) {
@@ -90,6 +180,37 @@ function rewriteDestructuredPropAccess(expression, names, propsParameter) {
90
180
  });
91
181
  return file.program.body[0].expression;
92
182
  }
183
+ function collectDestructuredPropNames(expression, names, propsParameter) {
184
+ const referenced = /* @__PURE__ */ new Set();
185
+ if (names.size === 0) return referenced;
186
+ core.traverse(expressionFile(cloneExpression(expression)), {
187
+ MemberExpression(path) {
188
+ const { object, property, computed } = path.node;
189
+ if (computed || !core.types.isIdentifier(object, { name: propsParameter.name }) || !core.types.isIdentifier(property) || !names.has(property.name)) {
190
+ return;
191
+ }
192
+ referenced.add(property.name);
193
+ }
194
+ });
195
+ return referenced;
196
+ }
197
+ function rewriteTrackedPropAccess(expression, propsParameter, bindingsByName) {
198
+ if (bindingsByName.size === 0) return cloneExpression(expression);
199
+ const file = expressionFile(cloneExpression(expression));
200
+ core.traverse(file, {
201
+ MemberExpression(path) {
202
+ const { object, property, computed } = path.node;
203
+ if (computed || !core.types.isIdentifier(object, { name: propsParameter.name }) || !core.types.isIdentifier(property)) {
204
+ return;
205
+ }
206
+ const binding = bindingsByName.get(property.name);
207
+ if (!binding) return;
208
+ path.replaceWith(core.types.identifier(binding.valueName));
209
+ path.skip();
210
+ }
211
+ });
212
+ return file.program.body[0].expression;
213
+ }
93
214
  function rewriteHandlerAccess(root, handlersByName) {
94
215
  if (handlersByName.size === 0) return { root: core.types.cloneNode(root, true) };
95
216
  const file = expressionFile(core.types.cloneNode(root, true));
@@ -769,7 +890,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
769
890
  const reason = visit(row, []);
770
891
  return reason ? { reason } : { bindings, events, conditionals };
771
892
  }
772
- function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames) {
893
+ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acceptUnsupportedRow = false) {
773
894
  let collection;
774
895
  let keyCallback;
775
896
  let renderCallback;
@@ -824,17 +945,29 @@ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames) {
824
945
  safeGlobals,
825
946
  new Set([...statesByValue.values()].map((state) => state.setterName))
826
947
  );
827
- if (rowAnalysis.reason) return void 0;
948
+ if (rowAnalysis.reason && !acceptUnsupportedRow) return void 0;
949
+ const keyExpression = returnedExpression(keyCallback);
950
+ const structureDependencies = new Set(collectStateDependencies(collection, statesByValue));
951
+ if (keyExpression) {
952
+ for (const dependency of collectStateDependencies(keyExpression, statesByValue)) {
953
+ structureDependencies.add(dependency);
954
+ }
955
+ }
828
956
  return {
829
957
  source,
830
958
  collection,
959
+ structureDependencies: [...structureDependencies].sort((left, right) => left - right),
831
960
  keyCallback,
832
961
  renderCallback,
833
962
  row,
834
963
  dependencies,
835
- bindings: rowAnalysis.bindings || [],
964
+ bindings: (rowAnalysis.bindings || []).map((binding) => ({
965
+ ...binding,
966
+ dependencies: collectStateDependencies(binding.value, statesByValue)
967
+ })),
836
968
  events: rowAnalysis.events || [],
837
969
  conditionals: rowAnalysis.conditionals || [],
970
+ rowReason: rowAnalysis.reason,
838
971
  syntax
839
972
  };
840
973
  }
@@ -851,22 +984,7 @@ function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNa
851
984
  }
852
985
  const children = meaningfulJsxChildren(container);
853
986
  if (children.length !== 1) return void 0;
854
- return analyzeKeyedRowChild(children[0], statesByValue, safeGlobals, listNames);
855
- }
856
- function isStaticRangeSibling(element, statesByValue, safeGlobals) {
857
- for (const child of meaningfulJsxChildren(element)) {
858
- if (core.types.isJSXFragment(child)) return false;
859
- if (core.types.isJSXElement(child)) {
860
- if (!isHostElement(child) || !isStaticRangeSibling(child, statesByValue, safeGlobals)) {
861
- return false;
862
- }
863
- continue;
864
- }
865
- if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression) && !isTextExpression(child.expression, statesByValue, safeGlobals)) {
866
- return false;
867
- }
868
- }
869
- return true;
987
+ return analyzeKeyedRowChild(children[0], statesByValue, safeGlobals, listNames, true);
870
988
  }
871
989
  function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, listNames, allowSingleRange = false) {
872
990
  if (container.openingElement.attributes.some(
@@ -878,6 +996,7 @@ function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, list
878
996
  if (children.length < (allowSingleRange ? 1 : 2)) return void 0;
879
997
  const ranges = [];
880
998
  const dependencies = /* @__PURE__ */ new Set();
999
+ const staticBindings = [];
881
1000
  let staticBefore = 0;
882
1001
  for (const child of children) {
883
1002
  const range = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames);
@@ -898,18 +1017,31 @@ function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, list
898
1017
  continue;
899
1018
  }
900
1019
  if (!core.types.isJSXElement(child) || !isHostElement(child)) return void 0;
901
- if (!isStaticRangeSibling(child, statesByValue, safeGlobals)) return void 0;
1020
+ const analysis = analyzeHostConditionalTree(child, safeGlobals, true, statesByValue);
1021
+ if (analysis.reason) return void 0;
1022
+ for (const binding of analysis.bindings || []) {
1023
+ staticBindings.push({
1024
+ ...binding,
1025
+ segment: ranges.length,
1026
+ sibling: staticBefore
1027
+ });
1028
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1029
+ dependencies.add(dependency);
1030
+ }
1031
+ }
902
1032
  staticBefore += 1;
903
1033
  }
904
1034
  if (ranges.length === 0) return void 0;
905
1035
  return {
906
1036
  ranges,
907
1037
  trailing: staticBefore,
908
- dependencies: [...dependencies].sort((left, right) => left - right)
1038
+ dependencies: [...dependencies].sort((left, right) => left - right),
1039
+ staticBindings
909
1040
  };
910
1041
  }
911
- function analyzeHostConditionalTree(branch, safeGlobals) {
1042
+ function analyzeHostConditionalTree(branch, safeGlobals, allowStaticEvents = false, statefulOnly) {
912
1043
  const bindings = [];
1044
+ const needsStaticBinding = (expression) => !statefulOnly || collectStateDependencies(expression, statefulOnly).length > 0;
913
1045
  const visit = (element, path) => {
914
1046
  const tag = element.openingElement.name;
915
1047
  if (!core.types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
@@ -918,20 +1050,26 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
918
1050
  if (tag.name === "svg") return "compiler-owned conditionals do not support SVG yet";
919
1051
  for (const attribute of element.openingElement.attributes) {
920
1052
  if (core.types.isJSXSpreadAttribute(attribute)) {
1053
+ if (statefulOnly && !needsStaticBinding(attribute.argument)) continue;
921
1054
  return "compiler-owned conditionals do not support JSX attribute spreads";
922
1055
  }
923
1056
  const name = jsxAttributeName(attribute);
924
1057
  if (!name) return "compiler-owned conditionals do not support namespaced JSX attributes";
925
1058
  if (name === "ref" || name === "dangerouslySetInnerHTML" || name === "key") {
1059
+ if (statefulOnly && (!core.types.isJSXExpressionContainer(attribute.value) || core.types.isJSXEmptyExpression(attribute.value.expression) || !needsStaticBinding(attribute.value.expression))) {
1060
+ continue;
1061
+ }
926
1062
  return `compiler-owned conditional ${name} requires React ownership`;
927
1063
  }
928
1064
  if (/^on[A-Z]/.test(name)) {
1065
+ if (allowStaticEvents) continue;
929
1066
  return "compiler-owned conditional events require React ownership";
930
1067
  }
931
1068
  if (!core.types.isJSXExpressionContainer(attribute.value) || core.types.isJSXEmptyExpression(attribute.value.expression)) {
932
1069
  continue;
933
1070
  }
934
1071
  const expression = attribute.value.expression;
1072
+ if (!needsStaticBinding(expression)) continue;
935
1073
  if (name === "style") {
936
1074
  if (!core.types.isObjectExpression(expression)) {
937
1075
  return "compiler-owned conditional styles must use one inline object literal";
@@ -944,6 +1082,7 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
944
1082
  if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
945
1083
  return "compiler-owned conditional style names must use camelCase or a CSS custom property";
946
1084
  }
1085
+ if (!needsStaticBinding(property.value)) continue;
947
1086
  const unsupported2 = validateDerivedExpression(property.value, safeGlobals);
948
1087
  if (unsupported2) {
949
1088
  return `compiler-owned conditional style ${propertyName} cannot use ${unsupported2}`;
@@ -978,14 +1117,20 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
978
1117
  const expressions = element.children.filter(
979
1118
  (child) => core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)
980
1119
  );
981
- for (const child of expressions) {
982
- const unsupported = validateDerivedExpression(child.expression, safeGlobals);
983
- if (unsupported) return `compiler-owned conditional text cannot use ${unsupported}`;
1120
+ const boundExpressions = statefulOnly ? expressions.filter((child) => needsStaticBinding(child.expression)) : expressions;
1121
+ if (boundExpressions.length > 0) {
1122
+ for (const child of expressions) {
1123
+ const unsupported = validateDerivedExpression(
1124
+ child.expression,
1125
+ safeGlobals
1126
+ );
1127
+ if (unsupported) return `compiler-owned conditional text cannot use ${unsupported}`;
1128
+ }
984
1129
  }
985
- if (nestedElements.length > 0 && expressions.length > 0) {
1130
+ if (nestedElements.length > 0 && boundExpressions.length > 0) {
986
1131
  return "compiler-owned conditionals do not support dynamic text beside nested elements yet";
987
1132
  }
988
- if (nestedElements.length === 0 && expressions.length > 0) {
1133
+ if (nestedElements.length === 0 && boundExpressions.length > 0) {
989
1134
  const parts = [];
990
1135
  for (const child of element.children) {
991
1136
  if (core.types.isJSXText(child)) {
@@ -1009,7 +1154,369 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
1009
1154
  const reason = visit(branch, []);
1010
1155
  return reason ? { reason } : { bindings };
1011
1156
  }
1012
- function analyzeHostConditionalContainer(container, statesByValue, safeGlobals) {
1157
+ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames, parent, allocateId) {
1158
+ const bindings = [];
1159
+ const plans = [];
1160
+ const blocks = /* @__PURE__ */ new Map();
1161
+ const visit = (element, path, owner) => {
1162
+ const tag = element.openingElement.name;
1163
+ if (!core.types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
1164
+ return "recursive compiler-owned blocks support host elements only";
1165
+ }
1166
+ if (tag.name === "svg") return "recursive compiler-owned blocks do not support SVG yet";
1167
+ for (const attribute of element.openingElement.attributes) {
1168
+ if (core.types.isJSXSpreadAttribute(attribute)) {
1169
+ return "recursive compiler-owned blocks do not support JSX attribute spreads";
1170
+ }
1171
+ const name = jsxAttributeName(attribute);
1172
+ if (!name) return "recursive compiler-owned blocks do not support namespaced attributes";
1173
+ if (name === "ref" || name === "dangerouslySetInnerHTML" || name === "key") {
1174
+ return `recursive compiler-owned block ${name} requires React ownership`;
1175
+ }
1176
+ if (/^on[A-Z]/.test(name)) {
1177
+ return "recursive compiler-owned block events require React ownership";
1178
+ }
1179
+ if (!core.types.isJSXExpressionContainer(attribute.value) || core.types.isJSXEmptyExpression(attribute.value.expression)) {
1180
+ continue;
1181
+ }
1182
+ const expression = attribute.value.expression;
1183
+ if (name === "style") {
1184
+ if (!core.types.isObjectExpression(expression)) {
1185
+ return "recursive compiler-owned styles must use one inline object literal";
1186
+ }
1187
+ for (const property of expression.properties) {
1188
+ if (!core.types.isObjectProperty(property) || property.computed || !core.types.isExpression(property.value)) {
1189
+ return "recursive compiler-owned styles do not support spreads, methods, or computed properties";
1190
+ }
1191
+ const propertyName = core.types.isIdentifier(property.key) ? property.key.name : core.types.isStringLiteral(property.key) ? property.key.value : void 0;
1192
+ if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
1193
+ return "recursive compiler-owned style names must use camelCase or a CSS custom property";
1194
+ }
1195
+ const unsupported2 = validateDerivedExpression(property.value, safeGlobals);
1196
+ if (unsupported2) {
1197
+ return `recursive compiler-owned style ${propertyName} cannot use ${unsupported2}`;
1198
+ }
1199
+ bindings.push({
1200
+ kind: "style",
1201
+ path: [...path],
1202
+ name: propertyName,
1203
+ value: cloneExpression(property.value)
1204
+ });
1205
+ }
1206
+ continue;
1207
+ }
1208
+ if (name === "children") {
1209
+ return "recursive compiler-owned children props are not supported yet";
1210
+ }
1211
+ const unsupported = validateDerivedExpression(expression, safeGlobals);
1212
+ if (unsupported) return `recursive compiler-owned ${name} cannot use ${unsupported}`;
1213
+ bindings.push({
1214
+ kind: "attribute",
1215
+ path: [...path],
1216
+ name,
1217
+ value: cloneExpression(expression)
1218
+ });
1219
+ }
1220
+ const children = meaningfulJsxChildren(element);
1221
+ const hasConditionalRange = children.some(
1222
+ (child) => core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression) && conditionalBlockShape(child.expression) !== null
1223
+ );
1224
+ const hasKeyedRange = children.some(
1225
+ (child) => analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true) !== void 0
1226
+ );
1227
+ if (hasConditionalRange && hasKeyedRange) {
1228
+ const id = allocateId();
1229
+ const mixed = analyzeMixedRangesContainer(
1230
+ element,
1231
+ statesByValue,
1232
+ safeGlobals,
1233
+ listNames,
1234
+ id,
1235
+ allocateId
1236
+ );
1237
+ if (mixed) {
1238
+ plans.push(...mixed.nestedPlans);
1239
+ for (const [nestedElement, plan2] of mixed.descriptorBlocks) {
1240
+ blocks.set(nestedElement, plan2);
1241
+ }
1242
+ const plan = {
1243
+ kind: "nested-host-mixed-ranges",
1244
+ id,
1245
+ parent: owner,
1246
+ dependencies: mixed.dependencies,
1247
+ source: element,
1248
+ ranges: mixed.ranges,
1249
+ trailing: mixed.trailing,
1250
+ staticBindings: mixed.staticBindings
1251
+ };
1252
+ plans.push(plan);
1253
+ blocks.set(element, plan);
1254
+ return void 0;
1255
+ }
1256
+ }
1257
+ const conditionalChildren = /* @__PURE__ */ new Map();
1258
+ let conditionalContainer = children.length > 0;
1259
+ for (const child of children) {
1260
+ if (core.types.isJSXElement(child) && isHostElement(child)) continue;
1261
+ if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1262
+ const shape = conditionalBlockShape(child.expression);
1263
+ if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
1264
+ conditionalChildren.set(child.expression, shape);
1265
+ continue;
1266
+ }
1267
+ }
1268
+ conditionalContainer = false;
1269
+ break;
1270
+ }
1271
+ if (conditionalContainer && conditionalChildren.size > 0) {
1272
+ const id = allocateId();
1273
+ const ranges = [];
1274
+ const staticBindings = [];
1275
+ const dependencies = /* @__PURE__ */ new Set();
1276
+ let staticBefore2 = 0;
1277
+ for (const child of children) {
1278
+ if (core.types.isJSXElement(child)) {
1279
+ const nested = analyzeRecursiveHostTree(
1280
+ child,
1281
+ statesByValue,
1282
+ safeGlobals,
1283
+ listNames,
1284
+ owner,
1285
+ allocateId
1286
+ );
1287
+ if (nested.reason) return nested.reason;
1288
+ plans.push(...nested.plans);
1289
+ for (const [nestedElement, plan2] of nested.blocks) blocks.set(nestedElement, plan2);
1290
+ for (const binding of nested.bindings) {
1291
+ staticBindings.push({
1292
+ ...binding,
1293
+ segment: ranges.length,
1294
+ sibling: staticBefore2
1295
+ });
1296
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1297
+ dependencies.add(dependency);
1298
+ }
1299
+ }
1300
+ staticBefore2 += 1;
1301
+ continue;
1302
+ }
1303
+ if (!core.types.isJSXExpressionContainer(child) || core.types.isJSXEmptyExpression(child.expression)) {
1304
+ return "recursive conditional ranges contain an unsupported child";
1305
+ }
1306
+ const expression = child.expression;
1307
+ const shape = conditionalChildren.get(expression);
1308
+ const truthy = shape.truthy ? analyzeRecursiveHostTree(
1309
+ shape.truthy,
1310
+ statesByValue,
1311
+ safeGlobals,
1312
+ listNames,
1313
+ id,
1314
+ allocateId
1315
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1316
+ const falsy = shape.falsy ? analyzeRecursiveHostTree(
1317
+ shape.falsy,
1318
+ statesByValue,
1319
+ safeGlobals,
1320
+ listNames,
1321
+ id,
1322
+ allocateId
1323
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1324
+ if (truthy.reason) return truthy.reason;
1325
+ if (falsy.reason) return falsy.reason;
1326
+ plans.push(...truthy.plans, ...falsy.plans);
1327
+ for (const [nestedElement, plan2] of truthy.blocks) blocks.set(nestedElement, plan2);
1328
+ for (const [nestedElement, plan2] of falsy.blocks) blocks.set(nestedElement, plan2);
1329
+ for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
1330
+ dependencies.add(dependency);
1331
+ }
1332
+ for (const binding of [...truthy.bindings, ...falsy.bindings]) {
1333
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1334
+ dependencies.add(dependency);
1335
+ }
1336
+ }
1337
+ ranges.push({
1338
+ before: staticBefore2,
1339
+ source: expression,
1340
+ test: cloneExpression(shape.test),
1341
+ logical: shape.logical,
1342
+ truthy: shape.truthy,
1343
+ falsy: shape.falsy,
1344
+ truthyBindings: truthy.bindings,
1345
+ falsyBindings: falsy.bindings
1346
+ });
1347
+ staticBefore2 = 0;
1348
+ }
1349
+ const plan = {
1350
+ kind: "nested-host-conditional-ranges",
1351
+ id,
1352
+ parent: owner,
1353
+ dependencies: [...dependencies].sort((left, right) => left - right),
1354
+ source: element,
1355
+ ranges,
1356
+ trailing: staticBefore2,
1357
+ staticBindings
1358
+ };
1359
+ plans.push(plan);
1360
+ blocks.set(element, plan);
1361
+ return void 0;
1362
+ }
1363
+ const keyedRows = [];
1364
+ let keyedContainer = children.length > 0;
1365
+ let staticBefore = 0;
1366
+ const staticChildren = [];
1367
+ for (const child of children) {
1368
+ const range = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true);
1369
+ if (range) {
1370
+ keyedRows.push({ before: staticBefore, range });
1371
+ staticBefore = 0;
1372
+ } else if (core.types.isJSXElement(child) && isHostElement(child)) {
1373
+ staticChildren.push({
1374
+ element: child,
1375
+ segment: keyedRows.length,
1376
+ sibling: staticBefore
1377
+ });
1378
+ staticBefore += 1;
1379
+ } else {
1380
+ keyedContainer = false;
1381
+ break;
1382
+ }
1383
+ }
1384
+ if (keyedContainer && keyedRows.length > 0) {
1385
+ const id = allocateId();
1386
+ const keyedRanges = [];
1387
+ const staticBindings = [];
1388
+ const keyedDependencies = /* @__PURE__ */ new Set();
1389
+ for (const { before, range } of keyedRows) {
1390
+ if (range.events.length > 0) {
1391
+ return "recursive compiler-owned keyed rows cannot contain events";
1392
+ }
1393
+ const row = core.types.cloneNode(range.row, true);
1394
+ row.openingElement.attributes = row.openingElement.attributes.filter(
1395
+ (attribute) => !core.types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
1396
+ );
1397
+ const rowAnalysis = analyzeRecursiveHostTree(
1398
+ row,
1399
+ statesByValue,
1400
+ safeGlobals,
1401
+ listNames,
1402
+ id,
1403
+ allocateId
1404
+ );
1405
+ if (rowAnalysis.reason) return rowAnalysis.reason;
1406
+ plans.push(...rowAnalysis.plans);
1407
+ for (const [nestedElement, nestedPlan] of rowAnalysis.blocks) {
1408
+ blocks.set(nestedElement, nestedPlan);
1409
+ }
1410
+ keyedRanges.push({
1411
+ before,
1412
+ source: range.source,
1413
+ collection: range.collection,
1414
+ keyCallback: range.keyCallback,
1415
+ renderCallback: range.renderCallback,
1416
+ row,
1417
+ bindings: rowAnalysis.bindings,
1418
+ syntax: range.syntax
1419
+ });
1420
+ for (const dependency of range.dependencies) keyedDependencies.add(dependency);
1421
+ }
1422
+ for (const { element: child, segment, sibling } of staticChildren) {
1423
+ const nested = analyzeRecursiveHostTree(
1424
+ child,
1425
+ statesByValue,
1426
+ safeGlobals,
1427
+ listNames,
1428
+ owner,
1429
+ allocateId
1430
+ );
1431
+ if (nested.reason) return nested.reason;
1432
+ plans.push(...nested.plans);
1433
+ for (const [nestedElement, plan2] of nested.blocks) blocks.set(nestedElement, plan2);
1434
+ for (const binding of nested.bindings) {
1435
+ staticBindings.push({ ...binding, segment, sibling });
1436
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1437
+ keyedDependencies.add(dependency);
1438
+ }
1439
+ }
1440
+ }
1441
+ const plan = {
1442
+ kind: "nested-host-keyed-ranges",
1443
+ id,
1444
+ parent: owner,
1445
+ dependencies: [...keyedDependencies].sort((left, right) => left - right),
1446
+ source: element,
1447
+ ranges: keyedRanges,
1448
+ trailing: staticBefore,
1449
+ staticBindings
1450
+ };
1451
+ plans.push(plan);
1452
+ blocks.set(element, plan);
1453
+ return void 0;
1454
+ }
1455
+ if (element.children.some((child) => core.types.isJSXFragment(child))) {
1456
+ return "recursive compiler-owned blocks do not support fragments yet";
1457
+ }
1458
+ const nestedElements = element.children.filter(
1459
+ (child) => core.types.isJSXElement(child)
1460
+ );
1461
+ const expressions = element.children.filter(
1462
+ (child) => core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)
1463
+ );
1464
+ for (const child of expressions) {
1465
+ const unsupported = validateDerivedExpression(child.expression, safeGlobals);
1466
+ if (unsupported) return `recursive compiler-owned text cannot use ${unsupported}`;
1467
+ }
1468
+ if (nestedElements.length > 0 && expressions.length > 0) {
1469
+ return "recursive compiler-owned blocks do not support dynamic text beside nested elements";
1470
+ }
1471
+ if (nestedElements.length === 0 && expressions.length > 0) {
1472
+ const parts = [];
1473
+ for (const child of element.children) {
1474
+ if (core.types.isJSXText(child)) {
1475
+ const text = cleanJsxText(child.value);
1476
+ if (text) parts.push(core.types.stringLiteral(text));
1477
+ } else if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1478
+ parts.push(cloneExpression(child.expression));
1479
+ }
1480
+ }
1481
+ bindings.push({ kind: "text", path: [...path], value: core.types.arrayExpression(parts) });
1482
+ }
1483
+ let elementIndex = 0;
1484
+ for (const child of element.children) {
1485
+ if (!core.types.isJSXElement(child)) continue;
1486
+ const reason2 = visit(child, [...path, elementIndex], owner);
1487
+ if (reason2) return reason2;
1488
+ elementIndex += 1;
1489
+ }
1490
+ return void 0;
1491
+ };
1492
+ const reason = visit(branch, [], parent);
1493
+ return { bindings, plans, blocks, reason };
1494
+ }
1495
+ function analyzeCompilerOwnedKeyedRowHostBlocks(shape, statesByValue, safeGlobals, listNames, parent, allocateId) {
1496
+ if (shape.events.length > 0) return void 0;
1497
+ const row = core.types.cloneNode(shape.row, true);
1498
+ row.openingElement.attributes = row.openingElement.attributes.filter(
1499
+ (attribute) => !core.types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
1500
+ );
1501
+ const analysis = analyzeRecursiveHostTree(
1502
+ row,
1503
+ statesByValue,
1504
+ safeGlobals,
1505
+ listNames,
1506
+ parent,
1507
+ allocateId
1508
+ );
1509
+ if (analysis.reason || analysis.plans.length === 0) {
1510
+ return void 0;
1511
+ }
1512
+ return {
1513
+ row,
1514
+ bindings: analysis.bindings,
1515
+ descriptorBlocks: analysis.blocks,
1516
+ nestedPlans: analysis.plans
1517
+ };
1518
+ }
1519
+ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals, listNames, parent, allocateId) {
1013
1520
  const containerName = container.openingElement.name;
1014
1521
  if (!core.types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg") {
1015
1522
  return void 0;
@@ -1031,8 +1538,22 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals)
1031
1538
  }
1032
1539
  const shape = conditionalBlockShape(children[0].expression);
1033
1540
  if (!shape || validateDerivedExpression(shape.test, safeGlobals)) return void 0;
1034
- const truthyAnalysis = shape.truthy ? analyzeHostConditionalTree(shape.truthy, safeGlobals) : { bindings: [] };
1035
- const falsyAnalysis = shape.falsy ? analyzeHostConditionalTree(shape.falsy, safeGlobals) : { bindings: [] };
1541
+ const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
1542
+ shape.truthy,
1543
+ statesByValue,
1544
+ safeGlobals,
1545
+ listNames,
1546
+ parent,
1547
+ allocateId
1548
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1549
+ const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
1550
+ shape.falsy,
1551
+ statesByValue,
1552
+ safeGlobals,
1553
+ listNames,
1554
+ parent,
1555
+ allocateId
1556
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1036
1557
  if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
1037
1558
  const dependencies = new Set(collectStateDependencies(shape.test, statesByValue));
1038
1559
  for (const binding of [...truthyAnalysis.bindings || [], ...falsyAnalysis.bindings || []]) {
@@ -1047,10 +1568,12 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals)
1047
1568
  truthy: shape.truthy,
1048
1569
  falsy: shape.falsy,
1049
1570
  truthyBindings: truthyAnalysis.bindings || [],
1050
- falsyBindings: falsyAnalysis.bindings || []
1571
+ falsyBindings: falsyAnalysis.bindings || [],
1572
+ descriptorBlocks: new Map([...truthyAnalysis.blocks, ...falsyAnalysis.blocks]),
1573
+ nestedPlans: [...truthyAnalysis.plans, ...falsyAnalysis.plans]
1051
1574
  };
1052
1575
  }
1053
- function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals, allowSingleRange = false) {
1576
+ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals, allowSingleRange, listNames, parent, allocateId) {
1054
1577
  const containerName = container.openingElement.name;
1055
1578
  if (!core.types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg" || container.openingElement.attributes.some(
1056
1579
  (attribute) => core.types.isJSXSpreadAttribute(attribute) || core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
@@ -1061,14 +1584,34 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
1061
1584
  if (children.length < (allowSingleRange ? 1 : 2)) return void 0;
1062
1585
  const ranges = [];
1063
1586
  const dependencies = /* @__PURE__ */ new Set();
1587
+ const descriptorBlocks = /* @__PURE__ */ new Map();
1588
+ const nestedPlans = [];
1589
+ const staticBindings = [];
1064
1590
  let staticBefore = 0;
1065
1591
  for (const child of children) {
1066
1592
  if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1067
1593
  const shape = conditionalBlockShape(child.expression);
1068
1594
  if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
1069
- const truthyAnalysis = shape.truthy ? analyzeHostConditionalTree(shape.truthy, safeGlobals) : { bindings: [] };
1070
- const falsyAnalysis = shape.falsy ? analyzeHostConditionalTree(shape.falsy, safeGlobals) : { bindings: [] };
1595
+ const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
1596
+ shape.truthy,
1597
+ statesByValue,
1598
+ safeGlobals,
1599
+ listNames,
1600
+ parent,
1601
+ allocateId
1602
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1603
+ const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
1604
+ shape.falsy,
1605
+ statesByValue,
1606
+ safeGlobals,
1607
+ listNames,
1608
+ parent,
1609
+ allocateId
1610
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1071
1611
  if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
1612
+ nestedPlans.push(...truthyAnalysis.plans, ...falsyAnalysis.plans);
1613
+ for (const [element, plan] of truthyAnalysis.blocks) descriptorBlocks.set(element, plan);
1614
+ for (const [element, plan] of falsyAnalysis.blocks) descriptorBlocks.set(element, plan);
1072
1615
  const rangeDependencies = new Set(collectStateDependencies(shape.test, statesByValue));
1073
1616
  for (const binding of [
1074
1617
  ...truthyAnalysis.bindings || [],
@@ -1094,14 +1637,158 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
1094
1637
  }
1095
1638
  }
1096
1639
  if (!core.types.isJSXElement(child) || !isHostElement(child)) return void 0;
1097
- if (!isStaticRangeSibling(child, statesByValue, safeGlobals)) return void 0;
1640
+ const staticAnalysis = analyzeHostConditionalTree(child, safeGlobals, true, statesByValue);
1641
+ if (staticAnalysis.reason) return void 0;
1642
+ for (const binding of staticAnalysis.bindings || []) {
1643
+ staticBindings.push({
1644
+ ...binding,
1645
+ segment: ranges.length,
1646
+ sibling: staticBefore
1647
+ });
1648
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1649
+ dependencies.add(dependency);
1650
+ }
1651
+ }
1098
1652
  staticBefore += 1;
1099
1653
  }
1100
1654
  if (ranges.length === 0) return void 0;
1101
1655
  return {
1102
1656
  ranges,
1103
1657
  trailing: staticBefore,
1104
- dependencies: [...dependencies].sort((left, right) => left - right)
1658
+ dependencies: [...dependencies].sort((left, right) => left - right),
1659
+ staticBindings,
1660
+ descriptorBlocks,
1661
+ nestedPlans
1662
+ };
1663
+ }
1664
+ function analyzeMixedRangesContainer(container, statesByValue, safeGlobals, listNames, parent, allocateId) {
1665
+ const containerName = container.openingElement.name;
1666
+ if (!core.types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg" || container.openingElement.attributes.some(
1667
+ (attribute) => core.types.isJSXSpreadAttribute(attribute) || core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
1668
+ )) {
1669
+ return void 0;
1670
+ }
1671
+ const children = meaningfulJsxChildren(container);
1672
+ if (children.length < 2) return void 0;
1673
+ const ranges = [];
1674
+ const dependencies = /* @__PURE__ */ new Set();
1675
+ const descriptorBlocks = /* @__PURE__ */ new Map();
1676
+ const nestedPlans = [];
1677
+ const staticBindings = [];
1678
+ let conditionalCount = 0;
1679
+ let keyedCount = 0;
1680
+ let staticBefore = 0;
1681
+ const mergeAnalysis = (analysis) => {
1682
+ if (analysis.reason) return false;
1683
+ nestedPlans.push(...analysis.plans);
1684
+ for (const [element, plan] of analysis.blocks) descriptorBlocks.set(element, plan);
1685
+ for (const binding of analysis.bindings) {
1686
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1687
+ dependencies.add(dependency);
1688
+ }
1689
+ }
1690
+ return true;
1691
+ };
1692
+ for (const child of children) {
1693
+ if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1694
+ const shape = conditionalBlockShape(child.expression);
1695
+ if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
1696
+ const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
1697
+ shape.truthy,
1698
+ statesByValue,
1699
+ safeGlobals,
1700
+ listNames,
1701
+ parent,
1702
+ allocateId
1703
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1704
+ const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
1705
+ shape.falsy,
1706
+ statesByValue,
1707
+ safeGlobals,
1708
+ listNames,
1709
+ parent,
1710
+ allocateId
1711
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1712
+ if (!mergeAnalysis(truthyAnalysis) || !mergeAnalysis(falsyAnalysis)) return void 0;
1713
+ for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
1714
+ dependencies.add(dependency);
1715
+ }
1716
+ ranges.push({
1717
+ rangeKind: "conditional",
1718
+ before: staticBefore,
1719
+ source: child.expression,
1720
+ test: cloneExpression(shape.test),
1721
+ logical: shape.logical,
1722
+ truthy: shape.truthy,
1723
+ falsy: shape.falsy,
1724
+ truthyBindings: truthyAnalysis.bindings,
1725
+ falsyBindings: falsyAnalysis.bindings
1726
+ });
1727
+ conditionalCount += 1;
1728
+ staticBefore = 0;
1729
+ continue;
1730
+ }
1731
+ }
1732
+ const keyed = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true);
1733
+ if (keyed) {
1734
+ if (keyed.events.length > 0) return void 0;
1735
+ const row = core.types.cloneNode(keyed.row, true);
1736
+ row.openingElement.attributes = row.openingElement.attributes.filter(
1737
+ (attribute) => !core.types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
1738
+ );
1739
+ const rowAnalysis = analyzeRecursiveHostTree(
1740
+ row,
1741
+ statesByValue,
1742
+ safeGlobals,
1743
+ listNames,
1744
+ parent,
1745
+ allocateId
1746
+ );
1747
+ if (!mergeAnalysis(rowAnalysis)) return void 0;
1748
+ for (const dependency of keyed.dependencies) dependencies.add(dependency);
1749
+ ranges.push({
1750
+ rangeKind: "keyed",
1751
+ before: staticBefore,
1752
+ source: keyed.source,
1753
+ collection: keyed.collection,
1754
+ keyCallback: keyed.keyCallback,
1755
+ renderCallback: keyed.renderCallback,
1756
+ row,
1757
+ bindings: rowAnalysis.bindings,
1758
+ syntax: keyed.syntax
1759
+ });
1760
+ keyedCount += 1;
1761
+ staticBefore = 0;
1762
+ continue;
1763
+ }
1764
+ if (!core.types.isJSXElement(child) || !isHostElement(child)) return void 0;
1765
+ const staticAnalysis = analyzeRecursiveHostTree(
1766
+ child,
1767
+ statesByValue,
1768
+ safeGlobals,
1769
+ listNames,
1770
+ parent,
1771
+ allocateId
1772
+ );
1773
+ if (staticAnalysis.reason) return void 0;
1774
+ for (const binding of staticAnalysis.bindings) {
1775
+ staticBindings.push({
1776
+ ...binding,
1777
+ segment: ranges.length,
1778
+ sibling: staticBefore
1779
+ });
1780
+ }
1781
+ if (!mergeAnalysis(staticAnalysis)) return void 0;
1782
+ staticBefore += 1;
1783
+ }
1784
+ if (conditionalCount === 0 || keyedCount === 0) return void 0;
1785
+ return {
1786
+ ranges,
1787
+ trailing: staticBefore,
1788
+ dependencies: [...dependencies].sort((left, right) => left - right),
1789
+ staticBindings,
1790
+ descriptorBlocks,
1791
+ nestedPlans
1105
1792
  };
1106
1793
  }
1107
1794
  function keyedListBoundary(blockRuntime, plan, source) {
@@ -1126,14 +1813,14 @@ function keyedListBoundary(blockRuntime, plan, source) {
1126
1813
  true
1127
1814
  );
1128
1815
  }
1129
- function hostElementDescriptor(element) {
1816
+ function hostElementDescriptor(element, descriptorBlocks = /* @__PURE__ */ new Map()) {
1130
1817
  const tag = element.openingElement.name;
1131
1818
  const attributes = [];
1132
1819
  const styles = [];
1133
1820
  for (const attribute of element.openingElement.attributes) {
1134
1821
  if (!core.types.isJSXAttribute(attribute)) continue;
1135
1822
  const name = jsxAttributeName(attribute);
1136
- if (!name || name === "key" || /^on[A-Z]/.test(name)) continue;
1823
+ if (!name || name === "key" || name === "ref" || /^on[A-Z]/.test(name)) continue;
1137
1824
  if (name === "style") {
1138
1825
  if (core.types.isJSXExpressionContainer(attribute.value) && core.types.isObjectExpression(attribute.value.expression)) {
1139
1826
  for (const property of attribute.value.expression.properties) {
@@ -1157,24 +1844,93 @@ function hostElementDescriptor(element) {
1157
1844
  ])
1158
1845
  );
1159
1846
  }
1847
+ const block = descriptorBlocks.get(element);
1848
+ const conditionalBySource = /* @__PURE__ */ new Map();
1849
+ const keyedBySource = /* @__PURE__ */ new Map();
1850
+ if (block?.kind === "nested-host-conditional-ranges") {
1851
+ for (const range of block.ranges) conditionalBySource.set(range.source, range);
1852
+ } else if (block?.kind === "nested-host-keyed-ranges") {
1853
+ for (const range of block.ranges) keyedBySource.set(range.source, range);
1854
+ } else if (block?.kind === "nested-host-mixed-ranges") {
1855
+ for (const range of block.ranges) {
1856
+ if (range.rangeKind === "conditional") conditionalBySource.set(range.source, range);
1857
+ else keyedBySource.set(range.source, range);
1858
+ }
1859
+ }
1160
1860
  const children = [];
1161
1861
  for (const child of element.children) {
1162
1862
  if (core.types.isJSXText(child)) {
1163
1863
  const text = cleanJsxText(child.value);
1164
1864
  if (text) children.push(core.types.stringLiteral(text));
1165
1865
  } else if (core.types.isJSXElement(child)) {
1166
- children.push(hostElementDescriptor(child));
1866
+ const keyedRange = keyedBySource.get(child);
1867
+ if (keyedRange) {
1868
+ if (block?.kind !== "nested-host-keyed-ranges") {
1869
+ children.push(keyedRangeDescriptorChildren(keyedRange, descriptorBlocks));
1870
+ }
1871
+ } else {
1872
+ children.push(hostElementDescriptor(child, descriptorBlocks));
1873
+ }
1167
1874
  } else if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1168
- children.push(cloneExpression(child.expression));
1875
+ const conditionalRange = conditionalBySource.get(child.expression);
1876
+ const keyedRange = keyedBySource.get(child.expression);
1877
+ if (conditionalRange) {
1878
+ children.push(conditionalRangeDescriptorChild(conditionalRange, descriptorBlocks));
1879
+ } else if (keyedRange) {
1880
+ if (block?.kind !== "nested-host-keyed-ranges") {
1881
+ children.push(keyedRangeDescriptorChildren(keyedRange, descriptorBlocks));
1882
+ }
1883
+ } else {
1884
+ children.push(cloneExpression(child.expression));
1885
+ }
1169
1886
  }
1170
1887
  }
1171
- return core.types.objectExpression([
1888
+ const properties = [
1172
1889
  core.types.objectProperty(core.types.identifier("kind"), core.types.stringLiteral("element")),
1173
1890
  core.types.objectProperty(core.types.identifier("tag"), core.types.stringLiteral(tag.name)),
1174
1891
  core.types.objectProperty(core.types.identifier("attributes"), core.types.arrayExpression(attributes)),
1175
1892
  core.types.objectProperty(core.types.identifier("styles"), core.types.arrayExpression(styles)),
1176
1893
  core.types.objectProperty(core.types.identifier("children"), core.types.arrayExpression(children))
1177
- ]);
1894
+ ];
1895
+ if (block) {
1896
+ properties.push(
1897
+ core.types.objectProperty(core.types.identifier("block"), nestedHostBlockObject(block, descriptorBlocks))
1898
+ );
1899
+ }
1900
+ return core.types.objectExpression(properties);
1901
+ }
1902
+ function conditionalRangeDescriptorChild(range, descriptorBlocks) {
1903
+ const truthy = range.truthy ? hostElementDescriptor(range.truthy, descriptorBlocks) : core.types.nullLiteral();
1904
+ if (range.logical) {
1905
+ return core.types.logicalExpression("&&", cloneExpression(range.test), truthy);
1906
+ }
1907
+ return core.types.conditionalExpression(
1908
+ cloneExpression(range.test),
1909
+ truthy,
1910
+ range.falsy ? hostElementDescriptor(range.falsy, descriptorBlocks) : core.types.nullLiteral()
1911
+ );
1912
+ }
1913
+ function keyedRangeDescriptorChildren(range, descriptorBlocks) {
1914
+ const parameters = range.renderCallback.params.map(
1915
+ (parameter) => core.types.cloneNode(parameter, true)
1916
+ );
1917
+ const callback = core.types.arrowFunctionExpression(
1918
+ parameters,
1919
+ hostElementDescriptor(range.row, descriptorBlocks)
1920
+ );
1921
+ const collection = cloneExpression(range.collection);
1922
+ if (range.syntax === "map") {
1923
+ return core.types.callExpression(core.types.memberExpression(collection, core.types.identifier("map")), [callback]);
1924
+ }
1925
+ return core.types.callExpression(
1926
+ core.types.memberExpression(
1927
+ core.types.callExpression(core.types.memberExpression(core.types.identifier("Array"), core.types.identifier("from")), [
1928
+ core.types.logicalExpression("||", collection, core.types.arrayExpression([]))
1929
+ ]),
1930
+ core.types.identifier("map")
1931
+ ),
1932
+ [callback]
1933
+ );
1178
1934
  }
1179
1935
  function keyedRowBindingObject(binding, parameters) {
1180
1936
  const properties = [
@@ -1182,6 +1938,12 @@ function keyedRowBindingObject(binding, parameters) {
1182
1938
  core.types.objectProperty(
1183
1939
  core.types.identifier("path"),
1184
1940
  core.types.arrayExpression(binding.path.map((part) => core.types.numericLiteral(part)))
1941
+ ),
1942
+ core.types.objectProperty(
1943
+ core.types.identifier("dependencies"),
1944
+ core.types.arrayExpression(
1945
+ (binding.dependencies || []).map((dependency) => core.types.numericLiteral(dependency))
1946
+ )
1185
1947
  )
1186
1948
  ];
1187
1949
  if (binding.name) {
@@ -1198,6 +1960,16 @@ function keyedRowBindingObject(binding, parameters) {
1198
1960
  );
1199
1961
  return core.types.objectExpression(properties);
1200
1962
  }
1963
+ function staticRangeBindingObject(binding) {
1964
+ const value = keyedRowBindingObject(binding, []);
1965
+ value.properties.splice(
1966
+ 1,
1967
+ 0,
1968
+ core.types.objectProperty(core.types.identifier("segment"), core.types.numericLiteral(binding.segment)),
1969
+ core.types.objectProperty(core.types.identifier("sibling"), core.types.numericLiteral(binding.sibling))
1970
+ );
1971
+ return value;
1972
+ }
1201
1973
  function uniqueLocalIdentifier(base, nodes) {
1202
1974
  const names = /* @__PURE__ */ new Set();
1203
1975
  for (const node of nodes) {
@@ -1314,6 +2086,10 @@ function keyedRowEventObject(event, renderParameters) {
1314
2086
  const parameters = [core.types.cloneNode(renderParameters[0], true), index, syntheticEvent];
1315
2087
  return core.types.objectExpression([
1316
2088
  core.types.objectProperty(core.types.identifier("name"), core.types.stringLiteral(event.name)),
2089
+ core.types.objectProperty(
2090
+ core.types.identifier("path"),
2091
+ core.types.arrayExpression(event.path.map((part) => core.types.numericLiteral(part)))
2092
+ ),
1317
2093
  core.types.objectProperty(
1318
2094
  core.types.identifier("invoke"),
1319
2095
  core.types.arrowFunctionExpression(
@@ -1383,6 +2159,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
1383
2159
  plan.source,
1384
2160
  ...plan.conditionals.map((conditional) => conditional.test)
1385
2161
  ]);
2162
+ const delegatedEvents = canDelegateKeyedRowEvents(plan);
1386
2163
  const renderSource = keyedRowsRenderSource(plan, eventFactory, conditionalFactory);
1387
2164
  const renderFactoryParameters = plan.conditionals.length > 0 ? [core.types.cloneNode(eventFactory), core.types.cloneNode(conditionalFactory)] : plan.events.length > 0 ? [core.types.cloneNode(eventFactory)] : [];
1388
2165
  return core.types.jsxElement(
@@ -1400,6 +2177,14 @@ function keyedRowsBoundary(blockRuntime, plan) {
1400
2177
  core.types.jsxIdentifier("items"),
1401
2178
  core.types.jsxExpressionContainer(core.types.arrowFunctionExpression([], cloneExpression(plan.collection)))
1402
2179
  ),
2180
+ core.types.jsxAttribute(
2181
+ core.types.jsxIdentifier("structureDependencies"),
2182
+ core.types.jsxExpressionContainer(
2183
+ core.types.arrayExpression(
2184
+ plan.structureDependencies.map((dependency) => core.types.numericLiteral(dependency))
2185
+ )
2186
+ )
2187
+ ),
1403
2188
  core.types.jsxAttribute(
1404
2189
  core.types.jsxIdentifier("rowKey"),
1405
2190
  core.types.jsxExpressionContainer(core.types.cloneNode(plan.keyCallback, true))
@@ -1409,7 +2194,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
1409
2194
  core.types.jsxExpressionContainer(
1410
2195
  core.types.arrowFunctionExpression(
1411
2196
  parameters.map((parameter) => core.types.cloneNode(parameter, true)),
1412
- hostElementDescriptor(plan.row)
2197
+ hostElementDescriptor(plan.row, plan.descriptorBlocks)
1413
2198
  )
1414
2199
  )
1415
2200
  ),
@@ -1429,7 +2214,13 @@ function keyedRowsBoundary(blockRuntime, plan) {
1429
2214
  plan.events.map((event) => keyedRowEventObject(event, parameters))
1430
2215
  )
1431
2216
  )
1432
- )
2217
+ ),
2218
+ ...delegatedEvents ? [
2219
+ core.types.jsxAttribute(
2220
+ core.types.jsxIdentifier("delegateEvents"),
2221
+ core.types.jsxExpressionContainer(core.types.booleanLiteral(true))
2222
+ )
2223
+ ] : []
1433
2224
  ] : [],
1434
2225
  ...plan.conditionals.length > 0 ? [
1435
2226
  core.types.jsxAttribute(
@@ -1442,6 +2233,12 @@ function keyedRowsBoundary(blockRuntime, plan) {
1442
2233
  )
1443
2234
  )
1444
2235
  )
2236
+ ] : [],
2237
+ ...plan.descriptorBlocks?.size ? [
2238
+ core.types.jsxAttribute(
2239
+ core.types.jsxIdentifier("hostBlocks"),
2240
+ core.types.jsxExpressionContainer(core.types.booleanLiteral(true))
2241
+ )
1445
2242
  ] : []
1446
2243
  ],
1447
2244
  true
@@ -1451,7 +2248,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
1451
2248
  true
1452
2249
  );
1453
2250
  }
1454
- function keyedRangeObject(range) {
2251
+ function keyedRangeObject(range, descriptorBlocks = /* @__PURE__ */ new Map()) {
1455
2252
  const parameters = range.renderCallback.params.map(
1456
2253
  (parameter) => core.types.cloneNode(parameter, true)
1457
2254
  );
@@ -1466,7 +2263,7 @@ function keyedRangeObject(range) {
1466
2263
  core.types.identifier("create"),
1467
2264
  core.types.arrowFunctionExpression(
1468
2265
  parameters.map((parameter) => core.types.cloneNode(parameter, true)),
1469
- hostElementDescriptor(range.row)
2266
+ hostElementDescriptor(range.row, descriptorBlocks)
1470
2267
  )
1471
2268
  ),
1472
2269
  core.types.objectProperty(
@@ -1510,6 +2307,12 @@ function keyedRangesBoundary(blockRuntime, plan) {
1510
2307
  core.types.jsxAttribute(
1511
2308
  core.types.jsxIdentifier("trailing"),
1512
2309
  core.types.jsxExpressionContainer(core.types.numericLiteral(plan.trailing))
2310
+ ),
2311
+ core.types.jsxAttribute(
2312
+ core.types.jsxIdentifier("bindings"),
2313
+ core.types.jsxExpressionContainer(
2314
+ core.types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
2315
+ )
1513
2316
  )
1514
2317
  ],
1515
2318
  true
@@ -1519,11 +2322,11 @@ function keyedRangesBoundary(blockRuntime, plan) {
1519
2322
  true
1520
2323
  );
1521
2324
  }
1522
- function hostConditionalBranchObject(branch, bindings) {
2325
+ function hostConditionalBranchObject(branch, bindings, descriptorBlocks = /* @__PURE__ */ new Map()) {
1523
2326
  return core.types.objectExpression([
1524
2327
  core.types.objectProperty(
1525
2328
  core.types.identifier("create"),
1526
- core.types.arrowFunctionExpression([], hostElementDescriptor(branch))
2329
+ core.types.arrowFunctionExpression([], hostElementDescriptor(branch, descriptorBlocks))
1527
2330
  ),
1528
2331
  core.types.objectProperty(
1529
2332
  core.types.identifier("bindings"),
@@ -1552,7 +2355,9 @@ function hostConditionalBoundary(blockRuntime, plan) {
1552
2355
  attributes.push(
1553
2356
  core.types.jsxAttribute(
1554
2357
  core.types.jsxIdentifier("truthy"),
1555
- core.types.jsxExpressionContainer(hostConditionalBranchObject(plan.truthy, plan.truthyBindings))
2358
+ core.types.jsxExpressionContainer(
2359
+ hostConditionalBranchObject(plan.truthy, plan.truthyBindings, plan.descriptorBlocks)
2360
+ )
1556
2361
  )
1557
2362
  );
1558
2363
  }
@@ -1560,13 +2365,15 @@ function hostConditionalBoundary(blockRuntime, plan) {
1560
2365
  attributes.push(
1561
2366
  core.types.jsxAttribute(
1562
2367
  core.types.jsxIdentifier("falsy"),
1563
- core.types.jsxExpressionContainer(hostConditionalBranchObject(plan.falsy, plan.falsyBindings))
2368
+ core.types.jsxExpressionContainer(
2369
+ hostConditionalBranchObject(plan.falsy, plan.falsyBindings, plan.descriptorBlocks)
2370
+ )
1564
2371
  )
1565
2372
  );
1566
2373
  }
1567
2374
  return core.types.jsxElement(core.types.jsxOpeningElement(name, attributes, true), null, [], true);
1568
2375
  }
1569
- function conditionalRangeObject(range) {
2376
+ function conditionalRangeObject(range, descriptorBlocks = /* @__PURE__ */ new Map()) {
1570
2377
  const properties = [
1571
2378
  core.types.objectProperty(core.types.identifier("before"), core.types.numericLiteral(range.before)),
1572
2379
  core.types.objectProperty(
@@ -1581,7 +2388,7 @@ function conditionalRangeObject(range) {
1581
2388
  properties.push(
1582
2389
  core.types.objectProperty(
1583
2390
  core.types.identifier("truthy"),
1584
- hostConditionalBranchObject(range.truthy, range.truthyBindings)
2391
+ hostConditionalBranchObject(range.truthy, range.truthyBindings, descriptorBlocks)
1585
2392
  )
1586
2393
  );
1587
2394
  }
@@ -1589,12 +2396,78 @@ function conditionalRangeObject(range) {
1589
2396
  properties.push(
1590
2397
  core.types.objectProperty(
1591
2398
  core.types.identifier("falsy"),
1592
- hostConditionalBranchObject(range.falsy, range.falsyBindings)
2399
+ hostConditionalBranchObject(range.falsy, range.falsyBindings, descriptorBlocks)
1593
2400
  )
1594
2401
  );
1595
2402
  }
1596
2403
  return core.types.objectExpression(properties);
1597
2404
  }
2405
+ function nestedHostBlockObject(plan, descriptorBlocks) {
2406
+ const kind = plan.kind === "nested-host-conditional-ranges" ? "conditional-ranges" : plan.kind === "nested-host-keyed-ranges" ? "keyed-ranges" : "mixed-ranges";
2407
+ return core.types.objectExpression([
2408
+ core.types.objectProperty(core.types.identifier("kind"), core.types.stringLiteral(kind)),
2409
+ core.types.objectProperty(core.types.identifier("id"), core.types.numericLiteral(plan.id)),
2410
+ core.types.objectProperty(
2411
+ core.types.identifier("ranges"),
2412
+ core.types.arrayExpression(
2413
+ plan.kind === "nested-host-conditional-ranges" ? plan.ranges.map((range) => conditionalRangeObject(range, descriptorBlocks)) : plan.kind === "nested-host-keyed-ranges" ? plan.ranges.map((range) => keyedRangeObject(range, descriptorBlocks)) : plan.ranges.map((range) => mixedRangeObject(range, descriptorBlocks))
2414
+ )
2415
+ ),
2416
+ core.types.objectProperty(core.types.identifier("trailing"), core.types.numericLiteral(plan.trailing)),
2417
+ core.types.objectProperty(
2418
+ core.types.identifier("bindings"),
2419
+ core.types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
2420
+ ),
2421
+ ...plan.kind === "nested-host-keyed-ranges" ? [core.types.objectProperty(core.types.identifier("staticChildrenOnly"), core.types.booleanLiteral(true))] : []
2422
+ ]);
2423
+ }
2424
+ function mixedRangeObject(range, descriptorBlocks) {
2425
+ const value = range.rangeKind === "conditional" ? conditionalRangeObject(range, descriptorBlocks) : keyedRangeObject(range, descriptorBlocks);
2426
+ value.properties.unshift(
2427
+ core.types.objectProperty(core.types.identifier("kind"), core.types.stringLiteral(range.rangeKind))
2428
+ );
2429
+ return value;
2430
+ }
2431
+ function mixedRangesBoundary(blockRuntime, plan) {
2432
+ const name = core.types.jsxMemberExpression(
2433
+ core.types.jsxIdentifier(blockRuntime.name),
2434
+ core.types.jsxIdentifier("MixedRanges")
2435
+ );
2436
+ const source = core.types.cloneNode(plan.source, true);
2437
+ const rootRefIndex = source.openingElement.attributes.findIndex(
2438
+ (attribute) => core.types.isJSXAttribute(attribute) && jsxAttributeName(attribute) === "ref"
2439
+ );
2440
+ const rootRef = rootRefIndex >= 0 ? source.openingElement.attributes.splice(rootRefIndex, 1)[0] : void 0;
2441
+ const nestedPlan = {
2442
+ kind: "nested-host-mixed-ranges",
2443
+ id: plan.id,
2444
+ parent: plan.parent,
2445
+ dependencies: plan.dependencies,
2446
+ source: plan.source,
2447
+ ranges: plan.ranges,
2448
+ trailing: plan.trailing,
2449
+ staticBindings: plan.staticBindings
2450
+ };
2451
+ const descriptorBlocks = new Map(plan.descriptorBlocks);
2452
+ descriptorBlocks.set(plan.source, nestedPlan);
2453
+ const attributes = [
2454
+ core.types.jsxAttribute(core.types.jsxIdentifier("id"), core.types.jsxExpressionContainer(core.types.numericLiteral(plan.id))),
2455
+ core.types.jsxAttribute(
2456
+ core.types.jsxIdentifier("render"),
2457
+ core.types.jsxExpressionContainer(core.types.arrowFunctionExpression([], source))
2458
+ ),
2459
+ core.types.jsxAttribute(
2460
+ core.types.jsxIdentifier("create"),
2461
+ core.types.jsxExpressionContainer(
2462
+ core.types.arrowFunctionExpression([], hostElementDescriptor(plan.source, descriptorBlocks))
2463
+ )
2464
+ )
2465
+ ];
2466
+ if (rootRef?.value) {
2467
+ attributes.push(core.types.jsxAttribute(core.types.jsxIdentifier("rootRef"), core.types.cloneNode(rootRef.value, true)));
2468
+ }
2469
+ return core.types.jsxElement(core.types.jsxOpeningElement(name, attributes, true), null, [], true);
2470
+ }
1598
2471
  function conditionalRangesBoundary(blockRuntime, plan) {
1599
2472
  const name = core.types.jsxMemberExpression(
1600
2473
  core.types.jsxIdentifier(blockRuntime.name),
@@ -1614,12 +2487,20 @@ function conditionalRangesBoundary(blockRuntime, plan) {
1614
2487
  core.types.jsxAttribute(
1615
2488
  core.types.jsxIdentifier("ranges"),
1616
2489
  core.types.jsxExpressionContainer(
1617
- core.types.arrayExpression(plan.ranges.map((range) => conditionalRangeObject(range)))
2490
+ core.types.arrayExpression(
2491
+ plan.ranges.map((range) => conditionalRangeObject(range, plan.descriptorBlocks))
2492
+ )
1618
2493
  )
1619
2494
  ),
1620
2495
  core.types.jsxAttribute(
1621
2496
  core.types.jsxIdentifier("trailing"),
1622
2497
  core.types.jsxExpressionContainer(core.types.numericLiteral(plan.trailing))
2498
+ ),
2499
+ core.types.jsxAttribute(
2500
+ core.types.jsxIdentifier("bindings"),
2501
+ core.types.jsxExpressionContainer(
2502
+ core.types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
2503
+ )
1623
2504
  )
1624
2505
  ];
1625
2506
  if (rootRef?.value) {
@@ -1792,6 +2673,41 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1792
2673
  }
1793
2674
  if (core.types.isJSXElement(child)) {
1794
2675
  if (isHostElement(child)) {
2676
+ const mixedRangeStart = nextId;
2677
+ const mixedRangeId = nextId++;
2678
+ const mixedRanges = insideConditional ? void 0 : analyzeMixedRangesContainer(
2679
+ child,
2680
+ statesByValue,
2681
+ safeGlobals,
2682
+ listNames,
2683
+ mixedRangeId,
2684
+ () => nextId++
2685
+ );
2686
+ if (mixedRanges) {
2687
+ plans.push({
2688
+ kind: "mixed-ranges",
2689
+ id: mixedRangeId,
2690
+ parent,
2691
+ dependencies: mixedRanges.dependencies,
2692
+ source: child,
2693
+ ranges: mixedRanges.ranges,
2694
+ trailing: mixedRanges.trailing,
2695
+ staticBindings: mixedRanges.staticBindings,
2696
+ descriptorBlocks: mixedRanges.descriptorBlocks
2697
+ });
2698
+ plans.push(...mixedRanges.nestedPlans);
2699
+ for (const range of mixedRanges.ranges) {
2700
+ if (range.rangeKind === "conditional") {
2701
+ conditionalExpressions.add(range.source);
2702
+ } else if (core.types.isJSXElement(range.source)) {
2703
+ ownedElements.add(range.source);
2704
+ } else {
2705
+ keyedExpressions.add(range.source);
2706
+ }
2707
+ }
2708
+ continue;
2709
+ }
2710
+ nextId = mixedRangeStart;
1795
2711
  const keyedRanges = insideConditional ? void 0 : analyzeKeyedRangesContainer(child, statesByValue, safeGlobals, listNames);
1796
2712
  if (keyedRanges) {
1797
2713
  plans.push({
@@ -1801,7 +2717,8 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1801
2717
  dependencies: keyedRanges.dependencies,
1802
2718
  source: child,
1803
2719
  ranges: keyedRanges.ranges,
1804
- trailing: keyedRanges.trailing
2720
+ trailing: keyedRanges.trailing,
2721
+ staticBindings: keyedRanges.staticBindings
1805
2722
  });
1806
2723
  for (const range of keyedRanges.ranges) {
1807
2724
  if (core.types.isJSXElement(range.source)) ownedElements.add(range.source);
@@ -1809,58 +2726,102 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1809
2726
  }
1810
2727
  continue;
1811
2728
  }
1812
- const conditionalRanges = insideConditional ? void 0 : analyzeConditionalRangesContainer(child, statesByValue, safeGlobals);
2729
+ const conditionalRangeStart = nextId;
2730
+ const conditionalRangeId = nextId++;
2731
+ const conditionalRanges = insideConditional ? void 0 : analyzeConditionalRangesContainer(
2732
+ child,
2733
+ statesByValue,
2734
+ safeGlobals,
2735
+ false,
2736
+ listNames,
2737
+ conditionalRangeId,
2738
+ () => nextId++
2739
+ );
1813
2740
  if (conditionalRanges) {
1814
2741
  plans.push({
1815
2742
  kind: "conditional-ranges",
1816
- id: nextId++,
2743
+ id: conditionalRangeId,
1817
2744
  parent,
1818
2745
  dependencies: conditionalRanges.dependencies,
1819
2746
  source: child,
1820
2747
  ranges: conditionalRanges.ranges,
1821
- trailing: conditionalRanges.trailing
2748
+ trailing: conditionalRanges.trailing,
2749
+ staticBindings: conditionalRanges.staticBindings,
2750
+ descriptorBlocks: conditionalRanges.descriptorBlocks
1822
2751
  });
2752
+ plans.push(...conditionalRanges.nestedPlans || []);
1823
2753
  for (const range of conditionalRanges.ranges) {
1824
2754
  conditionalExpressions.add(range.source);
1825
2755
  }
1826
2756
  continue;
1827
2757
  }
2758
+ nextId = conditionalRangeStart;
2759
+ const hostConditionalStart = nextId;
2760
+ const hostConditionalId = nextId++;
1828
2761
  const hostConditional = analyzeHostConditionalContainer(
1829
2762
  child,
1830
2763
  statesByValue,
1831
- safeGlobals
2764
+ safeGlobals,
2765
+ listNames,
2766
+ hostConditionalId,
2767
+ () => nextId++
1832
2768
  );
1833
2769
  if (hostConditional) {
1834
2770
  plans.push({
1835
2771
  kind: "host-conditional",
1836
- id: nextId++,
2772
+ id: hostConditionalId,
1837
2773
  parent,
1838
2774
  source: child,
1839
2775
  ...hostConditional
1840
2776
  });
2777
+ plans.push(...hostConditional.nestedPlans || []);
1841
2778
  ownedElements.add(child);
1842
2779
  continue;
1843
2780
  }
2781
+ nextId = hostConditionalStart;
2782
+ const keyedRowsStart = nextId;
2783
+ const keyedRowsId = nextId++;
1844
2784
  const keyedRows = analyzeKeyedRowsContainer(child, statesByValue, safeGlobals, listNames);
1845
2785
  if (keyedRows) {
2786
+ const nestedStart = nextId;
2787
+ const hostBlocks = analyzeCompilerOwnedKeyedRowHostBlocks(
2788
+ keyedRows,
2789
+ statesByValue,
2790
+ safeGlobals,
2791
+ listNames,
2792
+ keyedRowsId,
2793
+ () => nextId++
2794
+ );
2795
+ if (!hostBlocks) nextId = nestedStart;
2796
+ if (keyedRows.rowReason && !hostBlocks) {
2797
+ nextId = keyedRowsStart;
2798
+ const nested2 = visitHost(child, parent, insideConditional);
2799
+ if (nested2.reason) return { dependencies, reason: nested2.reason };
2800
+ mergeDependencies(dependencies, nested2.dependencies);
2801
+ continue;
2802
+ }
1846
2803
  plans.push({
1847
2804
  kind: "keyed-rows",
1848
- id: nextId++,
2805
+ id: keyedRowsId,
1849
2806
  parent,
1850
2807
  dependencies: keyedRows.dependencies,
1851
2808
  source: child,
1852
2809
  collection: keyedRows.collection,
2810
+ structureDependencies: keyedRows.structureDependencies,
1853
2811
  keyCallback: keyedRows.keyCallback,
1854
2812
  renderCallback: keyedRows.renderCallback,
1855
- row: keyedRows.row,
1856
- bindings: keyedRows.bindings,
2813
+ row: hostBlocks?.row || keyedRows.row,
2814
+ bindings: hostBlocks?.bindings || keyedRows.bindings,
1857
2815
  events: keyedRows.events,
1858
- conditionals: keyedRows.conditionals,
2816
+ conditionals: hostBlocks ? [] : keyedRows.conditionals,
2817
+ descriptorBlocks: hostBlocks?.descriptorBlocks,
1859
2818
  syntax: keyedRows.syntax
1860
2819
  });
2820
+ plans.push(...hostBlocks?.nestedPlans || []);
1861
2821
  ownedElements.add(child);
1862
2822
  continue;
1863
2823
  }
2824
+ nextId = keyedRowsStart;
1864
2825
  const nested = visitHost(child, parent, insideConditional);
1865
2826
  if (nested.reason) return { dependencies, reason: nested.reason };
1866
2827
  mergeDependencies(dependencies, nested.dependencies);
@@ -1957,6 +2918,46 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1957
2918
  }
1958
2919
  return { dependencies };
1959
2920
  };
2921
+ const rootMixedRangeStart = nextId;
2922
+ const rootMixedRangeId = nextId++;
2923
+ const rootMixedRanges = analyzeMixedRangesContainer(
2924
+ root,
2925
+ statesByValue,
2926
+ safeGlobals,
2927
+ listNames,
2928
+ rootMixedRangeId,
2929
+ () => nextId++
2930
+ );
2931
+ if (rootMixedRanges) {
2932
+ plans.push({
2933
+ kind: "mixed-ranges",
2934
+ id: rootMixedRangeId,
2935
+ dependencies: rootMixedRanges.dependencies,
2936
+ source: root,
2937
+ ranges: rootMixedRanges.ranges,
2938
+ trailing: rootMixedRanges.trailing,
2939
+ staticBindings: rootMixedRanges.staticBindings,
2940
+ descriptorBlocks: rootMixedRanges.descriptorBlocks
2941
+ });
2942
+ plans.push(...rootMixedRanges.nestedPlans);
2943
+ for (const range of rootMixedRanges.ranges) {
2944
+ if (range.rangeKind === "conditional") {
2945
+ conditionalExpressions.add(range.source);
2946
+ } else if (core.types.isJSXElement(range.source)) {
2947
+ ownedElements.add(range.source);
2948
+ } else {
2949
+ keyedExpressions.add(range.source);
2950
+ }
2951
+ }
2952
+ return {
2953
+ plans,
2954
+ componentElements,
2955
+ conditionalExpressions,
2956
+ ownedElements,
2957
+ keyedExpressions
2958
+ };
2959
+ }
2960
+ nextId = rootMixedRangeStart;
1960
2961
  const rootRanges = analyzeKeyedRangesContainer(root, statesByValue, safeGlobals, listNames, true);
1961
2962
  if (rootRanges) {
1962
2963
  plans.push({
@@ -1965,7 +2966,8 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1965
2966
  dependencies: rootRanges.dependencies,
1966
2967
  source: root,
1967
2968
  ranges: rootRanges.ranges,
1968
- trailing: rootRanges.trailing
2969
+ trailing: rootRanges.trailing,
2970
+ staticBindings: rootRanges.staticBindings
1969
2971
  });
1970
2972
  for (const range of rootRanges.ranges) {
1971
2973
  if (core.types.isJSXElement(range.source)) ownedElements.add(range.source);
@@ -1979,21 +2981,29 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1979
2981
  keyedExpressions
1980
2982
  };
1981
2983
  }
2984
+ const rootConditionalRangeStart = nextId;
2985
+ const rootConditionalRangeId = nextId++;
1982
2986
  const rootConditionalRanges = analyzeConditionalRangesContainer(
1983
2987
  root,
1984
2988
  statesByValue,
1985
2989
  safeGlobals,
1986
- true
2990
+ true,
2991
+ listNames,
2992
+ rootConditionalRangeId,
2993
+ () => nextId++
1987
2994
  );
1988
2995
  if (rootConditionalRanges) {
1989
2996
  plans.push({
1990
2997
  kind: "conditional-ranges",
1991
- id: nextId++,
2998
+ id: rootConditionalRangeId,
1992
2999
  dependencies: rootConditionalRanges.dependencies,
1993
3000
  source: root,
1994
3001
  ranges: rootConditionalRanges.ranges,
1995
- trailing: rootConditionalRanges.trailing
3002
+ trailing: rootConditionalRanges.trailing,
3003
+ staticBindings: rootConditionalRanges.staticBindings,
3004
+ descriptorBlocks: rootConditionalRanges.descriptorBlocks
1996
3005
  });
3006
+ plans.push(...rootConditionalRanges.nestedPlans || []);
1997
3007
  for (const range of rootConditionalRanges.ranges) {
1998
3008
  conditionalExpressions.add(range.source);
1999
3009
  }
@@ -2005,6 +3015,7 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
2005
3015
  keyedExpressions
2006
3016
  };
2007
3017
  }
3018
+ nextId = rootConditionalRangeStart;
2008
3019
  const result = visitHost(root, void 0, false);
2009
3020
  if (result.reason) return { reason: result.reason };
2010
3021
  return {
@@ -2042,6 +3053,9 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
2042
3053
  plans.map((plan) => [plan.source, plan])
2043
3054
  );
2044
3055
  const rootPlan = planBySource.get(root);
3056
+ if (rootPlan?.kind === "mixed-ranges") {
3057
+ return mixedRangesBoundary(blockRuntime, rootPlan);
3058
+ }
2045
3059
  if (rootPlan?.kind === "keyed-ranges") {
2046
3060
  return keyedRangesBoundary(blockRuntime, rootPlan);
2047
3061
  }
@@ -2055,6 +3069,9 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
2055
3069
  if (plan2?.kind === "host-conditional") {
2056
3070
  return hostConditionalBoundary(blockRuntime, plan2);
2057
3071
  }
3072
+ if (plan2?.kind === "mixed-ranges") {
3073
+ return mixedRangesBoundary(blockRuntime, plan2);
3074
+ }
2058
3075
  if (plan2?.kind === "keyed-rows") {
2059
3076
  return keyedRowsBoundary(blockRuntime, plan2);
2060
3077
  }
@@ -2104,6 +3121,31 @@ function assignStableBindingTargets(bindings) {
2104
3121
  binding.target = target;
2105
3122
  }
2106
3123
  }
3124
+ function markShortCircuitBindings(bindings) {
3125
+ for (const binding of bindings) {
3126
+ if (binding.kind === "block" || binding.dependencies.length < 2) continue;
3127
+ let shortCircuits = false;
3128
+ core.traverse(expressionFile(core.types.cloneNode(binding.value, true)), {
3129
+ ConditionalExpression(path) {
3130
+ shortCircuits = true;
3131
+ path.stop();
3132
+ },
3133
+ LogicalExpression(path) {
3134
+ shortCircuits = true;
3135
+ path.stop();
3136
+ },
3137
+ OptionalCallExpression(path) {
3138
+ shortCircuits = true;
3139
+ path.stop();
3140
+ },
3141
+ OptionalMemberExpression(path) {
3142
+ shortCircuits = true;
3143
+ path.stop();
3144
+ }
3145
+ });
3146
+ if (shortCircuits) binding.tracking = "dynamic";
3147
+ }
3148
+ }
2107
3149
  function lowerStableBindingTargets(root, bindings, blockRuntime, ownedElements) {
2108
3150
  const targetByPath = /* @__PURE__ */ new Map();
2109
3151
  for (const binding of bindings) {
@@ -2373,6 +3415,9 @@ function bindingObject(binding, propsParameter, stateParameter, statesByValue, s
2373
3415
  core.types.objectProperty(core.types.identifier("target"), core.types.numericLiteral(binding.target))
2374
3416
  );
2375
3417
  }
3418
+ if (binding.tracking) {
3419
+ properties.push(core.types.objectProperty(core.types.identifier("tracking"), core.types.stringLiteral(binding.tracking)));
3420
+ }
2376
3421
  if (binding.name)
2377
3422
  properties.push(core.types.objectProperty(core.types.identifier("name"), core.types.stringLiteral(binding.name)));
2378
3423
  properties.push(
@@ -2391,7 +3436,7 @@ function wrapperElement(definitionIdentifier, props) {
2391
3436
  const attributes = props ? [core.types.jsxSpreadAttribute(core.types.cloneNode(props))] : [];
2392
3437
  return core.types.jsxElement(core.types.jsxOpeningElement(name, attributes, true), null, [], true);
2393
3438
  }
2394
- function compileCandidate(candidate, createComponentIdentifier, useStateNames, reactNames, listNames, moduleId) {
3439
+ function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureIdentifiers, usedRuntimeFeatures, useStateNames, reactNames, listNames, moduleId, reactivity) {
2395
3440
  const { path, name, statementPath } = candidate;
2396
3441
  if (path.node.async || path.node.generator)
2397
3442
  return "async and generator components are not supported";
@@ -2508,8 +3553,34 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2508
3553
  );
2509
3554
  const setterReason = validateSetterUsage(expandedRoot, statesBySetter);
2510
3555
  if (setterReason) return setterReason;
3556
+ const referencedPropNames = collectDestructuredPropNames(
3557
+ expandedRoot,
3558
+ propsPlan.destructuredNames,
3559
+ propsPlan.definitionParameter
3560
+ );
3561
+ let propBindings = referencedPropNames.has("children") ? [] : [...propsPlan.destructuredNames].filter((propName) => referencedPropNames.has(propName)).map(
3562
+ (localName, propIndex) => ({
3563
+ localName,
3564
+ valueName: path.scope.generateUidIdentifier(`farmProp${propIndex}`).name,
3565
+ index: states.length + propIndex
3566
+ })
3567
+ );
3568
+ const propBindingsByName = new Map(propBindings.map((binding) => [binding.localName, binding]));
3569
+ let reactiveByValue = new Map(statesByValue);
3570
+ for (const binding of propBindings) {
3571
+ reactiveByValue.set(binding.valueName, {
3572
+ valueName: binding.valueName,
3573
+ setterName: "",
3574
+ index: binding.index
3575
+ });
3576
+ }
3577
+ let expandedReactiveRoot = rewriteTrackedPropAccess(
3578
+ expandedRoot,
3579
+ propsPlan.definitionParameter,
3580
+ propBindingsByName
3581
+ );
2511
3582
  const referencedComponentNames = /* @__PURE__ */ new Set();
2512
- core.traverse(expressionFile(core.types.cloneNode(expandedRoot, true)), {
3583
+ core.traverse(expressionFile(core.types.cloneNode(expandedReactiveRoot, true)), {
2513
3584
  JSXOpeningElement(componentPath) {
2514
3585
  const componentName = componentPath.node.name;
2515
3586
  if (core.types.isJSXIdentifier(componentName) && isComponentName(componentName.name)) {
@@ -2526,32 +3597,55 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2526
3597
  );
2527
3598
  })
2528
3599
  );
2529
- const blockAnalysis = analyzeComposableBlocks(
2530
- expandedRoot,
2531
- statesByValue,
3600
+ let blockAnalysis = analyzeComposableBlocks(
3601
+ expandedReactiveRoot,
3602
+ reactiveByValue,
2532
3603
  safeGlobals,
2533
3604
  listNames,
2534
3605
  allowedComponentNames
2535
3606
  );
2536
- if (blockAnalysis.reason) return blockAnalysis.reason;
2537
- const blockPlans = blockAnalysis.plans || [];
2538
- const analysis = analyzeHostTree(
2539
- expandedRoot,
2540
- statesByValue,
3607
+ let analysis = analyzeHostTree(
3608
+ expandedReactiveRoot,
3609
+ reactiveByValue,
2541
3610
  safeGlobals,
2542
3611
  blockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
2543
3612
  blockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
2544
3613
  blockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
2545
3614
  blockAnalysis.componentElements || /* @__PURE__ */ new Set()
2546
3615
  );
3616
+ if (propBindings.length > 0 && (blockAnalysis.reason || analysis.reason)) {
3617
+ propBindings = [];
3618
+ reactiveByValue = new Map(statesByValue);
3619
+ expandedReactiveRoot = core.types.cloneNode(expandedRoot, true);
3620
+ blockAnalysis = analyzeComposableBlocks(
3621
+ expandedReactiveRoot,
3622
+ reactiveByValue,
3623
+ safeGlobals,
3624
+ listNames,
3625
+ allowedComponentNames
3626
+ );
3627
+ analysis = analyzeHostTree(
3628
+ expandedReactiveRoot,
3629
+ reactiveByValue,
3630
+ safeGlobals,
3631
+ blockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
3632
+ blockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
3633
+ blockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
3634
+ blockAnalysis.componentElements || /* @__PURE__ */ new Set()
3635
+ );
3636
+ }
3637
+ if (blockAnalysis.reason) return blockAnalysis.reason;
2547
3638
  if (analysis.reason) return analysis.reason;
3639
+ const blockPlans = blockAnalysis.plans || [];
3640
+ const runtimeFeatures = runtimeFeaturesForPlans(blockPlans);
3641
+ markShortCircuitBindings(analysis.bindings || []);
2548
3642
  assignStableBindingTargets(analysis.bindings || []);
2549
3643
  const stateParameter = path.scope.generateUidIdentifier("farmState");
2550
3644
  const blockParameter = path.scope.generateUidIdentifier("farmBlocks");
2551
3645
  const definitionIdentifier = path.scope.generateUidIdentifier(`${name}Compiled`);
2552
3646
  const propsParameter = propsPlan.definitionParameter;
2553
3647
  const rootWithTargets = lowerStableBindingTargets(
2554
- expandedRoot,
3648
+ expandedReactiveRoot,
2555
3649
  analysis.bindings || [],
2556
3650
  blockParameter,
2557
3651
  blockAnalysis.ownedElements || /* @__PURE__ */ new Set()
@@ -2565,12 +3659,13 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2565
3659
  const rewrittenRoot = rewriteStateAccess(
2566
3660
  rootWithBlocks,
2567
3661
  stateParameter,
2568
- statesByValue,
3662
+ reactiveByValue,
2569
3663
  statesBySetter
2570
3664
  );
2571
3665
  const definition = core.types.callExpression(core.types.cloneNode(createComponentIdentifier), [
2572
3666
  core.types.objectExpression([
2573
3667
  core.types.objectProperty(core.types.identifier("displayName"), core.types.stringLiteral(name)),
3668
+ core.types.objectProperty(core.types.identifier("reactivity"), core.types.stringLiteral(reactivity)),
2574
3669
  core.types.spreadElement(
2575
3670
  core.types.conditionalExpression(
2576
3671
  core.types.memberExpression(
@@ -2581,7 +3676,9 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2581
3676
  core.types.objectProperty(core.types.identifier("hmrId"), core.types.stringLiteral(`${moduleId}#${name}`)),
2582
3677
  core.types.objectProperty(
2583
3678
  core.types.identifier("stateSignature"),
2584
- core.types.stringLiteral(String(states.length))
3679
+ core.types.stringLiteral(
3680
+ propBindings.length === 0 ? String(states.length) : `${states.length}:${propBindings.map((binding) => binding.localName).join(",")}`
3681
+ )
2585
3682
  )
2586
3683
  ]),
2587
3684
  core.types.objectExpression([])
@@ -2604,6 +3701,22 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2604
3701
  )
2605
3702
  )
2606
3703
  ),
3704
+ ...propBindings.length > 0 ? [
3705
+ core.types.objectProperty(
3706
+ core.types.identifier("readProps"),
3707
+ core.types.arrowFunctionExpression(
3708
+ [core.types.cloneNode(propsParameter)],
3709
+ core.types.arrayExpression(
3710
+ propBindings.map(
3711
+ (binding) => core.types.memberExpression(
3712
+ core.types.cloneNode(propsParameter),
3713
+ core.types.identifier(binding.localName)
3714
+ )
3715
+ )
3716
+ )
3717
+ )
3718
+ )
3719
+ ] : [],
2607
3720
  core.types.objectProperty(
2608
3721
  core.types.identifier("render"),
2609
3722
  core.types.arrowFunctionExpression(
@@ -2623,11 +3736,14 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2623
3736
  dependencies: block.dependencies
2624
3737
  }))
2625
3738
  ].map(
2626
- (binding) => bindingObject(binding, propsParameter, stateParameter, statesByValue, statesBySetter)
3739
+ (binding) => bindingObject(binding, propsParameter, stateParameter, reactiveByValue, statesBySetter)
2627
3740
  )
2628
3741
  )
2629
3742
  )
2630
- ])
3743
+ ]),
3744
+ core.types.arrayExpression(
3745
+ runtimeFeatures.map((feature) => core.types.cloneNode(runtimeFeatureIdentifiers.get(feature)))
3746
+ )
2631
3747
  ]);
2632
3748
  path.get("body").replaceWith(
2633
3749
  core.types.blockStatement([
@@ -2637,6 +3753,7 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2637
3753
  statementPath.insertAfter(
2638
3754
  core.types.variableDeclaration("const", [core.types.variableDeclarator(definitionIdentifier, definition)])
2639
3755
  );
3756
+ for (const feature of runtimeFeatures) usedRuntimeFeatures.add(feature);
2640
3757
  return void 0;
2641
3758
  }
2642
3759
  function collectCandidates(programPath) {
@@ -2704,6 +3821,13 @@ async function compileReactModule(code, id, options) {
2704
3821
  }
2705
3822
  const candidates = collectCandidates(programPath);
2706
3823
  const createComponentIdentifier = programPath.scope.generateUidIdentifier("createCompiledComponent");
3824
+ const runtimeFeatureIdentifiers = new Map(
3825
+ Object.entries(COMPILER_RUNTIME_FEATURE_EXPORTS).map(([feature, exportName]) => [
3826
+ feature,
3827
+ programPath.scope.generateUidIdentifier(exportName)
3828
+ ])
3829
+ );
3830
+ const usedRuntimeFeatures = /* @__PURE__ */ new Set();
2707
3831
  for (const candidate of candidates) {
2708
3832
  const functionDirectives = new Set(
2709
3833
  core.types.isBlockStatement(candidate.path.node.body) ? directiveValues(candidate.path.node.body) : []
@@ -2714,10 +3838,13 @@ async function compileReactModule(code, id, options) {
2714
3838
  const reason = compileCandidate(
2715
3839
  candidate,
2716
3840
  createComponentIdentifier,
3841
+ runtimeFeatureIdentifiers,
3842
+ usedRuntimeFeatures,
2717
3843
  useStateNames,
2718
3844
  reactNames,
2719
3845
  listNames,
2720
- id
3846
+ id,
3847
+ options.reactivity
2721
3848
  );
2722
3849
  if (reason) {
2723
3850
  diagnostics.push({
@@ -2736,7 +3863,13 @@ async function compileReactModule(code, id, options) {
2736
3863
  [
2737
3864
  core.types.importSpecifier(
2738
3865
  createComponentIdentifier,
2739
- core.types.identifier("createCompiledComponent")
3866
+ core.types.identifier("createCompiledComponentWithFeatures")
3867
+ ),
3868
+ ...[...usedRuntimeFeatures].sort().map(
3869
+ (feature) => core.types.importSpecifier(
3870
+ core.types.cloneNode(runtimeFeatureIdentifiers.get(feature)),
3871
+ core.types.identifier(COMPILER_RUNTIME_FEATURE_EXPORTS[feature])
3872
+ )
2740
3873
  )
2741
3874
  ],
2742
3875
  core.types.stringLiteral("@farm.js/react/compiler-runtime")
@@ -2844,6 +3977,10 @@ function normalizeReactCompilerOptions(value) {
2844
3977
  if (!["fallback", "warn", "error"].includes(onUnsupported)) {
2845
3978
  throw new TypeError(`Unknown unsupported-component behavior: ${String(onUnsupported)}`);
2846
3979
  }
3980
+ const reactivity = options.reactivity || "hybrid";
3981
+ if (reactivity !== "static" && reactivity !== "hybrid") {
3982
+ throw new TypeError(`Unknown React compiler reactivity mode: ${String(reactivity)}`);
3983
+ }
2847
3984
  if (options.report !== void 0 && typeof options.report !== "boolean") {
2848
3985
  throw new TypeError("The React compiler report option must be a boolean.");
2849
3986
  }
@@ -2854,7 +3991,7 @@ function normalizeReactCompilerOptions(value) {
2854
3991
  }
2855
3992
  const reportFile = normalizeCompilerReportFile(options.reportFile);
2856
3993
  const report = options.report === true || options.reportFile !== void 0;
2857
- return { mode, directive, onUnsupported, report, reportFile };
3994
+ return { mode, directive, onUnsupported, reactivity, report, reportFile };
2858
3995
  }
2859
3996
 
2860
3997
  // src/vite.ts
@@ -2870,7 +4007,7 @@ function readCompilerOptions(rendererOptions) {
2870
4007
  );
2871
4008
  }
2872
4009
  const normalized = compiler;
2873
- if ((normalized.mode === "infer" || normalized.mode === "annotation") && typeof normalized.directive === "string" && (normalized.onUnsupported === "fallback" || normalized.onUnsupported === "warn" || normalized.onUnsupported === "error")) {
4010
+ if ((normalized.mode === "infer" || normalized.mode === "annotation") && typeof normalized.directive === "string" && (normalized.reactivity === "static" || normalized.reactivity === "hybrid") && (normalized.onUnsupported === "fallback" || normalized.onUnsupported === "warn" || normalized.onUnsupported === "error")) {
2874
4011
  return normalized;
2875
4012
  }
2876
4013
  return normalizeReactCompilerOptions(compiler);