@farm.js/react 0.1.0-beta.2 → 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 isStaticKeyedRangeSibling(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) || !isStaticKeyedRangeSibling(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 (!isStaticKeyedRangeSibling(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 || []]) {
@@ -1042,12 +1529,232 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals)
1042
1529
  }
1043
1530
  return {
1044
1531
  dependencies: [...dependencies].sort((left, right) => left - right),
1045
- test: cloneExpression(shape.test),
1046
- logical: shape.logical,
1047
- truthy: shape.truthy,
1048
- falsy: shape.falsy,
1049
- truthyBindings: truthyAnalysis.bindings || [],
1050
- falsyBindings: falsyAnalysis.bindings || []
1532
+ test: cloneExpression(shape.test),
1533
+ logical: shape.logical,
1534
+ truthy: shape.truthy,
1535
+ falsy: shape.falsy,
1536
+ truthyBindings: truthyAnalysis.bindings || [],
1537
+ falsyBindings: falsyAnalysis.bindings || [],
1538
+ descriptorBlocks: new Map([...truthyAnalysis.blocks, ...falsyAnalysis.blocks]),
1539
+ nestedPlans: [...truthyAnalysis.plans, ...falsyAnalysis.plans]
1540
+ };
1541
+ }
1542
+ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals, allowSingleRange, listNames, parent, allocateId) {
1543
+ const containerName = container.openingElement.name;
1544
+ if (!core.types.isJSXIdentifier(containerName) || !/^[a-z]/.test(containerName.name) || containerName.name === "svg" || container.openingElement.attributes.some(
1545
+ (attribute) => core.types.isJSXSpreadAttribute(attribute) || core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
1546
+ )) {
1547
+ return void 0;
1548
+ }
1549
+ const children = meaningfulJsxChildren(container);
1550
+ if (children.length < (allowSingleRange ? 1 : 2)) return void 0;
1551
+ const ranges = [];
1552
+ const dependencies = /* @__PURE__ */ new Set();
1553
+ const descriptorBlocks = /* @__PURE__ */ new Map();
1554
+ const nestedPlans = [];
1555
+ const staticBindings = [];
1556
+ let staticBefore = 0;
1557
+ for (const child of children) {
1558
+ if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1559
+ const shape = conditionalBlockShape(child.expression);
1560
+ if (shape && !validateDerivedExpression(shape.test, safeGlobals)) {
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() };
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);
1581
+ const rangeDependencies = new Set(collectStateDependencies(shape.test, statesByValue));
1582
+ for (const binding of [
1583
+ ...truthyAnalysis.bindings || [],
1584
+ ...falsyAnalysis.bindings || []
1585
+ ]) {
1586
+ for (const dependency of collectStateDependencies(binding.value, statesByValue)) {
1587
+ rangeDependencies.add(dependency);
1588
+ }
1589
+ }
1590
+ for (const dependency of rangeDependencies) dependencies.add(dependency);
1591
+ ranges.push({
1592
+ before: staticBefore,
1593
+ source: child.expression,
1594
+ test: cloneExpression(shape.test),
1595
+ logical: shape.logical,
1596
+ truthy: shape.truthy,
1597
+ falsy: shape.falsy,
1598
+ truthyBindings: truthyAnalysis.bindings || [],
1599
+ falsyBindings: falsyAnalysis.bindings || []
1600
+ });
1601
+ staticBefore = 0;
1602
+ continue;
1603
+ }
1604
+ }
1605
+ if (!core.types.isJSXElement(child) || !isHostElement(child)) 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
+ }
1618
+ staticBefore += 1;
1619
+ }
1620
+ if (ranges.length === 0) return void 0;
1621
+ return {
1622
+ ranges,
1623
+ trailing: staticBefore,
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
1051
1758
  };
1052
1759
  }
1053
1760
  function keyedListBoundary(blockRuntime, plan, source) {
@@ -1072,14 +1779,14 @@ function keyedListBoundary(blockRuntime, plan, source) {
1072
1779
  true
1073
1780
  );
1074
1781
  }
