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

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,62 @@ 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
+ }
9
65
  var SAFE_GLOBAL_CALLS = /* @__PURE__ */ new Set(["Boolean", "Number", "String"]);
10
66
  var SAFE_MATH_CALLS = /* @__PURE__ */ new Set(["abs", "ceil", "floor", "max", "min", "round", "sign", "trunc"]);
11
67
  function isComponentName(name) {
@@ -90,6 +146,37 @@ function rewriteDestructuredPropAccess(expression, names, propsParameter) {
90
146
  });
91
147
  return file.program.body[0].expression;
92
148
  }
149
+ function collectDestructuredPropNames(expression, names, propsParameter) {
150
+ const referenced = /* @__PURE__ */ new Set();
151
+ if (names.size === 0) return referenced;
152
+ core.traverse(expressionFile(cloneExpression(expression)), {
153
+ MemberExpression(path) {
154
+ const { object, property, computed } = path.node;
155
+ if (computed || !core.types.isIdentifier(object, { name: propsParameter.name }) || !core.types.isIdentifier(property) || !names.has(property.name)) {
156
+ return;
157
+ }
158
+ referenced.add(property.name);
159
+ }
160
+ });
161
+ return referenced;
162
+ }
163
+ function rewriteTrackedPropAccess(expression, propsParameter, bindingsByName) {
164
+ if (bindingsByName.size === 0) return cloneExpression(expression);
165
+ const file = expressionFile(cloneExpression(expression));
166
+ core.traverse(file, {
167
+ MemberExpression(path) {
168
+ const { object, property, computed } = path.node;
169
+ if (computed || !core.types.isIdentifier(object, { name: propsParameter.name }) || !core.types.isIdentifier(property)) {
170
+ return;
171
+ }
172
+ const binding = bindingsByName.get(property.name);
173
+ if (!binding) return;
174
+ path.replaceWith(core.types.identifier(binding.valueName));
175
+ path.skip();
176
+ }
177
+ });
178
+ return file.program.body[0].expression;
179
+ }
93
180
  function rewriteHandlerAccess(root, handlersByName) {
94
181
  if (handlersByName.size === 0) return { root: core.types.cloneNode(root, true) };
95
182
  const file = expressionFile(core.types.cloneNode(root, true));
@@ -769,7 +856,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
769
856
  const reason = visit(row, []);
770
857
  return reason ? { reason } : { bindings, events, conditionals };
771
858
  }
772
- function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames) {
859
+ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acceptUnsupportedRow = false) {
773
860
  let collection;
774
861
  let keyCallback;
775
862
  let renderCallback;
@@ -824,17 +911,29 @@ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames) {
824
911
  safeGlobals,
825
912
  new Set([...statesByValue.values()].map((state) => state.setterName))
826
913
  );
827
- if (rowAnalysis.reason) return void 0;
914
+ if (rowAnalysis.reason && !acceptUnsupportedRow) return void 0;
915
+ const keyExpression = returnedExpression(keyCallback);
916
+ const structureDependencies = new Set(collectStateDependencies(collection, statesByValue));
917
+ if (keyExpression) {
918
+ for (const dependency of collectStateDependencies(keyExpression, statesByValue)) {
919
+ structureDependencies.add(dependency);
920
+ }
921
+ }
828
922
  return {
829
923
  source,
830
924
  collection,
925
+ structureDependencies: [...structureDependencies].sort((left, right) => left - right),
831
926
  keyCallback,
832
927
  renderCallback,
833
928
  row,
834
929
  dependencies,
835
- bindings: rowAnalysis.bindings || [],
930
+ bindings: (rowAnalysis.bindings || []).map((binding) => ({
931
+ ...binding,
932
+ dependencies: collectStateDependencies(binding.value, statesByValue)
933
+ })),
836
934
  events: rowAnalysis.events || [],
837
935
  conditionals: rowAnalysis.conditionals || [],
936
+ rowReason: rowAnalysis.reason,
838
937
  syntax
839
938
  };
840
939
  }
@@ -851,22 +950,7 @@ function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNa
851
950
  }
852
951
  const children = meaningfulJsxChildren(container);
853
952
  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;
953
+ return analyzeKeyedRowChild(children[0], statesByValue, safeGlobals, listNames, true);
870
954
  }
871
955
  function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, listNames, allowSingleRange = false) {
872
956
  if (container.openingElement.attributes.some(
@@ -878,6 +962,7 @@ function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, list
878
962
  if (children.length < (allowSingleRange ? 1 : 2)) return void 0;
879
963
  const ranges = [];
880
964
  const dependencies = /* @__PURE__ */ new Set();
965
+ const staticBindings = [];
881
966
  let staticBefore = 0;
882
967
  for (const child of children) {
883
968
  const range = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames);
@@ -898,18 +983,31 @@ function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, list
898
983
  continue;
899
984
  }
900
985
  if (!core.types.isJSXElement(child) || !isHostElement(child)) return void 0;
901
- if (!isStaticRangeSibling(child, statesByValue, safeGlobals)) return void 0;
986
+ const analysis = analyzeHostConditionalTree(child, safeGlobals, true, statesByValue);
987
+ if (analysis.reason) return void 0;
988
+ for (const binding of analysis.bindings || []) {
989
+ staticBindings.push({
990
+ ...binding,
991
+ segment: ranges.length,
992
+ sibling: staticBefore
993
+ });
994
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
995
+ dependencies.add(dependency);
996
+ }
997
+ }
902
998
  staticBefore += 1;
903
999
  }
904
1000
  if (ranges.length === 0) return void 0;
905
1001
  return {
906
1002
  ranges,
907
1003
  trailing: staticBefore,
908
- dependencies: [...dependencies].sort((left, right) => left - right)
1004
+ dependencies: [...dependencies].sort((left, right) => left - right),
1005
+ staticBindings
909
1006
  };
910
1007
  }
