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

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
@@ -68,14 +68,46 @@ var COMPILER_RUNTIME_FEATURE_EXPORTS = {
68
68
  "conditional-ranges": "conditionalRangesRuntimeFeature",
69
69
  "keyed-list": "keyedListRuntimeFeature",
70
70
  "keyed-rows": "keyedRowsRuntimeFeature",
71
+ "keyed-rows-hinted": "keyedRowsHintedRuntimeFeature",
72
+ "keyed-rows-position-hinted": "keyedRowsPositionHintedRuntimeFeature",
73
+ "keyed-rows-reorder-hinted": "keyedRowsReorderHintedRuntimeFeature",
74
+ "keyed-rows-all-hinted": "keyedRowsAllHintedRuntimeFeature",
75
+ "keyed-rows-every-hinted": "keyedRowsEveryHintedRuntimeFeature",
76
+ "keyed-rows-filter-hinted": "keyedRowsFilterHintedRuntimeFeature",
77
+ "keyed-rows-prepend-hinted": "keyedRowsPrependHintedRuntimeFeature",
78
+ "keyed-rows-filter-prepend-hinted": "keyedRowsFilterPrependHintedRuntimeFeature",
71
79
  "keyed-rows-conditional": "keyedRowsConditionalRuntimeFeature",
80
+ "keyed-rows-conditional-hinted": "keyedRowsConditionalHintedRuntimeFeature",
81
+ "keyed-rows-conditional-position-hinted": "keyedRowsConditionalPositionHintedRuntimeFeature",
82
+ "keyed-rows-conditional-reorder-hinted": "keyedRowsConditionalReorderHintedRuntimeFeature",
83
+ "keyed-rows-conditional-all-hinted": "keyedRowsConditionalAllHintedRuntimeFeature",
84
+ "keyed-rows-conditional-every-hinted": "keyedRowsConditionalEveryHintedRuntimeFeature",
85
+ "keyed-rows-conditional-filter-hinted": "keyedRowsConditionalFilterHintedRuntimeFeature",
86
+ "keyed-rows-conditional-prepend-hinted": "keyedRowsConditionalPrependHintedRuntimeFeature",
87
+ "keyed-rows-conditional-filter-prepend-hinted": "keyedRowsConditionalFilterPrependHintedRuntimeFeature",
72
88
  "keyed-rows-host": "keyedRowsHostRuntimeFeature",
89
+ "keyed-rows-host-hinted": "keyedRowsHostHintedRuntimeFeature",
90
+ "keyed-rows-host-position-hinted": "keyedRowsHostPositionHintedRuntimeFeature",
91
+ "keyed-rows-host-reorder-hinted": "keyedRowsHostReorderHintedRuntimeFeature",
92
+ "keyed-rows-host-all-hinted": "keyedRowsHostAllHintedRuntimeFeature",
93
+ "keyed-rows-host-every-hinted": "keyedRowsHostEveryHintedRuntimeFeature",
94
+ "keyed-rows-host-filter-hinted": "keyedRowsHostFilterHintedRuntimeFeature",
95
+ "keyed-rows-host-prepend-hinted": "keyedRowsHostPrependHintedRuntimeFeature",
96
+ "keyed-rows-host-filter-prepend-hinted": "keyedRowsHostFilterPrependHintedRuntimeFeature",
73
97
  "keyed-rows-complete": "keyedRowsCompleteRuntimeFeature",
98
+ "keyed-rows-complete-hinted": "keyedRowsCompleteHintedRuntimeFeature",
99
+ "keyed-rows-complete-position-hinted": "keyedRowsCompletePositionHintedRuntimeFeature",
100
+ "keyed-rows-complete-reorder-hinted": "keyedRowsCompleteReorderHintedRuntimeFeature",
101
+ "keyed-rows-complete-all-hinted": "keyedRowsCompleteAllHintedRuntimeFeature",
102
+ "keyed-rows-complete-every-hinted": "keyedRowsCompleteEveryHintedRuntimeFeature",
103
+ "keyed-rows-complete-filter-hinted": "keyedRowsCompleteFilterHintedRuntimeFeature",
104
+ "keyed-rows-complete-prepend-hinted": "keyedRowsCompletePrependHintedRuntimeFeature",
105
+ "keyed-rows-complete-filter-prepend-hinted": "keyedRowsCompleteFilterPrependHintedRuntimeFeature",
74
106
  "keyed-ranges": "keyedRangesRuntimeFeature",
75
107
  "mixed-ranges": "mixedRangesRuntimeFeature",
76
108
  component: "componentRuntimeFeature"
77
109
  };
78
- function runtimeFeaturesForPlans(plans) {
110
+ function runtimeFeaturesForPlans(plans, keyedMapUpdateHints, keyedArrayFilterHints, keyedArrayPrependHints, keyedArrayPositionHints, keyedArrayReorderHints, keyedArrayRollingWindowHints) {
79
111
  const features = /* @__PURE__ */ new Set();
80
112
  let keyedRowsHaveConditionals = false;
81
113
  let keyedRowsHaveHostBlocks = false;
@@ -90,9 +122,10 @@ function runtimeFeaturesForPlans(plans) {
90
122
  }
91
123
  }
92
124
  if (plans.some((plan) => plan.kind === "keyed-rows")) {
93
- features.add(
94
- keyedRowsHaveConditionals && keyedRowsHaveHostBlocks ? "keyed-rows-complete" : keyedRowsHaveConditionals ? "keyed-rows-conditional" : keyedRowsHaveHostBlocks ? "keyed-rows-host" : "keyed-rows"
95
- );
125
+ const keyedRowsFeature = keyedRowsHaveConditionals && keyedRowsHaveHostBlocks ? "keyed-rows-complete" : keyedRowsHaveConditionals ? "keyed-rows-conditional" : keyedRowsHaveHostBlocks ? "keyed-rows-host" : "keyed-rows";
126
+ const arrayRangeHints = keyedArrayRollingWindowHints || keyedArrayFilterHints || keyedArrayPrependHints;
127
+ const hintSuffix = keyedArrayPositionHints && (arrayRangeHints || keyedArrayReorderHints) || keyedArrayReorderHints && arrayRangeHints ? "-every-hinted" : keyedArrayRollingWindowHints ? "-all-hinted" : keyedArrayPositionHints ? "-position-hinted" : keyedArrayReorderHints ? "-reorder-hinted" : keyedArrayFilterHints && keyedArrayPrependHints ? "-filter-prepend-hinted" : keyedArrayFilterHints ? "-filter-hinted" : keyedArrayPrependHints ? "-prepend-hinted" : keyedMapUpdateHints ? "-hinted" : "";
128
+ features.add(`${keyedRowsFeature}${hintSuffix}`);
96
129
  }
97
130
  return [...features].sort();
98
131
  }
@@ -141,6 +174,174 @@ function referencesIdentifier(expression, name) {
141
174
  });
142
175
  return referenced;
143
176
  }
177
+ function rewriteFreeIdentifierNames(expression, replacements) {
178
+ if (replacements.size === 0) return cloneExpression(expression);
179
+ const file = expressionFile(cloneExpression(expression));
180
+ core.traverse(file, {
181
+ ReferencedIdentifier(path) {
182
+ if (path.scope.hasBinding(path.node.name)) return;
183
+ const replacement = replacements.get(path.node.name);
184
+ if (!replacement) return;
185
+ path.replaceWith(core.types.cloneNode(replacement));
186
+ path.skip();
187
+ }
188
+ });
189
+ return file.program.body[0].expression;
190
+ }
191
+ function keyedIdentityTarget(binding, keyCallback, renderCallback, reactiveByValue, structureDependencies) {
192
+ const dependencies = binding.dependencies || [];
193
+ if (dependencies.length !== 1 || structureDependencies.has(dependencies[0])) return void 0;
194
+ const keyExpression = returnedExpression(keyCallback);
195
+ const keyItem = keyCallback.params[0];
196
+ const rowItem = renderCallback.params[0];
197
+ if (!keyExpression || !core.types.isIdentifier(keyItem) || !core.types.isIdentifier(rowItem)) return void 0;
198
+ const replacements = /* @__PURE__ */ new Map([[keyItem.name, rowItem]]);
199
+ const keyIndex = keyCallback.params[1];
200
+ const rowIndex = renderCallback.params[1];
201
+ if (core.types.isIdentifier(keyIndex) && core.types.isIdentifier(rowIndex)) {
202
+ replacements.set(keyIndex.name, rowIndex);
203
+ }
204
+ const rowKeyExpression = rewriteFreeIdentifierNames(keyExpression, replacements);
205
+ const file = expressionFile(cloneExpression(binding.value));
206
+ let target;
207
+ let valid = true;
208
+ let comparisons = 0;
209
+ core.traverse(file, {
210
+ ReferencedIdentifier(path) {
211
+ if (!valid || path.scope.hasBinding(path.node.name)) return;
212
+ const reactive = reactiveByValue.get(path.node.name);
213
+ if (!reactive) return;
214
+ if (reactive.index !== dependencies[0] || target && target !== reactive) {
215
+ valid = false;
216
+ path.stop();
217
+ return;
218
+ }
219
+ const parent = path.parentPath;
220
+ if (!parent.isBinaryExpression() || parent.node.operator !== "===" && parent.node.operator !== "!==") {
221
+ valid = false;
222
+ path.stop();
223
+ return;
224
+ }
225
+ const other = parent.node.left === path.node ? parent.node.right : parent.node.left;
226
+ if (!core.types.isExpression(other) || !core.types.isNodesEquivalent(other, rowKeyExpression)) {
227
+ valid = false;
228
+ path.stop();
229
+ return;
230
+ }
231
+ target = reactive;
232
+ comparisons += 1;
233
+ }
234
+ });
235
+ return valid && target && comparisons > 0 ? { dependency: target.index, value: core.types.identifier(target.valueName) } : void 0;
236
+ }
237
+ function isPotentialKeyedMembershipCall(expression, reactiveByValue) {
238
+ if (expression.arguments.length !== 1 || !core.types.isExpression(expression.arguments[0]) || !core.types.isMemberExpression(expression.callee) || expression.callee.computed || !core.types.isIdentifier(expression.callee.object) || !core.types.isIdentifier(expression.callee.property, { name: "has" })) {
239
+ return false;
240
+ }
241
+ const reactive = reactiveByValue.get(expression.callee.object.name);
242
+ return Boolean(reactive?.setterName);
243
+ }
244
+ function containsPotentialKeyedMembershipCall(expression, reactiveByValue) {
245
+ let found = false;
246
+ core.traverse(expressionFile(cloneExpression(expression)), {
247
+ CallExpression(path) {
248
+ if (!isPotentialKeyedMembershipCall(path.node, reactiveByValue)) return;
249
+ found = true;
250
+ path.stop();
251
+ }
252
+ });
253
+ return found;
254
+ }
255
+ function isPotentialKeyedMapLookupCall(expression, reactiveByValue) {
256
+ if (expression.arguments.length !== 1 || !core.types.isExpression(expression.arguments[0]) || !core.types.isMemberExpression(expression.callee) || expression.callee.computed || !core.types.isIdentifier(expression.callee.object) || !core.types.isIdentifier(expression.callee.property, { name: "get" })) {
257
+ return false;
258
+ }
259
+ const reactive = reactiveByValue.get(expression.callee.object.name);
260
+ return Boolean(reactive?.setterName);
261
+ }
262
+ function containsPotentialKeyedMapLookupCall(expression, reactiveByValue) {
263
+ let found = false;
264
+ core.traverse(expressionFile(cloneExpression(expression)), {
265
+ CallExpression(path) {
266
+ if (!isPotentialKeyedMapLookupCall(path.node, reactiveByValue)) return;
267
+ found = true;
268
+ path.stop();
269
+ }
270
+ });
271
+ return found;
272
+ }
273
+ function keyedMembershipTarget(binding, keyCallback, renderCallback, reactiveByValue, structureDependencies) {
274
+ const dependencies = binding.dependencies || [];
275
+ if (dependencies.length !== 1 || structureDependencies.has(dependencies[0])) return void 0;
276
+ const keyExpression = returnedExpression(keyCallback);
277
+ const keyItem = keyCallback.params[0];
278
+ const rowItem = renderCallback.params[0];
279
+ if (!keyExpression || !core.types.isIdentifier(keyItem) || !core.types.isIdentifier(rowItem)) return void 0;
280
+ const replacements = /* @__PURE__ */ new Map([[keyItem.name, rowItem]]);
281
+ const keyIndex = keyCallback.params[1];
282
+ const rowIndex = renderCallback.params[1];
283
+ if (core.types.isIdentifier(keyIndex) && core.types.isIdentifier(rowIndex)) {
284
+ replacements.set(keyIndex.name, rowIndex);
285
+ }
286
+ const rowKeyExpression = rewriteFreeIdentifierNames(keyExpression, replacements);
287
+ const file = expressionFile(cloneExpression(binding.value));
288
+ let target;
289
+ let valid = true;
290
+ let calls = 0;
291
+ core.traverse(file, {
292
+ ReferencedIdentifier(path) {
293
+ if (!valid || path.scope.hasBinding(path.node.name)) return;
294
+ const reactive = reactiveByValue.get(path.node.name);
295
+ if (!reactive) return;
296
+ const member = path.parentPath;
297
+ const call = member.parentPath;
298
+ if (!reactive.setterName || reactive.index !== dependencies[0] || target && target !== reactive || !member.isMemberExpression() || member.node.object !== path.node || member.node.computed || !core.types.isIdentifier(member.node.property, { name: "has" }) || !call || !call.isCallExpression() || call.node.callee !== member.node || call.node.arguments.length !== 1 || !core.types.isExpression(call.node.arguments[0]) || !core.types.isNodesEquivalent(call.node.arguments[0], rowKeyExpression)) {
299
+ valid = false;
300
+ path.stop();
301
+ return;
302
+ }
303
+ target = reactive;
304
+ calls += 1;
305
+ }
306
+ });
307
+ return valid && target && calls > 0 ? { dependency: target.index, value: core.types.identifier(target.valueName) } : void 0;
308
+ }
309
+ function keyedMapLookupTarget(binding, keyCallback, renderCallback, reactiveByValue, structureDependencies) {
310
+ const dependencies = binding.dependencies || [];
311
+ if (dependencies.length !== 1 || structureDependencies.has(dependencies[0])) return void 0;
312
+ const keyExpression = returnedExpression(keyCallback);
313
+ const keyItem = keyCallback.params[0];
314
+ const rowItem = renderCallback.params[0];
315
+ if (!keyExpression || !core.types.isIdentifier(keyItem) || !core.types.isIdentifier(rowItem)) return void 0;
316
+ const replacements = /* @__PURE__ */ new Map([[keyItem.name, rowItem]]);
317
+ const keyIndex = keyCallback.params[1];
318
+ const rowIndex = renderCallback.params[1];
319
+ if (core.types.isIdentifier(keyIndex) && core.types.isIdentifier(rowIndex)) {
320
+ replacements.set(keyIndex.name, rowIndex);
321
+ }
322
+ const rowKeyExpression = rewriteFreeIdentifierNames(keyExpression, replacements);
323
+ const file = expressionFile(cloneExpression(binding.value));
324
+ let target;
325
+ let valid = true;
326
+ let calls = 0;
327
+ core.traverse(file, {
328
+ ReferencedIdentifier(path) {
329
+ if (!valid || path.scope.hasBinding(path.node.name)) return;
330
+ const reactive = reactiveByValue.get(path.node.name);
331
+ if (!reactive) return;
332
+ const member = path.parentPath;
333
+ const call = member.parentPath;
334
+ if (!reactive.setterName || reactive.index !== dependencies[0] || target && target !== reactive || !member.isMemberExpression() || member.node.object !== path.node || member.node.computed || !core.types.isIdentifier(member.node.property, { name: "get" }) || !call || !call.isCallExpression() || call.node.callee !== member.node || call.node.arguments.length !== 1 || !core.types.isExpression(call.node.arguments[0]) || !core.types.isNodesEquivalent(call.node.arguments[0], rowKeyExpression)) {
335
+ valid = false;
336
+ path.stop();
337
+ return;
338
+ }
339
+ target = reactive;
340
+ calls += 1;
341
+ }
342
+ });
343
+ return valid && target && calls > 0 ? { dependency: target.index, value: core.types.identifier(target.valueName) } : void 0;
344
+ }
144
345
  function collectReferencedLocals(expression, names) {
145
346
  const references = /* @__PURE__ */ new Set();
146
347
  core.traverse(expressionFile(cloneExpression(expression)), {
@@ -241,7 +442,9 @@ function rewriteHandlerAccess(root, handlersByName) {
241
442
  path.skip();
242
443
  }
243
444
  });
244
- return reason ? { reason } : { root: file.program.body[0].expression };
445
+ return reason ? { reason } : {
446
+ root: file.program.body[0].expression
447
+ };
245
448
  }