1075
- function hostElementDescriptor(element) {
1782
+ function hostElementDescriptor(element, descriptorBlocks = /* @__PURE__ */ new Map()) {
1076
1783
  const tag = element.openingElement.name;
1077
1784
  const attributes = [];
1078
1785
  const styles = [];
1079
1786
  for (const attribute of element.openingElement.attributes) {
1080
1787
  if (!core.types.isJSXAttribute(attribute)) continue;
1081
1788
  const name = jsxAttributeName(attribute);
1082
- if (!name || name === "key" || /^on[A-Z]/.test(name)) continue;
1789
+ if (!name || name === "key" || name === "ref" || /^on[A-Z]/.test(name)) continue;
1083
1790
  if (name === "style") {
1084
1791
  if (core.types.isJSXExpressionContainer(attribute.value) && core.types.isObjectExpression(attribute.value.expression)) {
1085
1792
  for (const property of attribute.value.expression.properties) {
@@ -1103,24 +1810,93 @@ function hostElementDescriptor(element) {
1103
1810
  ])
1104
1811
  );
1105
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
+ }
1106
1826
  const children = [];
1107
1827
  for (const child of element.children) {
1108
1828
  if (core.types.isJSXText(child)) {
1109
1829
  const text = cleanJsxText(child.value);
1110
1830
  if (text) children.push(core.types.stringLiteral(text));
1111
1831
  } else if (core.types.isJSXElement(child)) {
1112
- 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
+ }
1113
1840
  } else if (core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)) {
1114
- 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
+ }
1115
1852
  }
1116
1853
  }
1117
- return core.types.objectExpression([
1854
+ const properties = [
1118
1855
  core.types.objectProperty(core.types.identifier("kind"), core.types.stringLiteral("element")),
1119
1856
  core.types.objectProperty(core.types.identifier("tag"), core.types.stringLiteral(tag.name)),
1120
1857
  core.types.objectProperty(core.types.identifier("attributes"), core.types.arrayExpression(attributes)),
1121
1858
  core.types.objectProperty(core.types.identifier("styles"), core.types.arrayExpression(styles)),
1122
1859
  core.types.objectProperty(core.types.identifier("children"), core.types.arrayExpression(children))
1123
- ]);
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
+ );
1124
1900
  }
1125
1901
  function keyedRowBindingObject(binding, parameters) {
1126
1902
  const properties = [
@@ -1128,6 +1904,12 @@ function keyedRowBindingObject(binding, parameters) {
1128
1904
  core.types.objectProperty(
1129
1905
  core.types.identifier("path"),
1130
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
+ )
1131
1913
  )
1132
1914
  ];
1133
1915
  if (binding.name) {
@@ -1144,6 +1926,16 @@ function keyedRowBindingObject(binding, parameters) {
1144
1926
  );
1145
1927
  return core.types.objectExpression(properties);
1146
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
+ }
1147
1939
  function uniqueLocalIdentifier(base, nodes) {
1148
1940
  const names = /* @__PURE__ */ new Set();
1149
1941
  for (const node of nodes) {
@@ -1260,6 +2052,10 @@ function keyedRowEventObject(event, renderParameters) {
1260
2052
  const parameters = [core.types.cloneNode(renderParameters[0], true), index, syntheticEvent];
1261
2053
  return core.types.objectExpression([
1262
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
+ ),
1263
2059
  core.types.objectProperty(
1264
2060
  core.types.identifier("invoke"),
1265
2061
  core.types.arrowFunctionExpression(
@@ -1329,6 +2125,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
1329
2125
  plan.source,
1330
2126
  ...plan.conditionals.map((conditional) => conditional.test)
1331
2127
  ]);
2128
+ const delegatedEvents = canDelegateKeyedRowEvents(plan);
1332
2129
  const renderSource = keyedRowsRenderSource(plan, eventFactory, conditionalFactory);
1333
2130
  const renderFactoryParameters = plan.conditionals.length > 0 ? [core.types.cloneNode(eventFactory), core.types.cloneNode(conditionalFactory)] : plan.events.length > 0 ? [core.types.cloneNode(eventFactory)] : [];
1334
2131
  return core.types.jsxElement(
@@ -1346,6 +2143,14 @@ function keyedRowsBoundary(blockRuntime, plan) {
1346
2143
  core.types.jsxIdentifier("items"),
1347
2144
  core.types.jsxExpressionContainer(core.types.arrowFunctionExpression([], cloneExpression(plan.collection)))
1348
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
+ ),
1349
2154
  core.types.jsxAttribute(
1350
2155
  core.types.jsxIdentifier("rowKey"),
1351
2156
  core.types.jsxExpressionContainer(core.types.cloneNode(plan.keyCallback, true))
@@ -1355,7 +2160,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
1355
2160
  core.types.jsxExpressionContainer(
1356
2161
  core.types.arrowFunctionExpression(
1357
2162
  parameters.map((parameter) => core.types.cloneNode(parameter, true)),
1358
- hostElementDescriptor(plan.row)
2163
+ hostElementDescriptor(plan.row, plan.descriptorBlocks)
1359
2164
  )
1360
2165
  )
1361
2166
  ),
@@ -1375,7 +2180,13 @@ function keyedRowsBoundary(blockRuntime, plan) {
1375
2180
  plan.events.map((event) => keyedRowEventObject(event, parameters))
1376
2181
  )
1377
2182
  )
1378
- )
2183
+ ),
2184
+ ...delegatedEvents ? [
2185
+ core.types.jsxAttribute(
2186
+ core.types.jsxIdentifier("delegateEvents"),
2187
+ core.types.jsxExpressionContainer(core.types.booleanLiteral(true))
2188
+ )
2189
+ ] : []
1379
2190
  ] : [],
1380
2191
  ...plan.conditionals.length > 0 ? [
1381
2192
  core.types.jsxAttribute(
@@ -1388,6 +2199,12 @@ function keyedRowsBoundary(blockRuntime, plan) {
1388
2199
  )
1389
2200
  )
1390
2201
  )
2202
+ ] : [],
2203
+ ...plan.descriptorBlocks?.size ? [
2204
+ core.types.jsxAttribute(
2205
+ core.types.jsxIdentifier("hostBlocks"),
2206
+ core.types.jsxExpressionContainer(core.types.booleanLiteral(true))
2207
+ )
1391
2208
  ] : []
1392
2209
  ],
