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