246
449
  function isSafeCompilerCall(expression, safeGlobals) {
247
450
  if (core.types.isIdentifier(expression.callee)) {
@@ -249,7 +452,7 @@ function isSafeCompilerCall(expression, safeGlobals) {
249
452
  }
250
453
  return core.types.isMemberExpression(expression.callee) && !expression.callee.computed && core.types.isIdentifier(expression.callee.object, { name: "Math" }) && safeGlobals.has("Math") && core.types.isIdentifier(expression.callee.property) && SAFE_MATH_CALLS.has(expression.callee.property.name);
251
454
  }
252
- function validateDerivedExpression(expression, safeGlobals) {
455
+ function validateDerivedExpression(expression, safeGlobals, additionalSafeCall) {
253
456
  let unsupported;
254
457
  const reject = (reason, path) => {
255
458
  unsupported = reason;
@@ -260,7 +463,9 @@ function validateDerivedExpression(expression, safeGlobals) {
260
463
  AssignmentExpression: (path) => reject("assignments", path),
261
464
  AwaitExpression: (path) => reject("await expressions", path),
262
465
  CallExpression(path) {
263
- if (!isSafeCompilerCall(path.node, safeGlobals)) reject("function calls", path);
466
+ if (!isSafeCompilerCall(path.node, safeGlobals) && !additionalSafeCall?.(path.node)) {
467
+ reject("function calls", path);
468
+ }
264
469
  },
265
470
  ClassExpression: (path) => reject("class expressions", path),
266
471
  Function: (path) => reject("function expressions", path),
@@ -300,6 +505,941 @@ function validateSetterUsage(root, statesBySetter) {
300
505
  });
301
506
  return reason;
302
507
  }
508
+ function isUnchangedMapItem(expression, item) {
509
+ return core.types.isIdentifier(expression, { name: item.name });
510
+ }
511
+ function isSafeKeyedMapReplacement(expression, item, safeGlobals) {
512
+ if (!core.types.isObjectExpression(expression)) return false;
513
+ let spreadsItem = false;
514
+ for (const property of expression.properties) {
515
+ if (core.types.isSpreadElement(property)) {
516
+ if (!core.types.isIdentifier(property.argument, { name: item.name })) return false;
517
+ spreadsItem = true;
518
+ continue;
519
+ }
520
+ if (!core.types.isObjectProperty(property) || property.computed || !core.types.isExpression(property.value)) {
521
+ return false;
522
+ }
523
+ if (validateDerivedExpression(property.value, safeGlobals)) return false;
524
+ }
525
+ return spreadsItem;
526
+ }
527
+ function isSafeKeyedMapResult(expression, item, safeGlobals) {
528
+ if (!core.types.isConditionalExpression(expression)) return false;
529
+ if (validateDerivedExpression(expression.test, safeGlobals)) return false;
530
+ return isUnchangedMapItem(expression.consequent, item) && isSafeKeyedMapReplacement(expression.alternate, item, safeGlobals) || isUnchangedMapItem(expression.alternate, item) && isSafeKeyedMapReplacement(expression.consequent, item, safeGlobals);
531
+ }
532
+ function rewriteKeyedMapUpdateHints(root, hintedStateIndices, statesBySetter, helperIdentifier, safeGlobals) {
533
+ if (hintedStateIndices.size === 0) return { root: core.types.cloneNode(root, true), count: 0 };
534
+ const file = expressionFile(core.types.cloneNode(root, true));
535
+ let count = 0;
536
+ core.traverse(file, {
537
+ CallExpression(path) {
538
+ const callee = path.get("callee");
539
+ if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
540
+ const state = statesBySetter.get(callee.node.name);
541
+ if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
542
+ return;
543
+ }
544
+ const updater = path.node.arguments[0];
545
+ if (!core.types.isArrowFunctionExpression(updater) || updater.async || updater.generator || updater.params.length !== 1 || !core.types.isIdentifier(updater.params[0]) || !core.types.isCallExpression(updater.body) || !core.types.isMemberExpression(updater.body.callee) || updater.body.callee.computed || !core.types.isIdentifier(updater.body.callee.object, {
546
+ name: updater.params[0].name
547
+ }) || !core.types.isIdentifier(updater.body.callee.property, { name: "map" })) {
548
+ return;
549
+ }
550
+ const callback = updater.body.arguments[0];
551
+ if (!core.types.isArrowFunctionExpression(callback) || callback.async || callback.generator || callback.params.length === 0 || callback.params.length > 3 || callback.params.some((parameter) => !core.types.isIdentifier(parameter)) || !core.types.isExpression(callback.body)) {
552
+ return;
553
+ }
554
+ const item = callback.params[0];
555
+ if (!isSafeKeyedMapResult(callback.body, item, safeGlobals)) return;
556
+ const changedIndices = path.scope.generateUidIdentifier("farmChangedIndices");
557
+ const mappedItem = path.scope.generateUidIdentifier("farmMappedItem");
558
+ const nextValue = path.scope.generateUidIdentifier("farmNextItems");
559
+ const index = core.types.isIdentifier(callback.params[1]) ? core.types.cloneNode(callback.params[1]) : path.scope.generateUidIdentifier("farmMapIndex");
560
+ const wrappedCallback = core.types.cloneNode(callback, true);
561
+ if (wrappedCallback.params.length === 1) wrappedCallback.params.push(core.types.cloneNode(index));
562
+ wrappedCallback.body = core.types.blockStatement([
563
+ core.types.variableDeclaration("const", [
564
+ core.types.variableDeclarator(core.types.cloneNode(mappedItem), core.types.cloneNode(callback.body, true))
565
+ ]),
566
+ core.types.ifStatement(
567
+ core.types.binaryExpression("!==", core.types.cloneNode(mappedItem), core.types.cloneNode(item)),
568
+ core.types.expressionStatement(
569
+ core.types.callExpression(
570
+ core.types.memberExpression(core.types.cloneNode(changedIndices), core.types.identifier("push")),
571
+ [core.types.cloneNode(index)]
572
+ )
573
+ )
574
+ ),
575
+ core.types.returnStatement(core.types.cloneNode(mappedItem))
576
+ ]);
577
+ const mapCall = core.types.cloneNode(updater.body, true);
578
+ mapCall.arguments[0] = wrappedCallback;
579
+ const previous = core.types.cloneNode(updater.params[0]);
580
+ path.node.arguments[0] = core.types.arrowFunctionExpression(
581
+ [core.types.cloneNode(previous)],
582
+ core.types.blockStatement([
583
+ core.types.variableDeclaration("const", [
584
+ core.types.variableDeclarator(core.types.cloneNode(changedIndices), core.types.arrayExpression([]))
585
+ ]),
586
+ core.types.variableDeclaration("const", [core.types.variableDeclarator(core.types.cloneNode(nextValue), mapCall)]),
587
+ core.types.returnStatement(
588
+ core.types.callExpression(core.types.cloneNode(helperIdentifier), [
589
+ core.types.cloneNode(previous),
590
+ core.types.cloneNode(nextValue),
591
+ core.types.cloneNode(changedIndices)
592
+ ])
593
+ )
594
+ ])
595
+ );
596
+ count += 1;
597
+ path.skip();
598
+ }
599
+ });
600
+ return {
601
+ root: file.program.body[0].expression,
602
+ count
603
+ };
604
+ }
605
+ function rewriteKeyedArrayAppendHints(root, hintedStateIndices, statesBySetter, helperIdentifier, safeGlobals) {
606
+ if (hintedStateIndices.size === 0) return { root: core.types.cloneNode(root, true), count: 0 };
607
+ const file = expressionFile(core.types.cloneNode(root, true));
608
+ let count = 0;
609
+ core.traverse(file, {
610
+ CallExpression(path) {
611
+ const callee = path.get("callee");
612
+ if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
613
+ const state = statesBySetter.get(callee.node.name);
614
+ if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
615
+ return;
616
+ }
617
+ const updater = path.node.arguments[0];
618
+ if (!core.types.isArrowFunctionExpression(updater) || updater.async || updater.generator || updater.params.length !== 1 || !core.types.isIdentifier(updater.params[0]) || !core.types.isArrayExpression(updater.body) || updater.body.elements.length < 2 || updater.body.elements.some((element) => element === null) || !core.types.isSpreadElement(updater.body.elements[0]) || !core.types.isIdentifier(updater.body.elements[0].argument, {
619
+ name: updater.params[0].name
620
+ })) {
621
+ return;
622
+ }
623
+ const safeAppendValue = (value) => {
624
+ if (core.types.isArrayExpression(value)) {
625
+ return value.elements.every(
626
+ (element) => element !== null && !core.types.isJSXNamespacedName(element) && !core.types.isArgumentPlaceholder(element) && safeAppendValue(core.types.isSpreadElement(element) ? element.argument : element)
627
+ );
628
+ }
629
+ if (core.types.isObjectExpression(value)) {
630
+ return value.properties.every((property) => {
631
+ if (core.types.isSpreadElement(property)) return safeAppendValue(property.argument);
632
+ if (!core.types.isObjectProperty(property) || !core.types.isExpression(property.value)) return false;
633
+ return (!property.computed || core.types.isExpression(property.key) && safeAppendValue(property.key)) && safeAppendValue(property.value);
634
+ });
635
+ }
636
+ return validateDerivedExpression(value, safeGlobals) === void 0;
637
+ };
638
+ if (updater.body.elements.slice(1).some((element) => {
639
+ if (!element || core.types.isJSXNamespacedName(element) || core.types.isArgumentPlaceholder(element)) {
640
+ return true;
641
+ }
642
+ return !safeAppendValue(core.types.isSpreadElement(element) ? element.argument : element);
643
+ })) {
644
+ return;
645
+ }
646
+ const previous = core.types.cloneNode(updater.params[0]);
647
+ const nextValue = path.scope.generateUidIdentifier("farmNextItems");
648
+ path.node.arguments[0] = core.types.arrowFunctionExpression(
649
+ [core.types.cloneNode(previous)],
650
+ core.types.blockStatement([
651
+ core.types.variableDeclaration("const", [
652
+ core.types.variableDeclarator(core.types.cloneNode(nextValue), core.types.cloneNode(updater.body, true))
653
+ ]),
654
+ core.types.returnStatement(
655
+ core.types.callExpression(core.types.cloneNode(helperIdentifier), [
656
+ core.types.cloneNode(previous),
657
+ core.types.cloneNode(nextValue)
658
+ ])
659
+ )
660
+ ])
661
+ );
662
+ count += 1;
663
+ path.skip();
664
+ }
665
+ });
666
+ return {
667
+ root: file.program.body[0].expression,
668
+ count
669
+ };
670
+ }
671
+ function rewriteKeyedArrayPrependHints(root, hintedStateIndices, statesBySetter, helperIdentifier, safeGlobals) {
672
+ if (hintedStateIndices.size === 0) {
673
+ return { root: core.types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
674
+ }
675
+ const file = expressionFile(core.types.cloneNode(root, true));
676
+ const stateIndices = /* @__PURE__ */ new Set();
677
+ let count = 0;
678
+ core.traverse(file, {
679
+ CallExpression(path) {
680
+ const callee = path.get("callee");
681
+ if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
682
+ const state = statesBySetter.get(callee.node.name);
683
+ if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
684
+ return;
685
+ }
686
+ const updater = path.node.arguments[0];
687
+ if (!core.types.isArrowFunctionExpression(updater) || updater.async || updater.generator || updater.params.length !== 1 || !core.types.isIdentifier(updater.params[0]) || !core.types.isArrayExpression(updater.body) || updater.body.elements.length < 2 || updater.body.elements.some((element) => element === null)) {
688
+ return;
689
+ }
690
+ const suffix = updater.body.elements[updater.body.elements.length - 1];
691
+ if (!core.types.isSpreadElement(suffix) || !core.types.isIdentifier(suffix.argument, { name: updater.params[0].name })) {
692
+ return;
693
+ }
694
+ const safePrependValue = (value) => {
695
+ if (core.types.isArrayExpression(value)) {
696
+ return value.elements.every(
697
+ (element) => element !== null && !core.types.isJSXNamespacedName(element) && !core.types.isArgumentPlaceholder(element) && safePrependValue(core.types.isSpreadElement(element) ? element.argument : element)
698
+ );
699
+ }
700
+ if (core.types.isObjectExpression(value)) {
701
+ return value.properties.every((property) => {
702
+ if (core.types.isSpreadElement(property)) return safePrependValue(property.argument);
703
+ if (!core.types.isObjectProperty(property) || !core.types.isExpression(property.value)) return false;
704
+ return (!property.computed || core.types.isExpression(property.key) && safePrependValue(property.key)) && safePrependValue(property.value);
705
+ });
706
+ }
707
+ return validateDerivedExpression(value, safeGlobals) === void 0;
708
+ };
709
+ if (updater.body.elements.slice(0, -1).some((element) => {
710
+ if (!element || core.types.isJSXNamespacedName(element) || core.types.isArgumentPlaceholder(element)) {
711
+ return true;
712
+ }
713
+ return !safePrependValue(core.types.isSpreadElement(element) ? element.argument : element);
714
+ })) {
715
+ return;
716
+ }
717
+ const previous = core.types.cloneNode(updater.params[0]);
718
+ const nextValue = path.scope.generateUidIdentifier("farmNextItems");
719
+ path.node.arguments[0] = core.types.arrowFunctionExpression(
720
+ [core.types.cloneNode(previous)],
721
+ core.types.blockStatement([
722
+ core.types.variableDeclaration("const", [
723
+ core.types.variableDeclarator(core.types.cloneNode(nextValue), core.types.cloneNode(updater.body, true))
724
+ ]),
725
+ core.types.returnStatement(
726
+ core.types.callExpression(core.types.cloneNode(helperIdentifier), [
727
+ core.types.cloneNode(previous),
728
+ core.types.cloneNode(nextValue)
729
+ ])
730
+ )
731
+ ])
732
+ );
733
+ count += 1;
734
+ stateIndices.add(state.index);
735
+ path.skip();
736
+ }
737
+ });
738
+ return {
739
+ root: file.program.body[0].expression,
740
+ count,
741
+ stateIndices
742
+ };
743
+ }
744
+ function rewriteKeyedArrayRollingWindowHints(root, hintedStateIndices, statesBySetter, sliceHelperIdentifier, rollingWindowHelperIdentifier, safeGlobals) {
745
+ if (hintedStateIndices.size === 0) {
746
+ return { root: core.types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
747
+ }
748
+ const file = expressionFile(core.types.cloneNode(root, true));
749
+ const stateIndices = /* @__PURE__ */ new Set();
750
+ let count = 0;
751
+ core.traverse(file, {
752
+ CallExpression(path) {
753
+ const callee = path.get("callee");
754
+ if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
755
+ const state = statesBySetter.get(callee.node.name);
756
+ if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
757
+ return;
758
+ }
759
+ const updater = path.node.arguments[0];
760
+ if (!core.types.isArrowFunctionExpression(updater) || updater.async || updater.generator || updater.params.length !== 1 || !core.types.isIdentifier(updater.params[0]) || !core.types.isArrayExpression(updater.body) || updater.body.elements.length < 2 || updater.body.elements.some((element) => element === null)) {
761
+ return;
762
+ }
763
+ const retainedSpread = updater.body.elements[0];
764
+ if (!core.types.isSpreadElement(retainedSpread) || !core.types.isCallExpression(retainedSpread.argument) || retainedSpread.argument.arguments.length !== 1 || !core.types.isMemberExpression(retainedSpread.argument.callee) || retainedSpread.argument.callee.computed || !core.types.isIdentifier(retainedSpread.argument.callee.object, {
765
+ name: updater.params[0].name
766
+ }) || !core.types.isIdentifier(retainedSpread.argument.callee.property, { name: "slice" }) || !core.types.isExpression(retainedSpread.argument.arguments[0])) {
767
+ return;
768
+ }
769
+ const retainedStart = staticSliceIndex(retainedSpread.argument.arguments[0]);
770
+ if (retainedStart === void 0 || retainedStart === 0) return;
771
+ const safeIncomingValue = (value) => {
772
+ if (core.types.isArrayExpression(value)) {
773
+ return value.elements.every(
774
+ (element) => element !== null && !core.types.isJSXNamespacedName(element) && !core.types.isArgumentPlaceholder(element) && safeIncomingValue(core.types.isSpreadElement(element) ? element.argument : element)
775
+ );
776
+ }
777
+ if (core.types.isObjectExpression(value)) {
778
+ return value.properties.every((property) => {
779
+ if (core.types.isSpreadElement(property)) return safeIncomingValue(property.argument);
780
+ if (!core.types.isObjectProperty(property) || !core.types.isExpression(property.value)) return false;
781
+ return (!property.computed || core.types.isExpression(property.key) && safeIncomingValue(property.key)) && safeIncomingValue(property.value);
782
+ });
783
+ }
784
+ return validateDerivedExpression(value, safeGlobals) === void 0;
785
+ };
786
+ if (updater.body.elements.slice(1).some((element) => {
787
+ if (!element || core.types.isJSXNamespacedName(element) || core.types.isArgumentPlaceholder(element)) {
788
+ return true;
789
+ }
790
+ return !safeIncomingValue(core.types.isSpreadElement(element) ? element.argument : element);
791
+ })) {
792
+ return;
793
+ }
794
+ const previous = core.types.cloneNode(updater.params[0]);
795
+ const sliceMethod = path.scope.generateUidIdentifier("farmSlice");
796
+ const retained = path.scope.generateUidIdentifier("farmRetainedItems");
797
+ const nextValue = path.scope.generateUidIdentifier("farmNextItems");
798
+ const nextElements = core.types.cloneNode(updater.body, true).elements;
799
+ nextElements[0] = core.types.spreadElement(core.types.cloneNode(retained));
800
+ path.node.arguments[0] = core.types.arrowFunctionExpression(
801
+ [core.types.cloneNode(previous)],
802
+ core.types.blockStatement([
803
+ core.types.variableDeclaration("const", [
804
+ core.types.variableDeclarator(
805
+ core.types.cloneNode(sliceMethod),
806
+ core.types.memberExpression(core.types.cloneNode(previous), core.types.identifier("slice"))
807
+ ),
808
+ core.types.variableDeclarator(
809
+ core.types.cloneNode(retained),
810
+ core.types.callExpression(core.types.cloneNode(sliceHelperIdentifier), [
811
+ core.types.cloneNode(previous),
812
+ core.types.cloneNode(sliceMethod),
813
+ core.types.numericLiteral(retainedStart)
814
+ ])
815
+ ),
816
+ core.types.variableDeclarator(core.types.cloneNode(nextValue), core.types.arrayExpression(nextElements))
817
+ ]),
818
+ core.types.returnStatement(
819
+ core.types.callExpression(core.types.cloneNode(rollingWindowHelperIdentifier), [
820
+ core.types.cloneNode(previous),
821
+ core.types.cloneNode(retained),
822
+ core.types.cloneNode(nextValue)
823
+ ])
824
+ )
825
+ ])
826
+ );
827
+ count += 1;
828
+ stateIndices.add(state.index);
829
+ path.skip();
830
+ }
831
+ });
832
+ return {
833
+ root: file.program.body[0].expression,
834
+ count,
835
+ stateIndices
836
+ };
837
+ }
838
+ function staticSliceIndex(expression) {
839
+ if (core.types.isNumericLiteral(expression) && Number.isSafeInteger(expression.value)) {
840
+ return expression.value;
841
+ }
842
+ if (core.types.isUnaryExpression(expression) && (expression.operator === "+" || expression.operator === "-") && core.types.isNumericLiteral(expression.argument)) {
843
+ const value = expression.operator === "-" ? -expression.argument.value : expression.argument.value;
844
+ return Number.isSafeInteger(value) ? value : void 0;
845
+ }
846
+ return void 0;
847
+ }
848
+ function validateKeyedArrayPositionExpression(expression, safeGlobals) {
849
+ const isNumericLiteral = core.types.isNumericLiteral(expression) || core.types.isUnaryExpression(expression) && (expression.operator === "+" || expression.operator === "-") && core.types.isNumericLiteral(expression.argument);
850
+ if (isNumericLiteral && staticSliceIndex(expression) === void 0) {
851
+ return "non-safe-integer position literals";
852
+ }
853
+ return validateDerivedExpression(expression, safeGlobals);
854
+ }
855
+ function rewriteKeyedArrayPositionHints(root, hintedStateIndices, statesBySetter, helperIdentifier, safeGlobals) {
856
+ if (hintedStateIndices.size === 0) {
857
+ return { root: core.types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
858
+ }
859
+ const file = expressionFile(core.types.cloneNode(root, true));
860
+ const stateIndices = /* @__PURE__ */ new Set();
861
+ let count = 0;
862
+ core.traverse(file, {
863
+ CallExpression(path) {
864
+ const callee = path.get("callee");
865
+ if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
866
+ const state = statesBySetter.get(callee.node.name);
867
+ if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
868
+ return;
869
+ }
870
+ const updater = path.node.arguments[0];
871
+ if (!core.types.isArrowFunctionExpression(updater) || updater.async || updater.generator || updater.params.length !== 1 || !core.types.isIdentifier(updater.params[0]) || !core.types.isCallExpression(updater.body) || !core.types.isMemberExpression(updater.body.callee) || updater.body.callee.computed || !core.types.isIdentifier(updater.body.callee.object, { name: updater.params[0].name }) || !core.types.isIdentifier(updater.body.callee.property)) {
872
+ return;
873
+ }
874
+ const methodName = updater.body.callee.property.name;
875
+ const args = updater.body.arguments;
876
+ const kind = methodName === "with" && args.length === 2 ? "replace" : methodName === "toSpliced" && args.length === 3 && core.types.isNumericLiteral(args[1], { value: 0 }) ? "insert" : methodName === "toSpliced" && args.length === 2 && core.types.isNumericLiteral(args[1], { value: 1 }) ? "remove" : void 0;
877
+ if (!kind || !core.types.isExpression(args[0])) return;
878
+ const position = args[0];
879
+ const item = kind === "remove" ? void 0 : args.at(-1);
880
+ if (validateKeyedArrayPositionExpression(position, safeGlobals) !== void 0 || item !== void 0 && (!core.types.isExpression(item) || validateDerivedExpression(item, safeGlobals) !== void 0)) {
881
+ return;
882
+ }
883
+ const previous = core.types.cloneNode(updater.params[0]);
884
+ const method = path.scope.generateUidIdentifier(
885
+ methodName === "with" ? "farmWith" : "farmToSpliced"
886
+ );
887
+ path.node.arguments[0] = core.types.arrowFunctionExpression(
888
+ [core.types.cloneNode(previous)],
889
+ core.types.blockStatement([
890
+ core.types.variableDeclaration("const", [
891
+ core.types.variableDeclarator(
892
+ core.types.cloneNode(method),
893
+ core.types.memberExpression(core.types.cloneNode(previous), core.types.identifier(methodName))
894
+ )
895
+ ]),
896
+ core.types.returnStatement(
897
+ core.types.callExpression(core.types.cloneNode(helperIdentifier), [
898
+ core.types.cloneNode(previous),
899
+ core.types.cloneNode(method),
900
+ core.types.stringLiteral(kind),
901
+ ...args.map((argument) => core.types.cloneNode(argument, true))
902
+ ])
903
+ )
904
+ ])
905
+ );
906
+ count += 1;
907
+ stateIndices.add(state.index);
908
+ path.skip();
909
+ }
910
+ });
911
+ return {
912
+ root: file.program.body[0].expression,
913
+ count,
914
+ stateIndices
915
+ };
916
+ }
917
+ function rewriteKeyedArrayReorderHints(root, hintedStateIndices, statesBySetter, helperIdentifier) {
918
+ if (hintedStateIndices.size === 0) {
919
+ return { root: core.types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
920
+ }
921
+ const file = expressionFile(core.types.cloneNode(root, true));
922
+ const stateIndices = /* @__PURE__ */ new Set();
923
+ let count = 0;
924
+ core.traverse(file, {
925
+ CallExpression(path) {
926
+ const callee = path.get("callee");
927
+ if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
928
+ const state = statesBySetter.get(callee.node.name);
929
+ if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
930
+ return;
931
+ }
932
+ const updater = path.node.arguments[0];
933
+ if (!core.types.isArrowFunctionExpression(updater) || updater.async || updater.generator || updater.params.length !== 1 || !core.types.isIdentifier(updater.params[0]) || !core.types.isCallExpression(updater.body) || updater.body.arguments.length !== 0 || !core.types.isMemberExpression(updater.body.callee) || updater.body.callee.computed || !core.types.isIdentifier(updater.body.callee.object, { name: updater.params[0].name }) || !core.types.isIdentifier(updater.body.callee.property, { name: "toReversed" })) {
934
+ return;
935
+ }
936
+ const previous = core.types.cloneNode(updater.params[0]);
937
+ const method = path.scope.generateUidIdentifier("farmToReversed");
938
+ path.node.arguments[0] = core.types.arrowFunctionExpression(
939
+ [core.types.cloneNode(previous)],
940
+ core.types.blockStatement([
941
+ core.types.variableDeclaration("const", [
942
+ core.types.variableDeclarator(
943
+ core.types.cloneNode(method),
944
+ core.types.memberExpression(core.types.cloneNode(previous), core.types.identifier("toReversed"))
945
+ )
946
+ ]),
947
+ core.types.returnStatement(
948
+ core.types.callExpression(core.types.cloneNode(helperIdentifier), [
949
+ core.types.cloneNode(previous),
950
+ core.types.cloneNode(method)
951
+ ])
952
+ )
953
+ ])
954
+ );
955
+ count += 1;
956
+ stateIndices.add(state.index);
957
+ path.skip();
958
+ }
959
+ });
960
+ return {
961
+ root: file.program.body[0].expression,
962
+ count,
963
+ stateIndices
964
+ };
965
+ }
966
+ function rewriteKeyedArraySortHints(root, hintedStateIndices, statesBySetter, helperIdentifier, safeGlobals) {
967
+ if (hintedStateIndices.size === 0) {
968
+ return { root: core.types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
969
+ }
970
+ const file = expressionFile(core.types.cloneNode(root, true));
971
+ const stateIndices = /* @__PURE__ */ new Set();
972
+ let count = 0;
973
+ core.traverse(file, {
974
+ CallExpression(path) {
975
+ const callee = path.get("callee");
976
+ if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
977
+ const state = statesBySetter.get(callee.node.name);
978
+ if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
979
+ return;
980
+ }
981
+ const updater = path.node.arguments[0];
982
+ if (!core.types.isArrowFunctionExpression(updater) || updater.async || updater.generator || updater.params.length !== 1 || !core.types.isIdentifier(updater.params[0]) || !core.types.isCallExpression(updater.body) || updater.body.arguments.length > 1 || !core.types.isMemberExpression(updater.body.callee) || updater.body.callee.computed || !core.types.isIdentifier(updater.body.callee.object, { name: updater.params[0].name }) || !core.types.isIdentifier(updater.body.callee.property, { name: "toSorted" })) {
983
+ return;
984
+ }
985
+ const comparator = updater.body.arguments[0];
986
+ if (comparator && !core.types.isArrowFunctionExpression(comparator) && !core.types.isFunctionExpression(comparator)) {
987
+ return;
988
+ }
989
+ if (comparator && validateCollectionCallback(comparator, "toSorted", safeGlobals)) return;
990
+ const previous = core.types.cloneNode(updater.params[0]);
991
+ const method = path.scope.generateUidIdentifier("farmToSorted");
992
+ path.node.arguments[0] = core.types.arrowFunctionExpression(
993
+ [core.types.cloneNode(previous)],
994
+ core.types.blockStatement([
995
+ core.types.variableDeclaration("const", [
996
+ core.types.variableDeclarator(
997
+ core.types.cloneNode(method),
998
+ core.types.memberExpression(core.types.cloneNode(previous), core.types.identifier("toSorted"))
999
+ )
1000
+ ]),
1001
+ core.types.returnStatement(
1002
+ core.types.callExpression(core.types.cloneNode(helperIdentifier), [
1003
+ core.types.cloneNode(previous),
1004
+ core.types.cloneNode(method),
1005
+ ...comparator ? [core.types.cloneNode(comparator, true)] : []
1006
+ ])
1007
+ )
1008
+ ])
1009
+ );
1010
+ count += 1;
1011
+ stateIndices.add(state.index);
1012
+ path.skip();
1013
+ }
1014
+ });
1015
+ return {
1016
+ root: file.program.body[0].expression,
1017
+ count,
1018
+ stateIndices
1019
+ };
1020
+ }
1021
+ function rewriteKeyedArraySliceHints(root, hintedStateIndices, statesBySetter, helperIdentifier) {
1022
+ if (hintedStateIndices.size === 0) {
1023
+ return { root: core.types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
1024
+ }
1025
+ const file = expressionFile(core.types.cloneNode(root, true));
1026
+ const stateIndices = /* @__PURE__ */ new Set();
1027
+ let count = 0;
1028
+ core.traverse(file, {
1029
+ CallExpression(path) {
1030
+ const callee = path.get("callee");
1031
+ if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
1032
+ const state = statesBySetter.get(callee.node.name);
1033
+ if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
1034
+ return;
1035
+ }
1036
+ const updater = path.node.arguments[0];
1037
+ if (!core.types.isArrowFunctionExpression(updater) || updater.async || updater.generator || updater.params.length !== 1 || !core.types.isIdentifier(updater.params[0]) || !core.types.isCallExpression(updater.body) || updater.body.arguments.length < 1 || updater.body.arguments.length > 2 || !core.types.isMemberExpression(updater.body.callee) || updater.body.callee.computed || !core.types.isIdentifier(updater.body.callee.object, { name: updater.params[0].name }) || !core.types.isIdentifier(updater.body.callee.property, { name: "slice" })) {
1038
+ return;
1039
+ }
1040
+ const indexes = [];
1041
+ for (const argument of updater.body.arguments) {
1042
+ if (!core.types.isExpression(argument)) return;
1043
+ const value = staticSliceIndex(argument);
1044
+ if (value === void 0) return;
1045
+ indexes.push(value);
1046
+ }
1047
+ if (indexes.length === 1 && indexes[0] === 0) return;
1048
+ const previous = core.types.cloneNode(updater.params[0]);
1049
+ const sliceMethod = path.scope.generateUidIdentifier("farmSlice");
1050
+ path.node.arguments[0] = core.types.arrowFunctionExpression(
1051
+ [core.types.cloneNode(previous)],
1052
+ core.types.blockStatement([
1053
+ core.types.variableDeclaration("const", [
1054
+ core.types.variableDeclarator(
1055
+ core.types.cloneNode(sliceMethod),
1056
+ core.types.memberExpression(core.types.cloneNode(previous), core.types.identifier("slice"))
1057
+ )
1058
+ ]),
1059
+ core.types.returnStatement(
1060
+ core.types.callExpression(core.types.cloneNode(helperIdentifier), [
1061
+ core.types.cloneNode(previous),
1062
+ core.types.cloneNode(sliceMethod),
1063
+ ...indexes.map((value) => core.types.numericLiteral(value))
1064
+ ])
1065
+ )
1066
+ ])
1067
+ );
1068
+ count += 1;
1069
+ stateIndices.add(state.index);
1070
+ path.skip();
1071
+ }
1072
+ });
1073
+ return {
1074
+ root: file.program.body[0].expression,
1075
+ count,
1076
+ stateIndices
1077
+ };
1078
+ }
1079
+ function rewriteKeyedArrayFilterHints(root, hintedStateIndices, statesBySetter, helperIdentifier, safeGlobals) {
1080
+ if (hintedStateIndices.size === 0) {
1081
+ return { root: core.types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
1082
+ }
1083
+ const file = expressionFile(core.types.cloneNode(root, true));
1084
+ const stateIndices = /* @__PURE__ */ new Set();
1085
+ let count = 0;
1086
+ core.traverse(file, {
1087
+ CallExpression(path) {
1088
+ const callee = path.get("callee");
1089
+ if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
1090
+ const state = statesBySetter.get(callee.node.name);
1091
+ if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
1092
+ return;
1093
+ }
1094
+ const updater = path.node.arguments[0];
1095
+ if (!core.types.isArrowFunctionExpression(updater) || updater.async || updater.generator || updater.params.length !== 1 || !core.types.isIdentifier(updater.params[0]) || !core.types.isCallExpression(updater.body) || updater.body.arguments.length !== 1 || !core.types.isMemberExpression(updater.body.callee) || updater.body.callee.computed || !core.types.isIdentifier(updater.body.callee.object, {
1096
+ name: updater.params[0].name
1097
+ }) || !core.types.isIdentifier(updater.body.callee.property, { name: "filter" })) {
1098
+ return;
1099
+ }
1100
+ const predicate = updater.body.arguments[0];
1101
+ if (!core.types.isArrowFunctionExpression(predicate) || predicate.async || predicate.generator || predicate.params.length !== 1 || !core.types.isIdentifier(predicate.params[0]) || !core.types.isExpression(predicate.body) || validateDerivedExpression(predicate.body, safeGlobals)) {
1102
+ return;
1103
+ }
1104
+ const previous = core.types.cloneNode(updater.params[0]);
1105
+ const filterMethod = path.scope.generateUidIdentifier("farmFilter");
1106
+ path.node.arguments[0] = core.types.arrowFunctionExpression(
1107
+ [core.types.cloneNode(previous)],
1108
+ core.types.blockStatement([
1109
+ core.types.variableDeclaration("const", [
1110
+ core.types.variableDeclarator(
1111
+ core.types.cloneNode(filterMethod),
1112
+ core.types.memberExpression(core.types.cloneNode(previous), core.types.identifier("filter"))
1113
+ )
1114
+ ]),
1115
+ core.types.returnStatement(
1116
+ core.types.callExpression(core.types.cloneNode(helperIdentifier), [
1117
+ core.types.cloneNode(previous),
1118
+ core.types.cloneNode(filterMethod),
1119
+ core.types.cloneNode(predicate, true)
1120
+ ])
1121
+ )
1122
+ ])
1123
+ );
1124
+ count += 1;
1125
+ stateIndices.add(state.index);
1126
+ path.skip();
1127
+ }
1128
+ });
1129
+ return {
1130
+ root: file.program.body[0].expression,
1131
+ count,
1132
+ stateIndices
1133
+ };
1134
+ }
1135
+ function collectionConstructorName(kind) {
1136
+ return kind === "set" ? "Set" : "Map";
1137
+ }
1138
+ function isCollectionConstruction(expression, kind, previous) {
1139
+ if (!core.types.isNewExpression(expression) || !core.types.isIdentifier(expression.callee, {
1140
+ name: collectionConstructorName(kind)
1141
+ })) {
1142
+ return false;
1143
+ }
1144
+ if (!previous) return true;
1145
+ return expression.arguments.length === 1 && core.types.isIdentifier(expression.arguments[0], { name: previous.name });
1146
+ }
1147
+ function collectionStateInitializerIsOwned(initialValue, kind, constructorIsGlobal) {
1148
+ if (!initialValue || !constructorIsGlobal) return false;
1149
+ if (isCollectionConstruction(initialValue, kind)) return true;
1150
+ if (!core.types.isArrowFunctionExpression(initialValue) && !core.types.isFunctionExpression(initialValue)) {
1151
+ return false;
1152
+ }
1153
+ if (core.types.isBlockStatement(initialValue.body) && initialValue.body.body.length !== 1) return false;
1154
+ const value = returnedExpression(initialValue);
1155
+ return Boolean(value && isCollectionConstruction(value, kind));
1156
+ }
1157
+ function collectionStateHasOnlyOwnedReads(root, state, kind) {
1158
+ const file = expressionFile(core.types.cloneNode(root, true));
1159
+ let valid = true;
1160
+ const readMethods = kind === "set" ? /* @__PURE__ */ new Set(["has"]) : /* @__PURE__ */ new Set(["get", "has"]);
1161
+ core.traverse(file, {
1162
+ ReferencedIdentifier(path) {
1163
+ if (!valid || !core.types.isIdentifier(path.node) || path.node.name !== state.valueName || path.scope.hasBinding(path.node.name)) {
1164
+ return;
1165
+ }
1166
+ const parent = path.parentPath;
1167
+ if (parent.isNewExpression() && core.types.isIdentifier(parent.node.callee, {
1168
+ name: collectionConstructorName(kind)
1169
+ }) && parent.node.arguments.length === 1 && parent.node.arguments[0] === path.node) {
1170
+ return;
1171
+ }
1172
+ if (!parent.isMemberExpression() || parent.node.object !== path.node || parent.node.computed || !core.types.isIdentifier(parent.node.property)) {
1173
+ valid = false;
1174
+ path.stop();
1175
+ return;
1176
+ }
1177
+ const property = parent.node.property.name;
1178
+ if (property === "size") return;
1179
+ const call = parent.parentPath;
1180
+ if (!readMethods.has(property) || !call?.isCallExpression() || call.node.callee !== parent.node) {
1181
+ valid = false;
1182
+ path.stop();
1183
+ }
1184
+ }
1185
+ });
1186
+ return valid;
1187
+ }
1188
+ function collectionMutationOperation(kind, method) {
1189
+ if (kind === "set" && method === "add") return "set-add";
1190
+ if (kind === "set" && method === "delete") return "set-delete";
1191
+ if (kind === "map" && method === "set") return "map-set";
1192
+ if (kind === "map" && method === "delete") return "map-delete";
1193
+ return void 0;
1194
+ }
1195
+ function collectionMutationArgumentsAreValid(operation, args) {
1196
+ if (!operation || args.some((argument) => !core.types.isExpression(argument))) return false;
1197
+ return operation === "map-set" ? args.length === 2 : args.length === 1;
1198
+ }
1199
+ function prepareKeyedCollectionUpdater(updater, kind, updateHelper, mutationHelper) {
1200
+ if (updater.async || updater.generator || updater.params.length !== 1 || !core.types.isIdentifier(updater.params[0])) {
1201
+ return void 0;
1202
+ }
1203
+ const previous = updater.params[0];
1204
+ if (core.types.isExpression(updater.body)) {
1205
+ if (!core.types.isCallExpression(updater.body) || !core.types.isMemberExpression(updater.body.callee) || updater.body.callee.computed || !core.types.isIdentifier(updater.body.callee.property)) {
1206
+ return void 0;
1207
+ }
1208
+ const operation = collectionMutationOperation(kind, updater.body.callee.property.name);
1209
+ if (operation !== "set-add" && operation !== "map-set" || !collectionMutationArgumentsAreValid(operation, updater.body.arguments) || !isCollectionConstruction(updater.body.callee.object, kind, previous)) {
1210
+ return void 0;
1211
+ }
1212
+ const collection = uniqueLocalIdentifier("_farmCollection", [updater]);
1213
+ const body = core.types.blockStatement([
1214
+ core.types.variableDeclaration("const", [
1215
+ core.types.variableDeclarator(
1216
+ core.types.cloneNode(collection),
1217
+ core.types.cloneNode(updater.body.callee.object, true)
1218
+ )
1219
+ ]),
1220
+ core.types.returnStatement(
1221
+ core.types.callExpression(core.types.cloneNode(updateHelper), [
1222
+ core.types.cloneNode(previous),
1223
+ core.types.callExpression(core.types.cloneNode(mutationHelper), [
1224
+ core.types.cloneNode(collection),
1225
+ core.types.memberExpression(core.types.cloneNode(collection), core.types.cloneNode(updater.body.callee.property)),
1226
+ core.types.stringLiteral(operation),
1227
+ ...updater.body.arguments.map(
1228
+ (argument) => core.types.cloneNode(argument, true)
1229
+ )
1230
+ ]),
1231
+ core.types.stringLiteral(kind)
1232
+ ])
1233
+ )
1234
+ ]);
1235
+ return {
1236
+ updater: core.types.arrowFunctionExpression([core.types.cloneNode(previous)], body),
1237
+ mutations: 1
1238
+ };
1239
+ }
1240
+ const cloned = core.types.cloneNode(updater, true);
1241
+ const file = expressionFile(cloned);
1242
+ let functionPath;
1243
+ core.traverse(file, {
1244
+ Function(path) {
1245
+ if (functionPath) return;
1246
+ if (path.isArrowFunctionExpression() || path.isFunctionExpression()) {
1247
+ functionPath = path;
1248
+ }
1249
+ }
1250
+ });
1251
+ if (!functionPath || !core.types.isBlockStatement(functionPath.node.body)) return void 0;
1252
+ const clonedPrevious = functionPath.node.params[0];
1253
+ if (!core.types.isIdentifier(clonedPrevious)) return void 0;
1254
+ let collectionDeclaration;
1255
+ const updaterBody = functionPath.get("body");
1256
+ if (!updaterBody.isBlockStatement()) return void 0;
1257
+ for (const statement of updaterBody.get("body")) {
1258
+ if (!statement.isVariableDeclaration({ kind: "const" })) continue;
1259
+ for (const declaration of statement.get("declarations")) {
1260
+ if (declaration.isVariableDeclarator() && core.types.isIdentifier(declaration.node.id) && core.types.isExpression(declaration.node.init) && isCollectionConstruction(declaration.node.init, kind, clonedPrevious)) {
1261
+ if (collectionDeclaration) return void 0;
1262
+ collectionDeclaration = declaration;
1263
+ }
1264
+ }
1265
+ }
1266
+ if (!collectionDeclaration || !core.types.isIdentifier(collectionDeclaration.node.id)) return void 0;
1267
+ if (collectionDeclaration.scope.getBinding(collectionConstructorName(kind))) return void 0;
1268
+ const collectionName = collectionDeclaration.node.id.name;
1269
+ const collectionBinding = collectionDeclaration.scope.getBinding(collectionName);
1270
+ const previousBinding = functionPath.scope.getBinding(clonedPrevious.name);
1271
+ if (!collectionBinding || !previousBinding) return void 0;
1272
+ let valid = true;
1273
+ let mutations = 0;
1274
+ core.traverse(file, {
1275
+ ReferencedIdentifier(path) {
1276
+ if (!valid) return;
1277
+ const binding = path.scope.getBinding(path.node.name);
1278
+ const belongsToUpdater = path.getFunctionParent()?.node === functionPath?.node;
1279
+ if (binding === collectionBinding) {
1280
+ if (!belongsToUpdater) {
1281
+ valid = false;
1282
+ path.stop();
1283
+ return;
1284
+ }
1285
+ const parent = path.parentPath;
1286
+ if (parent.isReturnStatement() && parent.node.argument === path.node) return;
1287
+ if (!parent.isMemberExpression() || parent.node.object !== path.node || parent.node.computed || !core.types.isIdentifier(parent.node.property)) {
1288
+ valid = false;
1289
+ path.stop();
1290
+ return;
1291
+ }
1292
+ const method = parent.node.property.name;
1293
+ if (method === "size") return;
1294
+ const call = parent.parentPath;
1295
+ if (!call?.isCallExpression() || call.node.callee !== parent.node) {
1296
+ valid = false;
1297
+ path.stop();
1298
+ return;
1299
+ }
1300
+ const operation = collectionMutationOperation(kind, method);
1301
+ const read = kind === "set" ? method === "has" : method === "get" || method === "has";
1302
+ if (read) return;
1303
+ if (!collectionMutationArgumentsAreValid(operation, call.node.arguments) || call.parentPath.isMemberExpression() && call.parentPath.node.object === call.node) {
1304
+ valid = false;
1305
+ path.stop();
1306
+ return;
1307
+ }
1308
+ mutations += 1;
1309
+ return;
1310
+ }
1311
+ if (binding === previousBinding) {
1312
+ if (!belongsToUpdater) {
1313
+ valid = false;
1314
+ path.stop();
1315
+ return;
1316
+ }
1317
+ const parent = path.parentPath;
1318
+ if (parent.isReturnStatement() && parent.node.argument === path.node) return;
1319
+ if (parent.isNewExpression() && parent.node.arguments.length === 1 && parent.node.arguments[0] === path.node && core.types.isIdentifier(parent.node.callee, {
1320
+ name: collectionConstructorName(kind)
1321
+ })) {
1322
+ return;
1323
+ }
1324
+ if (parent.isMemberExpression() && parent.node.object === path.node && !parent.node.computed && core.types.isIdentifier(parent.node.property)) {
1325
+ const method = parent.node.property.name;
1326
+ const call = parent.parentPath;
1327
+ if (method === "size" || (kind === "set" ? method === "has" : method === "get" || method === "has") && call?.isCallExpression() && call.node.callee === parent.node) {
1328
+ return;
1329
+ }
1330
+ }
1331
+ valid = false;
1332
+ path.stop();
1333
+ }
1334
+ },
1335
+ ReturnStatement(path) {
1336
+ if (!valid || path.getFunctionParent()?.node !== functionPath?.node || !path.node.argument) {
1337
+ return;
1338
+ }
1339
+ const value = path.node.argument;
1340
+ const returnsOwnedCollection = core.types.isIdentifier(value) && (path.scope.getBinding(value.name) === collectionBinding || path.scope.getBinding(value.name) === previousBinding) || isCollectionConstruction(value, kind);
1341
+ if (!returnsOwnedCollection) {
1342
+ valid = false;
1343
+ path.stop();
1344
+ }
1345
+ }
1346
+ });
1347
+ if (!valid || mutations === 0) return void 0;
1348
+ core.traverse(file, {
1349
+ CallExpression(path) {
1350
+ if (path.getFunctionParent()?.node !== functionPath?.node) return;
1351
+ const callee = path.node.callee;
1352
+ if (!core.types.isMemberExpression(callee) || callee.computed || !core.types.isIdentifier(callee.object, { name: collectionName }) || path.scope.getBinding(collectionName) !== collectionBinding || !core.types.isIdentifier(callee.property)) {
1353
+ return;
1354
+ }
1355
+ const operation = collectionMutationOperation(kind, callee.property.name);
1356
+ if (!collectionMutationArgumentsAreValid(operation, path.node.arguments)) return;
1357
+ path.replaceWith(
1358
+ core.types.callExpression(core.types.cloneNode(mutationHelper), [
1359
+ core.types.cloneNode(callee.object),
1360
+ core.types.memberExpression(core.types.cloneNode(callee.object), core.types.cloneNode(callee.property)),
1361
+ core.types.stringLiteral(operation),
1362
+ ...path.node.arguments.map((argument) => core.types.cloneNode(argument, true))
1363
+ ])
1364
+ );
1365
+ path.skip();
1366
+ },
1367
+ ReturnStatement(path) {
1368
+ if (path.getFunctionParent()?.node !== functionPath?.node || !path.node.argument) return;
1369
+ path.node.argument = core.types.callExpression(core.types.cloneNode(updateHelper), [
1370
+ core.types.cloneNode(clonedPrevious),
1371
+ core.types.cloneNode(path.node.argument, true),
1372
+ core.types.stringLiteral(kind)
1373
+ ]);
1374
+ }
1375
+ });
1376
+ const prepared = file.program.body[0].expression;
1377
+ return core.types.isArrowFunctionExpression(prepared) || core.types.isFunctionExpression(prepared) ? { updater: prepared, mutations } : void 0;
1378
+ }
1379
+ function rewriteKeyedCollectionUpdateHints(root, targetKinds, states, statesBySetter, updateHelper, mutationHelper, globalCollections) {
1380
+ if (targetKinds.size === 0) return { root: core.types.cloneNode(root, true), count: 0 };
1381
+ const file = expressionFile(core.types.cloneNode(root, true));
1382
+ let count = 0;
1383
+ for (const [stateIndex, kind] of targetKinds) {
1384
+ const state = states[stateIndex];
1385
+ if (!state || !collectionStateInitializerIsOwned(
1386
+ state.initialValue,
1387
+ kind,
1388
+ globalCollections.has(collectionConstructorName(kind))
1389
+ ) || !collectionStateHasOnlyOwnedReads(root, state, kind)) {
1390
+ continue;
1391
+ }
1392
+ const replacements = /* @__PURE__ */ new Map();
1393
+ let valid = true;
1394
+ core.traverse(file, {
1395
+ CallExpression(path) {
1396
+ if (!valid) return;
1397
+ const callee = path.get("callee");
1398
+ if (!callee.isIdentifier({ name: state.setterName }) || callee.scope.hasBinding(callee.node.name) || statesBySetter.get(callee.node.name)?.index !== stateIndex) {
1399
+ return;
1400
+ }
1401
+ if (path.node.arguments.length !== 1 || !core.types.isExpression(path.node.arguments[0])) {
1402
+ valid = false;
1403
+ path.stop();
1404
+ return;
1405
+ }
1406
+ const update = path.node.arguments[0];
1407
+ if (path.scope.getBinding(collectionConstructorName(kind))) {
1408
+ valid = false;
1409
+ path.stop();
1410
+ return;
1411
+ }
1412
+ if (isCollectionConstruction(update, kind)) return;
1413
+ if (!core.types.isArrowFunctionExpression(update) && !core.types.isFunctionExpression(update)) {
1414
+ valid = false;
1415
+ path.stop();
1416
+ return;
1417
+ }
1418
+ const prepared = prepareKeyedCollectionUpdater(update, kind, updateHelper, mutationHelper);
1419
+ if (!prepared) {
1420
+ valid = false;
1421
+ path.stop();
1422
+ return;
1423
+ }
1424
+ replacements.set(path.node, prepared);
1425
+ }
1426
+ });
1427
+ if (!valid || replacements.size === 0) continue;
1428
+ core.traverse(file, {
1429
+ CallExpression(path) {
1430
+ const prepared = replacements.get(path.node);
1431
+ if (!prepared) return;
1432
+ path.node.arguments[0] = core.types.cloneNode(prepared.updater, true);
1433
+ count += prepared.mutations;
1434
+ path.skip();
1435
+ }
1436
+ });
1437
+ }
1438
+ return {
1439
+ root: file.program.body[0].expression,
1440
+ count
1441
+ };
1442
+ }
303
1443
  function rewriteStateAccess(expression, stateParameter, statesByValue, statesBySetter) {
304
1444
  const file = expressionFile(cloneExpression(expression));
305
1445
  core.traverse(file, {
@@ -550,21 +1690,28 @@ function analyzeMapList(expression, statesByValue, safeGlobals) {
550
1690
  const collection = callee.object;
551
1691
  const collectionUnsupported = validateCollectionPipeline(collection, safeGlobals);
552
1692
  if (collectionUnsupported) {
553
- return { reason: `keyed list collection cannot use ${collectionUnsupported}` };
1693
+ return {
1694
+ reason: `keyed list collection cannot use ${collectionUnsupported}`
1695
+ };
554
1696
  }
555
1697
  if (expression.arguments.length !== 1 || !core.types.isArrowFunctionExpression(expression.arguments[0]) && !core.types.isFunctionExpression(expression.arguments[0])) {
556
1698
  return { reason: "keyed list map must use one inline render callback" };
557
1699
  }
558
1700
  const callback = expression.arguments[0];
559
1701
  if (containsDirectHookCall(callback)) {
560
- return { reason: "Hooks cannot be called directly inside a keyed list callback" };
1702
+ return {
1703
+ reason: "Hooks cannot be called directly inside a keyed list callback"
1704
+ };
561
1705
  }
562
1706
  const row = returnedExpression(callback);
563
1707
  if (!row || !core.types.isJSXElement(row)) {
564
1708
  return { reason: "keyed list map callbacks must return one React element" };
565
1709
  }
566
1710
  const key = jsxKeyExpression(row);
567
- if (!key) return { reason: "automatically compiled lists require an explicit item key" };
1711
+ if (!key)
1712
+ return {
1713
+ reason: "automatically compiled lists require an explicit item key"
1714
+ };
568
1715
  const keyReason = validateKeyFunction(callback, key, safeGlobals);
569
1716
  if (keyReason) return { reason: keyReason };
570
1717
  return { dependencies: collectStateDependencies(expression, statesByValue) };
@@ -579,7 +1726,9 @@ function listAttributeExpression(element, name) {
579
1726
  }
580
1727
  function analyzePublicList(element, statesByValue, safeGlobals) {
581
1728
  if (element.openingElement.attributes.some((attribute) => core.types.isJSXSpreadAttribute(attribute))) {
582
- return { reason: "compiled List boundaries do not support JSX attribute spreads" };
1729
+ return {
1730
+ reason: "compiled List boundaries do not support JSX attribute spreads"
1731
+ };
583
1732
  }
584
1733
  const each = listAttributeExpression(element, "each");
585
1734
  const by = listAttributeExpression(element, "by");
@@ -597,7 +1746,9 @@ function analyzePublicList(element, statesByValue, safeGlobals) {
597
1746
  if (keyReason) return { reason: keyReason };
598
1747
  const children = meaningfulJsxChildren(element);
599
1748
  if (children.length !== 1 || !core.types.isJSXExpressionContainer(children[0]) || core.types.isJSXEmptyExpression(children[0].expression) || !core.types.isArrowFunctionExpression(children[0].expression) && !core.types.isFunctionExpression(children[0].expression)) {
600
- return { reason: "compiled List children must use one inline render function" };
1749
+ return {
1750
+ reason: "compiled List children must use one inline render function"
1751
+ };
601
1752
  }
602
1753
  const render = children[0].expression;
603
1754
  if (!returnedExpression(render)) {
@@ -711,13 +1862,20 @@ function stabilizeDeferredEventCurrentTargets(root, compilerSetters) {
711
1862
  const expression = file.program.body[0].expression;
712
1863
  return core.types.isJSXElement(expression) ? expression : core.types.cloneNode(root, true);
713
1864
  }
714
- function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters) {
1865
+ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters, keyedTargetReactiveByValue) {
715
1866
  if (renderCallback.async || renderCallback.generator || renderCallback.params.length < 1 || renderCallback.params.length > 2 || !core.types.isIdentifier(renderCallback.params[0]) || renderCallback.params[1] !== void 0 && !core.types.isIdentifier(renderCallback.params[1])) {
716
- return { reason: "compiled keyed rows require item and optional index identifiers" };
1867
+ return {
1868
+ reason: "compiled keyed rows require item and optional index identifiers"
1869
+ };
717
1870
  }
718
1871
  const bindings = [];
719
1872
  const events = [];
720
1873
  const conditionals = [];
1874
+ const validateBindingExpression = (expression) => validateDerivedExpression(
1875
+ expression,
1876
+ safeGlobals,
1877
+ keyedTargetReactiveByValue ? (call) => isPotentialKeyedMembershipCall(call, keyedTargetReactiveByValue) || isPotentialKeyedMapLookupCall(call, keyedTargetReactiveByValue) : void 0
1878
+ );
721
1879
  const visit = (element, path) => {
722
1880
  const tag = element.openingElement.name;
723
1881
  if (!core.types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
@@ -796,7 +1954,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
796
1954
  if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
797
1955
  return "compiled keyed row style names must use camelCase or a CSS custom property";
798
1956
  }
799
- const unsupported2 = validateDerivedExpression(property.value, safeGlobals);
1957
+ const unsupported2 = validateBindingExpression(property.value);
800
1958
  if (unsupported2) {
801
1959
  return `compiled keyed row style ${propertyName} cannot use ${unsupported2}`;
802
1960
  }
@@ -810,7 +1968,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
810
1968
  continue;
811
1969
  }
812
1970
  if (name === "children") return "compiled keyed row children props are not supported yet";
813
- const unsupported = validateDerivedExpression(expression, safeGlobals);
1971
+ const unsupported = validateBindingExpression(expression);
814
1972
  if (unsupported) return `compiled keyed row ${name} cannot use ${unsupported}`;
815
1973
  bindings.push({
816
1974
  kind: "attribute",
@@ -860,7 +2018,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
860
2018
  (child) => core.types.isJSXExpressionContainer(child) && !core.types.isJSXEmptyExpression(child.expression)
861
2019
  );
862
2020
  for (const child of expressions) {
863
- const unsupported = validateDerivedExpression(child.expression, safeGlobals);
2021
+ const unsupported = validateBindingExpression(child.expression);
864
2022
  if (unsupported) return `compiled keyed row text cannot use ${unsupported}`;
865
2023
  }
866
2024
  if (nestedElements.length > 0 && expressions.length > 0) {
@@ -876,7 +2034,11 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
876
2034
  parts.push(cloneExpression(child.expression));
877
2035
  }
878
2036
  }
879
- bindings.push({ kind: "text", path: [...path], value: core.types.arrayExpression(parts) });
2037
+ bindings.push({
2038
+ kind: "text",
2039
+ path: [...path],
2040
+ value: core.types.arrayExpression(parts)
2041
+ });
880
2042
  }
881
2043
  let elementIndex = 0;
882
2044
  for (const child of element.children) {
@@ -890,7 +2052,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
890
2052
  const reason = visit(row, []);
891
2053
  return reason ? { reason } : { bindings, events, conditionals };
892
2054
  }
893
- function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acceptUnsupportedRow = false) {
2055
+ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acceptUnsupportedRow = false, allowMembershipTargets = false) {
894
2056
  let collection;
895
2057
  let keyCallback;
896
2058
  let renderCallback;
@@ -943,7 +2105,8 @@ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acce
943
2105
  row,
944
2106
  renderCallback,
945
2107
  safeGlobals,
946
- new Set([...statesByValue.values()].map((state) => state.setterName))
2108
+ new Set([...statesByValue.values()].map((state) => state.setterName)),
2109
+ allowMembershipTargets ? statesByValue : void 0
947
2110
  );
948
2111
  if (rowAnalysis.reason && !acceptUnsupportedRow) return void 0;
949
2112
  const keyExpression = returnedExpression(keyCallback);
@@ -956,6 +2119,7 @@ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acce
956
2119
  return {
957
2120
  source,
958
2121
  collection,
2122
+ collectionDependency: core.types.isIdentifier(collection) ? statesByValue.get(collection.name)?.index : void 0,
959
2123
  structureDependencies: [...structureDependencies].sort((left, right) => left - right),
960
2124
  keyCallback,
961
2125
  renderCallback,
@@ -975,16 +2139,83 @@ function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNa
975
2139
  if (container.openingElement.attributes.some(
976
2140
  (attribute) => core.types.isJSXSpreadAttribute(attribute) || core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && (attribute.name.name === "ref" || attribute.name.name === "dangerouslySetInnerHTML")
977
2141
  )) {
978
- return void 0;
2142
+ return void 0;
2143
+ }
2144
+ for (const attribute of container.openingElement.attributes) {
2145
+ if (core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && core.types.isJSXExpressionContainer(attribute.value) && !core.types.isJSXEmptyExpression(attribute.value.expression) && !/^on[A-Z]/.test(attribute.name.name) && collectStateDependencies(attribute.value.expression, statesByValue).length > 0) {
2146
+ return void 0;
2147
+ }
2148
+ }
2149
+ const children = meaningfulJsxChildren(container);
2150
+ if (children.length !== 1) return void 0;
2151
+ const shape = analyzeKeyedRowChild(
2152
+ children[0],
2153
+ statesByValue,
2154
+ safeGlobals,
2155
+ listNames,
2156
+ true,
2157
+ true
2158
+ );
2159
+ if (!shape || shape.rowReason) return shape;
2160
+ const needsMembershipProof = (binding) => containsPotentialKeyedMembershipCall(binding.value, statesByValue);
2161
+ const needsMapLookupProof = (binding) => containsPotentialKeyedMapLookupCall(binding.value, statesByValue);
2162
+ if (shape.conditionals.length > 0 || shape.events.length > 0 && !canDelegateKeyedRowEvents({
2163
+ conditionals: shape.conditionals,
2164
+ events: shape.events,
2165
+ source: container
2166
+ })) {
2167
+ return shape.bindings.some(
2168
+ (binding) => needsMembershipProof(binding) || needsMapLookupProof(binding)
2169
+ ) ? {
2170
+ ...shape,
2171
+ rowReason: "keyed collection targets require compiler-owned rows without React-owned branches or events"
2172
+ } : shape;
2173
+ }
2174
+ const structureDependencies = new Set(shape.structureDependencies);
2175
+ const bindings = shape.bindings.map((binding) => ({
2176
+ ...binding,
2177
+ identityTarget: keyedIdentityTarget(
2178
+ binding,
2179
+ shape.keyCallback,
2180
+ shape.renderCallback,
2181
+ statesByValue,
2182
+ structureDependencies
2183
+ ),
2184
+ membershipTarget: keyedMembershipTarget(
2185
+ binding,
2186
+ shape.keyCallback,
2187
+ shape.renderCallback,
2188
+ statesByValue,
2189
+ structureDependencies
2190
+ ),
2191
+ mapLookupTarget: keyedMapLookupTarget(
2192
+ binding,
2193
+ shape.keyCallback,
2194
+ shape.renderCallback,
2195
+ statesByValue,
2196
+ structureDependencies
2197
+ )
2198
+ }));
2199
+ if (bindings.some(
2200
+ (binding, index) => needsMembershipProof(shape.bindings[index]) && !binding.membershipTarget
2201
+ )) {
2202
+ return {
2203
+ ...shape,
2204
+ rowReason: "keyed membership targets must call one local Set state with the exact row key"
2205
+ };
979
2206
  }
980
- for (const attribute of container.openingElement.attributes) {
981
- if (core.types.isJSXAttribute(attribute) && core.types.isJSXIdentifier(attribute.name) && core.types.isJSXExpressionContainer(attribute.value) && !core.types.isJSXEmptyExpression(attribute.value.expression) && !/^on[A-Z]/.test(attribute.name.name) && collectStateDependencies(attribute.value.expression, statesByValue).length > 0) {
982
- return void 0;
983
- }
2207
+ if (bindings.some(
2208
+ (binding, index) => needsMapLookupProof(shape.bindings[index]) && !binding.mapLookupTarget
2209
+ )) {
2210
+ return {
2211
+ ...shape,
2212
+ rowReason: "keyed Map lookup targets must call one local Map state with the exact row key"
2213
+ };
984
2214
  }
985
- const children = meaningfulJsxChildren(container);
986
- if (children.length !== 1) return void 0;
987
- return analyzeKeyedRowChild(children[0], statesByValue, safeGlobals, listNames, true);
2215
+ return {
2216
+ ...shape,
2217
+ bindings
2218
+ };
988
2219
  }
989
2220
  function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, listNames, allowSingleRange = false) {
990
2221
  if (container.openingElement.attributes.some(
@@ -1140,7 +2371,11 @@ function analyzeHostConditionalTree(branch, safeGlobals, allowStaticEvents = fal
1140
2371
  parts.push(cloneExpression(child.expression));
1141
2372
  }
1142
2373
  }
1143
- bindings.push({ kind: "text", path: [...path], value: core.types.arrayExpression(parts) });
2374
+ bindings.push({
2375
+ kind: "text",
2376
+ path: [...path],
2377
+ value: core.types.arrayExpression(parts)
2378
+ });
1144
2379
  }
1145
2380
  let elementIndex = 0;
1146
2381
  for (const child of element.children) {
@@ -1312,7 +2547,11 @@ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames,
1312
2547
  listNames,
1313
2548
  id,
1314
2549
  allocateId
1315
- ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
2550
+ ) : {
2551
+ bindings: [],
2552
+ plans: [],
2553
+ blocks: /* @__PURE__ */ new Map()
2554
+ };
1316
2555
  const falsy = shape.falsy ? analyzeRecursiveHostTree(
1317
2556
  shape.falsy,
1318
2557
  statesByValue,
@@ -1320,7 +2559,11 @@ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames,
1320
2559
  listNames,
1321
2560
  id,
1322
2561
  allocateId
1323
- ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
2562
+ ) : {
2563
+ bindings: [],
2564
+ plans: [],
2565
+ blocks: /* @__PURE__ */ new Map()
2566
+ };
1324
2567
  if (truthy.reason) return truthy.reason;
1325
2568
  if (falsy.reason) return falsy.reason;
1326
2569
  plans.push(...truthy.plans, ...falsy.plans);
@@ -1478,7 +2721,11 @@ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames,
1478
2721
  parts.push(cloneExpression(child.expression));
1479
2722
  }
1480
2723
  }
1481
- bindings.push({ kind: "text", path: [...path], value: core.types.arrayExpression(parts) });
2724
+ bindings.push({
2725
+ kind: "text",
2726
+ path: [...path],
2727
+ value: core.types.arrayExpression(parts)
2728
+ });
1482
2729
  }
1483
2730
  let elementIndex = 0;
1484
2731
  for (const child of element.children) {
@@ -1545,7 +2792,11 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals,
1545
2792
  listNames,
1546
2793
  parent,
1547
2794
  allocateId
1548
- ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
2795
+ ) : {
2796
+ bindings: [],
2797
+ plans: [],
2798
+ blocks: /* @__PURE__ */ new Map()
2799
+ };
1549
2800
  const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
1550
2801
  shape.falsy,
1551
2802
  statesByValue,
@@ -1553,7 +2804,11 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals,
1553
2804
  listNames,
1554
2805
  parent,
1555
2806
  allocateId
1556
- ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
2807
+ ) : {
2808
+ bindings: [],
2809
+ plans: [],
2810
+ blocks: /* @__PURE__ */ new Map()
2811
+ };
1557
2812
  if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
1558
2813
  const dependencies = new Set(collectStateDependencies(shape.test, statesByValue));
1559
2814
  for (const binding of [...truthyAnalysis.bindings || [], ...falsyAnalysis.bindings || []]) {
@@ -1599,7 +2854,11 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
1599
2854
  listNames,
1600
2855
  parent,
1601
2856
  allocateId
1602
- ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
2857
+ ) : {
2858
+ bindings: [],
2859
+ plans: [],
2860
+ blocks: /* @__PURE__ */ new Map()
2861
+ };
1603
2862
  const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
1604
2863
  shape.falsy,
1605
2864
  statesByValue,
@@ -1607,7 +2866,11 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
1607
2866
  listNames,
1608
2867
  parent,
1609
2868
  allocateId
1610
- ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
2869
+ ) : {
2870
+ bindings: [],
2871
+ plans: [],
2872
+ blocks: /* @__PURE__ */ new Map()
2873
+ };
1611
2874
  if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
1612
2875
  nestedPlans.push(...truthyAnalysis.plans, ...falsyAnalysis.plans);
1613
2876
  for (const [element, plan] of truthyAnalysis.blocks) descriptorBlocks.set(element, plan);
@@ -1700,7 +2963,11 @@ function analyzeMixedRangesContainer(container, statesByValue, safeGlobals, list
1700
2963
  listNames,
1701
2964
  parent,
1702
2965
  allocateId
1703
- ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
2966
+ ) : {
2967
+ bindings: [],
2968
+ plans: [],
2969
+ blocks: /* @__PURE__ */ new Map()
2970
+ };
1704
2971
  const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
1705
2972
  shape.falsy,
1706
2973
  statesByValue,
@@ -1708,7 +2975,11 @@ function analyzeMixedRangesContainer(container, statesByValue, safeGlobals, list
1708
2975
  listNames,
1709
2976
  parent,
1710
2977
  allocateId
1711
- ) : { bindings: [], plans: [], blocks: /* @__PURE__ */ new Map() };
2978
+ ) : {
2979
+ bindings: [],
2980
+ plans: [],
2981
+ blocks: /* @__PURE__ */ new Map()
2982
+ };
1712
2983
  if (!mergeAnalysis(truthyAnalysis) || !mergeAnalysis(falsyAnalysis)) return void 0;
1713
2984
  for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
1714
2985
  dependencies.add(dependency);
@@ -1949,6 +3220,57 @@ function keyedRowBindingObject(binding, parameters) {
1949
3220
  if (binding.name) {
1950
3221
  properties.push(core.types.objectProperty(core.types.identifier("name"), core.types.stringLiteral(binding.name)));
1951
3222
  }
3223
+ if (binding.identityTarget) {
3224
+ properties.push(
3225
+ core.types.objectProperty(
3226
+ core.types.identifier("identityTarget"),
3227
+ core.types.objectExpression([
3228
+ core.types.objectProperty(
3229
+ core.types.identifier("dependency"),
3230
+ core.types.numericLiteral(binding.identityTarget.dependency)
3231
+ ),
3232
+ core.types.objectProperty(
3233
+ core.types.identifier("read"),
3234
+ core.types.arrowFunctionExpression([], cloneExpression(binding.identityTarget.value))
3235
+ )
3236
+ ])
3237
+ )
3238
+ );
3239
+ }
3240
+ if (binding.membershipTarget) {
3241
+ properties.push(
3242
+ core.types.objectProperty(
3243
+ core.types.identifier("membershipTarget"),
3244
+ core.types.objectExpression([
3245
+ core.types.objectProperty(
3246
+ core.types.identifier("dependency"),
3247
+ core.types.numericLiteral(binding.membershipTarget.dependency)
3248
+ ),
3249
+ core.types.objectProperty(
3250
+ core.types.identifier("read"),
3251
+ core.types.arrowFunctionExpression([], cloneExpression(binding.membershipTarget.value))
3252
+ )
3253
+ ])
3254
+ )
3255
+ );
3256
+ }
3257
+ if (binding.mapLookupTarget) {
3258
+ properties.push(
3259
+ core.types.objectProperty(
3260
+ core.types.identifier("mapLookupTarget"),
3261
+ core.types.objectExpression([
3262
+ core.types.objectProperty(
3263
+ core.types.identifier("dependency"),
3264
+ core.types.numericLiteral(binding.mapLookupTarget.dependency)
3265
+ ),
3266
+ core.types.objectProperty(
3267
+ core.types.identifier("read"),
3268
+ core.types.arrowFunctionExpression([], cloneExpression(binding.mapLookupTarget.value))
3269
+ )
3270
+ ])
3271
+ )
3272
+ );
3273
+ }
1952
3274
  properties.push(
1953
3275
  core.types.objectProperty(
1954
3276
  core.types.identifier("read"),
@@ -2143,7 +3465,7 @@ function keyedRowConditionalObject(conditional, parameters) {
2143
3465
  }
2144
3466
  return core.types.objectExpression(properties);
2145
3467
  }
2146
- function keyedRowsBoundary(blockRuntime, plan) {
3468
+ function keyedRowsBoundary(blockRuntime, plan, keyedMapUpdateHints, keyedArrayFilterHintedStateIndices, keyedArrayPrependHintedStateIndices, keyedArrayPositionHintedStateIndices, keyedArrayReorderHintedStateIndices) {
2147
3469
  const name = core.types.jsxMemberExpression(
2148
3470
  core.types.jsxIdentifier(blockRuntime.name),
2149
3471
  core.types.jsxIdentifier("KeyedRows")
@@ -2177,6 +3499,16 @@ function keyedRowsBoundary(blockRuntime, plan) {
2177
3499
  core.types.jsxIdentifier("items"),
2178
3500
  core.types.jsxExpressionContainer(core.types.arrowFunctionExpression([], cloneExpression(plan.collection)))
2179
3501
  ),
3502
+ ...keyedMapUpdateHints ? [
3503
+ core.types.jsxAttribute(
3504
+ core.types.jsxIdentifier("dependencies"),
3505
+ core.types.jsxExpressionContainer(
3506
+ core.types.arrayExpression(
3507
+ plan.dependencies.map((dependency) => core.types.numericLiteral(dependency))
3508
+ )
3509
+ )
3510
+ )
3511
+ ] : [],
2180
3512
  core.types.jsxAttribute(
2181
3513
  core.types.jsxIdentifier("structureDependencies"),
2182
3514
  core.types.jsxExpressionContainer(
@@ -2185,6 +3517,36 @@ function keyedRowsBoundary(blockRuntime, plan) {
2185
3517
  )
2186
3518
  )
2187
3519
  ),
3520
+ ...!keyedMapUpdateHints || plan.collectionDependency === void 0 ? [] : [
3521
+ core.types.jsxAttribute(
3522
+ core.types.jsxIdentifier("collectionDependency"),
3523
+ core.types.jsxExpressionContainer(core.types.numericLiteral(plan.collectionDependency))
3524
+ )
3525
+ ],
3526
+ ...plan.collectionDependency !== void 0 && keyedArrayFilterHintedStateIndices.has(plan.collectionDependency) ? [
3527
+ core.types.jsxAttribute(
3528
+ core.types.jsxIdentifier("filterIndexIndependent"),
3529
+ core.types.jsxExpressionContainer(core.types.booleanLiteral(true))
3530
+ )
3531
+ ] : [],
3532
+ ...plan.collectionDependency !== void 0 && keyedArrayPrependHintedStateIndices.has(plan.collectionDependency) ? [
3533
+ core.types.jsxAttribute(
3534
+ core.types.jsxIdentifier("prependIndexIndependent"),
3535
+ core.types.jsxExpressionContainer(core.types.booleanLiteral(true))
3536
+ )
3537
+ ] : [],
3538
+ ...plan.collectionDependency !== void 0 && keyedArrayPositionHintedStateIndices.has(plan.collectionDependency) ? [
3539
+ core.types.jsxAttribute(
3540
+ core.types.jsxIdentifier("positionIndexIndependent"),
3541
+ core.types.jsxExpressionContainer(core.types.booleanLiteral(true))
3542
+ )
3543
+ ] : [],
3544
+ ...plan.collectionDependency !== void 0 && keyedArrayReorderHintedStateIndices.has(plan.collectionDependency) ? [
3545
+ core.types.jsxAttribute(
3546
+ core.types.jsxIdentifier("reorderIndexIndependent"),
3547
+ core.types.jsxExpressionContainer(core.types.booleanLiteral(true))
3548
+ )
3549
+ ] : [],
2188
3550
  core.types.jsxAttribute(
2189
3551
  core.types.jsxIdentifier("rowKey"),
2190
3552
  core.types.jsxExpressionContainer(core.types.cloneNode(plan.keyCallback, true))
@@ -2511,7 +3873,9 @@ function conditionalRangesBoundary(blockRuntime, plan) {
2511
3873
  function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allowedComponentNames) {
2512
3874
  const name = element.openingElement.name;
2513
3875
  if (!core.types.isJSXIdentifier(name) || !isComponentName(name.name)) {
2514
- return { reason: "component islands require a direct component identifier" };
3876
+ return {
3877
+ reason: "component islands require a direct component identifier"
3878
+ };
2515
3879
  }
2516
3880
  if (!allowedComponentNames.has(name.name)) {
2517
3881
  return {
@@ -2519,19 +3883,27 @@ function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allo
2519
3883
  };
2520
3884
  }
2521
3885
  if (meaningfulJsxChildren(element).length > 0) {
2522
- return { reason: `component island ${name.name} does not support children yet` };
3886
+ return {
3887
+ reason: `component island ${name.name} does not support children yet`
3888
+ };
2523
3889
  }
2524
3890
  const dependencies = /* @__PURE__ */ new Set();
2525
3891
  for (const attribute of element.openingElement.attributes) {
2526
3892
  if (core.types.isJSXSpreadAttribute(attribute)) {
2527
- return { reason: `component island ${name.name} does not support JSX attribute spreads` };
3893
+ return {
3894
+ reason: `component island ${name.name} does not support JSX attribute spreads`
3895
+ };
2528
3896
  }
2529
3897
  const attributeName = jsxAttributeName(attribute);
2530
3898
  if (!attributeName) {
2531
- return { reason: `component island ${name.name} does not support namespaced JSX attributes` };
3899
+ return {
3900
+ reason: `component island ${name.name} does not support namespaced JSX attributes`
3901
+ };
2532
3902
  }
2533
3903
  if (attributeName === "ref" || attributeName === "key" || attributeName === "children") {
2534
- return { reason: `component island ${name.name} does not support ${attributeName} yet` };
3904
+ return {
3905
+ reason: `component island ${name.name} does not support ${attributeName} yet`
3906
+ };
2535
3907
  }
2536
3908
  if (!core.types.isJSXExpressionContainer(attribute.value) || core.types.isJSXEmptyExpression(attribute.value.expression)) {
2537
3909
  continue;
@@ -2550,7 +3922,9 @@ function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allo
2550
3922
  (dependency) => dependencies.add(dependency)
2551
3923
  );
2552
3924
  }
2553
- return { dependencies: [...dependencies].sort((left, right) => left - right) };
3925
+ return {
3926
+ dependencies: [...dependencies].sort((left, right) => left - right)
3927
+ };
2554
3928
  }
2555
3929
  function componentIslandBoundary(blockRuntime, plan, source) {
2556
3930
  const name = core.types.jsxMemberExpression(
@@ -2807,6 +4181,7 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
2807
4181
  dependencies: keyedRows.dependencies,
2808
4182
  source: child,
2809
4183
  collection: keyedRows.collection,
4184
+ collectionDependency: keyedRows.collectionDependency,
2810
4185
  structureDependencies: keyedRows.structureDependencies,
2811
4186
  keyCallback: keyedRows.keyCallback,
2812
4187
  renderCallback: keyedRows.renderCallback,
@@ -3048,7 +4423,7 @@ function conditionalBlockBoundary(blockRuntime, plan, source) {
3048
4423
  true
3049
4424
  );
3050
4425
  }
3051
- function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
4426
+ function lowerComposableBlocks(root, plans, blockRuntime, listNames, keyedMapUpdateHints, keyedArrayFilterHintedStateIndices, keyedArrayPrependHintedStateIndices, keyedArrayPositionHintedStateIndices, keyedArrayReorderHintedStateIndices) {
3052
4427
  const planBySource = new Map(
3053
4428
  plans.map((plan) => [plan.source, plan])
3054
4429
  );
@@ -3073,7 +4448,15 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
3073
4448
  return mixedRangesBoundary(blockRuntime, plan2);
3074
4449
  }
3075
4450
  if (plan2?.kind === "keyed-rows") {
3076
- return keyedRowsBoundary(blockRuntime, plan2);
4451
+ return keyedRowsBoundary(
4452
+ blockRuntime,
4453
+ plan2,
4454
+ keyedMapUpdateHints,
4455
+ keyedArrayFilterHintedStateIndices,
4456
+ keyedArrayPrependHintedStateIndices,
4457
+ keyedArrayPositionHintedStateIndices,
4458
+ keyedArrayReorderHintedStateIndices
4459
+ );
3077
4460
  }
3078
4461
  if (plan2?.kind === "keyed-ranges") {
3079
4462
  return keyedRangesBoundary(blockRuntime, plan2);
@@ -3436,7 +4819,7 @@ function wrapperElement(definitionIdentifier, props) {
3436
4819
  const attributes = props ? [core.types.jsxSpreadAttribute(core.types.cloneNode(props))] : [];
3437
4820
  return core.types.jsxElement(core.types.jsxOpeningElement(name, attributes, true), null, [], true);
3438
4821
  }
3439
- function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureIdentifiers, usedRuntimeFeatures, useStateNames, reactNames, listNames, moduleId, reactivity) {
4822
+ function compileCandidate(candidate, createComponentIdentifier, keyedMapUpdateIdentifier, keyedArrayAppendIdentifier, keyedArrayFilterIdentifier, keyedArrayPrependIdentifier, keyedArrayPositionIdentifier, keyedArrayReorderIdentifier, keyedArraySortIdentifier, keyedArrayRollingWindowIdentifier, keyedArraySliceIdentifier, keyedCollectionUpdateIdentifier, keyedCollectionMutationIdentifier, runtimeFeatureIdentifiers, usedRuntimeFeatures, optimizationCounts, useStateNames, reactNames, listNames, moduleId, reactivity) {
3440
4823
  const { path, name, statementPath } = candidate;
3441
4824
  if (path.node.async || path.node.generator)
3442
4825
  return "async and generator components are not supported";
@@ -3448,6 +4831,7 @@ function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureId
3448
4831
  const safeGlobals = new Set(
3449
4832
  [...SAFE_GLOBAL_CALLS, "Math"].filter((name2) => !path.scope.getBinding(name2))
3450
4833
  );
4834
+ const globalCollections = new Set(["Set", "Map"].filter((name2) => !path.scope.getBinding(name2)));
3451
4835
  const states = [];
3452
4836
  const locals = [];
3453
4837
  let returned;
@@ -3495,9 +4879,17 @@ function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureId
3495
4879
  if (declaration.init.async || declaration.init.generator) {
3496
4880
  return `event handler ${declaration.id.name} must be synchronous`;
3497
4881
  }
3498
- locals.push({ kind: "handler", name: declaration.id.name, value: declaration.init });
4882
+ locals.push({
4883
+ kind: "handler",
4884
+ name: declaration.id.name,
4885
+ value: declaration.init
4886
+ });
3499
4887
  } else {
3500
- locals.push({ kind: "derived", name: declaration.id.name, value: declaration.init });
4888
+ locals.push({
4889
+ kind: "derived",
4890
+ name: declaration.id.name,
4891
+ value: declaration.init
4892
+ });
3501
4893
  }
3502
4894
  }
3503
4895
  if (states.length === 0) return "no local useState binding was found";
@@ -3636,8 +5028,413 @@ function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureId
3636
5028
  }
3637
5029
  if (blockAnalysis.reason) return blockAnalysis.reason;
3638
5030
  if (analysis.reason) return analysis.reason;
5031
+ const hintedStateIndices = new Set(
5032
+ (blockAnalysis.plans || []).filter(
5033
+ (plan) => plan.kind === "keyed-rows" && plan.collectionDependency !== void 0
5034
+ ).map((plan) => plan.collectionDependency)
5035
+ );
5036
+ const hintedRoot = rewriteKeyedMapUpdateHints(
5037
+ expandedReactiveRoot,
5038
+ hintedStateIndices,
5039
+ statesBySetter,
5040
+ keyedMapUpdateIdentifier,
5041
+ safeGlobals
5042
+ );
5043
+ let appliedKeyedMapUpdateHints = 0;
5044
+ if (hintedRoot.count > 0) {
5045
+ const hintedBlockAnalysis = analyzeComposableBlocks(
5046
+ hintedRoot.root,
5047
+ reactiveByValue,
5048
+ safeGlobals,
5049
+ listNames,
5050
+ allowedComponentNames
5051
+ );
5052
+ const hintedAnalysis = analyzeHostTree(
5053
+ hintedRoot.root,
5054
+ reactiveByValue,
5055
+ safeGlobals,
5056
+ hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
5057
+ hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
5058
+ hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
5059
+ hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
5060
+ );
5061
+ if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
5062
+ expandedReactiveRoot = hintedRoot.root;
5063
+ blockAnalysis = hintedBlockAnalysis;
5064
+ analysis = hintedAnalysis;
5065
+ appliedKeyedMapUpdateHints = hintedRoot.count;
5066
+ optimizationCounts.keyedMapUpdateHints += hintedRoot.count;
5067
+ }
5068
+ }
5069
+ const appendHintedStateIndices = new Set(hintedStateIndices);
5070
+ for (const plan of blockAnalysis.plans || []) {
5071
+ if (plan.kind !== "keyed-rows" || plan.collectionDependency === void 0) continue;
5072
+ const keyExpression = returnedExpression(plan.keyCallback);
5073
+ if (!keyExpression || collectStateDependencies(keyExpression, reactiveByValue).includes(plan.collectionDependency)) {
5074
+ appendHintedStateIndices.delete(plan.collectionDependency);
5075
+ }
5076
+ }
5077
+ const appendHintedRoot = rewriteKeyedArrayAppendHints(
5078
+ expandedReactiveRoot,
5079
+ appendHintedStateIndices,
5080
+ statesBySetter,
5081
+ keyedArrayAppendIdentifier,
5082
+ safeGlobals
5083
+ );
5084
+ let appliedKeyedArrayAppendHints = 0;
5085
+ if (appendHintedRoot.count > 0) {
5086
+ const hintedBlockAnalysis = analyzeComposableBlocks(
5087
+ appendHintedRoot.root,
5088
+ reactiveByValue,
5089
+ safeGlobals,
5090
+ listNames,
5091
+ allowedComponentNames
5092
+ );
5093
+ const hintedAnalysis = analyzeHostTree(
5094
+ appendHintedRoot.root,
5095
+ reactiveByValue,
5096
+ safeGlobals,
5097
+ hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
5098
+ hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
5099
+ hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
5100
+ hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
5101
+ );
5102
+ if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
5103
+ expandedReactiveRoot = appendHintedRoot.root;
5104
+ blockAnalysis = hintedBlockAnalysis;
5105
+ analysis = hintedAnalysis;
5106
+ appliedKeyedArrayAppendHints = appendHintedRoot.count;
5107
+ optimizationCounts.keyedArrayAppendHints += appendHintedRoot.count;
5108
+ }
5109
+ }
5110
+ const shiftedIndexIndependentStateIndices = new Set(hintedStateIndices);
5111
+ for (const plan of blockAnalysis.plans || []) {
5112
+ if (plan.kind !== "keyed-rows" || plan.collectionDependency === void 0) continue;
5113
+ const keyExpression = returnedExpression(plan.keyCallback);
5114
+ if (plan.renderCallback.params.length > 1 || !keyExpression || collectStateDependencies(keyExpression, reactiveByValue).includes(plan.collectionDependency)) {
5115
+ shiftedIndexIndependentStateIndices.delete(plan.collectionDependency);
5116
+ }
5117
+ }
5118
+ const prependHintedRoot = rewriteKeyedArrayPrependHints(
5119
+ expandedReactiveRoot,
5120
+ shiftedIndexIndependentStateIndices,
5121
+ statesBySetter,
5122
+ keyedArrayPrependIdentifier,
5123
+ safeGlobals
5124
+ );
5125
+ let appliedKeyedArrayPrependHints = 0;
5126
+ let appliedPrependHintedStateIndices = /* @__PURE__ */ new Set();
5127
+ if (prependHintedRoot.count > 0) {
5128
+ const hintedBlockAnalysis = analyzeComposableBlocks(
5129
+ prependHintedRoot.root,
5130
+ reactiveByValue,
5131
+ safeGlobals,
5132
+ listNames,
5133
+ allowedComponentNames
5134
+ );
5135
+ const hintedAnalysis = analyzeHostTree(
5136
+ prependHintedRoot.root,
5137
+ reactiveByValue,
5138
+ safeGlobals,
5139
+ hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
5140
+ hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
5141
+ hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
5142
+ hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
5143
+ );
5144
+ if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
5145
+ expandedReactiveRoot = prependHintedRoot.root;
5146
+ blockAnalysis = hintedBlockAnalysis;
5147
+ analysis = hintedAnalysis;
5148
+ appliedKeyedArrayPrependHints = prependHintedRoot.count;
5149
+ appliedPrependHintedStateIndices = prependHintedRoot.stateIndices;
5150
+ optimizationCounts.keyedArrayPrependHints += prependHintedRoot.count;
5151
+ }
5152
+ }
5153
+ const rollingWindowHintedRoot = rewriteKeyedArrayRollingWindowHints(
5154
+ expandedReactiveRoot,
5155
+ shiftedIndexIndependentStateIndices,
5156
+ statesBySetter,
5157
+ keyedArraySliceIdentifier,
5158
+ keyedArrayRollingWindowIdentifier,
5159
+ safeGlobals
5160
+ );
5161
+ let appliedKeyedArrayRollingWindowHints = 0;
5162
+ let appliedRollingWindowHintedStateIndices = /* @__PURE__ */ new Set();
5163
+ if (rollingWindowHintedRoot.count > 0) {
5164
+ const hintedBlockAnalysis = analyzeComposableBlocks(
5165
+ rollingWindowHintedRoot.root,
5166
+ reactiveByValue,
5167
+ safeGlobals,
5168
+ listNames,
5169
+ allowedComponentNames
5170
+ );
5171
+ const hintedAnalysis = analyzeHostTree(
5172
+ rollingWindowHintedRoot.root,
5173
+ reactiveByValue,
5174
+ safeGlobals,
5175
+ hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
5176
+ hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
5177
+ hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
5178
+ hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
5179
+ );
5180
+ if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
5181
+ expandedReactiveRoot = rollingWindowHintedRoot.root;
5182
+ blockAnalysis = hintedBlockAnalysis;
5183
+ analysis = hintedAnalysis;
5184
+ appliedKeyedArrayRollingWindowHints = rollingWindowHintedRoot.count;
5185
+ appliedRollingWindowHintedStateIndices = rollingWindowHintedRoot.stateIndices;
5186
+ optimizationCounts.keyedArrayRollingWindowHints += rollingWindowHintedRoot.count;
5187
+ }
5188
+ }
5189
+ const positionHintedRoot = rewriteKeyedArrayPositionHints(
5190
+ expandedReactiveRoot,
5191
+ shiftedIndexIndependentStateIndices,
5192
+ statesBySetter,
5193
+ keyedArrayPositionIdentifier,
5194
+ safeGlobals
5195
+ );
5196
+ let appliedKeyedArrayPositionHints = 0;
5197
+ let appliedPositionHintedStateIndices = /* @__PURE__ */ new Set();
5198
+ if (positionHintedRoot.count > 0) {
5199
+ const hintedBlockAnalysis = analyzeComposableBlocks(
5200
+ positionHintedRoot.root,
5201
+ reactiveByValue,
5202
+ safeGlobals,
5203
+ listNames,
5204
+ allowedComponentNames
5205
+ );
5206
+ const hintedAnalysis = analyzeHostTree(
5207
+ positionHintedRoot.root,
5208
+ reactiveByValue,
5209
+ safeGlobals,
5210
+ hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
5211
+ hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
5212
+ hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
5213
+ hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
5214
+ );
5215
+ if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
5216
+ expandedReactiveRoot = positionHintedRoot.root;
5217
+ blockAnalysis = hintedBlockAnalysis;
5218
+ analysis = hintedAnalysis;
5219
+ appliedKeyedArrayPositionHints = positionHintedRoot.count;
5220
+ appliedPositionHintedStateIndices = positionHintedRoot.stateIndices;
5221
+ optimizationCounts.keyedArrayPositionHints += positionHintedRoot.count;
5222
+ }
5223
+ }
5224
+ const reorderHintedRoot = rewriteKeyedArrayReorderHints(
5225
+ expandedReactiveRoot,
5226
+ shiftedIndexIndependentStateIndices,
5227
+ statesBySetter,
5228
+ keyedArrayReorderIdentifier
5229
+ );
5230
+ let appliedKeyedArrayReorderHints = 0;
5231
+ let appliedReorderHintedStateIndices = /* @__PURE__ */ new Set();
5232
+ if (reorderHintedRoot.count > 0) {
5233
+ const hintedBlockAnalysis = analyzeComposableBlocks(
5234
+ reorderHintedRoot.root,
5235
+ reactiveByValue,
5236
+ safeGlobals,
5237
+ listNames,
5238
+ allowedComponentNames
5239
+ );
5240
+ const hintedAnalysis = analyzeHostTree(
5241
+ reorderHintedRoot.root,
5242
+ reactiveByValue,
5243
+ safeGlobals,
5244
+ hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
5245
+ hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
5246
+ hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
5247
+ hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
5248
+ );
5249
+ if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
5250
+ expandedReactiveRoot = reorderHintedRoot.root;
5251
+ blockAnalysis = hintedBlockAnalysis;
5252
+ analysis = hintedAnalysis;
5253
+ appliedKeyedArrayReorderHints = reorderHintedRoot.count;
5254
+ appliedReorderHintedStateIndices = reorderHintedRoot.stateIndices;
5255
+ optimizationCounts.keyedArrayReorderHints += reorderHintedRoot.count;
5256
+ }
5257
+ }
5258
+ const sortHintedRoot = rewriteKeyedArraySortHints(
5259
+ expandedReactiveRoot,
5260
+ shiftedIndexIndependentStateIndices,
5261
+ statesBySetter,
5262
+ keyedArraySortIdentifier,
5263
+ safeGlobals
5264
+ );
5265
+ let appliedKeyedArraySortHints = 0;
5266
+ let appliedSortHintedStateIndices = /* @__PURE__ */ new Set();
5267
+ if (sortHintedRoot.count > 0) {
5268
+ const hintedBlockAnalysis = analyzeComposableBlocks(
5269
+ sortHintedRoot.root,
5270
+ reactiveByValue,
5271
+ safeGlobals,
5272
+ listNames,
5273
+ allowedComponentNames
5274
+ );
5275
+ const hintedAnalysis = analyzeHostTree(
5276
+ sortHintedRoot.root,
5277
+ reactiveByValue,
5278
+ safeGlobals,
5279
+ hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
5280
+ hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
5281
+ hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
5282
+ hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
5283
+ );
5284
+ if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
5285
+ expandedReactiveRoot = sortHintedRoot.root;
5286
+ blockAnalysis = hintedBlockAnalysis;
5287
+ analysis = hintedAnalysis;
5288
+ appliedKeyedArraySortHints = sortHintedRoot.count;
5289
+ appliedSortHintedStateIndices = sortHintedRoot.stateIndices;
5290
+ optimizationCounts.keyedArraySortHints += sortHintedRoot.count;
5291
+ }
5292
+ }
5293
+ const sliceHintedRoot = rewriteKeyedArraySliceHints(
5294
+ expandedReactiveRoot,
5295
+ shiftedIndexIndependentStateIndices,
5296
+ statesBySetter,
5297
+ keyedArraySliceIdentifier
5298
+ );
5299
+ let appliedKeyedArraySliceHints = 0;
5300
+ let appliedSliceHintedStateIndices = /* @__PURE__ */ new Set();
5301
+ if (sliceHintedRoot.count > 0) {
5302
+ const hintedBlockAnalysis = analyzeComposableBlocks(
5303
+ sliceHintedRoot.root,
5304
+ reactiveByValue,
5305
+ safeGlobals,
5306
+ listNames,
5307
+ allowedComponentNames
5308
+ );
5309
+ const hintedAnalysis = analyzeHostTree(
5310
+ sliceHintedRoot.root,
5311
+ reactiveByValue,
5312
+ safeGlobals,
5313
+ hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
5314
+ hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
5315
+ hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
5316
+ hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
5317
+ );
5318
+ if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
5319
+ expandedReactiveRoot = sliceHintedRoot.root;
5320
+ blockAnalysis = hintedBlockAnalysis;
5321
+ analysis = hintedAnalysis;
5322
+ appliedKeyedArraySliceHints = sliceHintedRoot.count;
5323
+ appliedSliceHintedStateIndices = sliceHintedRoot.stateIndices;
5324
+ optimizationCounts.keyedArraySliceHints += sliceHintedRoot.count;
5325
+ }
5326
+ }
5327
+ const filterHintedRoot = rewriteKeyedArrayFilterHints(
5328
+ expandedReactiveRoot,
5329
+ shiftedIndexIndependentStateIndices,
5330
+ statesBySetter,
5331
+ keyedArrayFilterIdentifier,
5332
+ safeGlobals
5333
+ );
5334
+ let appliedKeyedArrayFilterHints = 0;
5335
+ let appliedFilterHintedStateIndices = /* @__PURE__ */ new Set();
5336
+ if (filterHintedRoot.count > 0) {
5337
+ const hintedBlockAnalysis = analyzeComposableBlocks(
5338
+ filterHintedRoot.root,
5339
+ reactiveByValue,
5340
+ safeGlobals,
5341
+ listNames,
5342
+ allowedComponentNames
5343
+ );
5344
+ const hintedAnalysis = analyzeHostTree(
5345
+ filterHintedRoot.root,
5346
+ reactiveByValue,
5347
+ safeGlobals,
5348
+ hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
5349
+ hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
5350
+ hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
5351
+ hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
5352
+ );
5353
+ if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
5354
+ expandedReactiveRoot = filterHintedRoot.root;
5355
+ blockAnalysis = hintedBlockAnalysis;
5356
+ analysis = hintedAnalysis;
5357
+ appliedKeyedArrayFilterHints = filterHintedRoot.count;
5358
+ appliedFilterHintedStateIndices = filterHintedRoot.stateIndices;
5359
+ optimizationCounts.keyedArrayFilterHints += filterHintedRoot.count;
5360
+ }
5361
+ }
5362
+ const keyedCollectionTargetKinds = /* @__PURE__ */ new Map();
5363
+ const conflictingKeyedCollectionTargets = /* @__PURE__ */ new Set();
5364
+ for (const plan of blockAnalysis.plans || []) {
5365
+ if (plan.kind !== "keyed-rows") continue;
5366
+ for (const binding of plan.bindings) {
5367
+ const target = binding.membershipTarget || binding.mapLookupTarget;
5368
+ if (!target) continue;
5369
+ const kind = binding.membershipTarget ? "set" : "map";
5370
+ const previousKind = keyedCollectionTargetKinds.get(target.dependency);
5371
+ if (previousKind && previousKind !== kind) {
5372
+ conflictingKeyedCollectionTargets.add(target.dependency);
5373
+ } else {
5374
+ keyedCollectionTargetKinds.set(target.dependency, kind);
5375
+ }
5376
+ }
5377
+ }
5378
+ for (const dependency of conflictingKeyedCollectionTargets) {
5379
+ keyedCollectionTargetKinds.delete(dependency);
5380
+ }
5381
+ const keyedCollectionHintedRoot = rewriteKeyedCollectionUpdateHints(
5382
+ expandedReactiveRoot,
5383
+ keyedCollectionTargetKinds,
5384
+ states,
5385
+ statesBySetter,
5386
+ keyedCollectionUpdateIdentifier,
5387
+ keyedCollectionMutationIdentifier,
5388
+ globalCollections
5389
+ );
5390
+ if (keyedCollectionHintedRoot.count > 0) {
5391
+ const hintedBlockAnalysis = analyzeComposableBlocks(
5392
+ keyedCollectionHintedRoot.root,
5393
+ reactiveByValue,
5394
+ safeGlobals,
5395
+ listNames,
5396
+ allowedComponentNames
5397
+ );
5398
+ const hintedAnalysis = analyzeHostTree(
5399
+ keyedCollectionHintedRoot.root,
5400
+ reactiveByValue,
5401
+ safeGlobals,
5402
+ hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
5403
+ hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
5404
+ hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
5405
+ hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
5406
+ );
5407
+ if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
5408
+ expandedReactiveRoot = keyedCollectionHintedRoot.root;
5409
+ blockAnalysis = hintedBlockAnalysis;
5410
+ analysis = hintedAnalysis;
5411
+ optimizationCounts.keyedCollectionUpdateHints += keyedCollectionHintedRoot.count;
5412
+ }
5413
+ }
3639
5414
  const blockPlans = blockAnalysis.plans || [];