1393
2210
  true
@@ -1397,7 +2214,7 @@ function keyedRowsBoundary(blockRuntime, plan) {
1397
2214
  true
1398
2215
  );
1399
2216
  }
1400
- function keyedRangeObject(range) {
2217
+ function keyedRangeObject(range, descriptorBlocks = /* @__PURE__ */ new Map()) {
1401
2218
  const parameters = range.renderCallback.params.map(
1402
2219
  (parameter) => core.types.cloneNode(parameter, true)
1403
2220
  );
@@ -1412,7 +2229,7 @@ function keyedRangeObject(range) {
1412
2229
  core.types.identifier("create"),
1413
2230
  core.types.arrowFunctionExpression(
1414
2231
  parameters.map((parameter) => core.types.cloneNode(parameter, true)),
1415
- hostElementDescriptor(range.row)
2232
+ hostElementDescriptor(range.row, descriptorBlocks)
1416
2233
  )
1417
2234
  ),
1418
2235
  core.types.objectProperty(
@@ -1456,6 +2273,12 @@ function keyedRangesBoundary(blockRuntime, plan) {
1456
2273
  core.types.jsxAttribute(
1457
2274
  core.types.jsxIdentifier("trailing"),
1458
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
+ )
1459
2282
  )
1460
2283
  ],
1461
2284
  true
@@ -1465,11 +2288,11 @@ function keyedRangesBoundary(blockRuntime, plan) {
1465
2288
  true
1466
2289
  );
1467
2290
  }
1468
- function hostConditionalBranchObject(branch, bindings) {
2291
+ function hostConditionalBranchObject(branch, bindings, descriptorBlocks = /* @__PURE__ */ new Map()) {
1469
2292
  return core.types.objectExpression([
1470
2293
  core.types.objectProperty(
1471
2294
  core.types.identifier("create"),
1472
- core.types.arrowFunctionExpression([], hostElementDescriptor(branch))
2295
+ core.types.arrowFunctionExpression([], hostElementDescriptor(branch, descriptorBlocks))
1473
2296
  ),
1474
2297
  core.types.objectProperty(
1475
2298
  core.types.identifier("bindings"),
@@ -1498,7 +2321,9 @@ function hostConditionalBoundary(blockRuntime, plan) {
1498
2321
  attributes.push(
1499
2322
  core.types.jsxAttribute(
1500
2323
  core.types.jsxIdentifier("truthy"),
1501
- core.types.jsxExpressionContainer(hostConditionalBranchObject(plan.truthy, plan.truthyBindings))
2324
+ core.types.jsxExpressionContainer(
2325
+ hostConditionalBranchObject(plan.truthy, plan.truthyBindings, plan.descriptorBlocks)
2326
+ )
1502
2327
  )
1503
2328
  );
1504
2329
  }
@@ -1506,10 +2331,147 @@ function hostConditionalBoundary(blockRuntime, plan) {
1506
2331
  attributes.push(
1507
2332
  core.types.jsxAttribute(
1508
2333
  core.types.jsxIdentifier("falsy"),
1509
- core.types.jsxExpressionContainer(hostConditionalBranchObject(plan.falsy, plan.falsyBindings))
2334
+ core.types.jsxExpressionContainer(
2335
+ hostConditionalBranchObject(plan.falsy, plan.falsyBindings, plan.descriptorBlocks)
2336
+ )
2337
+ )
2338
+ );
2339
+ }
2340
+ return core.types.jsxElement(core.types.jsxOpeningElement(name, attributes, true), null, [], true);
2341
+ }
2342
+ function conditionalRangeObject(range, descriptorBlocks = /* @__PURE__ */ new Map()) {
2343
+ const properties = [
2344
+ core.types.objectProperty(core.types.identifier("before"), core.types.numericLiteral(range.before)),
2345
+ core.types.objectProperty(
2346
+ core.types.identifier("test"),
2347
+ core.types.arrowFunctionExpression([], cloneExpression(range.test))
2348
+ )
2349
+ ];
2350
+ if (range.logical) {
2351
+ properties.push(core.types.objectProperty(core.types.identifier("logical"), core.types.booleanLiteral(true)));
2352
+ }
2353
+ if (range.truthy) {
2354
+ properties.push(
2355
+ core.types.objectProperty(
2356
+ core.types.identifier("truthy"),
2357
+ hostConditionalBranchObject(range.truthy, range.truthyBindings, descriptorBlocks)
2358
+ )
2359
+ );
2360
+ }
2361
+ if (range.falsy) {
2362
+ properties.push(
2363
+ core.types.objectProperty(
2364
+ core.types.identifier("falsy"),
2365
+ hostConditionalBranchObject(range.falsy, range.falsyBindings, descriptorBlocks)
1510
2366
  )
1511
2367
  );
1512
2368
  }
2369
+ return core.types.objectExpression(properties);
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
+ }
2437
+ function conditionalRangesBoundary(blockRuntime, plan) {
2438
+ const name = core.types.jsxMemberExpression(
2439
+ core.types.jsxIdentifier(blockRuntime.name),
2440
+ core.types.jsxIdentifier("ConditionalRanges")
2441
+ );
2442
+ const source = core.types.cloneNode(plan.source, true);
2443
+ const rootRefIndex = source.openingElement.attributes.findIndex(
2444
+ (attribute) => core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && attribute.name.name === "ref"
2445
+ );
2446
+ const rootRef = rootRefIndex >= 0 ? source.openingElement.attributes.splice(rootRefIndex, 1)[0] : void 0;
2447
+ const attributes = [
2448
+ core.types.jsxAttribute(core.types.jsxIdentifier("id"), core.types.jsxExpressionContainer(core.types.numericLiteral(plan.id))),
2449
+ core.types.jsxAttribute(
2450
+ core.types.jsxIdentifier("render"),
2451
+ core.types.jsxExpressionContainer(core.types.arrowFunctionExpression([], source))
2452
+ ),
2453
+ core.types.jsxAttribute(
2454
+ core.types.jsxIdentifier("ranges"),
2455
+ core.types.jsxExpressionContainer(
2456
+ core.types.arrayExpression(
2457
+ plan.ranges.map((range) => conditionalRangeObject(range, plan.descriptorBlocks))
2458
+ )
2459
+ )
2460
+ ),
2461
+ core.types.jsxAttribute(
2462
+ core.types.jsxIdentifier("trailing"),
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
+ )
2470
+ )
2471
+ ];
2472
+ if (rootRef?.value) {
2473
+ attributes.push(core.types.jsxAttribute(core.types.jsxIdentifier("rootRef"), core.types.cloneNode(rootRef.value, true)));
2474
+ }
1513
2475
  return core.types.jsxElement(core.types.jsxOpeningElement(name, attributes, true), null, [], true);
1514
2476
  }
1515
2477
  function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allowedComponentNames) {
@@ -1677,6 +2639,41 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1677
2639
  }
1678
2640
  if (core.types.isJSXElement(child)) {
1679
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;
1680
2677
  const keyedRanges = insideConditional ? void 0 : analyzeKeyedRangesContainer(child, statesByValue, safeGlobals, listNames);
1681
2678
  if (keyedRanges) {
1682
2679
  plans.push({
@@ -1686,7 +2683,8 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1686
2683
  dependencies: keyedRanges.dependencies,
1687
2684
  source: child,
1688
2685
  ranges: keyedRanges.ranges,
1689
- trailing: keyedRanges.trailing
2686
+ trailing: keyedRanges.trailing,
2687
+ staticBindings: keyedRanges.staticBindings
1690
2688
  });
1691
2689
  for (const range of keyedRanges.ranges) {
1692
2690
  if (core.types.isJSXElement(range.source)) ownedElements.add(range.source);
@@ -1694,42 +2692,102 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1694
2692
  }
1695
2693
  continue;
1696
2694
  }
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
+ );
2706
+ if (conditionalRanges) {
2707
+ plans.push({
2708
+ kind: "conditional-ranges",
2709
+ id: conditionalRangeId,
2710
+ parent,
2711
+ dependencies: conditionalRanges.dependencies,
2712
+ source: child,
2713
+ ranges: conditionalRanges.ranges,
2714
+ trailing: conditionalRanges.trailing,
2715
+ staticBindings: conditionalRanges.staticBindings,
2716
+ descriptorBlocks: conditionalRanges.descriptorBlocks
2717
+ });
2718
+ plans.push(...conditionalRanges.nestedPlans || []);
2719
+ for (const range of conditionalRanges.ranges) {
2720
+ conditionalExpressions.add(range.source);
2721
+ }
2722
+ continue;
2723
+ }
2724
+ nextId = conditionalRangeStart;
2725
+ const hostConditionalStart = nextId;
2726
+ const hostConditionalId = nextId++;
1697
2727
  const hostConditional = analyzeHostConditionalContainer(
1698
2728
  child,
1699
2729
  statesByValue,
1700
- safeGlobals
2730
+ safeGlobals,
2731
+ listNames,
2732
+ hostConditionalId,
2733
+ () => nextId++
1701
2734
  );
1702
2735
  if (hostConditional) {
1703
2736
  plans.push({
1704
2737
  kind: "host-conditional",
1705
- id: nextId++,
2738
+ id: hostConditionalId,
1706
2739
  parent,
1707
2740
  source: child,
1708
2741
  ...hostConditional
1709
2742
  });
2743
+ plans.push(...hostConditional.nestedPlans || []);
1710
2744
  ownedElements.add(child);
1711
2745
  continue;
1712
2746
  }
2747
+ nextId = hostConditionalStart;
2748
+ const keyedRowsStart = nextId;
2749
+ const keyedRowsId = nextId++;
1713
2750
  const keyedRows = analyzeKeyedRowsContainer(child, statesByValue, safeGlobals, listNames);
1714
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
+ }
1715
2769
  plans.push({
1716
2770
  kind: "keyed-rows",
1717
- id: nextId++,
2771
+ id: keyedRowsId,
1718
2772
  parent,
1719
2773
  dependencies: keyedRows.dependencies,
1720
2774
  source: child,
1721
2775
  collection: keyedRows.collection,
2776
+ structureDependencies: keyedRows.structureDependencies,
1722
2777
  keyCallback: keyedRows.keyCallback,
1723
2778
  renderCallback: keyedRows.renderCallback,
1724
- row: keyedRows.row,
1725
- bindings: keyedRows.bindings,
2779
+ row: hostBlocks?.row || keyedRows.row,
2780
+ bindings: hostBlocks?.bindings || keyedRows.bindings,
1726
2781
  events: keyedRows.events,
1727
- conditionals: keyedRows.conditionals,
2782
+ conditionals: hostBlocks ? [] : keyedRows.conditionals,
2783
+ descriptorBlocks: hostBlocks?.descriptorBlocks,
1728
2784
  syntax: keyedRows.syntax
1729
2785
  });
2786
+ plans.push(...hostBlocks?.nestedPlans || []);
1730
2787
  ownedElements.add(child);
1731
2788
  continue;
1732
2789
  }
2790
+ nextId = keyedRowsStart;
1733
2791
  const nested = visitHost(child, parent, insideConditional);
1734
2792
  if (nested.reason) return { dependencies, reason: nested.reason };
1735
2793
  mergeDependencies(dependencies, nested.dependencies);
@@ -1826,6 +2884,46 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1826
2884
  }