911
- function analyzeHostConditionalTree(branch, safeGlobals) {
1008
+ function analyzeHostConditionalTree(branch, safeGlobals, allowStaticEvents = false, statefulOnly) {
912
1009
  const bindings = [];
1010
+ const needsStaticBinding = (expression) => !statefulOnly || collectStateDependencies(expression, statefulOnly).length > 0;
913
1011
  const visit = (element, path) => {
914
1012
  const tag = element.openingElement.name;
915
1013
  if (!core.types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
@@ -918,20 +1016,26 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
918
1016
  if (tag.name === "svg") return "compiler-owned conditionals do not support SVG yet";
919
1017
  for (const attribute of element.openingElement.attributes) {
920
1018
  if (core.types.isJSXSpreadAttribute(attribute)) {
1019
+ if (statefulOnly && !needsStaticBinding(attribute.argument)) continue;
921
1020
  return "compiler-owned conditionals do not support JSX attribute spreads";
922
1021
  }
923
1022
  const name = jsxAttributeName(attribute);
924
1023
  if (!name) return "compiler-owned conditionals do not support namespaced JSX attributes";
925
1024
  if (name === "ref" || name === "dangerouslySetInnerHTML" || name === "key") {
1025
+ if (statefulOnly && (!core.types.isJSXExpressionContainer(attribute.value) || core.types.isJSXEmptyExpression(attribute.value.expression) || !needsStaticBinding(attribute.value.expression))) {
1026
+ continue;
1027
+ }
926
1028
  return `compiler-owned conditional ${name} requires React ownership`;
927
1029
  }
928
1030
  if (/^on[A-Z]/.test(name)) {
1031
+ if (allowStaticEvents) continue;
929
1032
  return "compiler-owned conditional events require React ownership";
930
1033
  }
931
1034
  if (!core.types.isJSXExpressionContainer(attribute.value) || core.types.isJSXEmptyExpression(attribute.value.expression)) {
932
1035
  continue;
933
1036
  }
934
1037
  const expression = attribute.value.expression;
1038
+ if (!needsStaticBinding(expression)) continue;
935
1039
  if (name === "style") {
936
1040
  if (!core.types.isObjectExpression(expression)) {
937
1041
  return "compiler-owned conditional styles must use one inline object literal";
@@ -944,6 +1048,7 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
944
1048
  if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
945
1049
  return "compiler-owned conditional style names must use camelCase or a CSS custom property";
946
1050
  }
1051
+ if (!needsStaticBinding(property.value)) continue;
947
1052
  const unsupported2 = validateDerivedExpression(property.value, safeGlobals);
948
1053
  if (unsupported2) {
949
1054
  return `compiler-owned conditional style ${propertyName} cannot use ${unsupported2}`;
@@ -978,14 +1083,20 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
978
1083
  const expressions = element.children.filter(
979
1084
  (child) => core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)
980
1085
  );
981
- for (const child of expressions) {
982
- const unsupported = validateDerivedExpression(child.expression, safeGlobals);
983
- if (unsupported) return `compiler-owned conditional text cannot use ${unsupported}`;
1086
+ const boundExpressions = statefulOnly ? expressions.filter((child) => needsStaticBinding(child.expression)) : expressions;
1087
+ if (boundExpressions.length > 0) {
1088
+ for (const child of expressions) {
1089
+ const unsupported = validateDerivedExpression(
1090
+ child.expression,
1091
+ safeGlobals
1092
+ );
1093
+ if (unsupported) return `compiler-owned conditional text cannot use ${unsupported}`;
1094
+ }
984
1095
  }
985
- if (nestedElements.length > 0 && expressions.length > 0) {
1096
+ if (nestedElements.length > 0 && boundExpressions.length > 0) {
986
1097
  return "compiler-owned conditionals do not support dynamic text beside nested elements yet";
987
1098
  }
988
- if (nestedElements.length === 0 && expressions.length > 0) {
1099
+ if (nestedElements.length === 0 && boundExpressions.length > 0) {
989
1100
  const parts = [];
990
1101
  for (const child of element.children) {
991
1102
  if (core.types.isJSXText(child)) {
@@ -1009,7 +1120,369 @@ function analyzeHostConditionalTree(branch, safeGlobals) {
1009
1120
  const reason = visit(branch, []);
1010
1121
  return reason ? { reason } : { bindings };
1011
1122
  }
1012
- function analyzeHostConditionalContainer(container, statesByValue, safeGlobals) {
1123
+ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames, parent, allocateId) {
1124
+ const bindings = [];
1125
+ const plans = [];
1126
+ const blocks = /* @__PURE__ */ new Map();
1127
+ const visit = (element, path, owner) => {
1128
+ const tag = element.openingElement.name;
1129
+ if (!core.types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
1130
+ return "recursive compiler-owned blocks support host elements only";
1131
+ }
1132
+ if (tag.name === "svg") return "recursive compiler-owned blocks do not support SVG yet";
1133
+ for (const attribute of element.openingElement.attributes) {
1134
+ if (core.types.isJSXSpreadAttribute(attribute)) {
1135
+ return "recursive compiler-owned blocks do not support JSX attribute spreads";
1136
+ }
1137
+ const name = jsxAttributeName(attribute);
1138
+ if (!name) return "recursive compiler-owned blocks do not support namespaced attributes";
1139
+ if (name === "ref" || name === "dangerouslySetInnerHTML" || name === "key") {
1140
+ return `recursive compiler-owned block ${name} requires React ownership`;
1141
+ }
1142
+ if (/^on[A-Z]/.test(name)) {
1143
+ return "recursive compiler-owned block events require React ownership";
1144
+ }
1145
+ if (!core.types.isJSXExpressionContainer(attribute.value) || core.types.isJSXEmptyExpression(attribute.value.expression)) {
1146
+ continue;
1147
+ }
1148
+ const expression = attribute.value.expression;
1149
+ if (name === "style") {
1150
+ if (!core.types.isObjectExpression(expression)) {
1151
+ return "recursive compiler-owned styles must use one inline object literal";
1152
+ }
1153
+ for (const property of expression.properties) {
1154
+ if (!core.types.isObjectProperty(property) || property.computed || !core.types.isExpression(property.value)) {
1155
+ return "recursive compiler-owned styles do not support spreads, methods, or computed properties";
1156
+ }
1157
+ const propertyName = core.types.isIdentifier(property.key) ? property.key.name : core.types.isStringLiteral(property.key) ? property.key.value : void 0;
1158
+ if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
1159
+ return "recursive compiler-owned style names must use camelCase or a CSS custom property";
1160
+ }
1161
+ const unsupported2 = validateDerivedExpression(property.value, safeGlobals);
1162
+ if (unsupported2) {
1163
+ return `recursive compiler-owned style ${propertyName} cannot use ${unsupported2}`;
1164
+ }
1165
+ bindings.push({
1166
+ kind: "style",
1167
+ path: [...path],
1168
+ name: propertyName,
1169
+ value: cloneExpression(property.value)
1170
+ });
1171
+ }
1172
+ continue;
1173
+ }
1174
+ if (name === "children") {
1175
+ return "recursive compiler-owned children props are not supported yet";
1176
+ }
1177
+ const unsupported = validateDerivedExpression(expression, safeGlobals);
1178
+ if (unsupported) return `recursive compiler-owned ${name} cannot use ${unsupported}`;
1179
+ bindings.push({
1180
+ kind: "attribute",
1181
+ path: [...path],
1182
+ name,
1183
+ value: cloneExpression(expression)
1184
+ });
1185
+ }
1186
+ const children = meaningfulJsxChildren(element);
1187
+ const hasConditionalRange = children.some(
1188
+ (child) => core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression) && conditionalBlockShape(child.expression) !== null
1189
+ );
1190
+ const hasKeyedRange = children.some(
1191
+ (child) => analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true) !== void 0
1192
+ );
1193
+ if (hasConditionalRange && hasKeyedRange) {
1194
+ const id = allocateId();
1195
+ const mixed = analyzeMixedRangesContainer(
1196
+ element,
1197
+ statesByValue,
1198
+ safeGlobals,
1199
+ listNames,
1200
+ id,
1201
+ allocateId
1202
+ );
1203
+ if (mixed) {
1204
+ plans.push(...mixed.nestedPlans);
1205
+ for (const [nestedElement, plan2] of mixed.descriptorBlocks) {
1206
+ blocks.set(nestedElement, plan2);
1207
+ }
1208
+ const plan = {
1209
+ kind: "nested-host-mixed-ranges",
1210
+ id,
1211
+ parent: owner,
1212
+ dependencies: mixed.dependencies,
1213
+ source: element,
1214
+ ranges: mixed.ranges,
1215
+ trailing: mixed.trailing,
1216
+ staticBindings: mixed.staticBindings
1217
+ };
1218
+ plans.push(plan);
1219
+ blocks.set(element, plan);
1220
+ return void 0;
1221
+ }
1222
+ }
1223
+ const conditionalChildren = /* @__PURE__ */ new Map();
1224
+ let conditionalContainer = children.length > 0;
1225
+ for (const child of children) {
1226
+ if (core.types.isJSXElement(child) && isHostElement(child)) continue;
1227
+ if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1228
+ const shape = conditionalBlockShape(child.expression);
1229
+ if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
1230
+ conditionalChildren.set(child.expression, shape);
1231
+ continue;
1232
+ }
1233
+ }
1234
+ conditionalContainer = false;
1235
+ break;
1236
+ }
1237
+ if (conditionalContainer && conditionalChildren.size > 0) {
1238
+ const id = allocateId();
1239
+ const ranges = [];
1240
+ const staticBindings = [];
1241
+ const dependencies = /* @__PURE__ */ new Set();
1242
+ let staticBefore2 = 0;
1243
+ for (const child of children) {
1244
+ if (core.types.isJSXElement(child)) {
1245
+ const nested = analyzeRecursiveHostTree(
1246
+ child,
1247
+ statesByValue,
1248
+ safeGlobals,
1249
+ listNames,
1250
+ owner,
1251
+ allocateId
1252
+ );
1253
+ if (nested.reason) return nested.reason;
1254
+ plans.push(...nested.plans);
1255
+ for (const [nestedElement, plan2] of nested.blocks) blocks.set(nestedElement, plan2);
1256
+ for (const binding of nested.bindings) {
1257
+ staticBindings.push({
1258
+ ...binding,
1259
+ segment: ranges.length,
1260
+ sibling: staticBefore2
1261
+ });
1262
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1263
+ dependencies.add(dependency);
1264
+ }
1265
+ }
1266
+ staticBefore2 += 1;
1267
+ continue;
1268
+ }
1269
+ if (!core.types.isJSXExpressionContainer(child) || core.types.isJSXEmptyExpression(child.expression)) {
1270
+ return "recursive conditional ranges contain an unsupported child";
1271
+ }
1272
+ const expression = child.expression;
1273
+ const shape = conditionalChildren.get(expression);
1274
+ const truthy = shape.truthy ? analyzeRecursiveHostTree(
1275
+ shape.truthy,
1276
+ statesByValue,
1277
+ safeGlobals,
1278
+ listNames,
1279
+ id,
1280
+ allocateId
1281
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1282
+ const falsy = shape.falsy ? analyzeRecursiveHostTree(
1283
+ shape.falsy,
1284
+ statesByValue,
1285
+ safeGlobals,
1286
+ listNames,
1287
+ id,
1288
+ allocateId
1289
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1290
+ if (truthy.reason) return truthy.reason;
1291
+ if (falsy.reason) return falsy.reason;
1292
+ plans.push(...truthy.plans, ...falsy.plans);
1293
+ for (const [nestedElement, plan2] of truthy.blocks) blocks.set(nestedElement, plan2);
1294
+ for (const [nestedElement, plan2] of falsy.blocks) blocks.set(nestedElement, plan2);
1295
+ for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
1296
+ dependencies.add(dependency);
1297
+ }
1298
+ for (const binding of [...truthy.bindings, ...falsy.bindings]) {
1299
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1300
+ dependencies.add(dependency);
1301
+ }
1302
+ }
1303
+ ranges.push({
1304
+ before: staticBefore2,
1305
+ source: expression,
1306
+ test: cloneExpression(shape.test),
1307
+ logical: shape.logical,
1308
+ truthy: shape.truthy,
1309
+ falsy: shape.falsy,
1310
+ truthyBindings: truthy.bindings,
1311
+ falsyBindings: falsy.bindings
1312
+ });
1313
+ staticBefore2 = 0;
1314
+ }
1315
+ const plan = {
1316
+ kind: "nested-host-conditional-ranges",
1317
+ id,
1318
+ parent: owner,
1319
+ dependencies: [...dependencies].sort((left, right) => left - right),
1320
+ source: element,
1321
+ ranges,
1322
+ trailing: staticBefore2,
1323
+ staticBindings
1324
+ };
1325
+ plans.push(plan);
1326
+ blocks.set(element, plan);
1327
+ return void 0;
1328
+ }
1329
+ const keyedRows = [];
1330
+ let keyedContainer = children.length > 0;
1331
+ let staticBefore = 0;
1332
+ const staticChildren = [];
1333
+ for (const child of children) {
1334
+ const range = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true);
1335
+ if (range) {
1336
+ keyedRows.push({ before: staticBefore, range });
1337
+ staticBefore = 0;
1338
+ } else if (core.types.isJSXElement(child) && isHostElement(child)) {
1339
+ staticChildren.push({
1340
+ element: child,
1341
+ segment: keyedRows.length,
1342
+ sibling: staticBefore
1343
+ });
1344
+ staticBefore += 1;
1345
+ } else {
1346
+ keyedContainer = false;
1347
+ break;
1348
+ }
1349
+ }
1350
+ if (keyedContainer && keyedRows.length > 0) {
1351
+ const id = allocateId();
1352
+ const keyedRanges = [];
1353
+ const staticBindings = [];
1354
+ const keyedDependencies = /* @__PURE__ */ new Set();
1355
+ for (const { before, range } of keyedRows) {
1356
+ if (range.events.length > 0) {
1357
+ return "recursive compiler-owned keyed rows cannot contain events";
1358
+ }
1359
+ const row = core.types.cloneNode(range.row, true);
1360
+ row.openingElement.attributes = row.openingElement.attributes.filter(
1361
+ (attribute) => !core.types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
1362
+ );
1363
+ const rowAnalysis = analyzeRecursiveHostTree(
1364
+ row,
1365
+ statesByValue,
1366
+ safeGlobals,
1367
+ listNames,
1368
+ id,
1369
+ allocateId
1370
+ );
1371
+ if (rowAnalysis.reason) return rowAnalysis.reason;
1372
+ plans.push(...rowAnalysis.plans);
1373
+ for (const [nestedElement, nestedPlan] of rowAnalysis.blocks) {
1374
+ blocks.set(nestedElement, nestedPlan);
1375
+ }
1376
+ keyedRanges.push({
1377
+ before,
1378
+ source: range.source,
1379
+ collection: range.collection,
1380
+ keyCallback: range.keyCallback,
1381
+ renderCallback: range.renderCallback,
1382
+ row,
1383
+ bindings: rowAnalysis.bindings,
1384
+ syntax: range.syntax
1385
+ });
1386
+ for (const dependency of range.dependencies) keyedDependencies.add(dependency);
1387
+ }
1388
+ for (const { element: child, segment, sibling } of staticChildren) {
1389
+ const nested = analyzeRecursiveHostTree(
1390
+ child,
1391
+ statesByValue,
1392
+ safeGlobals,
1393
+ listNames,
1394
+ owner,
1395
+ allocateId
1396
+ );
1397
+ if (nested.reason) return nested.reason;
1398
+ plans.push(...nested.plans);
1399
+ for (const [nestedElement, plan2] of nested.blocks) blocks.set(nestedElement, plan2);
1400
+ for (const binding of nested.bindings) {
1401
+ staticBindings.push({ ...binding, segment, sibling });
1402
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1403
+ keyedDependencies.add(dependency);
1404
+ }
1405
+ }
1406
+ }
1407
+ const plan = {
1408
+ kind: "nested-host-keyed-ranges",
1409
+ id,
1410
+ parent: owner,
1411
+ dependencies: [...keyedDependencies].sort((left, right) => left - right),
1412
+ source: element,
1413
+ ranges: keyedRanges,
1414
+ trailing: staticBefore,
1415
+ staticBindings
1416
+ };
1417
+ plans.push(plan);
1418
+ blocks.set(element, plan);
1419
+ return void 0;
1420
+ }
1421
+ if (element.children.some((child) => core.types.isJSXFragment(child))) {
1422
+ return "recursive compiler-owned blocks do not support fragments yet";
1423
+ }
1424
+ const nestedElements = element.children.filter(
1425
+ (child) => core.types.isJSXElement(child)
1426
+ );
1427
+ const expressions = element.children.filter(
1428
+ (child) => core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)
1429
+ );
1430
+ for (const child of expressions) {
1431
+ const unsupported = validateDerivedExpression(child.expression, safeGlobals);
1432
+ if (unsupported) return `recursive compiler-owned text cannot use ${unsupported}`;
1433
+ }
1434
+ if (nestedElements.length > 0 && expressions.length > 0) {
1435
+ return "recursive compiler-owned blocks do not support dynamic text beside nested elements";
1436
+ }
1437
+ if (nestedElements.length === 0 && expressions.length > 0) {
1438
+ const parts = [];
1439
+ for (const child of element.children) {
1440
+ if (core.types.isJSXText(child)) {
1441
+ const text = cleanJsxText(child.value);
1442
+ if (text) parts.push(core.types.stringLiteral(text));
1443
+ } else if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1444
+ parts.push(cloneExpression(child.expression));
1445
+ }
1446
+ }
1447
+ bindings.push({ kind: "text", path: [...path], value: core.types.arrayExpression(parts) });
1448
+ }
1449
+ let elementIndex = 0;
1450
+ for (const child of element.children) {
1451
+ if (!core.types.isJSXElement(child)) continue;
1452
+ const reason2 = visit(child, [...path, elementIndex], owner);
1453
+ if (reason2) return reason2;
1454
+ elementIndex += 1;
1455
+ }
1456
+ return void 0;
1457
+ };
1458
+ const reason = visit(branch, [], parent);
1459
+ return { bindings, plans, blocks, reason };
1460
+ }
1461
+ function analyzeCompilerOwnedKeyedRowHostBlocks(shape, statesByValue, safeGlobals, listNames, parent, allocateId) {
1462
+ if (shape.events.length > 0) return void 0;
1463
+ const row = core.types.cloneNode(shape.row, true);
1464
+ row.openingElement.attributes = row.openingElement.attributes.filter(
1465
+ (attribute) => !core.types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
1466
+ );
1467
+ const analysis = analyzeRecursiveHostTree(
1468
+ row,
1469
+ statesByValue,
1470
+ safeGlobals,
1471
+ listNames,
1472
+ parent,
1473
+ allocateId
1474
+ );
1475
+ if (analysis.reason || analysis.plans.length === 0) {
1476
+ return void 0;
1477
+ }
1478
+ return {
1479
+ row,
1480
+ bindings: analysis.bindings,
1481
+ descriptorBlocks: analysis.blocks,
1482
+ nestedPlans: analysis.plans
1483
+ };
1484
+ }
1485
+ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals, listNames, parent, allocateId) {
1013
1486
  const containerName = container.openingElement.name;
1014
1487
  if (!core.types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg") {
1015
1488
  return void 0;
@@ -1031,8 +1504,22 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals)
1031
1504
  }
1032
1505
  const shape = conditionalBlockShape(children[0].expression);
1033
1506
  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: [] };