3640
- const runtimeFeatures = runtimeFeaturesForPlans(blockPlans);
5415
+ optimizationCounts.keyedIdentityTargets += blockPlans.reduce(
5416
+ (count, plan) => count + (plan.kind === "keyed-rows" ? plan.bindings.filter((binding) => binding.identityTarget !== void 0).length : 0),
5417
+ 0
5418
+ );
5419
+ optimizationCounts.keyedMembershipTargets += blockPlans.reduce(
5420
+ (count, plan) => count + (plan.kind === "keyed-rows" ? plan.bindings.filter((binding) => binding.membershipTarget !== void 0).length : 0),
5421
+ 0
5422
+ );
5423
+ optimizationCounts.keyedMapLookupTargets += blockPlans.reduce(
5424
+ (count, plan) => count + (plan.kind === "keyed-rows" ? plan.bindings.filter((binding) => binding.mapLookupTarget !== void 0).length : 0),
5425
+ 0
5426
+ );
5427
+ const hasKeyedUpdateHints = appliedKeyedMapUpdateHints > 0 || appliedKeyedArrayAppendHints > 0 || appliedKeyedArrayFilterHints > 0 || appliedKeyedArrayPrependHints > 0 || appliedKeyedArrayPositionHints > 0 || appliedKeyedArrayReorderHints > 0 || appliedKeyedArraySortHints > 0 || appliedKeyedArrayRollingWindowHints > 0 || appliedKeyedArraySliceHints > 0;
5428
+ const hasKeyedArrayRemovalHints = appliedKeyedArrayFilterHints > 0 || appliedKeyedArrayRollingWindowHints > 0 || appliedKeyedArraySliceHints > 0;
5429
+ const runtimeFeatures = runtimeFeaturesForPlans(
5430
+ blockPlans,
5431
+ hasKeyedUpdateHints,
5432
+ hasKeyedArrayRemovalHints,
5433
+ appliedKeyedArrayPrependHints > 0,
5434
+ appliedKeyedArrayPositionHints > 0,
5435
+ appliedKeyedArrayReorderHints > 0 || appliedKeyedArraySortHints > 0,
5436
+ appliedKeyedArrayRollingWindowHints > 0
5437
+ );
3641
5438
  markShortCircuitBindings(analysis.bindings || []);