1827
2885
  return { dependencies };
1828
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;
1829
2927
  const rootRanges = analyzeKeyedRangesContainer(root, statesByValue, safeGlobals, listNames, true);
1830
2928
  if (rootRanges) {
1831
2929
  plans.push({
@@ -1834,7 +2932,8 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1834
2932
  dependencies: rootRanges.dependencies,
1835
2933
  source: root,
1836
2934
  ranges: rootRanges.ranges,
1837
- trailing: rootRanges.trailing
2935
+ trailing: rootRanges.trailing,
2936
+ staticBindings: rootRanges.staticBindings
1838
2937
  });
1839
2938
  for (const range of rootRanges.ranges) {
1840
2939
  if (core.types.isJSXElement(range.source)) ownedElements.add(range.source);
@@ -1848,6 +2947,41 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
1848
2947
  keyedExpressions
1849
2948
  };
1850
2949
  }
2950
+ const rootConditionalRangeStart = nextId;
2951
+ const rootConditionalRangeId = nextId++;
2952
+ const rootConditionalRanges = analyzeConditionalRangesContainer(
2953
+ root,
2954
+ statesByValue,
2955
+ safeGlobals,
2956
+ true,
2957
+ listNames,
2958
+ rootConditionalRangeId,
2959
+ () => nextId++
2960
+ );
2961
+ if (rootConditionalRanges) {
2962
+ plans.push({
2963
+ kind: "conditional-ranges",
2964
+ id: rootConditionalRangeId,
2965
+ dependencies: rootConditionalRanges.dependencies,
2966
+ source: root,
2967
+ ranges: rootConditionalRanges.ranges,
2968
+ trailing: rootConditionalRanges.trailing,
2969
+ staticBindings: rootConditionalRanges.staticBindings,
2970
+ descriptorBlocks: rootConditionalRanges.descriptorBlocks
2971
+ });
2972
+ plans.push(...rootConditionalRanges.nestedPlans || []);
2973
+ for (const range of rootConditionalRanges.ranges) {
2974
+ conditionalExpressions.add(range.source);
2975
+ }
2976
+ return {
2977
+ plans,
2978
+ componentElements,
2979
+ conditionalExpressions,
2980
+ ownedElements,
2981
+ keyedExpressions
2982
+ };
2983
+ }
2984
+ nextId = rootConditionalRangeStart;
1851
2985
  const result = visitHost(root, void 0, false);