1507
+ const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
1508
+ shape.truthy,
1509
+ statesByValue,
1510
+ safeGlobals,
1511
+ listNames,
1512
+ parent,
1513
+ allocateId
1514
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1515
+ const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
1516
+ shape.falsy,
1517
+ statesByValue,
1518
+ safeGlobals,
1519
+ listNames,
1520
+ parent,
1521
+ allocateId
1522
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1036
1523
  if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
1037
1524
  const dependencies = new Set(collectStateDependencies(shape.test, statesByValue));
1038
1525
  for (const binding of [...truthyAnalysis.bindings || [], ...falsyAnalysis.bindings || []]) {
@@ -1047,10 +1534,12 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals)
1047
1534
  truthy: shape.truthy,
1048
1535
  falsy: shape.falsy,
1049
1536
  truthyBindings: truthyAnalysis.bindings || [],
1050
- falsyBindings: falsyAnalysis.bindings || []
1537
+ falsyBindings: falsyAnalysis.bindings || [],
1538
+ descriptorBlocks: new Map([...truthyAnalysis.blocks, ...falsyAnalysis.blocks]),
1539
+ nestedPlans: [...truthyAnalysis.plans, ...falsyAnalysis.plans]
1051
1540
  };
1052
1541
  }
1053
- function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals, allowSingleRange = false) {
1542
+ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals, allowSingleRange, listNames, parent, allocateId) {
1054
1543
  const containerName = container.openingElement.name;
1055
1544
  if (!core.types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg" || container.openingElement.attributes.some(
1056
1545
  (attribute) => core.types.isJSXSpreadAttribute(attribute) || core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
@@ -1061,14 +1550,34 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
1061
1550
  if (children.length < (allowSingleRange ? 1 : 2)) return void 0;
1062
1551
  const ranges = [];
1063
1552
  const dependencies = /* @__PURE__ */ new Set();
1553
+ const descriptorBlocks = /* @__PURE__ */ new Map();
1554
+ const nestedPlans = [];
1555
+ const staticBindings = [];
1064
1556
  let staticBefore = 0;
1065
1557
  for (const child of children) {
1066
1558
  if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1067
1559
  const shape = conditionalBlockShape(child.expression);
1068
1560
  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: [] };
1561
+ const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
1562
+ shape.truthy,
1563
+ statesByValue,
1564
+ safeGlobals,
1565
+ listNames,
1566
+ parent,
1567
+ allocateId
1568
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1569
+ const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
1570
+ shape.falsy,
1571
+ statesByValue,
1572
+ safeGlobals,
1573
+ listNames,
1574
+ parent,
1575
+ allocateId
1576
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1071
1577
  if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
1578
+ nestedPlans.push(...truthyAnalysis.plans, ...falsyAnalysis.plans);
1579
+ for (const [element, plan] of truthyAnalysis.blocks) descriptorBlocks.set(element, plan);
1580
+ for (const [element, plan] of falsyAnalysis.blocks) descriptorBlocks.set(element, plan);
1072
1581
  const rangeDependencies = new Set(collectStateDependencies(shape.test, statesByValue));
1073
1582
  for (const binding of [
1074
1583
  ...truthyAnalysis.bindings || [],
@@ -1094,14 +1603,158 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
1094
1603
  }
1095
1604
  }
1096
1605
  if (!core.types.isJSXElement(child) || !isHostElement(child)) return void 0;
1097
- if (!isStaticRangeSibling(child, statesByValue, safeGlobals)) return void 0;
1606
+ const staticAnalysis = analyzeHostConditionalTree(child, safeGlobals, true, statesByValue);
1607
+ if (staticAnalysis.reason) return void 0;
1608
+ for (const binding of staticAnalysis.bindings || []) {
1609
+ staticBindings.push({
1610
+ ...binding,
1611
+ segment: ranges.length,
1612
+ sibling: staticBefore
1613
+ });
1614
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1615
+ dependencies.add(dependency);
1616
+ }
1617
+ }
1098
1618
  staticBefore += 1;
1099
1619
  }
1100
1620
  if (ranges.length === 0) return void 0;