3642
5439
  assignStableBindingTargets(analysis.bindings || []);
3643
5440
  const stateParameter = path.scope.generateUidIdentifier("farmState");
@@ -3650,11 +5447,21 @@ function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureId
3650
5447
  blockParameter,
3651
5448
  blockAnalysis.ownedElements || /* @__PURE__ */ new Set()
3652
5449
  );
5450
+ const appliedRemovalHintedStateIndices = /* @__PURE__ */ new Set([
5451
+ ...appliedFilterHintedStateIndices,
5452
+ ...appliedRollingWindowHintedStateIndices,
5453
+ ...appliedSliceHintedStateIndices
5454
+ ]);
3653
5455
  const rootWithBlocks = lowerComposableBlocks(
3654
5456
  rootWithTargets,
3655
5457
  blockPlans,
3656
5458
  blockParameter,
3657
- listNames
5459
+ listNames,
5460
+ hasKeyedUpdateHints,
5461
+ appliedRemovalHintedStateIndices,
5462
+ appliedPrependHintedStateIndices,
5463
+ appliedPositionHintedStateIndices,
5464
+ /* @__PURE__ */ new Set([...appliedReorderHintedStateIndices, ...appliedSortHintedStateIndices])
3658
5465
  );
3659
5466
  const rewrittenRoot = rewriteStateAccess(
3660
5467
  rootWithBlocks,
@@ -3792,6 +5599,21 @@ function collectCandidates(programPath) {
3792
5599
  async function compileReactModule(code, id, options) {
3793
5600
  const compiled = [];
3794
5601
  const diagnostics = [];
5602
+ const optimizationCounts = {
5603
+ keyedArrayAppendHints: 0,
5604
+ keyedArrayFilterHints: 0,
5605
+ keyedArrayPrependHints: 0,
5606
+ keyedArrayPositionHints: 0,
5607
+ keyedArrayReorderHints: 0,
5608
+ keyedArraySortHints: 0,
5609
+ keyedArrayRollingWindowHints: 0,
5610
+ keyedArraySliceHints: 0,
5611
+ keyedCollectionUpdateHints: 0,
5612
+ keyedIdentityTargets: 0,
5613
+ keyedMapLookupTargets: 0,
5614
+ keyedMembershipTargets: 0,
5615
+ keyedMapUpdateHints: 0
5616
+ };
3795
5617
  const plugin = () => ({
3796
5618
  name: "farm-react-aot",
3797
5619
  visitor: {
@@ -3821,6 +5643,39 @@ async function compileReactModule(code, id, options) {
3821
5643
  }
3822
5644
  const candidates = collectCandidates(programPath);
3823
5645
  const createComponentIdentifier = programPath.scope.generateUidIdentifier("createCompiledComponent");
5646
+ const keyedMapUpdateIdentifier = programPath.scope.generateUidIdentifier(
5647
+ "createCompilerKeyedMapUpdate"
5648
+ );
5649
+ const keyedArrayAppendIdentifier = programPath.scope.generateUidIdentifier(
5650
+ "createCompilerKeyedArrayAppend"
5651
+ );
5652
+ const keyedArrayFilterIdentifier = programPath.scope.generateUidIdentifier(
5653
+ "createCompilerKeyedArrayFilter"
5654
+ );
5655
+ const keyedArrayPrependIdentifier = programPath.scope.generateUidIdentifier(
5656
+ "createCompilerKeyedArrayPrepend"
5657
+ );
5658
+ const keyedArrayPositionIdentifier = programPath.scope.generateUidIdentifier(
5659
+ "createCompilerKeyedArrayPositionUpdate"
5660
+ );
5661
+ const keyedArrayReorderIdentifier = programPath.scope.generateUidIdentifier(
5662
+ "createCompilerKeyedArrayReorder"
5663
+ );
5664
+ const keyedArraySortIdentifier = programPath.scope.generateUidIdentifier(
5665
+ "createCompilerKeyedArraySort"
5666
+ );
5667
+ const keyedArrayRollingWindowIdentifier = programPath.scope.generateUidIdentifier(
5668
+ "createCompilerKeyedArrayRollingWindow"
5669
+ );
5670
+ const keyedArraySliceIdentifier = programPath.scope.generateUidIdentifier(
5671
+ "createCompilerKeyedArraySlice"
5672
+ );
5673
+ const keyedCollectionUpdateIdentifier = programPath.scope.generateUidIdentifier(
5674
+ "createCompilerKeyedCollectionUpdate"
5675
+ );
5676
+ const keyedCollectionMutationIdentifier = programPath.scope.generateUidIdentifier(
5677
+ "applyCompilerKeyedCollectionMutation"
5678
+ );
3824
5679
  const runtimeFeatureIdentifiers = new Map(
3825
5680
  Object.entries(COMPILER_RUNTIME_FEATURE_EXPORTS).map(([feature, exportName]) => [
3826
5681
  feature,
@@ -3838,8 +5693,20 @@ async function compileReactModule(code, id, options) {
3838
5693
  const reason = compileCandidate(
3839
5694
  candidate,
3840
5695
  createComponentIdentifier,
5696
+ keyedMapUpdateIdentifier,
5697
+ keyedArrayAppendIdentifier,
5698
+ keyedArrayFilterIdentifier,
5699
+ keyedArrayPrependIdentifier,
5700
+ keyedArrayPositionIdentifier,
5701
+ keyedArrayReorderIdentifier,
5702
+ keyedArraySortIdentifier,
5703
+ keyedArrayRollingWindowIdentifier,
5704
+ keyedArraySliceIdentifier,
5705
+ keyedCollectionUpdateIdentifier,
5706
+ keyedCollectionMutationIdentifier,
3841
5707
  runtimeFeatureIdentifiers,
3842
5708
  usedRuntimeFeatures,
5709
+ optimizationCounts,
3843
5710
  useStateNames,
3844
5711
  reactNames,
3845
5712
  listNames,
@@ -3865,6 +5732,70 @@ async function compileReactModule(code, id, options) {
3865
5732
  createComponentIdentifier,
3866
5733
  core.types.identifier("createCompiledComponentWithFeatures")
3867
5734
  ),
5735
+ ...optimizationCounts.keyedMapUpdateHints > 0 ? [
5736
+ core.types.importSpecifier(
5737
+ keyedMapUpdateIdentifier,
5738
+ core.types.identifier("createCompilerKeyedMapUpdate")
5739
+ )
5740
+ ] : [],
5741
+ ...optimizationCounts.keyedArrayAppendHints > 0 ? [
5742
+ core.types.importSpecifier(
5743
+ keyedArrayAppendIdentifier,
5744
+ core.types.identifier("createCompilerKeyedArrayAppend")
5745
+ )
5746
+ ] : [],
5747
+ ...optimizationCounts.keyedArrayFilterHints > 0 ? [
5748
+ core.types.importSpecifier(
5749
+ keyedArrayFilterIdentifier,
5750
+ core.types.identifier("createCompilerKeyedArrayFilter")
5751
+ )
5752
+ ] : [],
5753
+ ...optimizationCounts.keyedArrayPrependHints > 0 ? [
5754
+ core.types.importSpecifier(
5755
+ keyedArrayPrependIdentifier,
5756
+ core.types.identifier("createCompilerKeyedArrayPrepend")
5757
+ )
5758
+ ] : [],
5759
+ ...optimizationCounts.keyedArrayPositionHints > 0 ? [
5760
+ core.types.importSpecifier(
5761
+ keyedArrayPositionIdentifier,
5762
+ core.types.identifier("createCompilerKeyedArrayPositionUpdate")
5763
+ )
5764
+ ] : [],
5765
+ ...optimizationCounts.keyedArrayReorderHints > 0 ? [
5766
+ core.types.importSpecifier(
5767
+ keyedArrayReorderIdentifier,
5768
+ core.types.identifier("createCompilerKeyedArrayReorder")
5769
+ )
5770
+ ] : [],
5771
+ ...optimizationCounts.keyedArraySortHints > 0 ? [
5772
+ core.types.importSpecifier(
5773
+ keyedArraySortIdentifier,
5774
+ core.types.identifier("createCompilerKeyedArraySort")
5775
+ )
5776
+ ] : [],
5777
+ ...optimizationCounts.keyedArrayRollingWindowHints > 0 ? [
5778
+ core.types.importSpecifier(
5779
+ keyedArrayRollingWindowIdentifier,
5780
+ core.types.identifier("createCompilerKeyedArrayRollingWindow")
5781
+ )
5782
+ ] : [],
5783
+ ...optimizationCounts.keyedArraySliceHints > 0 || optimizationCounts.keyedArrayRollingWindowHints > 0 ? [
5784
+ core.types.importSpecifier(
5785
+ keyedArraySliceIdentifier,
5786
+ core.types.identifier("createCompilerKeyedArraySlice")
5787
+ )
5788
+ ] : [],
5789
+ ...optimizationCounts.keyedCollectionUpdateHints > 0 ? [
5790
+ core.types.importSpecifier(
5791
+ keyedCollectionUpdateIdentifier,
5792
+ core.types.identifier("createCompilerKeyedCollectionUpdate")
5793
+ ),
5794
+ core.types.importSpecifier(
5795
+ keyedCollectionMutationIdentifier,
5796
+ core.types.identifier("applyCompilerKeyedCollectionMutation")
5797
+ )
5798
+ ] : [],
3868
5799
  ...[...usedRuntimeFeatures].sort().map(
3869
5800
  (feature) => core.types.importSpecifier(
3870
5801
  core.types.cloneNode(runtimeFeatureIdentifiers.get(feature)),
@@ -3901,7 +5832,8 @@ async function compileReactModule(code, id, options) {
3901
5832
  code: result?.code || code,
3902
5833
  map: result?.map || null,
3903
5834
  compiled,
3904
- diagnostics
5835
+ diagnostics,
5836
+ optimizations: optimizationCounts
3905
5837
  };
3906
5838
  }
3907
5839
  function projectRelativeId(projectRoot, id) {
@@ -3912,10 +5844,36 @@ function createReactCompilerReport(projectRoot, observations) {
3912
5844
  let componentsConsidered = 0;
3913
5845
  let compiled = 0;
3914
5846
  let fallback = 0;
5847
+ let keyedArrayAppendHints = 0;
5848
+ let keyedArrayFilterHints = 0;
5849
+ let keyedArrayPrependHints = 0;
5850
+ let keyedArrayPositionHints = 0;
5851
+ let keyedArrayReorderHints = 0;
5852
+ let keyedArraySortHints = 0;
5853
+ let keyedArrayRollingWindowHints = 0;
5854
+ let keyedArraySliceHints = 0;
5855
+ let keyedCollectionUpdateHints = 0;
5856
+ let keyedIdentityTargets = 0;
5857
+ let keyedMapLookupTargets = 0;
5858
+ let keyedMembershipTargets = 0;
5859
+ let keyedMapUpdateHints = 0;
3915
5860
  const modules = [...observations].map(({ id, result }) => {
3916
5861
  componentsConsidered += result.compiled.length + result.diagnostics.length;
3917
5862
  compiled += result.compiled.length;
3918
5863
  fallback += result.diagnostics.length;
5864
+ keyedArrayAppendHints += result.optimizations.keyedArrayAppendHints || 0;
5865
+ keyedArrayFilterHints += result.optimizations.keyedArrayFilterHints || 0;
5866
+ keyedArrayPrependHints += result.optimizations.keyedArrayPrependHints || 0;
5867
+ keyedArrayPositionHints += result.optimizations.keyedArrayPositionHints || 0;
5868
+ keyedArrayReorderHints += result.optimizations.keyedArrayReorderHints || 0;
5869
+ keyedArraySortHints += result.optimizations.keyedArraySortHints || 0;
5870
+ keyedArrayRollingWindowHints += result.optimizations.keyedArrayRollingWindowHints || 0;
5871
+ keyedArraySliceHints += result.optimizations.keyedArraySliceHints || 0;
5872
+ keyedCollectionUpdateHints += result.optimizations.keyedCollectionUpdateHints || 0;
5873
+ keyedIdentityTargets += result.optimizations.keyedIdentityTargets || 0;
5874
+ keyedMapLookupTargets += result.optimizations.keyedMapLookupTargets || 0;
5875
+ keyedMembershipTargets += result.optimizations.keyedMembershipTargets || 0;
5876
+ keyedMapUpdateHints += result.optimizations.keyedMapUpdateHints;
3919
5877
  const moduleId = projectRelativeId(projectRoot, id);
3920
5878
  const fallbacks = result.diagnostics.map((diagnostic) => {
3921
5879
  reasonCounts.set(diagnostic.reason, (reasonCounts.get(diagnostic.reason) || 0) + 1);
@@ -3924,6 +5882,7 @@ function createReactCompilerReport(projectRoot, observations) {
3924
5882
  return {
3925
5883
  id: moduleId,
3926
5884
  compiled: [...result.compiled].sort(),
5885
+ optimizations: result.optimizations,
3927
5886
  fallbacks
3928
5887
  };
3929
5888
  }).sort((left, right) => left.id.localeCompare(right.id));
@@ -3934,7 +5893,20 @@ function createReactCompilerReport(projectRoot, observations) {
3934
5893
  modules: modules.length,
3935
5894
  componentsConsidered,
3936
5895
  compiled,
3937
- fallback
5896
+ fallback,
5897
+ keyedArrayAppendHints,
5898
+ keyedArrayFilterHints,
5899
+ keyedArrayPrependHints,
5900
+ keyedArrayPositionHints,
5901
+ keyedArrayReorderHints,
5902
+ keyedArraySortHints,
5903
+ keyedArrayRollingWindowHints,
5904
+ keyedArraySliceHints,
5905
+ keyedCollectionUpdateHints,
5906
+ keyedIdentityTargets,
5907
+ keyedMapLookupTargets,
5908
+ keyedMembershipTargets,
5909
+ keyedMapUpdateHints
3938
5910
  },
3939
5911
  fallbackReasons,
3940
5912
  modules