1852
2986
  if (result.reason) return { reason: result.reason };
1853
2987
  return {
@@ -1885,9 +3019,15 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
1885
3019
  plans.map((plan) => [plan.source, plan])
1886
3020
  );
1887
3021
  const rootPlan = planBySource.get(root);
3022
+ if (rootPlan?.kind === "mixed-ranges") {
3023
+ return mixedRangesBoundary(blockRuntime, rootPlan);
3024
+ }
1888
3025
  if (rootPlan?.kind === "keyed-ranges") {
1889
3026
  return keyedRangesBoundary(blockRuntime, rootPlan);
1890
3027
  }
3028
+ if (rootPlan?.kind === "conditional-ranges") {
3029
+ return conditionalRangesBoundary(blockRuntime, rootPlan);
3030
+ }
1891
3031
  const visit = (element) => {
1892
3032
  element.children = element.children.map((child) => {
1893
3033
  if (core.types.isJSXElement(child)) {
@@ -1895,12 +3035,18 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
1895
3035
  if (plan2?.kind === "host-conditional") {
1896
3036
  return hostConditionalBoundary(blockRuntime, plan2);
1897
3037
  }
3038
+ if (plan2?.kind === "mixed-ranges") {
3039
+ return mixedRangesBoundary(blockRuntime, plan2);
3040
+ }
1898
3041
  if (plan2?.kind === "keyed-rows") {
1899
3042
  return keyedRowsBoundary(blockRuntime, plan2);
1900
3043
  }
1901
3044
  if (plan2?.kind === "keyed-ranges") {
1902
3045
  return keyedRangesBoundary(blockRuntime, plan2);
1903
3046
  }
3047
+ if (plan2?.kind === "conditional-ranges") {
3048
+ return conditionalRangesBoundary(blockRuntime, plan2);
3049
+ }
1904
3050
  if (plan2?.kind === "component") {
1905
3051
  return componentIslandBoundary(blockRuntime, plan2, child);
1906
3052
  }
@@ -1941,6 +3087,31 @@ function assignStableBindingTargets(bindings) {
1941
3087
  binding.target = target;
1942
3088
  }
1943
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
+ }
1944
3115
  function lowerStableBindingTargets(root, bindings, blockRuntime, ownedElements) {
1945
3116
  const targetByPath = /* @__PURE__ */ new Map();
1946
3117
  for (const binding of bindings) {
@@ -2210,6 +3381,9 @@ function bindingObject(binding, propsParameter, stateParameter, statesByValue, s
2210
3381
  core.types.objectProperty(core.types.identifier("target"), core.types.numericLiteral(binding.target))
2211
3382
  );
2212
3383
  }
3384
+ if (binding.tracking) {
3385
+ properties.push(core.types.objectProperty(core.types.identifier("tracking"), core.types.stringLiteral(binding.tracking)));
3386
+ }
2213
3387
  if (binding.name)
2214
3388
  properties.push(core.types.objectProperty(core.types.identifier("name"), core.types.stringLiteral(binding.name)));
2215
3389
  properties.push(
@@ -2228,7 +3402,7 @@ function wrapperElement(definitionIdentifier, props) {
2228
3402
  const attributes = props ? [core.types.jsxSpreadAttribute(core.types.cloneNode(props))] : [];
2229
3403
  return core.types.jsxElement(core.types.jsxOpeningElement(name, attributes, true), null, [], true);
2230
3404
  }
2231
- function compileCandidate(candidate, createComponentIdentifier, useStateNames, reactNames, listNames, moduleId) {
3405
+ function compileCandidate(candidate, createComponentIdentifier, useStateNames, reactNames, listNames, moduleId, reactivity) {
2232
3406
  const { path, name, statementPath } = candidate;
2233
3407
  if (path.node.async || path.node.generator)
2234
3408
  return "async and generator components are not supported";
@@ -2345,8 +3519,34 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2345
3519
  );
2346
3520
  const setterReason = validateSetterUsage(expandedRoot, statesBySetter);
2347
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
+ );
2348
3548
  const referencedComponentNames = /* @__PURE__ */ new Set();
2349
- core.traverse(expressionFile(core.types.cloneNode(expandedRoot, true)), {
3549
+ core.traverse(expressionFile(core.types.cloneNode(expandedReactiveRoot, true)), {
2350
3550
  JSXOpeningElement(componentPath) {
2351
3551
  const componentName = componentPath.node.name;
2352
3552
  if (core.types.isJSXIdentifier(componentName) && isComponentName(componentName.name)) {
@@ -2363,32 +3563,54 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2363
3563
  );
2364
3564
  })
2365
3565
  );
2366
- const blockAnalysis = analyzeComposableBlocks(
2367
- expandedRoot,
2368
- statesByValue,
3566
+ let blockAnalysis = analyzeComposableBlocks(
3567
+ expandedReactiveRoot,
3568
+ reactiveByValue,
2369
3569
  safeGlobals,
2370
3570
  listNames,
2371
3571
  allowedComponentNames
2372
3572
  );
2373
- if (blockAnalysis.reason) return blockAnalysis.reason;
2374
- const blockPlans = blockAnalysis.plans || [];
2375
- const analysis = analyzeHostTree(
2376
- expandedRoot,
2377
- statesByValue,
3573
+ let analysis = analyzeHostTree(
3574
+ expandedReactiveRoot,
3575
+ reactiveByValue,
2378
3576
  safeGlobals,
2379
3577
  blockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
2380
3578
  blockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
2381
3579
  blockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
2382
3580
  blockAnalysis.componentElements || /* @__PURE__ */ new Set()
2383
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;
2384
3604
  if (analysis.reason) return analysis.reason;
3605
+ const blockPlans = blockAnalysis.plans || [];
3606
+ markShortCircuitBindings(analysis.bindings || []);
2385
3607
  assignStableBindingTargets(analysis.bindings || []);
2386
3608
  const stateParameter = path.scope.generateUidIdentifier("farmState");
2387
3609
  const blockParameter = path.scope.generateUidIdentifier("farmBlocks");
2388
3610
  const definitionIdentifier = path.scope.generateUidIdentifier(`${name}Compiled`);
2389
3611
  const propsParameter = propsPlan.definitionParameter;
2390
3612
  const rootWithTargets = lowerStableBindingTargets(
2391
- expandedRoot,
3613
+ expandedReactiveRoot,
2392
3614
  analysis.bindings || [],
2393
3615
  blockParameter,
2394
3616
  blockAnalysis.ownedElements || /* @__PURE__ */ new Set()
@@ -2402,12 +3624,13 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2402
3624
  const rewrittenRoot = rewriteStateAccess(
2403
3625
  rootWithBlocks,
2404
3626
  stateParameter,
2405
- statesByValue,
3627
+ reactiveByValue,
2406
3628
  statesBySetter
2407
3629
  );
2408
3630
  const definition = core.types.callExpression(core.types.cloneNode(createComponentIdentifier), [
2409
3631
  core.types.objectExpression([
2410
3632
  core.types.objectProperty(core.types.identifier("displayName"), core.types.stringLiteral(name)),
3633
+ core.types.objectProperty(core.types.identifier("reactivity"), core.types.stringLiteral(reactivity)),
2411
3634
  core.types.spreadElement(
2412
3635
  core.types.conditionalExpression(
2413
3636
  core.types.memberExpression(
@@ -2418,7 +3641,9 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2418
3641
  core.types.objectProperty(core.types.identifier("hmrId"), core.types.stringLiteral(`${moduleId}#${name}`)),
2419
3642
  core.types.objectProperty(
2420
3643
  core.types.identifier("stateSignature"),
2421
- 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
+ )
2422
3647
  )
2423
3648
  ]),
2424
3649
  core.types.objectExpression([])
@@ -2441,6 +3666,22 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2441
3666
  )
2442
3667
  )
2443
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
+ ] : [],
2444
3685
  core.types.objectProperty(
2445
3686
  core.types.identifier("render"),
2446
3687
  core.types.arrowFunctionExpression(
@@ -2460,7 +3701,7 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
2460
3701
  dependencies: block.dependencies
2461
3702
  }))
2462
3703
  ].map(
2463
- (binding) => bindingObject(binding, propsParameter, stateParameter, statesByValue, statesBySetter)
3704
+ (binding) => bindingObject(binding, propsParameter, stateParameter, reactiveByValue, statesBySetter)
2464
3705
  )
2465
3706
  )
2466
3707
  )
@@ -2554,7 +3795,8 @@ async function compileReactModule(code, id, options) {
2554
3795
  useStateNames,
2555
3796
  reactNames,
2556
3797
  listNames,
2557
- id
3798
+ id,
3799
+ options.reactivity
2558
3800
  );
2559
3801
  if (reason) {
2560
3802
  diagnostics.push({
@@ -2681,6 +3923,10 @@ function normalizeReactCompilerOptions(value) {
2681
3923
  if (!["fallback", "warn", "error"].includes(onUnsupported)) {
2682
3924
  throw new TypeError(`Unknown unsupported-component behavior: ${String(onUnsupported)}`);
2683
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
+ }
2684
3930
  if (options.report !== void 0 && typeof options.report !== "boolean") {
2685
3931
  throw new TypeError("The React compiler report option must be a boolean.");
2686
3932
  }
@@ -2691,7 +3937,7 @@ function normalizeReactCompilerOptions(value) {
2691
3937
  }
2692
3938
  const reportFile = normalizeCompilerReportFile(options.reportFile);
2693
3939
  const report = options.report === true || options.reportFile !== void 0;
2694
- return { mode, directive, onUnsupported, report, reportFile };
3940
+ return { mode, directive, onUnsupported, reactivity, report, reportFile };
2695
3941
  }
2696
3942
 
2697
3943
  // src/vite.ts
@@ -2707,7 +3953,7 @@ function readCompilerOptions(rendererOptions) {
2707
3953
  );
2708
3954
  }
2709
3955
  const normalized = compiler;
2710
- 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")) {
2711
3957
  return normalized;
2712
3958
  }
2713
3959
  return normalizeReactCompilerOptions(compiler);