1101
1621
  return {
1102
1622
  ranges,
1103
1623
  trailing: staticBefore,
1104
- dependencies: [...dependencies].sort((left, right) => left - right)
1624
+ dependencies: [...dependencies].sort((left, right) => left - right),
1625
+ staticBindings,
1626
+ descriptorBlocks,
1627
+ nestedPlans
1628
+ };
1629
+ }
1630
+ function analyzeMixedRangesContainer(container, statesByValue, safeGlobals, listNames, parent, allocateId) {
1631
+ const containerName = container.openingElement.name;
1632
+ if (!core.types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg" || container.openingElement.attributes.some(
1633
+ (attribute) => core.types.isJSXSpreadAttribute(attribute) || core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
1634
+ )) {
1635
+ return void 0;
1636
+ }
1637
+ const children = meaningfulJsxChildren(container);
1638
+ if (children.length < 2) return void 0;
1639
+ const ranges = [];
1640
+ const dependencies = /* @__PURE__ */ new Set();
1641
+ const descriptorBlocks = /* @__PURE__ */ new Map();
1642
+ const nestedPlans = [];
1643
+ const staticBindings = [];
1644
+ let conditionalCount = 0;
1645
+ let keyedCount = 0;
1646
+ let staticBefore = 0;
1647
+ const mergeAnalysis = (analysis) => {
1648
+ if (analysis.reason) return false;
1649
+ nestedPlans.push(...analysis.plans);
1650
+ for (const [element, plan] of analysis.blocks) descriptorBlocks.set(element, plan);
1651
+ for (const binding of analysis.bindings) {
1652
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1653
+ dependencies.add(dependency);
1654
+ }
1655
+ }
1656
+ return true;
1657
+ };
1658
+ for (const child of children) {
1659
+ if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1660
+ const shape = conditionalBlockShape(child.expression);
1661
+ if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
1662
+ const truthyAnalysis = shape.truthy ? analyzeRecursiveHostTree(
1663
+ shape.truthy,
1664
+ statesByValue,
1665
+ safeGlobals,
1666
+ listNames,
1667
+ parent,
1668
+ allocateId
1669
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1670
+ const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
1671
+ shape.falsy,
1672
+ statesByValue,
1673
+ safeGlobals,
1674
+ listNames,
1675
+ parent,
1676
+ allocateId
1677
+ ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
1678
+ if (!mergeAnalysis(truthyAnalysis) || !mergeAnalysis(falsyAnalysis)) return void 0;
1679
+ for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
1680
+ dependencies.add(dependency);
1681
+ }
1682
+ ranges.push({
1683
+ rangeKind: "conditional",
1684
+ before: staticBefore,
1685
+ source: child.expression,
1686
+ test: cloneExpression(shape.test),
1687
+ logical: shape.logical,
1688
+ truthy: shape.truthy,
1689
+ falsy: shape.falsy,
1690
+ truthyBindings: truthyAnalysis.bindings,
1691
+ falsyBindings: falsyAnalysis.bindings
1692
+ });
1693
+ conditionalCount += 1;
1694
+ staticBefore = 0;
1695
+ continue;
1696
+ }
1697
+ }
1698
+ const keyed = analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, true);
1699
+ if (keyed) {
1700
+ if (keyed.events.length > 0) return void 0;
1701
+ const row = core.types.cloneNode(keyed.row, true);
1702
+ row.openingElement.attributes = row.openingElement.attributes.filter(
1703
+ (attribute) => !core.types.isJSXAttribute(attribute) || jsxAttributeName(attribute) !== "key"
1704
+ );
1705
+ const rowAnalysis = analyzeRecursiveHostTree(
1706
+ row,
1707
+ statesByValue,
1708
+ safeGlobals,
1709
+ listNames,
1710
+ parent,
1711
+ allocateId
1712
+ );
1713
+ if (!mergeAnalysis(rowAnalysis)) return void 0;
1714
+ for (const dependency of keyed.dependencies) dependencies.add(dependency);
1715
+ ranges.push({
1716
+ rangeKind: "keyed",
1717
+ before: staticBefore,
1718
+ source: keyed.source,
1719
+ collection: keyed.collection,
1720
+ keyCallback: keyed.keyCallback,
1721
+ renderCallback: keyed.renderCallback,
1722
+ row,
1723
+ bindings: rowAnalysis.bindings,
1724
+ syntax: keyed.syntax
1725
+ });
1726
+ keyedCount += 1;
1727
+ staticBefore = 0;
1728
+ continue;
1729
+ }
1730
+ if (!core.types.isJSXElement(child) || !isHostElement(child)) return void 0;
1731
+ const staticAnalysis = analyzeRecursiveHostTree(
1732
+ child,
1733
+ statesByValue,
1734
+ safeGlobals,
1735
+ listNames,
1736
+ parent,
1737
+ allocateId
1738
+ );
1739
+ if (staticAnalysis.reason) return void 0;
1740
+ for (const binding of staticAnalysis.bindings) {
1741
+ staticBindings.push({
1742
+ ...binding,
1743
+ segment: ranges.length,
1744
+ sibling: staticBefore
1745
+ });
1746
+ }
1747
+ if (!mergeAnalysis(staticAnalysis)) return void 0;
1748
+ staticBefore += 1;
1749
+ }
1750
+ if (conditionalCount === 0 || keyedCount === 0) return void 0;
1751
+ return {
1752
+ ranges,
1753
+ trailing: staticBefore,
1754
+ dependencies: [...dependencies].sort((left, right) => left - right),
1755
+ staticBindings,
1756
+ descriptorBlocks,
1757
+ nestedPlans
1105
1758
  };
1106
1759
  }
1107
1760
  function keyedListBoundary(blockRuntime, plan, source) {
@@ -1126,14 +1779,14 @@ function keyedListBoundary(blockRuntime, plan, source) {
1126
1779
  true
1127
1780
  );
1128
1781
  }
1129
- function hostElementDescriptor(element) {
1782
+ function hostElementDescriptor(element, descriptorBlocks = /* @__PURE__ */ new Map()) {
1130
1783
  const tag = element.openingElement.name;
1131
1784
  const attributes = [];
1132
1785
  const styles = [];
1133
1786
  for (const attribute of element.openingElement.attributes) {
1134
1787
  if (!core.types.isJSXAttribute(attribute)) continue;
1135
1788
  const name = jsxAttributeName(attribute);
1136
- if (!name || name === "key" || /^on[A-Z]/.test(name)) continue;
1789
+ if (!name || name === "key" || name === "ref" || /^on[A-Z]/.test(name)) continue;
1137
1790
  if (name === "style") {
1138
1791
  if (core.types.isJSXExpressionContainer(attribute.value) && core.types.isObjectExpression(attribute.value.expression)) {
1139
1792
  for (const property of attribute.value.expression.properties) {
@@ -1157,24 +1810,93 @@ function hostElementDescriptor(element) {
1157
1810
  ])
1158
1811
  );
1159
1812
  }
1813
+ const block = descriptorBlocks.get(element);
1814
+ const conditionalBySource = /* @__PURE__ */ new Map();
1815
+ const keyedBySource = /* @__PURE__ */ new Map();
1816
+ if (block?.kind === "nested-host-conditional-ranges") {
1817
+ for (const range of block.ranges) conditionalBySource.set(range.source, range);
1818
+ } else if (block?.kind === "nested-host-keyed-ranges") {
1819
+ for (const range of block.ranges) keyedBySource.set(range.source, range);
1820
+ } else if (block?.kind === "nested-host-mixed-ranges") {
1821
+ for (const range of block.ranges) {
1822
+ if (range.rangeKind === "conditional") conditionalBySource.set(range.source, range);
1823
+ else keyedBySource.set(range.source, range);
1824
+ }
1825
+ }
1160
1826
  const children = [];
1161
1827
  for (const child of element.children) {
1162
1828
  if (core.types.isJSXText(child)) {
1163
1829
  const text = cleanJsxText(child.value);
1164
1830
  if (text) children.push(core.types.stringLiteral(text));
1165
1831
  } else if (core.types.isJSXElement(child)) {
1166
- children.push(hostElementDescriptor(child));
1832
+ const keyedRange = keyedBySource.get(child);
1833
+ if (keyedRange) {
1834
+ if (block?.kind !== "nested-host-keyed-ranges") {
1835
+ children.push(keyedRangeDescriptorChildren(keyedRange, descriptorBlocks));
1836
+ }
1837
+ } else {
1838
+ children.push(hostElementDescriptor(child, descriptorBlocks));
1839
+ }
1167
1840
  } else if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1168
- children.push(cloneExpression(child.expression));
1841
+ const conditionalRange = conditionalBySource.get(child.expression);
1842
+ const keyedRange = keyedBySource.get(child.expression);
1843
+ if (conditionalRange) {
1844
+ children.push(conditionalRangeDescriptorChild(conditionalRange, descriptorBlocks));
1845
+ } else if (keyedRange) {
1846
+ if (block?.kind !== "nested-host-keyed-ranges") {
1847
+ children.push(keyedRangeDescriptorChildren(keyedRange, descriptorBlocks));
1848
+ }
1849
+ } else {
1850
+ children.push(cloneExpression(child.expression));
1851
+ }
1169
1852
  }
1170
1853
  }
1171
- return core.types.objectExpression([
1854
+ const properties = [
1172
1855
  core.types.objectProperty(core.types.identifier("kind"), core.types.stringLiteral("element")),
1173
1856
  core.types.objectProperty(core.types.identifier("tag"), core.types.stringLiteral(tag.name)),
1174
1857
  core.types.objectProperty(core.types.identifier("attributes"), core.types.arrayExpression(attributes)),
1175
1858
  core.types.objectProperty(core.types.identifier("styles"), core.types.arrayExpression(styles)),
1176
1859
  core.types.objectProperty(core.types.identifier("children"), core.types.arrayExpression(children))
1177
- ]);
1860
+ ];
1861
+ if (block) {
1862
+ properties.push(
1863
+ core.types.objectProperty(core.types.identifier("block"), nestedHostBlockObject(block, descriptorBlocks))
1864
+ );
1865
+ }
1866
+ return core.types.objectExpression(properties);
1867
+ }
1868
+ function conditionalRangeDescriptorChild(range, descriptorBlocks) {
1869
+ const truthy = range.truthy ? hostElementDescriptor(range.truthy, descriptorBlocks) : core.types.nullLiteral();
1870
+ if (range.logical) {
1871
+ return core.types.logicalExpression("&&", cloneExpression(range.test), truthy);
1872
+ }
1873
+ return core.types.conditionalExpression(
1874
+ cloneExpression(range.test),
1875
+ truthy,
1876
+ range.falsy ? hostElementDescriptor(range.falsy, descriptorBlocks) : core.types.nullLiteral()
1877
+ );
1878
+ }
1879
+ function keyedRangeDescriptorChildren(range, descriptorBlocks) {
1880
+ const parameters = range.renderCallback.params.map(
1881
+ (parameter) => core.types.cloneNode(parameter, true)
1882
+ );
1883
+ const callback = core.types.arrowFunctionExpression(
1884
+ parameters,
1885
+ hostElementDescriptor(range.row, descriptorBlocks)
1886
+ );
1887
+ const collection = cloneExpression(range.collection);
1888
+ if (range.syntax === "map") {
1889
+ return core.types.callExpression(core.types.memberExpression(collection, core.types.identifier("map")), [callback]);
1890
+ }
1891
+ return core.types.callExpression(
1892
+ core.types.memberExpression(
1893
+ core.types.callExpression(core.types.memberExpression(core.types.identifier("Array"), core.types.identifier("from")), [
1894
+ core.types.logicalExpression("||", collection, core.types.arrayExpression([]))
1895
+ ]),
1896
+ core.types.identifier("map")
1897
+ ),
1898
+ [callback]
1899
+ );
1178
1900
  }
1179
1901
  function keyedRowBindingObject(binding, parameters) {
1180
1902
  const properties = [
@@ -1182,6 +1904,12 @@ function keyedRowBindingObject(binding, parameters) {
1182
1904
  core.types.objectProperty(
1183
1905
  core.types.identifier("path"),
1184
1906
  core.types.arrayExpression(binding.path.map((part) => core.types.numericLiteral(part)))
1907
+ ),
1908
+ core.types.objectProperty(
1909
+ core.types.identifier("dependencies"),
1910
+ core.types.arrayExpression(
1911
+ (binding.dependencies || []).map((dependency) => core.types.numericLiteral(dependency))
1912
+ )
1185
1913
  )
1186
1914
  ];
1187
1915
  if (binding.name) {
@@ -1198,6 +1926,16 @@ function keyedRowBindingObject(binding, parameters) {
1198
1926
  );
1199
1927
  return core.types.objectExpression(properties);
1200
1928
  }
1929
+ function staticRangeBindingObject(binding) {
1930
+ const value = keyedRowBindingObject(binding, []);
1931
+ value.properties.splice(
1932
+ 1,
1933
+ 0,
1934
+ core.types.objectProperty(core.types.identifier("segment"), core.types.numericLiteral(binding.segment)),
1935
+ core.types.objectProperty(core.types.identifier("sibling"), core.types.numericLiteral(binding.sibling))
1936
+ );
1937
+ return value;
1938
+ }
1201
1939
  function uniqueLocalIdentifier(base, nodes) {
1202
1940
  const names = /* @__PURE__ */ new Set();
1203
1941
  for (const node of nodes) {
@@ -1314,6 +2052,10 @@ function keyedRowEventObject(event, renderParameters) {
1314
2052
  const parameters = [core.types.cloneNode(renderParameters[0], true), index, syntheticEvent];
1315
2053
  return core.types.objectExpression([
1316
2054
  core.types.objectProperty(core.types.identifier("name"), core.types.stringLiteral(event.name)),
2055
+ core.types.objectProperty(
2056
+ core.types.identifier("path"),
2057
+ core.types.arrayExpression(event.path.map((part) => core.types.numericLiteral(part)))
2058
+ ),
1317
2059
  core.types.objectProperty(
1318
2060
  core.types.identifier("invoke"),
1319
2061
  core.types.arrowFunctionExpression(
@@ -1383,6 +2125,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
1383
2125
  plan.source,
1384
2126
  ...plan.conditionals.map((conditional) => conditional.test)
1385
2127
  ]);
2128
+ const delegatedEvents = canDelegateKeyedRowEvents(plan);
1386
2129
  const renderSource = keyedRowsRenderSource(plan, eventFactory, conditionalFactory);
1387
2130
  const renderFactoryParameters = plan.conditionals.length > 0 ? [core.types.cloneNode(eventFactory), core.types.cloneNode(conditionalFactory)] : plan.events.length > 0 ? [core.types.cloneNode(eventFactory)] : [];
1388
2131
  return core.types.jsxElement(
@@ -1400,6 +2143,14 @@ function keyedRowsBoundary(blockRuntime, plan) {
1400
2143
  core.types.jsxIdentifier("items"),
1401
2144
  core.types.jsxExpressionContainer(core.types.arrowFunctionExpression([], cloneExpression(plan.collection)))
1402
2145
  ),
2146
+ core.types.jsxAttribute(
2147
+ core.types.jsxIdentifier("structureDependencies"),
2148
+ core.types.jsxExpressionContainer(
2149
+ core.types.arrayExpression(
2150
+ plan.structureDependencies.map((dependency) => core.types.numericLiteral(dependency))
2151
+ )
2152
+ )
2153
+ ),
1403
2154
  core.types.jsxAttribute(
1404
2155
  core.types.jsxIdentifier("rowKey"),
1405
2156
  core.types.jsxExpressionContainer(core.types.cloneNode(plan.keyCallback, true))
@@ -1409,7 +2160,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
1409
2160
  core.types.jsxExpressionContainer(
1410
2161
  core.types.arrowFunctionExpression(
1411
2162
  parameters.map((parameter) => core.types.cloneNode(parameter, true)),
1412
- hostElementDescriptor(plan.row)
2163
+ hostElementDescriptor(plan.row, plan.descriptorBlocks)
1413
2164
  )
1414
2165
  )
1415
2166
  ),
@@ -1429,7 +2180,13 @@ function keyedRowsBoundary(blockRuntime, plan) {
1429
2180
  plan.events.map((event) => keyedRowEventObject(event, parameters))
1430
2181
  )
1431
2182
  )
1432
- )
2183
+ ),
2184
+ ...delegatedEvents ? [
2185
+ core.types.jsxAttribute(
2186
+ core.types.jsxIdentifier("delegateEvents"),
2187
+ core.types.jsxExpressionContainer(core.types.booleanLiteral(true))
2188
+ )
2189
+ ] : []
1433
2190
  ] : [],
1434
2191
  ...plan.conditionals.length > 0 ? [
1435
2192
  core.types.jsxAttribute(
@@ -1442,6 +2199,12 @@ function keyedRowsBoundary(blockRuntime, plan) {
1442
2199
  )
1443
2200
  )
1444
2201
  )
2202
+ ] : [],
2203
+ ...plan.descriptorBlocks?.size ? [
2204
+ core.types.jsxAttribute(
2205
+ core.types.jsxIdentifier("hostBlocks"),
2206
+ core.types.jsxExpressionContainer(core.types.booleanLiteral(true))
2207
+ )
1445
2208
  ] : []
1446
2209
  ],
1447
2210
  true
@@ -1451,7 +2214,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
1451
2214
  true
1452
2215
  );
1453
2216
  }
1454
- function keyedRangeObject(range) {
2217
+ function keyedRangeObject(range, descriptorBlocks = /* @__PURE__ */ new Map()) {
1455
2218
  const parameters = range.renderCallback.params.map(
1456
2219
  (parameter) => core.types.cloneNode(parameter, true)
1457
2220
  );
@@ -1466,7 +2229,7 @@ function keyedRangeObject(range) {
1466
2229
  core.types.identifier("create"),
1467
2230
  core.types.arrowFunctionExpression(
1468
2231
  parameters.map((parameter) => core.types.cloneNode(parameter, true)),
1469
- hostElementDescriptor(range.row)
2232
+ hostElementDescriptor(range.row, descriptorBlocks)
1470
2233
  )
1471
2234
  ),
1472
2235
  core.types.objectProperty(
@@ -1510,6 +2273,12 @@ function keyedRangesBoundary(blockRuntime, plan) {
1510
2273
  core.types.jsxAttribute(
1511
2274
  core.types.jsxIdentifier("trailing"),
1512
2275
  core.types.jsxExpressionContainer(core.types.numericLiteral(plan.trailing))
2276
+ ),
2277
+ core.types.jsxAttribute(
2278
+ core.types.jsxIdentifier("bindings"),
2279
+ core.types.jsxExpressionContainer(
2280
+ core.types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
2281
+ )
1513
2282
  )
1514
2283
  ],
1515
2284
  true
@@ -1519,11 +2288,11 @@ function keyedRangesBoundary(blockRuntime, plan) {
1519
2288
  true
1520
2289
  );
1521
2290
  }
1522
- function hostConditionalBranchObject(branch, bindings) {
2291
+ function hostConditionalBranchObject(branch, bindings, descriptorBlocks = /* @__PURE__ */ new Map()) {
1523
2292
  return core.types.objectExpression([
1524
2293
  core.types.objectProperty(
1525
2294
  core.types.identifier("create"),
1526
- core.types.arrowFunctionExpression([], hostElementDescriptor(branch))
2295
+ core.types.arrowFunctionExpression([], hostElementDescriptor(branch, descriptorBlocks))
1527
2296
  ),
1528
2297
  core.types.objectProperty(
1529
2298
  core.types.identifier("bindings"),
@@ -1552,7 +2321,9 @@ function hostConditionalBoundary(blockRuntime, plan) {
1552
2321
  attributes.push(
1553
2322
  core.types.jsxAttribute(
1554
2323
  core.types.jsxIdentifier("truthy"),
1555
- core.types.jsxExpressionContainer(hostConditionalBranchObject(plan.truthy, plan.truthyBindings))
2324
+ core.types.jsxExpressionContainer(
2325
+ hostConditionalBranchObject(plan.truthy, plan.truthyBindings, plan.descriptorBlocks)
2326
+ )
1556
2327
  )
1557
2328
  );
1558
2329
  }
@@ -1560,13 +2331,15 @@ function hostConditionalBoundary(blockRuntime, plan) {
1560
2331
  attributes.push(
1561
2332
  core.types.jsxAttribute(
1562
2333
  core.types.jsxIdentifier("falsy"),
1563
- core.types.jsxExpressionContainer(hostConditionalBranchObject(plan.falsy, plan.falsyBindings))
2334
+ core.types.jsxExpressionContainer(
2335
+ hostConditionalBranchObject(plan.falsy, plan.falsyBindings, plan.descriptorBlocks)
2336
+ )
1564
2337
  )
1565
2338
  );
1566
2339
  }
1567
2340
  return core.types.jsxElement(core.types.jsxOpeningElement(name, attributes, true), null, [], true);
1568
2341
  }
1569
- function conditionalRangeObject(range) {
2342
+ function conditionalRangeObject(range, descriptorBlocks = /* @__PURE__ */ new Map()) {
1570
2343
  const properties = [
1571
2344
  core.types.objectProperty(core.types.identifier("before"), core.types.numericLiteral(range.before)),
1572
2345
  core.types.objectProperty(
@@ -1581,7 +2354,7 @@ function conditionalRangeObject(range) {
1581
2354
  properties.push(
1582
2355
  core.types.objectProperty(
1583
2356
  core.types.identifier("truthy"),
1584
- hostConditionalBranchObject(range.truthy, range.truthyBindings)
2357
+ hostConditionalBranchObject(range.truthy, range.truthyBindings, descriptorBlocks)
1585
2358
  )
1586
2359
  );
1587
2360
  }
@@ -1589,12 +2362,78 @@ function conditionalRangeObject(range) {
1589
2362
  properties.push(
1590
2363
  core.types.objectProperty(
1591
2364
  core.types.identifier("falsy"),
1592
- hostConditionalBranchObject(range.falsy, range.falsyBindings)
2365
+ hostConditionalBranchObject(range.falsy, range.falsyBindings, descriptorBlocks)
1593
2366
  )
1594
2367
  );
1595
2368
  }
1596
2369
  return core.types.objectExpression(properties);
1597
2370
  }
2371
+ function nestedHostBlockObject(plan, descriptorBlocks) {
2372
+ const kind = plan.kind === "nested-host-conditional-ranges" ? "conditional-ranges" : plan.kind === "nested-host-keyed-ranges" ? "keyed-ranges" : "mixed-ranges";
2373
+ return core.types.objectExpression([
2374
+ core.types.objectProperty(core.types.identifier("kind"), core.types.stringLiteral(kind)),
2375
+ core.types.objectProperty(core.types.identifier("id"), core.types.numericLiteral(plan.id)),
2376
+ core.types.objectProperty(
2377
+ core.types.identifier("ranges"),
2378
+ core.types.arrayExpression(
2379
+ 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))
2380
+ )
2381
+ ),
2382
+ core.types.objectProperty(core.types.identifier("trailing"), core.types.numericLiteral(plan.trailing)),
2383
+ core.types.objectProperty(
2384
+ core.types.identifier("bindings"),
2385
+ core.types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
2386
+ ),
2387
+ ...plan.kind === "nested-host-keyed-ranges" ? [core.types.objectProperty(core.types.identifier("staticChildrenOnly"), core.types.booleanLiteral(true))] : []
2388
+ ]);
2389
+ }
2390
+ function mixedRangeObject(range, descriptorBlocks) {
2391
+ const value = range.rangeKind === "conditional" ? conditionalRangeObject(range, descriptorBlocks) : keyedRangeObject(range, descriptorBlocks);
2392
+ value.properties.unshift(
2393
+ core.types.objectProperty(core.types.identifier("kind"), core.types.stringLiteral(range.rangeKind))
2394
+ );
2395
+ return value;
2396
+ }
2397
+ function mixedRangesBoundary(blockRuntime, plan) {
2398
+ const name = core.types.jsxMemberExpression(
2399
+ core.types.jsxIdentifier(blockRuntime.name),
2400
+ core.types.jsxIdentifier("MixedRanges")
2401
+ );
2402
+ const source = core.types.cloneNode(plan.source, true);
2403
+ const rootRefIndex = source.openingElement.attributes.findIndex(
2404
+ (attribute) => core.types.isJSXAttribute(attribute) && jsxAttributeName(attribute) === "ref"
2405
+ );
2406
+ const rootRef = rootRefIndex >= 0 ? source.openingElement.attributes.splice(rootRefIndex, 1)[0] : void 0;
2407
+ const nestedPlan = {
2408
+ kind: "nested-host-mixed-ranges",
2409
+ id: plan.id,
2410
+ parent: plan.parent,
2411
+ dependencies: plan.dependencies,
2412
+ source: plan.source,
2413
+ ranges: plan.ranges,
2414
+ trailing: plan.trailing,
2415
+ staticBindings: plan.staticBindings
2416
+ };
2417
+ const descriptorBlocks = new Map(plan.descriptorBlocks);
2418
+ descriptorBlocks.set(plan.source, nestedPlan);
2419
+ const attributes = [
2420
+ core.types.jsxAttribute(core.types.jsxIdentifier("id"), core.types.jsxExpressionContainer(core.types.numericLiteral(plan.id))),
2421
+ core.types.jsxAttribute(
2422
+ core.types.jsxIdentifier("render"),
2423
+ core.types.jsxExpressionContainer(core.types.arrowFunctionExpression([], source))
2424
+ ),
2425
+ core.types.jsxAttribute(
2426
+ core.types.jsxIdentifier("create"),
2427
+ core.types.jsxExpressionContainer(
2428
+ core.types.arrowFunctionExpression([], hostElementDescriptor(plan.source, descriptorBlocks))
2429
+ )
2430
+ )
2431
+ ];
2432
+ if (rootRef?.value) {
2433
+ attributes.push(core.types.jsxAttribute(core.types.jsxIdentifier("rootRef"), core.types.cloneNode(rootRef.value, true)));
2434
+ }
2435
+ return core.types.jsxElement(core.types.jsxOpeningElement(name, attributes, true), null, [], true);
2436
+ }
1598
2437
  function conditionalRangesBoundary(blockRuntime, plan) {
1599
2438
  const name = core.types.jsxMemberExpression(
1600
2439
  core.types.jsxIdentifier(blockRuntime.name),
@@ -1614,12 +2453,20 @@ function conditionalRangesBoundary(blockRuntime, plan) {
1614
2453
  core.types.jsxAttribute(
1615
2454
  core.types.jsxIdentifier("ranges"),
1616
2455
  core.types.jsxExpressionContainer(
1617
- core.types.arrayExpression(plan.ranges.map((range) => conditionalRangeObject(range)))
2456
+ core.types.arrayExpression(
2457
+ plan.ranges.map((range) => conditionalRangeObject(range, plan.descriptorBlocks))
2458
+ )
1618
2459
  )
1619
2460
  ),
1620
2461
  core.types.jsxAttribute(
1621
2462
  core.types.jsxIdentifier("trailing"),
1622
2463
  core.types.jsxExpressionContainer(core.types.numericLiteral(plan.trailing))
2464
+ ),
2465
+ core.types.jsxAttribute(
2466
+ core.types.jsxIdentifier("bindings"),
2467
+ core.types.jsxExpressionContainer(
2468
+ core.types.arrayExpression(plan.staticBindings.map(staticRangeBindingObject))
2469
+ )
1623
2470
  )
1624
2471
  ];
1625
2472
  if (rootRef?.value) {
@@ -1792,6 +2639,41 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1792
2639
  }
1793
2640
  if (core.types.isJSXElement(child)) {
1794
2641
  if (isHostElement(child)) {
2642
+ const mixedRangeStart = nextId;
2643
+ const mixedRangeId = nextId++;
2644
+ const mixedRanges = insideConditional ? void 0 : analyzeMixedRangesContainer(
2645
+ child,
2646
+ statesByValue,
2647
+ safeGlobals,
2648
+ listNames,
2649
+ mixedRangeId,
2650
+ () => nextId++
2651
+ );
2652
+ if (mixedRanges) {
2653
+ plans.push({
2654
+ kind: "mixed-ranges",
2655
+ id: mixedRangeId,
2656
+ parent,
2657
+ dependencies: mixedRanges.dependencies,
2658
+ source: child,
2659
+ ranges: mixedRanges.ranges,
2660
+ trailing: mixedRanges.trailing,
2661
+ staticBindings: mixedRanges.staticBindings,
2662
+ descriptorBlocks: mixedRanges.descriptorBlocks
2663
+ });
2664
+ plans.push(...mixedRanges.nestedPlans);
2665
+ for (const range of mixedRanges.ranges) {
2666
+ if (range.rangeKind === "conditional") {
2667
+ conditionalExpressions.add(range.source);
2668
+ } else if (core.types.isJSXElement(range.source)) {
2669
+ ownedElements.add(range.source);
2670
+ } else {
2671
+ keyedExpressions.add(range.source);
2672
+ }
2673
+ }
2674
+ continue;
2675
+ }
2676
+ nextId = mixedRangeStart;
1795
2677
  const keyedRanges = insideConditional ? void 0 : analyzeKeyedRangesContainer(child, statesByValue, safeGlobals, listNames);
1796
2678
  if (keyedRanges) {
1797
2679
  plans.push({
@@ -1801,7 +2683,8 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1801
2683
  dependencies: keyedRanges.dependencies,
1802
2684
  source: child,
1803
2685
  ranges: keyedRanges.ranges,
1804
- trailing: keyedRanges.trailing
2686
+ trailing: keyedRanges.trailing,
2687
+ staticBindings: keyedRanges.staticBindings
1805
2688
  });
1806
2689
  for (const range of keyedRanges.ranges) {
1807
2690
  if (core.types.isJSXElement(range.source)) ownedElements.add(range.source);
@@ -1809,58 +2692,102 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1809
2692
  }
1810
2693
  continue;
1811
2694
  }
1812
- const conditionalRanges = insideConditional ? void 0 : analyzeConditionalRangesContainer(child, statesByValue, safeGlobals);
2695
+ const conditionalRangeStart = nextId;
2696
+ const conditionalRangeId = nextId++;
2697
+ const conditionalRanges = insideConditional ? void 0 : analyzeConditionalRangesContainer(
2698
+ child,
2699
+ statesByValue,
2700
+ safeGlobals,
2701
+ false,
2702
+ listNames,
2703
+ conditionalRangeId,
2704
+ () => nextId++
2705
+ );
1813
2706
  if (conditionalRanges) {
1814
2707
  plans.push({
1815
2708
  kind: "conditional-ranges",
1816
- id: nextId++,
2709
+ id: conditionalRangeId,
1817
2710
  parent,
1818
2711
  dependencies: conditionalRanges.dependencies,
1819
2712
  source: child,
1820
2713
  ranges: conditionalRanges.ranges,
1821
- trailing: conditionalRanges.trailing
2714
+ trailing: conditionalRanges.trailing,
2715
+ staticBindings: conditionalRanges.staticBindings,
2716
+ descriptorBlocks: conditionalRanges.descriptorBlocks
1822
2717
  });
2718
+ plans.push(...conditionalRanges.nestedPlans || []);
1823
2719
  for (const range of conditionalRanges.ranges) {
1824
2720
  conditionalExpressions.add(range.source);
1825
2721
  }
1826
2722
  continue;
1827
2723
  }
2724
+ nextId = conditionalRangeStart;
2725
+ const hostConditionalStart = nextId;
2726
+ const hostConditionalId = nextId++;
1828
2727
  const hostConditional = analyzeHostConditionalContainer(
1829
2728
  child,
1830
2729
  statesByValue,
1831
- safeGlobals
2730
+ safeGlobals,
2731
+ listNames,
2732
+ hostConditionalId,
2733
+ () => nextId++
1832
2734
  );
1833
2735
  if (hostConditional) {
1834
2736
  plans.push({
1835
2737
  kind: "host-conditional",
1836
- id: nextId++,
2738
+ id: hostConditionalId,
1837
2739
  parent,
1838
2740
  source: child,
1839
2741
  ...hostConditional
1840
2742
  });
2743
+ plans.push(...hostConditional.nestedPlans || []);
1841
2744
  ownedElements.add(child);
1842
2745
  continue;
1843
2746
  }
2747
+ nextId = hostConditionalStart;
2748
+ const keyedRowsStart = nextId;
2749
+ const keyedRowsId = nextId++;
1844
2750
  const keyedRows = analyzeKeyedRowsContainer(child, statesByValue, safeGlobals, listNames);
1845
2751
  if (keyedRows) {
2752
+ const nestedStart = nextId;
2753
+ const hostBlocks = analyzeCompilerOwnedKeyedRowHostBlocks(
2754
+ keyedRows,
2755
+ statesByValue,
2756
+ safeGlobals,
2757
+ listNames,
2758
+ keyedRowsId,
2759
+ () => nextId++
2760
+ );
2761
+ if (!hostBlocks) nextId = nestedStart;
2762
+ if (keyedRows.rowReason && !hostBlocks) {
2763
+ nextId = keyedRowsStart;
2764
+ const nested2 = visitHost(child, parent, insideConditional);
2765
+ if (nested2.reason) return { dependencies, reason: nested2.reason };
2766
+ mergeDependencies(dependencies, nested2.dependencies);
2767
+ continue;
2768
+ }
1846
2769
  plans.push({
1847
2770
  kind: "keyed-rows",
1848
- id: nextId++,
2771
+ id: keyedRowsId,
1849
2772
  parent,
1850
2773
  dependencies: keyedRows.dependencies,
1851
2774
  source: child,
1852
2775
  collection: keyedRows.collection,
2776
+ structureDependencies: keyedRows.structureDependencies,
1853
2777
  keyCallback: keyedRows.keyCallback,
1854
2778
  renderCallback: keyedRows.renderCallback,
1855
- row: keyedRows.row,
1856
- bindings: keyedRows.bindings,
2779
+ row: hostBlocks?.row || keyedRows.row,
2780
+ bindings: hostBlocks?.bindings || keyedRows.bindings,
1857
2781
  events: keyedRows.events,
1858
- conditionals: keyedRows.conditionals,
2782
+ conditionals: hostBlocks ? [] : keyedRows.conditionals,
2783
+ descriptorBlocks: hostBlocks?.descriptorBlocks,
1859
2784
  syntax: keyedRows.syntax
1860
2785
  });
2786
+ plans.push(...hostBlocks?.nestedPlans || []);
1861
2787
  ownedElements.add(child);
1862
2788
  continue;
1863
2789
  }
2790
+ nextId = keyedRowsStart;
1864
2791
  const nested = visitHost(child, parent, insideConditional);
1865
2792
  if (nested.reason) return { dependencies, reason: nested.reason };
1866
2793
  mergeDependencies(dependencies, nested.dependencies);
@@ -1957,6 +2884,46 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1957
2884
  }
1958
2885
  return { dependencies };
1959
2886
  };
2887
+ const rootMixedRangeStart = nextId;
2888
+ const rootMixedRangeId = nextId++;
2889
+ const rootMixedRanges = analyzeMixedRangesContainer(
2890
+ root,
2891
+ statesByValue,
2892
+ safeGlobals,
2893
+ listNames,
2894
+ rootMixedRangeId,
2895
+ () => nextId++
2896
+ );
2897
+ if (rootMixedRanges) {
2898
+ plans.push({
2899
+ kind: "mixed-ranges",
2900
+ id: rootMixedRangeId,
2901
+ dependencies: rootMixedRanges.dependencies,
2902
+ source: root,
2903
+ ranges: rootMixedRanges.ranges,
2904
+ trailing: rootMixedRanges.trailing,
2905
+ staticBindings: rootMixedRanges.staticBindings,
2906
+ descriptorBlocks: rootMixedRanges.descriptorBlocks
2907
+ });
2908
+ plans.push(...rootMixedRanges.nestedPlans);
2909
+ for (const range of rootMixedRanges.ranges) {
2910
+ if (range.rangeKind === "conditional") {
2911
+ conditionalExpressions.add(range.source);
2912
+ } else if (core.types.isJSXElement(range.source)) {
2913
+ ownedElements.add(range.source);
2914
+ } else {
2915
+ keyedExpressions.add(range.source);
2916
+ }
2917
+ }
2918
+ return {
2919
+ plans,
2920
+ componentElements,
2921
+ conditionalExpressions,
2922
+ ownedElements,
2923
+ keyedExpressions
2924
+ };
2925
+ }
2926
+ nextId = rootMixedRangeStart;
1960
2927
  const rootRanges = analyzeKeyedRangesContainer(root, statesByValue, safeGlobals, listNames, true);
1961
2928
  if (rootRanges) {
1962
2929
  plans.push({
@@ -1965,7 +2932,8 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1965
2932
  dependencies: rootRanges.dependencies,
1966
2933
  source: root,
1967
2934
  ranges: rootRanges.ranges,
1968
- trailing: rootRanges.trailing
2935
+ trailing: rootRanges.trailing,
2936
+ staticBindings: rootRanges.staticBindings
1969
2937
  });
1970
2938
  for (const range of rootRanges.ranges) {
1971
2939
  if (core.types.isJSXElement(range.source)) ownedElements.add(range.source);
@@ -1979,21 +2947,29 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1979
2947
  keyedExpressions
1980
2948
  };
1981
2949
  }
2950
+ const rootConditionalRangeStart = nextId;
2951
+ const rootConditionalRangeId = nextId++;
1982
2952
  const rootConditionalRanges = analyzeConditionalRangesContainer(
1983
2953
  root,
1984
2954
  statesByValue,
1985
2955
  safeGlobals,
1986
- true
2956
+ true,
2957
+ listNames,
2958
+ rootConditionalRangeId,
2959
+ () => nextId++
1987
2960
  );
1988
2961
  if (rootConditionalRanges) {
1989
2962
  plans.push({
1990
2963
  kind: "conditional-ranges",
1991
- id: nextId++,
2964
+ id: rootConditionalRangeId,
1992
2965
  dependencies: rootConditionalRanges.dependencies,
1993
2966
  source: root,
1994
2967
  ranges: rootConditionalRanges.ranges,
1995
- trailing: rootConditionalRanges.trailing
2968
+ trailing: rootConditionalRanges.trailing,
2969
+ staticBindings: rootConditionalRanges.staticBindings,
2970
+ descriptorBlocks: rootConditionalRanges.descriptorBlocks
1996
2971
  });
2972
+ plans.push(...rootConditionalRanges.nestedPlans || []);
1997
2973
  for (const range of rootConditionalRanges.ranges) {
1998
2974
  conditionalExpressions.add(range.source);
1999
2975
  }
@@ -2005,6 +2981,7 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
2005
2981
  keyedExpressions
2006
2982
  };
2007
2983
  }
2984
+ nextId = rootConditionalRangeStart;
2008
2985
  const result = visitHost(root, void 0, false);
2009
2986
  if (result.reason) return { reason: result.reason };
2010
2987
  return {
@@ -2042,6 +3019,9 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
2042
3019
  plans.map((plan) => [plan.source, plan])
2043
3020
  );
2044
3021
  const rootPlan = planBySource.get(root);
3022
+ if (rootPlan?.kind === "mixed-ranges") {
3023
+ return mixedRangesBoundary(blockRuntime, rootPlan);
3024
+ }
2045
3025
  if (rootPlan?.kind === "keyed-ranges") {
2046
3026
  return keyedRangesBoundary(blockRuntime, rootPlan);
2047
3027
  }
@@ -2055,6 +3035,9 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
2055
3035
  if (plan2?.kind === "host-conditional") {
2056
3036
  return hostConditionalBoundary(blockRuntime, plan2);
2057
3037
  }
3038
+ if (plan2?.kind === "mixed-ranges") {
3039
+ return mixedRangesBoundary(blockRuntime, plan2);
3040
+ }
2058
3041
  if (plan2?.kind === "keyed-rows") {
2059
3042
  return keyedRowsBoundary(blockRuntime, plan2);
2060
3043
  }
@@ -2104,6 +3087,31 @@ function assignStableBindingTargets(bindings) {
2104
3087
  binding.target = target;
2105
3088
  }
2106
3089
  }
3090
+ function markShortCircuitBindings(bindings) {
3091
+ for (const binding of bindings) {
3092
+ if (binding.kind === "block" || binding.dependencies.length < 2) continue;
3093
+ let shortCircuits = false;
3094
+ core.traverse(expressionFile(core.types.cloneNode(binding.value, true)), {
3095
+ ConditionalExpression(path) {
3096
+ shortCircuits = true;
3097
+ path.stop();
3098
+ },
3099
+ LogicalExpression(path) {
3100
+ shortCircuits = true;
3101
+ path.stop();
3102
+ },
3103
+ OptionalCallExpression(path) {
3104
+ shortCircuits = true;
3105
+ path.stop();
3106
+ },
3107
+ OptionalMemberExpression(path) {
3108
+ shortCircuits = true;
3109
+ path.stop();
3110
+ }
3111
+ });
3112
+ if (shortCircuits) binding.tracking = "dynamic";
3113
+ }
3114
+ }
2107
3115
  function lowerStableBindingTargets(root, bindings, blockRuntime, ownedElements) {
2108
3116
  const targetByPath = /* @__PURE__ */ new Map();
2109
3117
  for (const binding of bindings) {
@@ -2373,6 +3381,9 @@ function bindingObject(binding, propsParameter, stateParameter, statesByValue, s
2373
3381
  core.types.objectProperty(core.types.identifier("target"), core.types.numericLiteral(binding.target))
2374
3382
  );
2375
3383
  }
3384
+ if (binding.tracking) {
3385
+ properties.push(core.types.objectProperty(core.types.identifier("tracking"), core.types.stringLiteral(binding.tracking)));
3386
+ }
2376
3387
  if (binding.name)
2377
3388
  properties.push(core.types.objectProperty(core.types.identifier("name"), core.types.stringLiteral(binding.name)));
2378
3389
  properties.push(
@@ -2391,7 +3402,7 @@ function wrapperElement(definitionIdentifier, props) {
2391
3402
  const attributes = props ? [core.types.jsxSpreadAttribute(core.types.cloneNode(props))] : [];
2392
3403
  return core.types.jsxElement(core.types.jsxOpeningElement(name, attributes, true), null, [], true);
2393
3404
  }
2394
- function compileCandidate(candidate, createComponentIdentifier, useStateNames, reactNames, listNames, moduleId) {
3405
+ function compileCandidate(candidate, createComponentIdentifier, useStateNames, reactNames, listNames, moduleId, reactivity) {
2395
3406
  const { path, name, statementPath } = candidate;
2396
3407
  if (path.node.async || path.node.generator)
2397
3408
  return "async and generator components are not supported";
@@ -2508,8 +3519,34 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2508
3519
  );
2509
3520
  const setterReason = validateSetterUsage(expandedRoot, statesBySetter);
2510
3521
  if (setterReason) return setterReason;
3522
+ const referencedPropNames = collectDestructuredPropNames(
3523
+ expandedRoot,
3524
+ propsPlan.destructuredNames,
3525
+ propsPlan.definitionParameter
3526
+ );
3527
+ let propBindings = referencedPropNames.has("children") ? [] : [...propsPlan.destructuredNames].filter((propName) => referencedPropNames.has(propName)).map(
3528
+ (localName, propIndex) => ({
3529
+ localName,
3530
+ valueName: path.scope.generateUidIdentifier(`farmProp${propIndex}`).name,
3531
+ index: states.length + propIndex
3532
+ })
3533
+ );
3534
+ const propBindingsByName = new Map(propBindings.map((binding) => [binding.localName, binding]));
3535
+ let reactiveByValue = new Map(statesByValue);
3536
+ for (const binding of propBindings) {
3537
+ reactiveByValue.set(binding.valueName, {
3538
+ valueName: binding.valueName,
3539
+ setterName: "",
3540
+ index: binding.index
3541
+ });
3542
+ }
3543
+ let expandedReactiveRoot = rewriteTrackedPropAccess(
3544
+ expandedRoot,
3545
+ propsPlan.definitionParameter,
3546
+ propBindingsByName
3547
+ );
2511
3548
  const referencedComponentNames = /* @__PURE__ */ new Set();
2512
- core.traverse(expressionFile(core.types.cloneNode(expandedRoot, true)), {
3549
+ core.traverse(expressionFile(core.types.cloneNode(expandedReactiveRoot, true)), {
2513
3550
  JSXOpeningElement(componentPath) {
2514
3551
  const componentName = componentPath.node.name;
2515
3552
  if (core.types.isJSXIdentifier(componentName) && isComponentName(componentName.name)) {
@@ -2526,32 +3563,54 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2526
3563
  );
2527
3564
  })
2528
3565
  );
2529
- const blockAnalysis = analyzeComposableBlocks(
2530
- expandedRoot,
2531
- statesByValue,
3566
+ let blockAnalysis = analyzeComposableBlocks(
3567
+ expandedReactiveRoot,
3568
+ reactiveByValue,
2532
3569
  safeGlobals,
2533
3570
  listNames,
2534
3571
  allowedComponentNames
2535
3572
  );
2536
- if (blockAnalysis.reason) return blockAnalysis.reason;
2537
- const blockPlans = blockAnalysis.plans || [];
2538
- const analysis = analyzeHostTree(
2539
- expandedRoot,
2540
- statesByValue,
3573
+ let analysis = analyzeHostTree(
3574
+ expandedReactiveRoot,
3575
+ reactiveByValue,
2541
3576
  safeGlobals,
2542
3577
  blockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
2543
3578
  blockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
2544
3579
  blockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
2545
3580
  blockAnalysis.componentElements || /* @__PURE__ */ new Set()
2546
3581
  );
3582
+ if (propBindings.length > 0 && (blockAnalysis.reason || analysis.reason)) {
3583
+ propBindings = [];
3584
+ reactiveByValue = new Map(statesByValue);
3585
+ expandedReactiveRoot = core.types.cloneNode(expandedRoot, true);
3586
+ blockAnalysis = analyzeComposableBlocks(
3587
+ expandedReactiveRoot,
3588
+ reactiveByValue,
3589
+ safeGlobals,
3590
+ listNames,
3591
+ allowedComponentNames
3592
+ );
3593
+ analysis = analyzeHostTree(
3594
+ expandedReactiveRoot,
3595
+ reactiveByValue,
3596
+ safeGlobals,
3597
+ blockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
3598
+ blockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
3599
+ blockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
3600
+ blockAnalysis.componentElements || /* @__PURE__ */ new Set()
3601
+ );
3602
+ }
3603
+ if (blockAnalysis.reason) return blockAnalysis.reason;
2547
3604
  if (analysis.reason) return analysis.reason;
3605
+ const blockPlans = blockAnalysis.plans || [];
3606
+ markShortCircuitBindings(analysis.bindings || []);
2548
3607
  assignStableBindingTargets(analysis.bindings || []);
2549
3608
  const stateParameter = path.scope.generateUidIdentifier("farmState");
2550
3609
  const blockParameter = path.scope.generateUidIdentifier("farmBlocks");
2551
3610
  const definitionIdentifier = path.scope.generateUidIdentifier(`${name}Compiled`);
2552
3611
  const propsParameter = propsPlan.definitionParameter;
2553
3612
  const rootWithTargets = lowerStableBindingTargets(
2554
- expandedRoot,
3613
+ expandedReactiveRoot,
2555
3614
  analysis.bindings || [],
2556
3615
  blockParameter,
2557
3616
  blockAnalysis.ownedElements || /* @__PURE__ */ new Set()
@@ -2565,12 +3624,13 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2565
3624
  const rewrittenRoot = rewriteStateAccess(
2566
3625
  rootWithBlocks,
2567
3626
  stateParameter,
2568
- statesByValue,
3627
+ reactiveByValue,
2569
3628
  statesBySetter
2570
3629
  );
2571
3630
  const definition = core.types.callExpression(core.types.cloneNode(createComponentIdentifier), [
2572
3631
  core.types.objectExpression([
2573
3632
  core.types.objectProperty(core.types.identifier("displayName"), core.types.stringLiteral(name)),
3633
+ core.types.objectProperty(core.types.identifier("reactivity"), core.types.stringLiteral(reactivity)),
2574
3634
  core.types.spreadElement(
2575
3635
  core.types.conditionalExpression(
2576
3636
  core.types.memberExpression(
@@ -2581,7 +3641,9 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2581
3641
  core.types.objectProperty(core.types.identifier("hmrId"), core.types.stringLiteral(`${moduleId}#${name}`)),
2582
3642
  core.types.objectProperty(
2583
3643
  core.types.identifier("stateSignature"),
2584
- core.types.stringLiteral(String(states.length))
3644
+ core.types.stringLiteral(
3645
+ propBindings.length === 0 ? String(states.length) : `${states.length}:${propBindings.map((binding) => binding.localName).join(",")}`
3646
+ )
2585
3647
  )
2586
3648
  ]),
2587
3649
  core.types.objectExpression([])
@@ -2604,6 +3666,22 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2604
3666
  )
2605
3667
  )
2606
3668
  ),
3669
+ ...propBindings.length > 0 ? [
3670
+ core.types.objectProperty(
3671
+ core.types.identifier("readProps"),
3672
+ core.types.arrowFunctionExpression(
3673
+ [core.types.cloneNode(propsParameter)],
3674
+ core.types.arrayExpression(
3675
+ propBindings.map(
3676
+ (binding) => core.types.memberExpression(
3677
+ core.types.cloneNode(propsParameter),
3678
+ core.types.identifier(binding.localName)
3679
+ )
3680
+ )
3681
+ )
3682
+ )
3683
+ )
3684
+ ] : [],
2607
3685
  core.types.objectProperty(
2608
3686
  core.types.identifier("render"),
2609
3687
  core.types.arrowFunctionExpression(
@@ -2623,7 +3701,7 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2623
3701
  dependencies: block.dependencies
2624
3702
  }))
2625
3703
  ].map(
2626
- (binding) => bindingObject(binding, propsParameter, stateParameter, statesByValue, statesBySetter)
3704
+ (binding) => bindingObject(binding, propsParameter, stateParameter, reactiveByValue, statesBySetter)
2627
3705
  )
2628
3706
  )
2629
3707
  )
@@ -2717,7 +3795,8 @@ async function compileReactModule(code, id, options) {
2717
3795
  useStateNames,
2718
3796
  reactNames,
2719
3797
  listNames,
2720
- id
3798
+ id,
3799
+ options.reactivity
2721
3800
  );
2722
3801
  if (reason) {
2723
3802
  diagnostics.push({
@@ -2844,6 +3923,10 @@ function normalizeReactCompilerOptions(value) {
2844
3923
  if (!["fallback", "warn", "error"].includes(onUnsupported)) {
2845
3924
  throw new TypeError(`Unknown unsupported-component behavior: ${String(onUnsupported)}`);
2846
3925
  }
3926
+ const reactivity = options.reactivity || "hybrid";
3927
+ if (reactivity !== "static" && reactivity !== "hybrid") {
3928
+ throw new TypeError(`Unknown React compiler reactivity mode: ${String(reactivity)}`);
3929
+ }
2847
3930
  if (options.report !== void 0 && typeof options.report !== "boolean") {
2848
3931
  throw new TypeError("The React compiler report option must be a boolean.");
2849
3932
  }
@@ -2854,7 +3937,7 @@ function normalizeReactCompilerOptions(value) {
2854
3937
  }
2855
3938
  const reportFile = normalizeCompilerReportFile(options.reportFile);
2856
3939
  const report = options.report === true || options.reportFile !== void 0;
2857
- return { mode, directive, onUnsupported, report, reportFile };
3940
+ return { mode, directive, onUnsupported, reactivity, report, reportFile };
2858
3941
  }
2859
3942
 
2860
3943
  // src/vite.ts
@@ -2870,7 +3953,7 @@ function readCompilerOptions(rendererOptions) {
2870
3953
  );
2871
3954
  }
2872
3955
  const normalized = compiler;
2873
- if ((normalized.mode === "infer" || normalized.mode === "annotation") && typeof normalized.directive === "string" && (normalized.onUnsupported === "fallback" || normalized.onUnsupported === "warn" || normalized.onUnsupported === "error")) {
3956
+ 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
3957
  return normalized;
2875
3958
  }
2876
3959
  return normalizeReactCompilerOptions(compiler);