@farm.js/react 0.1.0-beta.5 → 0.1.0-beta.6
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 +200 -1
- package/dist/compiler-runtime.cjs +1751 -19
- package/dist/compiler-runtime.cjs.map +1 -1
- package/dist/compiler-runtime.d.mts +82 -1
- package/dist/compiler-runtime.d.ts +82 -1
- package/dist/compiler-runtime.mjs +1710 -20
- package/dist/compiler-runtime.mjs.map +1 -1
- package/dist/vite.cjs +1908 -47
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.mjs +1908 -47
- 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,879 @@ 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 rewriteKeyedArrayPositionHints(root, hintedStateIndices, statesBySetter, helperIdentifier, safeGlobals) {
|
|
847
|
+
if (hintedStateIndices.size === 0) {
|
|
848
|
+
return { root: types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
|
|
849
|
+
}
|
|
850
|
+
const file = expressionFile(types.cloneNode(root, true));
|
|
851
|
+
const stateIndices = /* @__PURE__ */ new Set();
|
|
852
|
+
let count = 0;
|
|
853
|
+
traverse(file, {
|
|
854
|
+
CallExpression(path) {
|
|
855
|
+
const callee = path.get("callee");
|
|
856
|
+
if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
|
|
857
|
+
const state = statesBySetter.get(callee.node.name);
|
|
858
|
+
if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
const updater = path.node.arguments[0];
|
|
862
|
+
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)) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
const methodName = updater.body.callee.property.name;
|
|
866
|
+
const args = updater.body.arguments;
|
|
867
|
+
const kind = methodName === "with" && args.length === 2 ? "replace" : methodName === "toSpliced" && args.length === 3 && types.isNumericLiteral(args[1], { value: 0 }) ? "insert" : void 0;
|
|
868
|
+
if (!kind || !types.isExpression(args[0]) || !types.isExpression(args.at(-1))) return;
|
|
869
|
+
const position = staticSliceIndex(args[0]);
|
|
870
|
+
const item = args.at(-1);
|
|
871
|
+
if (position === void 0 || !types.isExpression(item) || validateDerivedExpression(item, safeGlobals) !== void 0) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
const previous = types.cloneNode(updater.params[0]);
|
|
875
|
+
const method = path.scope.generateUidIdentifier(
|
|
876
|
+
methodName === "with" ? "farmWith" : "farmToSpliced"
|
|
877
|
+
);
|
|
878
|
+
path.node.arguments[0] = types.arrowFunctionExpression(
|
|
879
|
+
[types.cloneNode(previous)],
|
|
880
|
+
types.blockStatement([
|
|
881
|
+
types.variableDeclaration("const", [
|
|
882
|
+
types.variableDeclarator(
|
|
883
|
+
types.cloneNode(method),
|
|
884
|
+
types.memberExpression(types.cloneNode(previous), types.identifier(methodName))
|
|
885
|
+
)
|
|
886
|
+
]),
|
|
887
|
+
types.returnStatement(
|
|
888
|
+
types.callExpression(types.cloneNode(helperIdentifier), [
|
|
889
|
+
types.cloneNode(previous),
|
|
890
|
+
types.cloneNode(method),
|
|
891
|
+
types.stringLiteral(kind),
|
|
892
|
+
...args.map((argument) => types.cloneNode(argument, true))
|
|
893
|
+
])
|
|
894
|
+
)
|
|
895
|
+
])
|
|
896
|
+
);
|
|
897
|
+
count += 1;
|
|
898
|
+
stateIndices.add(state.index);
|
|
899
|
+
path.skip();
|
|
900
|
+
}
|
|
901
|
+
});
|
|
902
|
+
return {
|
|
903
|
+
root: file.program.body[0].expression,
|
|
904
|
+
count,
|
|
905
|
+
stateIndices
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
function rewriteKeyedArrayReorderHints(root, hintedStateIndices, statesBySetter, helperIdentifier) {
|
|
909
|
+
if (hintedStateIndices.size === 0) {
|
|
910
|
+
return { root: types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
|
|
911
|
+
}
|
|
912
|
+
const file = expressionFile(types.cloneNode(root, true));
|
|
913
|
+
const stateIndices = /* @__PURE__ */ new Set();
|
|
914
|
+
let count = 0;
|
|
915
|
+
traverse(file, {
|
|
916
|
+
CallExpression(path) {
|
|
917
|
+
const callee = path.get("callee");
|
|
918
|
+
if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
|
|
919
|
+
const state = statesBySetter.get(callee.node.name);
|
|
920
|
+
if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
const updater = path.node.arguments[0];
|
|
924
|
+
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" })) {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const previous = types.cloneNode(updater.params[0]);
|
|
928
|
+
const method = path.scope.generateUidIdentifier("farmToReversed");
|
|
929
|
+
path.node.arguments[0] = types.arrowFunctionExpression(
|
|
930
|
+
[types.cloneNode(previous)],
|
|
931
|
+
types.blockStatement([
|
|
932
|
+
types.variableDeclaration("const", [
|
|
933
|
+
types.variableDeclarator(
|
|
934
|
+
types.cloneNode(method),
|
|
935
|
+
types.memberExpression(types.cloneNode(previous), types.identifier("toReversed"))
|
|
936
|
+
)
|
|
937
|
+
]),
|
|
938
|
+
types.returnStatement(
|
|
939
|
+
types.callExpression(types.cloneNode(helperIdentifier), [
|
|
940
|
+
types.cloneNode(previous),
|
|
941
|
+
types.cloneNode(method)
|
|
942
|
+
])
|
|
943
|
+
)
|
|
944
|
+
])
|
|
945
|
+
);
|
|
946
|
+
count += 1;
|
|
947
|
+
stateIndices.add(state.index);
|
|
948
|
+
path.skip();
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
return {
|
|
952
|
+
root: file.program.body[0].expression,
|
|
953
|
+
count,
|
|
954
|
+
stateIndices
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
function rewriteKeyedArraySliceHints(root, hintedStateIndices, statesBySetter, helperIdentifier) {
|
|
958
|
+
if (hintedStateIndices.size === 0) {
|
|
959
|
+
return { root: types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
|
|
960
|
+
}
|
|
961
|
+
const file = expressionFile(types.cloneNode(root, true));
|
|
962
|
+
const stateIndices = /* @__PURE__ */ new Set();
|
|
963
|
+
let count = 0;
|
|
964
|
+
traverse(file, {
|
|
965
|
+
CallExpression(path) {
|
|
966
|
+
const callee = path.get("callee");
|
|
967
|
+
if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
|
|
968
|
+
const state = statesBySetter.get(callee.node.name);
|
|
969
|
+
if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
const updater = path.node.arguments[0];
|
|
973
|
+
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" })) {
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
const indexes = [];
|
|
977
|
+
for (const argument of updater.body.arguments) {
|
|
978
|
+
if (!types.isExpression(argument)) return;
|
|
979
|
+
const value = staticSliceIndex(argument);
|
|
980
|
+
if (value === void 0) return;
|
|
981
|
+
indexes.push(value);
|
|
982
|
+
}
|
|
983
|
+
if (indexes.length === 1 && indexes[0] === 0) return;
|
|
984
|
+
const previous = types.cloneNode(updater.params[0]);
|
|
985
|
+
const sliceMethod = path.scope.generateUidIdentifier("farmSlice");
|
|
986
|
+
path.node.arguments[0] = types.arrowFunctionExpression(
|
|
987
|
+
[types.cloneNode(previous)],
|
|
988
|
+
types.blockStatement([
|
|
989
|
+
types.variableDeclaration("const", [
|
|
990
|
+
types.variableDeclarator(
|
|
991
|
+
types.cloneNode(sliceMethod),
|
|
992
|
+
types.memberExpression(types.cloneNode(previous), types.identifier("slice"))
|
|
993
|
+
)
|
|
994
|
+
]),
|
|
995
|
+
types.returnStatement(
|
|
996
|
+
types.callExpression(types.cloneNode(helperIdentifier), [
|
|
997
|
+
types.cloneNode(previous),
|
|
998
|
+
types.cloneNode(sliceMethod),
|
|
999
|
+
...indexes.map((value) => types.numericLiteral(value))
|
|
1000
|
+
])
|
|
1001
|
+
)
|
|
1002
|
+
])
|
|
1003
|
+
);
|
|
1004
|
+
count += 1;
|
|
1005
|
+
stateIndices.add(state.index);
|
|
1006
|
+
path.skip();
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
return {
|
|
1010
|
+
root: file.program.body[0].expression,
|
|
1011
|
+
count,
|
|
1012
|
+
stateIndices
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
function rewriteKeyedArrayFilterHints(root, hintedStateIndices, statesBySetter, helperIdentifier, safeGlobals) {
|
|
1016
|
+
if (hintedStateIndices.size === 0) {
|
|
1017
|
+
return { root: types.cloneNode(root, true), count: 0, stateIndices: /* @__PURE__ */ new Set() };
|
|
1018
|
+
}
|
|
1019
|
+
const file = expressionFile(types.cloneNode(root, true));
|
|
1020
|
+
const stateIndices = /* @__PURE__ */ new Set();
|
|
1021
|
+
let count = 0;
|
|
1022
|
+
traverse(file, {
|
|
1023
|
+
CallExpression(path) {
|
|
1024
|
+
const callee = path.get("callee");
|
|
1025
|
+
if (!callee.isIdentifier() || callee.scope.hasBinding(callee.node.name)) return;
|
|
1026
|
+
const state = statesBySetter.get(callee.node.name);
|
|
1027
|
+
if (!state || !hintedStateIndices.has(state.index) || path.node.arguments.length !== 1) {
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
const updater = path.node.arguments[0];
|
|
1031
|
+
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, {
|
|
1032
|
+
name: updater.params[0].name
|
|
1033
|
+
}) || !types.isIdentifier(updater.body.callee.property, { name: "filter" })) {
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
const predicate = updater.body.arguments[0];
|
|
1037
|
+
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)) {
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
const previous = types.cloneNode(updater.params[0]);
|
|
1041
|
+
const filterMethod = path.scope.generateUidIdentifier("farmFilter");
|
|
1042
|
+
path.node.arguments[0] = types.arrowFunctionExpression(
|
|
1043
|
+
[types.cloneNode(previous)],
|
|
1044
|
+
types.blockStatement([
|
|
1045
|
+
types.variableDeclaration("const", [
|
|
1046
|
+
types.variableDeclarator(
|
|
1047
|
+
types.cloneNode(filterMethod),
|
|
1048
|
+
types.memberExpression(types.cloneNode(previous), types.identifier("filter"))
|
|
1049
|
+
)
|
|
1050
|
+
]),
|
|
1051
|
+
types.returnStatement(
|
|
1052
|
+
types.callExpression(types.cloneNode(helperIdentifier), [
|
|
1053
|
+
types.cloneNode(previous),
|
|
1054
|
+
types.cloneNode(filterMethod),
|
|
1055
|
+
types.cloneNode(predicate, true)
|
|
1056
|
+
])
|
|
1057
|
+
)
|
|
1058
|
+
])
|
|
1059
|
+
);
|
|
1060
|
+
count += 1;
|
|
1061
|
+
stateIndices.add(state.index);
|
|
1062
|
+
path.skip();
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
return {
|
|
1066
|
+
root: file.program.body[0].expression,
|
|
1067
|
+
count,
|
|
1068
|
+
stateIndices
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
function collectionConstructorName(kind) {
|
|
1072
|
+
return kind === "set" ? "Set" : "Map";
|
|
1073
|
+
}
|
|
1074
|
+
function isCollectionConstruction(expression, kind, previous) {
|
|
1075
|
+
if (!types.isNewExpression(expression) || !types.isIdentifier(expression.callee, {
|
|
1076
|
+
name: collectionConstructorName(kind)
|
|
1077
|
+
})) {
|
|
1078
|
+
return false;
|
|
1079
|
+
}
|
|
1080
|
+
if (!previous) return true;
|
|
1081
|
+
return expression.arguments.length === 1 && types.isIdentifier(expression.arguments[0], { name: previous.name });
|
|
1082
|
+
}
|
|
1083
|
+
function collectionStateInitializerIsOwned(initialValue, kind, constructorIsGlobal) {
|
|
1084
|
+
if (!initialValue || !constructorIsGlobal) return false;
|
|
1085
|
+
if (isCollectionConstruction(initialValue, kind)) return true;
|
|
1086
|
+
if (!types.isArrowFunctionExpression(initialValue) && !types.isFunctionExpression(initialValue)) {
|
|
1087
|
+
return false;
|
|
1088
|
+
}
|
|
1089
|
+
if (types.isBlockStatement(initialValue.body) && initialValue.body.body.length !== 1) return false;
|
|
1090
|
+
const value = returnedExpression(initialValue);
|
|
1091
|
+
return Boolean(value && isCollectionConstruction(value, kind));
|
|
1092
|
+
}
|
|
1093
|
+
function collectionStateHasOnlyOwnedReads(root, state, kind) {
|
|
1094
|
+
const file = expressionFile(types.cloneNode(root, true));
|
|
1095
|
+
let valid = true;
|
|
1096
|
+
const readMethods = kind === "set" ? /* @__PURE__ */ new Set(["has"]) : /* @__PURE__ */ new Set(["get", "has"]);
|
|
1097
|
+
traverse(file, {
|
|
1098
|
+
ReferencedIdentifier(path) {
|
|
1099
|
+
if (!valid || !types.isIdentifier(path.node) || path.node.name !== state.valueName || path.scope.hasBinding(path.node.name)) {
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
const parent = path.parentPath;
|
|
1103
|
+
if (parent.isNewExpression() && types.isIdentifier(parent.node.callee, {
|
|
1104
|
+
name: collectionConstructorName(kind)
|
|
1105
|
+
}) && parent.node.arguments.length === 1 && parent.node.arguments[0] === path.node) {
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
if (!parent.isMemberExpression() || parent.node.object !== path.node || parent.node.computed || !types.isIdentifier(parent.node.property)) {
|
|
1109
|
+
valid = false;
|
|
1110
|
+
path.stop();
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
const property = parent.node.property.name;
|
|
1114
|
+
if (property === "size") return;
|
|
1115
|
+
const call = parent.parentPath;
|
|
1116
|
+
if (!readMethods.has(property) || !call?.isCallExpression() || call.node.callee !== parent.node) {
|
|
1117
|
+
valid = false;
|
|
1118
|
+
path.stop();
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
return valid;
|
|
1123
|
+
}
|
|
1124
|
+
function collectionMutationOperation(kind, method) {
|
|
1125
|
+
if (kind === "set" && method === "add") return "set-add";
|
|
1126
|
+
if (kind === "set" && method === "delete") return "set-delete";
|
|
1127
|
+
if (kind === "map" && method === "set") return "map-set";
|
|
1128
|
+
if (kind === "map" && method === "delete") return "map-delete";
|
|
1129
|
+
return void 0;
|
|
1130
|
+
}
|
|
1131
|
+
function collectionMutationArgumentsAreValid(operation, args) {
|
|
1132
|
+
if (!operation || args.some((argument) => !types.isExpression(argument))) return false;
|
|
1133
|
+
return operation === "map-set" ? args.length === 2 : args.length === 1;
|
|
1134
|
+
}
|
|
1135
|
+
function prepareKeyedCollectionUpdater(updater, kind, updateHelper, mutationHelper) {
|
|
1136
|
+
if (updater.async || updater.generator || updater.params.length !== 1 || !types.isIdentifier(updater.params[0])) {
|
|
1137
|
+
return void 0;
|
|
1138
|
+
}
|
|
1139
|
+
const previous = updater.params[0];
|
|
1140
|
+
if (types.isExpression(updater.body)) {
|
|
1141
|
+
if (!types.isCallExpression(updater.body) || !types.isMemberExpression(updater.body.callee) || updater.body.callee.computed || !types.isIdentifier(updater.body.callee.property)) {
|
|
1142
|
+
return void 0;
|
|
1143
|
+
}
|
|
1144
|
+
const operation = collectionMutationOperation(kind, updater.body.callee.property.name);
|
|
1145
|
+
if (operation !== "set-add" && operation !== "map-set" || !collectionMutationArgumentsAreValid(operation, updater.body.arguments) || !isCollectionConstruction(updater.body.callee.object, kind, previous)) {
|
|
1146
|
+
return void 0;
|
|
1147
|
+
}
|
|
1148
|
+
const collection = uniqueLocalIdentifier("_farmCollection", [updater]);
|
|
1149
|
+
const body = types.blockStatement([
|
|
1150
|
+
types.variableDeclaration("const", [
|
|
1151
|
+
types.variableDeclarator(
|
|
1152
|
+
types.cloneNode(collection),
|
|
1153
|
+
types.cloneNode(updater.body.callee.object, true)
|
|
1154
|
+
)
|
|
1155
|
+
]),
|
|
1156
|
+
types.returnStatement(
|
|
1157
|
+
types.callExpression(types.cloneNode(updateHelper), [
|
|
1158
|
+
types.cloneNode(previous),
|
|
1159
|
+
types.callExpression(types.cloneNode(mutationHelper), [
|
|
1160
|
+
types.cloneNode(collection),
|
|
1161
|
+
types.memberExpression(types.cloneNode(collection), types.cloneNode(updater.body.callee.property)),
|
|
1162
|
+
types.stringLiteral(operation),
|
|
1163
|
+
...updater.body.arguments.map(
|
|
1164
|
+
(argument) => types.cloneNode(argument, true)
|
|
1165
|
+
)
|
|
1166
|
+
]),
|
|
1167
|
+
types.stringLiteral(kind)
|
|
1168
|
+
])
|
|
1169
|
+
)
|
|
1170
|
+
]);
|
|
1171
|
+
return {
|
|
1172
|
+
updater: types.arrowFunctionExpression([types.cloneNode(previous)], body),
|
|
1173
|
+
mutations: 1
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
const cloned = types.cloneNode(updater, true);
|
|
1177
|
+
const file = expressionFile(cloned);
|
|
1178
|
+
let functionPath;
|
|
1179
|
+
traverse(file, {
|
|
1180
|
+
Function(path) {
|
|
1181
|
+
if (functionPath) return;
|
|
1182
|
+
if (path.isArrowFunctionExpression() || path.isFunctionExpression()) {
|
|
1183
|
+
functionPath = path;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
});
|
|
1187
|
+
if (!functionPath || !types.isBlockStatement(functionPath.node.body)) return void 0;
|
|
1188
|
+
const clonedPrevious = functionPath.node.params[0];
|
|
1189
|
+
if (!types.isIdentifier(clonedPrevious)) return void 0;
|
|
1190
|
+
let collectionDeclaration;
|
|
1191
|
+
const updaterBody = functionPath.get("body");
|
|
1192
|
+
if (!updaterBody.isBlockStatement()) return void 0;
|
|
1193
|
+
for (const statement of updaterBody.get("body")) {
|
|
1194
|
+
if (!statement.isVariableDeclaration({ kind: "const" })) continue;
|
|
1195
|
+
for (const declaration of statement.get("declarations")) {
|
|
1196
|
+
if (declaration.isVariableDeclarator() && types.isIdentifier(declaration.node.id) && types.isExpression(declaration.node.init) && isCollectionConstruction(declaration.node.init, kind, clonedPrevious)) {
|
|
1197
|
+
if (collectionDeclaration) return void 0;
|
|
1198
|
+
collectionDeclaration = declaration;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
if (!collectionDeclaration || !types.isIdentifier(collectionDeclaration.node.id)) return void 0;
|
|
1203
|
+
if (collectionDeclaration.scope.getBinding(collectionConstructorName(kind))) return void 0;
|
|
1204
|
+
const collectionName = collectionDeclaration.node.id.name;
|
|
1205
|
+
const collectionBinding = collectionDeclaration.scope.getBinding(collectionName);
|
|
1206
|
+
const previousBinding = functionPath.scope.getBinding(clonedPrevious.name);
|
|
1207
|
+
if (!collectionBinding || !previousBinding) return void 0;
|
|
1208
|
+
let valid = true;
|
|
1209
|
+
let mutations = 0;
|
|
1210
|
+
traverse(file, {
|
|
1211
|
+
ReferencedIdentifier(path) {
|
|
1212
|
+
if (!valid) return;
|
|
1213
|
+
const binding = path.scope.getBinding(path.node.name);
|
|
1214
|
+
const belongsToUpdater = path.getFunctionParent()?.node === functionPath?.node;
|
|
1215
|
+
if (binding === collectionBinding) {
|
|
1216
|
+
if (!belongsToUpdater) {
|
|
1217
|
+
valid = false;
|
|
1218
|
+
path.stop();
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
const parent = path.parentPath;
|
|
1222
|
+
if (parent.isReturnStatement() && parent.node.argument === path.node) return;
|
|
1223
|
+
if (!parent.isMemberExpression() || parent.node.object !== path.node || parent.node.computed || !types.isIdentifier(parent.node.property)) {
|
|
1224
|
+
valid = false;
|
|
1225
|
+
path.stop();
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
const method = parent.node.property.name;
|
|
1229
|
+
if (method === "size") return;
|
|
1230
|
+
const call = parent.parentPath;
|
|
1231
|
+
if (!call?.isCallExpression() || call.node.callee !== parent.node) {
|
|
1232
|
+
valid = false;
|
|
1233
|
+
path.stop();
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
const operation = collectionMutationOperation(kind, method);
|
|
1237
|
+
const read = kind === "set" ? method === "has" : method === "get" || method === "has";
|
|
1238
|
+
if (read) return;
|
|
1239
|
+
if (!collectionMutationArgumentsAreValid(operation, call.node.arguments) || call.parentPath.isMemberExpression() && call.parentPath.node.object === call.node) {
|
|
1240
|
+
valid = false;
|
|
1241
|
+
path.stop();
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
mutations += 1;
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
if (binding === previousBinding) {
|
|
1248
|
+
if (!belongsToUpdater) {
|
|
1249
|
+
valid = false;
|
|
1250
|
+
path.stop();
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
const parent = path.parentPath;
|
|
1254
|
+
if (parent.isReturnStatement() && parent.node.argument === path.node) return;
|
|
1255
|
+
if (parent.isNewExpression() && parent.node.arguments.length === 1 && parent.node.arguments[0] === path.node && types.isIdentifier(parent.node.callee, {
|
|
1256
|
+
name: collectionConstructorName(kind)
|
|
1257
|
+
})) {
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
if (parent.isMemberExpression() && parent.node.object === path.node && !parent.node.computed && types.isIdentifier(parent.node.property)) {
|
|
1261
|
+
const method = parent.node.property.name;
|
|
1262
|
+
const call = parent.parentPath;
|
|
1263
|
+
if (method === "size" || (kind === "set" ? method === "has" : method === "get" || method === "has") && call?.isCallExpression() && call.node.callee === parent.node) {
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
valid = false;
|
|
1268
|
+
path.stop();
|
|
1269
|
+
}
|
|
1270
|
+
},
|
|
1271
|
+
ReturnStatement(path) {
|
|
1272
|
+
if (!valid || path.getFunctionParent()?.node !== functionPath?.node || !path.node.argument) {
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
const value = path.node.argument;
|
|
1276
|
+
const returnsOwnedCollection = types.isIdentifier(value) && (path.scope.getBinding(value.name) === collectionBinding || path.scope.getBinding(value.name) === previousBinding) || isCollectionConstruction(value, kind);
|
|
1277
|
+
if (!returnsOwnedCollection) {
|
|
1278
|
+
valid = false;
|
|
1279
|
+
path.stop();
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
});
|
|
1283
|
+
if (!valid || mutations === 0) return void 0;
|
|
1284
|
+
traverse(file, {
|
|
1285
|
+
CallExpression(path) {
|
|
1286
|
+
if (path.getFunctionParent()?.node !== functionPath?.node) return;
|
|
1287
|
+
const callee = path.node.callee;
|
|
1288
|
+
if (!types.isMemberExpression(callee) || callee.computed || !types.isIdentifier(callee.object, { name: collectionName }) || path.scope.getBinding(collectionName) !== collectionBinding || !types.isIdentifier(callee.property)) {
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
const operation = collectionMutationOperation(kind, callee.property.name);
|
|
1292
|
+
if (!collectionMutationArgumentsAreValid(operation, path.node.arguments)) return;
|
|
1293
|
+
path.replaceWith(
|
|
1294
|
+
types.callExpression(types.cloneNode(mutationHelper), [
|
|
1295
|
+
types.cloneNode(callee.object),
|
|
1296
|
+
types.memberExpression(types.cloneNode(callee.object), types.cloneNode(callee.property)),
|
|
1297
|
+
types.stringLiteral(operation),
|
|
1298
|
+
...path.node.arguments.map((argument) => types.cloneNode(argument, true))
|
|
1299
|
+
])
|
|
1300
|
+
);
|
|
1301
|
+
path.skip();
|
|
1302
|
+
},
|
|
1303
|
+
ReturnStatement(path) {
|
|
1304
|
+
if (path.getFunctionParent()?.node !== functionPath?.node || !path.node.argument) return;
|
|
1305
|
+
path.node.argument = types.callExpression(types.cloneNode(updateHelper), [
|
|
1306
|
+
types.cloneNode(clonedPrevious),
|
|
1307
|
+
types.cloneNode(path.node.argument, true),
|
|
1308
|
+
types.stringLiteral(kind)
|
|
1309
|
+
]);
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
const prepared = file.program.body[0].expression;
|
|
1313
|
+
return types.isArrowFunctionExpression(prepared) || types.isFunctionExpression(prepared) ? { updater: prepared, mutations } : void 0;
|
|
1314
|
+
}
|
|
1315
|
+
function rewriteKeyedCollectionUpdateHints(root, targetKinds, states, statesBySetter, updateHelper, mutationHelper, globalCollections) {
|
|
1316
|
+
if (targetKinds.size === 0) return { root: types.cloneNode(root, true), count: 0 };
|
|
1317
|
+
const file = expressionFile(types.cloneNode(root, true));
|
|
1318
|
+
let count = 0;
|
|
1319
|
+
for (const [stateIndex, kind] of targetKinds) {
|
|
1320
|
+
const state = states[stateIndex];
|
|
1321
|
+
if (!state || !collectionStateInitializerIsOwned(
|
|
1322
|
+
state.initialValue,
|
|
1323
|
+
kind,
|
|
1324
|
+
globalCollections.has(collectionConstructorName(kind))
|
|
1325
|
+
) || !collectionStateHasOnlyOwnedReads(root, state, kind)) {
|
|
1326
|
+
continue;
|
|
1327
|
+
}
|
|
1328
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
1329
|
+
let valid = true;
|
|
1330
|
+
traverse(file, {
|
|
1331
|
+
CallExpression(path) {
|
|
1332
|
+
if (!valid) return;
|
|
1333
|
+
const callee = path.get("callee");
|
|
1334
|
+
if (!callee.isIdentifier({ name: state.setterName }) || callee.scope.hasBinding(callee.node.name) || statesBySetter.get(callee.node.name)?.index !== stateIndex) {
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
if (path.node.arguments.length !== 1 || !types.isExpression(path.node.arguments[0])) {
|
|
1338
|
+
valid = false;
|
|
1339
|
+
path.stop();
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
const update = path.node.arguments[0];
|
|
1343
|
+
if (path.scope.getBinding(collectionConstructorName(kind))) {
|
|
1344
|
+
valid = false;
|
|
1345
|
+
path.stop();
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
if (isCollectionConstruction(update, kind)) return;
|
|
1349
|
+
if (!types.isArrowFunctionExpression(update) && !types.isFunctionExpression(update)) {
|
|
1350
|
+
valid = false;
|
|
1351
|
+
path.stop();
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
const prepared = prepareKeyedCollectionUpdater(update, kind, updateHelper, mutationHelper);
|
|
1355
|
+
if (!prepared) {
|
|
1356
|
+
valid = false;
|
|
1357
|
+
path.stop();
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
replacements.set(path.node, prepared);
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
if (!valid || replacements.size === 0) continue;
|
|
1364
|
+
traverse(file, {
|
|
1365
|
+
CallExpression(path) {
|
|
1366
|
+
const prepared = replacements.get(path.node);
|
|
1367
|
+
if (!prepared) return;
|
|
1368
|
+
path.node.arguments[0] = types.cloneNode(prepared.updater, true);
|
|
1369
|
+
count += prepared.mutations;
|
|
1370
|
+
path.skip();
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
return {
|
|
1375
|
+
root: file.program.body[0].expression,
|
|
1376
|
+
count
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
301
1379
|
function rewriteStateAccess(expression, stateParameter, statesByValue, statesBySetter) {
|
|
302
1380
|
const file = expressionFile(cloneExpression(expression));
|
|
303
1381
|
traverse(file, {
|
|
@@ -548,21 +1626,28 @@ function analyzeMapList(expression, statesByValue, safeGlobals) {
|
|
|
548
1626
|
const collection = callee.object;
|
|
549
1627
|
const collectionUnsupported = validateCollectionPipeline(collection, safeGlobals);
|
|
550
1628
|
if (collectionUnsupported) {
|
|
551
|
-
return {
|
|
1629
|
+
return {
|
|
1630
|
+
reason: `keyed list collection cannot use ${collectionUnsupported}`
|
|
1631
|
+
};
|
|
552
1632
|
}
|
|
553
1633
|
if (expression.arguments.length !== 1 || !types.isArrowFunctionExpression(expression.arguments[0]) && !types.isFunctionExpression(expression.arguments[0])) {
|
|
554
1634
|
return { reason: "keyed list map must use one inline render callback" };
|
|
555
1635
|
}
|
|
556
1636
|
const callback = expression.arguments[0];
|
|
557
1637
|
if (containsDirectHookCall(callback)) {
|
|
558
|
-
return {
|
|
1638
|
+
return {
|
|
1639
|
+
reason: "Hooks cannot be called directly inside a keyed list callback"
|
|
1640
|
+
};
|
|
559
1641
|
}
|
|
560
1642
|
const row = returnedExpression(callback);
|
|
561
1643
|
if (!row || !types.isJSXElement(row)) {
|
|
562
1644
|
return { reason: "keyed list map callbacks must return one React element" };
|
|
563
1645
|
}
|
|
564
1646
|
const key = jsxKeyExpression(row);
|
|
565
|
-
if (!key)
|
|
1647
|
+
if (!key)
|
|
1648
|
+
return {
|
|
1649
|
+
reason: "automatically compiled lists require an explicit item key"
|
|
1650
|
+
};
|
|
566
1651
|
const keyReason = validateKeyFunction(callback, key, safeGlobals);
|
|
567
1652
|
if (keyReason) return { reason: keyReason };
|
|
568
1653
|
return { dependencies: collectStateDependencies(expression, statesByValue) };
|
|
@@ -577,7 +1662,9 @@ function listAttributeExpression(element, name) {
|
|
|
577
1662
|
}
|
|
578
1663
|
function analyzePublicList(element, statesByValue, safeGlobals) {
|
|
579
1664
|
if (element.openingElement.attributes.some((attribute) => types.isJSXSpreadAttribute(attribute))) {
|
|
580
|
-
return {
|
|
1665
|
+
return {
|
|
1666
|
+
reason: "compiled List boundaries do not support JSX attribute spreads"
|
|
1667
|
+
};
|
|
581
1668
|
}
|
|
582
1669
|
const each = listAttributeExpression(element, "each");
|
|
583
1670
|
const by = listAttributeExpression(element, "by");
|
|
@@ -595,7 +1682,9 @@ function analyzePublicList(element, statesByValue, safeGlobals) {
|
|
|
595
1682
|
if (keyReason) return { reason: keyReason };
|
|
596
1683
|
const children = meaningfulJsxChildren(element);
|
|
597
1684
|
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 {
|
|
1685
|
+
return {
|
|
1686
|
+
reason: "compiled List children must use one inline render function"
|
|
1687
|
+
};
|
|
599
1688
|
}
|
|
600
1689
|
const render = children[0].expression;
|
|
601
1690
|
if (!returnedExpression(render)) {
|
|
@@ -709,13 +1798,20 @@ function stabilizeDeferredEventCurrentTargets(root, compilerSetters) {
|
|
|
709
1798
|
const expression = file.program.body[0].expression;
|
|
710
1799
|
return types.isJSXElement(expression) ? expression : types.cloneNode(root, true);
|
|
711
1800
|
}
|
|
712
|
-
function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters) {
|
|
1801
|
+
function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters, keyedTargetReactiveByValue) {
|
|
713
1802
|
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 {
|
|
1803
|
+
return {
|
|
1804
|
+
reason: "compiled keyed rows require item and optional index identifiers"
|
|
1805
|
+
};
|
|
715
1806
|
}
|
|
716
1807
|
const bindings = [];
|
|
717
1808
|
const events = [];
|
|
718
1809
|
const conditionals = [];
|
|
1810
|
+
const validateBindingExpression = (expression) => validateDerivedExpression(
|
|
1811
|
+
expression,
|
|
1812
|
+
safeGlobals,
|
|
1813
|
+
keyedTargetReactiveByValue ? (call) => isPotentialKeyedMembershipCall(call, keyedTargetReactiveByValue) || isPotentialKeyedMapLookupCall(call, keyedTargetReactiveByValue) : void 0
|
|
1814
|
+
);
|
|
719
1815
|
const visit = (element, path) => {
|
|
720
1816
|
const tag = element.openingElement.name;
|
|
721
1817
|
if (!types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
|
|
@@ -794,7 +1890,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
794
1890
|
if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
|
|
795
1891
|
return "compiled keyed row style names must use camelCase or a CSS custom property";
|
|
796
1892
|
}
|
|
797
|
-
const unsupported2 =
|
|
1893
|
+
const unsupported2 = validateBindingExpression(property.value);
|
|
798
1894
|
if (unsupported2) {
|
|
799
1895
|
return `compiled keyed row style ${propertyName} cannot use ${unsupported2}`;
|
|
800
1896
|
}
|
|
@@ -808,7 +1904,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
808
1904
|
continue;
|
|
809
1905
|
}
|
|
810
1906
|
if (name === "children") return "compiled keyed row children props are not supported yet";
|
|
811
|
-
const unsupported =
|
|
1907
|
+
const unsupported = validateBindingExpression(expression);
|
|
812
1908
|
if (unsupported) return `compiled keyed row ${name} cannot use ${unsupported}`;
|
|
813
1909
|
bindings.push({
|
|
814
1910
|
kind: "attribute",
|
|
@@ -858,7 +1954,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
858
1954
|
(child) => types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)
|
|
859
1955
|
);
|
|
860
1956
|
for (const child of expressions) {
|
|
861
|
-
const unsupported =
|
|
1957
|
+
const unsupported = validateBindingExpression(child.expression);
|
|
862
1958
|
if (unsupported) return `compiled keyed row text cannot use ${unsupported}`;
|
|
863
1959
|
}
|
|
864
1960
|
if (nestedElements.length > 0 && expressions.length > 0) {
|
|
@@ -874,7 +1970,11 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
874
1970
|
parts.push(cloneExpression(child.expression));
|
|
875
1971
|
}
|
|
876
1972
|
}
|
|
877
|
-
bindings.push({
|
|
1973
|
+
bindings.push({
|
|
1974
|
+
kind: "text",
|
|
1975
|
+
path: [...path],
|
|
1976
|
+
value: types.arrayExpression(parts)
|
|
1977
|
+
});
|
|
878
1978
|
}
|
|
879
1979
|
let elementIndex = 0;
|
|
880
1980
|
for (const child of element.children) {
|
|
@@ -888,7 +1988,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
888
1988
|
const reason = visit(row, []);
|
|
889
1989
|
return reason ? { reason } : { bindings, events, conditionals };
|
|
890
1990
|
}
|
|
891
|
-
function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acceptUnsupportedRow = false) {
|
|
1991
|
+
function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acceptUnsupportedRow = false, allowMembershipTargets = false) {
|
|
892
1992
|
let collection;
|
|
893
1993
|
let keyCallback;
|
|
894
1994
|
let renderCallback;
|
|
@@ -941,7 +2041,8 @@ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acce
|
|
|
941
2041
|
row,
|
|
942
2042
|
renderCallback,
|
|
943
2043
|
safeGlobals,
|
|
944
|
-
new Set([...statesByValue.values()].map((state) => state.setterName))
|
|
2044
|
+
new Set([...statesByValue.values()].map((state) => state.setterName)),
|
|
2045
|
+
allowMembershipTargets ? statesByValue : void 0
|
|
945
2046
|
);
|
|
946
2047
|
if (rowAnalysis.reason && !acceptUnsupportedRow) return void 0;
|
|
947
2048
|
const keyExpression = returnedExpression(keyCallback);
|
|
@@ -954,6 +2055,7 @@ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acce
|
|
|
954
2055
|
return {
|
|
955
2056
|
source,
|
|
956
2057
|
collection,
|
|
2058
|
+
collectionDependency: types.isIdentifier(collection) ? statesByValue.get(collection.name)?.index : void 0,
|
|
957
2059
|
structureDependencies: [...structureDependencies].sort((left, right) => left - right),
|
|
958
2060
|
keyCallback,
|
|
959
2061
|
renderCallback,
|
|
@@ -982,7 +2084,74 @@ function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNa
|
|
|
982
2084
|
}
|
|
983
2085
|
const children = meaningfulJsxChildren(container);
|
|
984
2086
|
if (children.length !== 1) return void 0;
|
|
985
|
-
|
|
2087
|
+
const shape = analyzeKeyedRowChild(
|
|
2088
|
+
children[0],
|
|
2089
|
+
statesByValue,
|
|
2090
|
+
safeGlobals,
|
|
2091
|
+
listNames,
|
|
2092
|
+
true,
|
|
2093
|
+
true
|
|
2094
|
+
);
|
|
2095
|
+
if (!shape || shape.rowReason) return shape;
|
|
2096
|
+
const needsMembershipProof = (binding) => containsPotentialKeyedMembershipCall(binding.value, statesByValue);
|
|
2097
|
+
const needsMapLookupProof = (binding) => containsPotentialKeyedMapLookupCall(binding.value, statesByValue);
|
|
2098
|
+
if (shape.conditionals.length > 0 || shape.events.length > 0 && !canDelegateKeyedRowEvents({
|
|
2099
|
+
conditionals: shape.conditionals,
|
|
2100
|
+
events: shape.events,
|
|
2101
|
+
source: container
|
|
2102
|
+
})) {
|
|
2103
|
+
return shape.bindings.some(
|
|
2104
|
+
(binding) => needsMembershipProof(binding) || needsMapLookupProof(binding)
|
|
2105
|
+
) ? {
|
|
2106
|
+
...shape,
|
|
2107
|
+
rowReason: "keyed collection targets require compiler-owned rows without React-owned branches or events"
|
|
2108
|
+
} : shape;
|
|
2109
|
+
}
|
|
2110
|
+
const structureDependencies = new Set(shape.structureDependencies);
|
|
2111
|
+
const bindings = shape.bindings.map((binding) => ({
|
|
2112
|
+
...binding,
|
|
2113
|
+
identityTarget: keyedIdentityTarget(
|
|
2114
|
+
binding,
|
|
2115
|
+
shape.keyCallback,
|
|
2116
|
+
shape.renderCallback,
|
|
2117
|
+
statesByValue,
|
|
2118
|
+
structureDependencies
|
|
2119
|
+
),
|
|
2120
|
+
membershipTarget: keyedMembershipTarget(
|
|
2121
|
+
binding,
|
|
2122
|
+
shape.keyCallback,
|
|
2123
|
+
shape.renderCallback,
|
|
2124
|
+
statesByValue,
|
|
2125
|
+
structureDependencies
|
|
2126
|
+
),
|
|
2127
|
+
mapLookupTarget: keyedMapLookupTarget(
|
|
2128
|
+
binding,
|
|
2129
|
+
shape.keyCallback,
|
|
2130
|
+
shape.renderCallback,
|
|
2131
|
+
statesByValue,
|
|
2132
|
+
structureDependencies
|
|
2133
|
+
)
|
|
2134
|
+
}));
|
|
2135
|
+
if (bindings.some(
|
|
2136
|
+
(binding, index) => needsMembershipProof(shape.bindings[index]) && !binding.membershipTarget
|
|
2137
|
+
)) {
|
|
2138
|
+
return {
|
|
2139
|
+
...shape,
|
|
2140
|
+
rowReason: "keyed membership targets must call one local Set state with the exact row key"
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
2143
|
+
if (bindings.some(
|
|
2144
|
+
(binding, index) => needsMapLookupProof(shape.bindings[index]) && !binding.mapLookupTarget
|
|
2145
|
+
)) {
|
|
2146
|
+
return {
|
|
2147
|
+
...shape,
|
|
2148
|
+
rowReason: "keyed Map lookup targets must call one local Map state with the exact row key"
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2151
|
+
return {
|
|
2152
|
+
...shape,
|
|
2153
|
+
bindings
|
|
2154
|
+
};
|
|
986
2155
|
}
|
|
987
2156
|
function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, listNames, allowSingleRange = false) {
|
|
988
2157
|
if (container.openingElement.attributes.some(
|
|
@@ -1138,7 +2307,11 @@ function analyzeHostConditionalTree(branch, safeGlobals, allowStaticEvents = fal
|
|
|
1138
2307
|
parts.push(cloneExpression(child.expression));
|
|
1139
2308
|
}
|
|
1140
2309
|
}
|
|
1141
|
-
bindings.push({
|
|
2310
|
+
bindings.push({
|
|
2311
|
+
kind: "text",
|
|
2312
|
+
path: [...path],
|
|
2313
|
+
value: types.arrayExpression(parts)
|
|
2314
|
+
});
|
|
1142
2315
|
}
|
|
1143
2316
|
let elementIndex = 0;
|
|
1144
2317
|
for (const child of element.children) {
|
|
@@ -1310,7 +2483,11 @@ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames,
|
|
|
1310
2483
|
listNames,
|
|
1311
2484
|
id,
|
|
1312
2485
|
allocateId
|
|
1313
|
-
) : {
|
|
2486
|
+
) : {
|
|
2487
|
+
bindings: [],
|
|
2488
|
+
plans: [],
|
|
2489
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2490
|
+
};
|
|
1314
2491
|
const falsy = shape.falsy ? analyzeRecursiveHostTree(
|
|
1315
2492
|
shape.falsy,
|
|
1316
2493
|
statesByValue,
|
|
@@ -1318,7 +2495,11 @@ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames,
|
|
|
1318
2495
|
listNames,
|
|
1319
2496
|
id,
|
|
1320
2497
|
allocateId
|
|
1321
|
-
) : {
|
|
2498
|
+
) : {
|
|
2499
|
+
bindings: [],
|
|
2500
|
+
plans: [],
|
|
2501
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2502
|
+
};
|
|
1322
2503
|
if (truthy.reason) return truthy.reason;
|
|
1323
2504
|
if (falsy.reason) return falsy.reason;
|
|
1324
2505
|
plans.push(...truthy.plans, ...falsy.plans);
|
|
@@ -1476,7 +2657,11 @@ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames,
|
|
|
1476
2657
|
parts.push(cloneExpression(child.expression));
|
|
1477
2658
|
}
|
|
1478
2659
|
}
|
|
1479
|
-
bindings.push({
|
|
2660
|
+
bindings.push({
|
|
2661
|
+
kind: "text",
|
|
2662
|
+
path: [...path],
|
|
2663
|
+
value: types.arrayExpression(parts)
|
|
2664
|
+
});
|
|
1480
2665
|
}
|
|
1481
2666
|
let elementIndex = 0;
|
|
1482
2667
|
for (const child of element.children) {
|
|
@@ -1543,7 +2728,11 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals,
|
|
|
1543
2728
|
listNames,
|
|
1544
2729
|
parent,
|
|
1545
2730
|
allocateId
|
|
1546
|
-
) : {
|
|
2731
|
+
) : {
|
|
2732
|
+
bindings: [],
|
|
2733
|
+
plans: [],
|
|
2734
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2735
|
+
};
|
|
1547
2736
|
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1548
2737
|
shape.falsy,
|
|
1549
2738
|
statesByValue,
|
|
@@ -1551,7 +2740,11 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals,
|
|
|
1551
2740
|
listNames,
|
|
1552
2741
|
parent,
|
|
1553
2742
|
allocateId
|
|
1554
|
-
) : {
|
|
2743
|
+
) : {
|
|
2744
|
+
bindings: [],
|
|
2745
|
+
plans: [],
|
|
2746
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2747
|
+
};
|
|
1555
2748
|
if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
|
|
1556
2749
|
const dependencies = new Set(collectStateDependencies(shape.test, statesByValue));
|
|
1557
2750
|
for (const binding of [...truthyAnalysis.bindings || [], ...falsyAnalysis.bindings || []]) {
|
|
@@ -1597,7 +2790,11 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
|
|
|
1597
2790
|
listNames,
|
|
1598
2791
|
parent,
|
|
1599
2792
|
allocateId
|
|
1600
|
-
) : {
|
|
2793
|
+
) : {
|
|
2794
|
+
bindings: [],
|
|
2795
|
+
plans: [],
|
|
2796
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2797
|
+
};
|
|
1601
2798
|
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1602
2799
|
shape.falsy,
|
|
1603
2800
|
statesByValue,
|
|
@@ -1605,7 +2802,11 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
|
|
|
1605
2802
|
listNames,
|
|
1606
2803
|
parent,
|
|
1607
2804
|
allocateId
|
|
1608
|
-
) : {
|
|
2805
|
+
) : {
|
|
2806
|
+
bindings: [],
|
|
2807
|
+
plans: [],
|
|
2808
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2809
|
+
};
|
|
1609
2810
|
if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
|
|
1610
2811
|
nestedPlans.push(...truthyAnalysis.plans, ...falsyAnalysis.plans);
|
|
1611
2812
|
for (const [element, plan] of truthyAnalysis.blocks) descriptorBlocks.set(element, plan);
|
|
@@ -1698,7 +2899,11 @@ function analyzeMixedRangesContainer(container, statesByValue, safeGlobals, list
|
|
|
1698
2899
|
listNames,
|
|
1699
2900
|
parent,
|
|
1700
2901
|
allocateId
|
|
1701
|
-
) : {
|
|
2902
|
+
) : {
|
|
2903
|
+
bindings: [],
|
|
2904
|
+
plans: [],
|
|
2905
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2906
|
+
};
|
|
1702
2907
|
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1703
2908
|
shape.falsy,
|
|
1704
2909
|
statesByValue,
|
|
@@ -1706,7 +2911,11 @@ function analyzeMixedRangesContainer(container, statesByValue, safeGlobals, list
|
|
|
1706
2911
|
listNames,
|
|
1707
2912
|
parent,
|
|
1708
2913
|
allocateId
|
|
1709
|
-
) : {
|
|
2914
|
+
) : {
|
|
2915
|
+
bindings: [],
|
|
2916
|
+
plans: [],
|
|
2917
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2918
|
+
};
|
|
1710
2919
|
if (!mergeAnalysis(truthyAnalysis) || !mergeAnalysis(falsyAnalysis)) return void 0;
|
|
1711
2920
|
for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
|
|
1712
2921
|
dependencies.add(dependency);
|
|
@@ -1947,6 +3156,57 @@ function keyedRowBindingObject(binding, parameters) {
|
|
|
1947
3156
|
if (binding.name) {
|
|
1948
3157
|
properties.push(types.objectProperty(types.identifier("name"), types.stringLiteral(binding.name)));
|
|
1949
3158
|
}
|
|
3159
|
+
if (binding.identityTarget) {
|
|
3160
|
+
properties.push(
|
|
3161
|
+
types.objectProperty(
|
|
3162
|
+
types.identifier("identityTarget"),
|
|
3163
|
+
types.objectExpression([
|
|
3164
|
+
types.objectProperty(
|
|
3165
|
+
types.identifier("dependency"),
|
|
3166
|
+
types.numericLiteral(binding.identityTarget.dependency)
|
|
3167
|
+
),
|
|
3168
|
+
types.objectProperty(
|
|
3169
|
+
types.identifier("read"),
|
|
3170
|
+
types.arrowFunctionExpression([], cloneExpression(binding.identityTarget.value))
|
|
3171
|
+
)
|
|
3172
|
+
])
|
|
3173
|
+
)
|
|
3174
|
+
);
|
|
3175
|
+
}
|
|
3176
|
+
if (binding.membershipTarget) {
|
|
3177
|
+
properties.push(
|
|
3178
|
+
types.objectProperty(
|
|
3179
|
+
types.identifier("membershipTarget"),
|
|
3180
|
+
types.objectExpression([
|
|
3181
|
+
types.objectProperty(
|
|
3182
|
+
types.identifier("dependency"),
|
|
3183
|
+
types.numericLiteral(binding.membershipTarget.dependency)
|
|
3184
|
+
),
|
|
3185
|
+
types.objectProperty(
|
|
3186
|
+
types.identifier("read"),
|
|
3187
|
+
types.arrowFunctionExpression([], cloneExpression(binding.membershipTarget.value))
|
|
3188
|
+
)
|
|
3189
|
+
])
|
|
3190
|
+
)
|
|
3191
|
+
);
|
|
3192
|
+
}
|
|
3193
|
+
if (binding.mapLookupTarget) {
|
|
3194
|
+
properties.push(
|
|
3195
|
+
types.objectProperty(
|
|
3196
|
+
types.identifier("mapLookupTarget"),
|
|
3197
|
+
types.objectExpression([
|
|
3198
|
+
types.objectProperty(
|
|
3199
|
+
types.identifier("dependency"),
|
|
3200
|
+
types.numericLiteral(binding.mapLookupTarget.dependency)
|
|
3201
|
+
),
|
|
3202
|
+
types.objectProperty(
|
|
3203
|
+
types.identifier("read"),
|
|
3204
|
+
types.arrowFunctionExpression([], cloneExpression(binding.mapLookupTarget.value))
|
|
3205
|
+
)
|
|
3206
|
+
])
|
|
3207
|
+
)
|
|
3208
|
+
);
|
|
3209
|
+
}
|
|
1950
3210
|
properties.push(
|
|
1951
3211
|
types.objectProperty(
|
|
1952
3212
|
types.identifier("read"),
|
|
@@ -2141,7 +3401,7 @@ function keyedRowConditionalObject(conditional, parameters) {
|
|
|
2141
3401
|
}
|
|
2142
3402
|
return types.objectExpression(properties);
|
|
2143
3403
|
}
|
|
2144
|
-
function keyedRowsBoundary(blockRuntime, plan) {
|
|
3404
|
+
function keyedRowsBoundary(blockRuntime, plan, keyedMapUpdateHints, keyedArrayFilterHintedStateIndices, keyedArrayPrependHintedStateIndices, keyedArrayPositionHintedStateIndices, keyedArrayReorderHintedStateIndices) {
|
|
2145
3405
|
const name = types.jsxMemberExpression(
|
|
2146
3406
|
types.jsxIdentifier(blockRuntime.name),
|
|
2147
3407
|
types.jsxIdentifier("KeyedRows")
|
|
@@ -2175,6 +3435,16 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
2175
3435
|
types.jsxIdentifier("items"),
|
|
2176
3436
|
types.jsxExpressionContainer(types.arrowFunctionExpression([], cloneExpression(plan.collection)))
|
|
2177
3437
|
),
|
|
3438
|
+
...keyedMapUpdateHints ? [
|
|
3439
|
+
types.jsxAttribute(
|
|
3440
|
+
types.jsxIdentifier("dependencies"),
|
|
3441
|
+
types.jsxExpressionContainer(
|
|
3442
|
+
types.arrayExpression(
|
|
3443
|
+
plan.dependencies.map((dependency) => types.numericLiteral(dependency))
|
|
3444
|
+
)
|
|
3445
|
+
)
|
|
3446
|
+
)
|
|
3447
|
+
] : [],
|
|
2178
3448
|
types.jsxAttribute(
|
|
2179
3449
|
types.jsxIdentifier("structureDependencies"),
|
|
2180
3450
|
types.jsxExpressionContainer(
|
|
@@ -2183,6 +3453,36 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
2183
3453
|
)
|
|
2184
3454
|
)
|
|
2185
3455
|
),
|
|
3456
|
+
...!keyedMapUpdateHints || plan.collectionDependency === void 0 ? [] : [
|
|
3457
|
+
types.jsxAttribute(
|
|
3458
|
+
types.jsxIdentifier("collectionDependency"),
|
|
3459
|
+
types.jsxExpressionContainer(types.numericLiteral(plan.collectionDependency))
|
|
3460
|
+
)
|
|
3461
|
+
],
|
|
3462
|
+
...plan.collectionDependency !== void 0 && keyedArrayFilterHintedStateIndices.has(plan.collectionDependency) ? [
|
|
3463
|
+
types.jsxAttribute(
|
|
3464
|
+
types.jsxIdentifier("filterIndexIndependent"),
|
|
3465
|
+
types.jsxExpressionContainer(types.booleanLiteral(true))
|
|
3466
|
+
)
|
|
3467
|
+
] : [],
|
|
3468
|
+
...plan.collectionDependency !== void 0 && keyedArrayPrependHintedStateIndices.has(plan.collectionDependency) ? [
|
|
3469
|
+
types.jsxAttribute(
|
|
3470
|
+
types.jsxIdentifier("prependIndexIndependent"),
|
|
3471
|
+
types.jsxExpressionContainer(types.booleanLiteral(true))
|
|
3472
|
+
)
|
|
3473
|
+
] : [],
|
|
3474
|
+
...plan.collectionDependency !== void 0 && keyedArrayPositionHintedStateIndices.has(plan.collectionDependency) ? [
|
|
3475
|
+
types.jsxAttribute(
|
|
3476
|
+
types.jsxIdentifier("positionIndexIndependent"),
|
|
3477
|
+
types.jsxExpressionContainer(types.booleanLiteral(true))
|
|
3478
|
+
)
|
|
3479
|
+
] : [],
|
|
3480
|
+
...plan.collectionDependency !== void 0 && keyedArrayReorderHintedStateIndices.has(plan.collectionDependency) ? [
|
|
3481
|
+
types.jsxAttribute(
|
|
3482
|
+
types.jsxIdentifier("reorderIndexIndependent"),
|
|
3483
|
+
types.jsxExpressionContainer(types.booleanLiteral(true))
|
|
3484
|
+
)
|
|
3485
|
+
] : [],
|
|
2186
3486
|
types.jsxAttribute(
|
|
2187
3487
|
types.jsxIdentifier("rowKey"),
|
|
2188
3488
|
types.jsxExpressionContainer(types.cloneNode(plan.keyCallback, true))
|
|
@@ -2509,7 +3809,9 @@ function conditionalRangesBoundary(blockRuntime, plan) {
|
|
|
2509
3809
|
function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allowedComponentNames) {
|
|
2510
3810
|
const name = element.openingElement.name;
|
|
2511
3811
|
if (!types.isJSXIdentifier(name) || !isComponentName(name.name)) {
|
|
2512
|
-
return {
|
|
3812
|
+
return {
|
|
3813
|
+
reason: "component islands require a direct component identifier"
|
|
3814
|
+
};
|
|
2513
3815
|
}
|
|
2514
3816
|
if (!allowedComponentNames.has(name.name)) {
|
|
2515
3817
|
return {
|
|
@@ -2517,19 +3819,27 @@ function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allo
|
|
|
2517
3819
|
};
|
|
2518
3820
|
}
|
|
2519
3821
|
if (meaningfulJsxChildren(element).length > 0) {
|
|
2520
|
-
return {
|
|
3822
|
+
return {
|
|
3823
|
+
reason: `component island ${name.name} does not support children yet`
|
|
3824
|
+
};
|
|
2521
3825
|
}
|
|
2522
3826
|
const dependencies = /* @__PURE__ */ new Set();
|
|
2523
3827
|
for (const attribute of element.openingElement.attributes) {
|
|
2524
3828
|
if (types.isJSXSpreadAttribute(attribute)) {
|
|
2525
|
-
return {
|
|
3829
|
+
return {
|
|
3830
|
+
reason: `component island ${name.name} does not support JSX attribute spreads`
|
|
3831
|
+
};
|
|
2526
3832
|
}
|
|
2527
3833
|
const attributeName = jsxAttributeName(attribute);
|
|
2528
3834
|
if (!attributeName) {
|
|
2529
|
-
return {
|
|
3835
|
+
return {
|
|
3836
|
+
reason: `component island ${name.name} does not support namespaced JSX attributes`
|
|
3837
|
+
};
|
|
2530
3838
|
}
|
|
2531
3839
|
if (attributeName === "ref" || attributeName === "key" || attributeName === "children") {
|
|
2532
|
-
return {
|
|
3840
|
+
return {
|
|
3841
|
+
reason: `component island ${name.name} does not support ${attributeName} yet`
|
|
3842
|
+
};
|
|
2533
3843
|
}
|
|
2534
3844
|
if (!types.isJSXExpressionContainer(attribute.value) || types.isJSXEmptyExpression(attribute.value.expression)) {
|
|
2535
3845
|
continue;
|
|
@@ -2548,7 +3858,9 @@ function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allo
|
|
|
2548
3858
|
(dependency) => dependencies.add(dependency)
|
|
2549
3859
|
);
|
|
2550
3860
|
}
|
|
2551
|
-
return {
|
|
3861
|
+
return {
|
|
3862
|
+
dependencies: [...dependencies].sort((left, right) => left - right)
|
|
3863
|
+
};
|
|
2552
3864
|
}
|
|
2553
3865
|
function componentIslandBoundary(blockRuntime, plan, source) {
|
|
2554
3866
|
const name = types.jsxMemberExpression(
|
|
@@ -2805,6 +4117,7 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
2805
4117
|
dependencies: keyedRows.dependencies,
|
|
2806
4118
|
source: child,
|
|
2807
4119
|
collection: keyedRows.collection,
|
|
4120
|
+
collectionDependency: keyedRows.collectionDependency,
|
|
2808
4121
|
structureDependencies: keyedRows.structureDependencies,
|
|
2809
4122
|
keyCallback: keyedRows.keyCallback,
|
|
2810
4123
|
renderCallback: keyedRows.renderCallback,
|
|
@@ -3046,7 +4359,7 @@ function conditionalBlockBoundary(blockRuntime, plan, source) {
|
|
|
3046
4359
|
true
|
|
3047
4360
|
);
|
|
3048
4361
|
}
|
|
3049
|
-
function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
|
|
4362
|
+
function lowerComposableBlocks(root, plans, blockRuntime, listNames, keyedMapUpdateHints, keyedArrayFilterHintedStateIndices, keyedArrayPrependHintedStateIndices, keyedArrayPositionHintedStateIndices, keyedArrayReorderHintedStateIndices) {
|
|
3050
4363
|
const planBySource = new Map(
|
|
3051
4364
|
plans.map((plan) => [plan.source, plan])
|
|
3052
4365
|
);
|
|
@@ -3071,7 +4384,15 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
|
|
|
3071
4384
|
return mixedRangesBoundary(blockRuntime, plan2);
|
|
3072
4385
|
}
|
|
3073
4386
|
if (plan2?.kind === "keyed-rows") {
|
|
3074
|
-
return keyedRowsBoundary(
|
|
4387
|
+
return keyedRowsBoundary(
|
|
4388
|
+
blockRuntime,
|
|
4389
|
+
plan2,
|
|
4390
|
+
keyedMapUpdateHints,
|
|
4391
|
+
keyedArrayFilterHintedStateIndices,
|
|
4392
|
+
keyedArrayPrependHintedStateIndices,
|
|
4393
|
+
keyedArrayPositionHintedStateIndices,
|
|
4394
|
+
keyedArrayReorderHintedStateIndices
|
|
4395
|
+
);
|
|
3075
4396
|
}
|
|
3076
4397
|
if (plan2?.kind === "keyed-ranges") {
|
|
3077
4398
|
return keyedRangesBoundary(blockRuntime, plan2);
|
|
@@ -3434,7 +4755,7 @@ function wrapperElement(definitionIdentifier, props) {
|
|
|
3434
4755
|
const attributes = props ? [types.jsxSpreadAttribute(types.cloneNode(props))] : [];
|
|
3435
4756
|
return types.jsxElement(types.jsxOpeningElement(name, attributes, true), null, [], true);
|
|
3436
4757
|
}
|
|
3437
|
-
function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureIdentifiers, usedRuntimeFeatures, useStateNames, reactNames, listNames, moduleId, reactivity) {
|
|
4758
|
+
function compileCandidate(candidate, createComponentIdentifier, keyedMapUpdateIdentifier, keyedArrayAppendIdentifier, keyedArrayFilterIdentifier, keyedArrayPrependIdentifier, keyedArrayPositionIdentifier, keyedArrayReorderIdentifier, keyedArrayRollingWindowIdentifier, keyedArraySliceIdentifier, keyedCollectionUpdateIdentifier, keyedCollectionMutationIdentifier, runtimeFeatureIdentifiers, usedRuntimeFeatures, optimizationCounts, useStateNames, reactNames, listNames, moduleId, reactivity) {
|
|
3438
4759
|
const { path, name, statementPath } = candidate;
|
|
3439
4760
|
if (path.node.async || path.node.generator)
|
|
3440
4761
|
return "async and generator components are not supported";
|
|
@@ -3446,6 +4767,7 @@ function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureId
|
|
|
3446
4767
|
const safeGlobals = new Set(
|
|
3447
4768
|
[...SAFE_GLOBAL_CALLS, "Math"].filter((name2) => !path.scope.getBinding(name2))
|
|
3448
4769
|
);
|
|
4770
|
+
const globalCollections = new Set(["Set", "Map"].filter((name2) => !path.scope.getBinding(name2)));
|
|
3449
4771
|
const states = [];
|
|
3450
4772
|
const locals = [];
|
|
3451
4773
|
let returned;
|
|
@@ -3493,9 +4815,17 @@ function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureId
|
|
|
3493
4815
|
if (declaration.init.async || declaration.init.generator) {
|
|
3494
4816
|
return `event handler ${declaration.id.name} must be synchronous`;
|
|
3495
4817
|
}
|
|
3496
|
-
locals.push({
|
|
4818
|
+
locals.push({
|
|
4819
|
+
kind: "handler",
|
|
4820
|
+
name: declaration.id.name,
|
|
4821
|
+
value: declaration.init
|
|
4822
|
+
});
|
|
3497
4823
|
} else {
|
|
3498
|
-
locals.push({
|
|
4824
|
+
locals.push({
|
|
4825
|
+
kind: "derived",
|
|
4826
|
+
name: declaration.id.name,
|
|
4827
|
+
value: declaration.init
|
|
4828
|
+
});
|
|
3499
4829
|
}
|
|
3500
4830
|
}
|
|
3501
4831
|
if (states.length === 0) return "no local useState binding was found";
|
|
@@ -3634,8 +4964,378 @@ function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureId
|
|
|
3634
4964
|
}
|
|
3635
4965
|
if (blockAnalysis.reason) return blockAnalysis.reason;
|
|
3636
4966
|
if (analysis.reason) return analysis.reason;
|
|
4967
|
+
const hintedStateIndices = new Set(
|
|
4968
|
+
(blockAnalysis.plans || []).filter(
|
|
4969
|
+
(plan) => plan.kind === "keyed-rows" && plan.collectionDependency !== void 0
|
|
4970
|
+
).map((plan) => plan.collectionDependency)
|
|
4971
|
+
);
|
|
4972
|
+
const hintedRoot = rewriteKeyedMapUpdateHints(
|
|
4973
|
+
expandedReactiveRoot,
|
|
4974
|
+
hintedStateIndices,
|
|
4975
|
+
statesBySetter,
|
|
4976
|
+
keyedMapUpdateIdentifier,
|
|
4977
|
+
safeGlobals
|
|
4978
|
+
);
|
|
4979
|
+
let appliedKeyedMapUpdateHints = 0;
|
|
4980
|
+
if (hintedRoot.count > 0) {
|
|
4981
|
+
const hintedBlockAnalysis = analyzeComposableBlocks(
|
|
4982
|
+
hintedRoot.root,
|
|
4983
|
+
reactiveByValue,
|
|
4984
|
+
safeGlobals,
|
|
4985
|
+
listNames,
|
|
4986
|
+
allowedComponentNames
|
|
4987
|
+
);
|
|
4988
|
+
const hintedAnalysis = analyzeHostTree(
|
|
4989
|
+
hintedRoot.root,
|
|
4990
|
+
reactiveByValue,
|
|
4991
|
+
safeGlobals,
|
|
4992
|
+
hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
4993
|
+
hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
4994
|
+
hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
4995
|
+
hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
4996
|
+
);
|
|
4997
|
+
if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
|
|
4998
|
+
expandedReactiveRoot = hintedRoot.root;
|
|
4999
|
+
blockAnalysis = hintedBlockAnalysis;
|
|
5000
|
+
analysis = hintedAnalysis;
|
|
5001
|
+
appliedKeyedMapUpdateHints = hintedRoot.count;
|
|
5002
|
+
optimizationCounts.keyedMapUpdateHints += hintedRoot.count;
|
|
5003
|
+
}
|
|
5004
|
+
}
|
|
5005
|
+
const appendHintedStateIndices = new Set(hintedStateIndices);
|
|
5006
|
+
for (const plan of blockAnalysis.plans || []) {
|
|
5007
|
+
if (plan.kind !== "keyed-rows" || plan.collectionDependency === void 0) continue;
|
|
5008
|
+
const keyExpression = returnedExpression(plan.keyCallback);
|
|
5009
|
+
if (!keyExpression || collectStateDependencies(keyExpression, reactiveByValue).includes(plan.collectionDependency)) {
|
|
5010
|
+
appendHintedStateIndices.delete(plan.collectionDependency);
|
|
5011
|
+
}
|
|
5012
|
+
}
|
|
5013
|
+
const appendHintedRoot = rewriteKeyedArrayAppendHints(
|
|
5014
|
+
expandedReactiveRoot,
|
|
5015
|
+
appendHintedStateIndices,
|
|
5016
|
+
statesBySetter,
|
|
5017
|
+
keyedArrayAppendIdentifier,
|
|
5018
|
+
safeGlobals
|
|
5019
|
+
);
|
|
5020
|
+
let appliedKeyedArrayAppendHints = 0;
|
|
5021
|
+
if (appendHintedRoot.count > 0) {
|
|
5022
|
+
const hintedBlockAnalysis = analyzeComposableBlocks(
|
|
5023
|
+
appendHintedRoot.root,
|
|
5024
|
+
reactiveByValue,
|
|
5025
|
+
safeGlobals,
|
|
5026
|
+
listNames,
|
|
5027
|
+
allowedComponentNames
|
|
5028
|
+
);
|
|
5029
|
+
const hintedAnalysis = analyzeHostTree(
|
|
5030
|
+
appendHintedRoot.root,
|
|
5031
|
+
reactiveByValue,
|
|
5032
|
+
safeGlobals,
|
|
5033
|
+
hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
5034
|
+
hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
5035
|
+
hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
5036
|
+
hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
5037
|
+
);
|
|
5038
|
+
if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
|
|
5039
|
+
expandedReactiveRoot = appendHintedRoot.root;
|
|
5040
|
+
blockAnalysis = hintedBlockAnalysis;
|
|
5041
|
+
analysis = hintedAnalysis;
|
|
5042
|
+
appliedKeyedArrayAppendHints = appendHintedRoot.count;
|
|
5043
|
+
optimizationCounts.keyedArrayAppendHints += appendHintedRoot.count;
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5046
|
+
const shiftedIndexIndependentStateIndices = new Set(hintedStateIndices);
|
|
5047
|
+
for (const plan of blockAnalysis.plans || []) {
|
|
5048
|
+
if (plan.kind !== "keyed-rows" || plan.collectionDependency === void 0) continue;
|
|
5049
|
+
const keyExpression = returnedExpression(plan.keyCallback);
|
|
5050
|
+
if (plan.renderCallback.params.length > 1 || !keyExpression || collectStateDependencies(keyExpression, reactiveByValue).includes(plan.collectionDependency)) {
|
|
5051
|
+
shiftedIndexIndependentStateIndices.delete(plan.collectionDependency);
|
|
5052
|
+
}
|
|
5053
|
+
}
|
|
5054
|
+
const prependHintedRoot = rewriteKeyedArrayPrependHints(
|
|
5055
|
+
expandedReactiveRoot,
|
|
5056
|
+
shiftedIndexIndependentStateIndices,
|
|
5057
|
+
statesBySetter,
|
|
5058
|
+
keyedArrayPrependIdentifier,
|
|
5059
|
+
safeGlobals
|
|
5060
|
+
);
|
|
5061
|
+
let appliedKeyedArrayPrependHints = 0;
|
|
5062
|
+
let appliedPrependHintedStateIndices = /* @__PURE__ */ new Set();
|
|
5063
|
+
if (prependHintedRoot.count > 0) {
|
|
5064
|
+
const hintedBlockAnalysis = analyzeComposableBlocks(
|
|
5065
|
+
prependHintedRoot.root,
|
|
5066
|
+
reactiveByValue,
|
|
5067
|
+
safeGlobals,
|
|
5068
|
+
listNames,
|
|
5069
|
+
allowedComponentNames
|
|
5070
|
+
);
|
|
5071
|
+
const hintedAnalysis = analyzeHostTree(
|
|
5072
|
+
prependHintedRoot.root,
|
|
5073
|
+
reactiveByValue,
|
|
5074
|
+
safeGlobals,
|
|
5075
|
+
hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
5076
|
+
hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
5077
|
+
hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
5078
|
+
hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
5079
|
+
);
|
|
5080
|
+
if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
|
|
5081
|
+
expandedReactiveRoot = prependHintedRoot.root;
|
|
5082
|
+
blockAnalysis = hintedBlockAnalysis;
|
|
5083
|
+
analysis = hintedAnalysis;
|
|
5084
|
+
appliedKeyedArrayPrependHints = prependHintedRoot.count;
|
|
5085
|
+
appliedPrependHintedStateIndices = prependHintedRoot.stateIndices;
|
|
5086
|
+
optimizationCounts.keyedArrayPrependHints += prependHintedRoot.count;
|
|
5087
|
+
}
|
|
5088
|
+
}
|
|
5089
|
+
const rollingWindowHintedRoot = rewriteKeyedArrayRollingWindowHints(
|
|
5090
|
+
expandedReactiveRoot,
|
|
5091
|
+
shiftedIndexIndependentStateIndices,
|
|
5092
|
+
statesBySetter,
|
|
5093
|
+
keyedArraySliceIdentifier,
|
|
5094
|
+
keyedArrayRollingWindowIdentifier,
|
|
5095
|
+
safeGlobals
|
|
5096
|
+
);
|
|
5097
|
+
let appliedKeyedArrayRollingWindowHints = 0;
|
|
5098
|
+
let appliedRollingWindowHintedStateIndices = /* @__PURE__ */ new Set();
|
|
5099
|
+
if (rollingWindowHintedRoot.count > 0) {
|
|
5100
|
+
const hintedBlockAnalysis = analyzeComposableBlocks(
|
|
5101
|
+
rollingWindowHintedRoot.root,
|
|
5102
|
+
reactiveByValue,
|
|
5103
|
+
safeGlobals,
|
|
5104
|
+
listNames,
|
|
5105
|
+
allowedComponentNames
|
|
5106
|
+
);
|
|
5107
|
+
const hintedAnalysis = analyzeHostTree(
|
|
5108
|
+
rollingWindowHintedRoot.root,
|
|
5109
|
+
reactiveByValue,
|
|
5110
|
+
safeGlobals,
|
|
5111
|
+
hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
5112
|
+
hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
5113
|
+
hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
5114
|
+
hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
5115
|
+
);
|
|
5116
|
+
if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
|
|
5117
|
+
expandedReactiveRoot = rollingWindowHintedRoot.root;
|
|
5118
|
+
blockAnalysis = hintedBlockAnalysis;
|
|
5119
|
+
analysis = hintedAnalysis;
|
|
5120
|
+
appliedKeyedArrayRollingWindowHints = rollingWindowHintedRoot.count;
|
|
5121
|
+
appliedRollingWindowHintedStateIndices = rollingWindowHintedRoot.stateIndices;
|
|
5122
|
+
optimizationCounts.keyedArrayRollingWindowHints += rollingWindowHintedRoot.count;
|
|
5123
|
+
}
|
|
5124
|
+
}
|
|
5125
|
+
const positionHintedRoot = rewriteKeyedArrayPositionHints(
|
|
5126
|
+
expandedReactiveRoot,
|
|
5127
|
+
shiftedIndexIndependentStateIndices,
|
|
5128
|
+
statesBySetter,
|
|
5129
|
+
keyedArrayPositionIdentifier,
|
|
5130
|
+
safeGlobals
|
|
5131
|
+
);
|
|
5132
|
+
let appliedKeyedArrayPositionHints = 0;
|
|
5133
|
+
let appliedPositionHintedStateIndices = /* @__PURE__ */ new Set();
|
|
5134
|
+
if (positionHintedRoot.count > 0) {
|
|
5135
|
+
const hintedBlockAnalysis = analyzeComposableBlocks(
|
|
5136
|
+
positionHintedRoot.root,
|
|
5137
|
+
reactiveByValue,
|
|
5138
|
+
safeGlobals,
|
|
5139
|
+
listNames,
|
|
5140
|
+
allowedComponentNames
|
|
5141
|
+
);
|
|
5142
|
+
const hintedAnalysis = analyzeHostTree(
|
|
5143
|
+
positionHintedRoot.root,
|
|
5144
|
+
reactiveByValue,
|
|
5145
|
+
safeGlobals,
|
|
5146
|
+
hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
5147
|
+
hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
5148
|
+
hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
5149
|
+
hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
5150
|
+
);
|
|
5151
|
+
if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
|
|
5152
|
+
expandedReactiveRoot = positionHintedRoot.root;
|
|
5153
|
+
blockAnalysis = hintedBlockAnalysis;
|
|
5154
|
+
analysis = hintedAnalysis;
|
|
5155
|
+
appliedKeyedArrayPositionHints = positionHintedRoot.count;
|
|
5156
|
+
appliedPositionHintedStateIndices = positionHintedRoot.stateIndices;
|
|
5157
|
+
optimizationCounts.keyedArrayPositionHints += positionHintedRoot.count;
|
|
5158
|
+
}
|
|
5159
|
+
}
|
|
5160
|
+
const reorderHintedRoot = rewriteKeyedArrayReorderHints(
|
|
5161
|
+
expandedReactiveRoot,
|
|
5162
|
+
shiftedIndexIndependentStateIndices,
|
|
5163
|
+
statesBySetter,
|
|
5164
|
+
keyedArrayReorderIdentifier
|
|
5165
|
+
);
|
|
5166
|
+
let appliedKeyedArrayReorderHints = 0;
|
|
5167
|
+
let appliedReorderHintedStateIndices = /* @__PURE__ */ new Set();
|
|
5168
|
+
if (reorderHintedRoot.count > 0) {
|
|
5169
|
+
const hintedBlockAnalysis = analyzeComposableBlocks(
|
|
5170
|
+
reorderHintedRoot.root,
|
|
5171
|
+
reactiveByValue,
|
|
5172
|
+
safeGlobals,
|
|
5173
|
+
listNames,
|
|
5174
|
+
allowedComponentNames
|
|
5175
|
+
);
|
|
5176
|
+
const hintedAnalysis = analyzeHostTree(
|
|
5177
|
+
reorderHintedRoot.root,
|
|
5178
|
+
reactiveByValue,
|
|
5179
|
+
safeGlobals,
|
|
5180
|
+
hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
5181
|
+
hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
5182
|
+
hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
5183
|
+
hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
5184
|
+
);
|
|
5185
|
+
if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
|
|
5186
|
+
expandedReactiveRoot = reorderHintedRoot.root;
|
|
5187
|
+
blockAnalysis = hintedBlockAnalysis;
|
|
5188
|
+
analysis = hintedAnalysis;
|
|
5189
|
+
appliedKeyedArrayReorderHints = reorderHintedRoot.count;
|
|
5190
|
+
appliedReorderHintedStateIndices = reorderHintedRoot.stateIndices;
|
|
5191
|
+
optimizationCounts.keyedArrayReorderHints += reorderHintedRoot.count;
|
|
5192
|
+
}
|
|
5193
|
+
}
|
|
5194
|
+
const sliceHintedRoot = rewriteKeyedArraySliceHints(
|
|
5195
|
+
expandedReactiveRoot,
|
|
5196
|
+
shiftedIndexIndependentStateIndices,
|
|
5197
|
+
statesBySetter,
|
|
5198
|
+
keyedArraySliceIdentifier
|
|
5199
|
+
);
|
|
5200
|
+
let appliedKeyedArraySliceHints = 0;
|
|
5201
|
+
let appliedSliceHintedStateIndices = /* @__PURE__ */ new Set();
|
|
5202
|
+
if (sliceHintedRoot.count > 0) {
|
|
5203
|
+
const hintedBlockAnalysis = analyzeComposableBlocks(
|
|
5204
|
+
sliceHintedRoot.root,
|
|
5205
|
+
reactiveByValue,
|
|
5206
|
+
safeGlobals,
|
|
5207
|
+
listNames,
|
|
5208
|
+
allowedComponentNames
|
|
5209
|
+
);
|
|
5210
|
+
const hintedAnalysis = analyzeHostTree(
|
|
5211
|
+
sliceHintedRoot.root,
|
|
5212
|
+
reactiveByValue,
|
|
5213
|
+
safeGlobals,
|
|
5214
|
+
hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
5215
|
+
hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
5216
|
+
hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
5217
|
+
hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
5218
|
+
);
|
|
5219
|
+
if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
|
|
5220
|
+
expandedReactiveRoot = sliceHintedRoot.root;
|
|
5221
|
+
blockAnalysis = hintedBlockAnalysis;
|
|
5222
|
+
analysis = hintedAnalysis;
|
|
5223
|
+
appliedKeyedArraySliceHints = sliceHintedRoot.count;
|
|
5224
|
+
appliedSliceHintedStateIndices = sliceHintedRoot.stateIndices;
|
|
5225
|
+
optimizationCounts.keyedArraySliceHints += sliceHintedRoot.count;
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
const filterHintedRoot = rewriteKeyedArrayFilterHints(
|
|
5229
|
+
expandedReactiveRoot,
|
|
5230
|
+
shiftedIndexIndependentStateIndices,
|
|
5231
|
+
statesBySetter,
|
|
5232
|
+
keyedArrayFilterIdentifier,
|
|
5233
|
+
safeGlobals
|
|
5234
|
+
);
|
|
5235
|
+
let appliedKeyedArrayFilterHints = 0;
|
|
5236
|
+
let appliedFilterHintedStateIndices = /* @__PURE__ */ new Set();
|
|
5237
|
+
if (filterHintedRoot.count > 0) {
|
|
5238
|
+
const hintedBlockAnalysis = analyzeComposableBlocks(
|
|
5239
|
+
filterHintedRoot.root,
|
|
5240
|
+
reactiveByValue,
|
|
5241
|
+
safeGlobals,
|
|
5242
|
+
listNames,
|
|
5243
|
+
allowedComponentNames
|
|
5244
|
+
);
|
|
5245
|
+
const hintedAnalysis = analyzeHostTree(
|
|
5246
|
+
filterHintedRoot.root,
|
|
5247
|
+
reactiveByValue,
|
|
5248
|
+
safeGlobals,
|
|
5249
|
+
hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
5250
|
+
hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
5251
|
+
hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
5252
|
+
hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
5253
|
+
);
|
|
5254
|
+
if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
|
|
5255
|
+
expandedReactiveRoot = filterHintedRoot.root;
|
|
5256
|
+
blockAnalysis = hintedBlockAnalysis;
|
|
5257
|
+
analysis = hintedAnalysis;
|
|
5258
|
+
appliedKeyedArrayFilterHints = filterHintedRoot.count;
|
|
5259
|
+
appliedFilterHintedStateIndices = filterHintedRoot.stateIndices;
|
|
5260
|
+
optimizationCounts.keyedArrayFilterHints += filterHintedRoot.count;
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5263
|
+
const keyedCollectionTargetKinds = /* @__PURE__ */ new Map();
|
|
5264
|
+
const conflictingKeyedCollectionTargets = /* @__PURE__ */ new Set();
|
|
5265
|
+
for (const plan of blockAnalysis.plans || []) {
|
|
5266
|
+
if (plan.kind !== "keyed-rows") continue;
|
|
5267
|
+
for (const binding of plan.bindings) {
|
|
5268
|
+
const target = binding.membershipTarget || binding.mapLookupTarget;
|
|
5269
|
+
if (!target) continue;
|
|
5270
|
+
const kind = binding.membershipTarget ? "set" : "map";
|
|
5271
|
+
const previousKind = keyedCollectionTargetKinds.get(target.dependency);
|
|
5272
|
+
if (previousKind && previousKind !== kind) {
|
|
5273
|
+
conflictingKeyedCollectionTargets.add(target.dependency);
|
|
5274
|
+
} else {
|
|
5275
|
+
keyedCollectionTargetKinds.set(target.dependency, kind);
|
|
5276
|
+
}
|
|
5277
|
+
}
|
|
5278
|
+
}
|
|
5279
|
+
for (const dependency of conflictingKeyedCollectionTargets) {
|
|
5280
|
+
keyedCollectionTargetKinds.delete(dependency);
|
|
5281
|
+
}
|
|
5282
|
+
const keyedCollectionHintedRoot = rewriteKeyedCollectionUpdateHints(
|
|
5283
|
+
expandedReactiveRoot,
|
|
5284
|
+
keyedCollectionTargetKinds,
|
|
5285
|
+
states,
|
|
5286
|
+
statesBySetter,
|
|
5287
|
+
keyedCollectionUpdateIdentifier,
|
|
5288
|
+
keyedCollectionMutationIdentifier,
|
|
5289
|
+
globalCollections
|
|
5290
|
+
);
|
|
5291
|
+
if (keyedCollectionHintedRoot.count > 0) {
|
|
5292
|
+
const hintedBlockAnalysis = analyzeComposableBlocks(
|
|
5293
|
+
keyedCollectionHintedRoot.root,
|
|
5294
|
+
reactiveByValue,
|
|
5295
|
+
safeGlobals,
|
|
5296
|
+
listNames,
|
|
5297
|
+
allowedComponentNames
|
|
5298
|
+
);
|
|
5299
|
+
const hintedAnalysis = analyzeHostTree(
|
|
5300
|
+
keyedCollectionHintedRoot.root,
|
|
5301
|
+
reactiveByValue,
|
|
5302
|
+
safeGlobals,
|
|
5303
|
+
hintedBlockAnalysis.conditionalExpressions || /* @__PURE__ */ new Set(),
|
|
5304
|
+
hintedBlockAnalysis.keyedExpressions || /* @__PURE__ */ new Set(),
|
|
5305
|
+
hintedBlockAnalysis.ownedElements || /* @__PURE__ */ new Set(),
|
|
5306
|
+
hintedBlockAnalysis.componentElements || /* @__PURE__ */ new Set()
|
|
5307
|
+
);
|
|
5308
|
+
if (!hintedBlockAnalysis.reason && !hintedAnalysis.reason) {
|
|
5309
|
+
expandedReactiveRoot = keyedCollectionHintedRoot.root;
|
|
5310
|
+
blockAnalysis = hintedBlockAnalysis;
|
|
5311
|
+
analysis = hintedAnalysis;
|
|
5312
|
+
optimizationCounts.keyedCollectionUpdateHints += keyedCollectionHintedRoot.count;
|
|
5313
|
+
}
|
|
5314
|
+
}
|
|
3637
5315
|
const blockPlans = blockAnalysis.plans || [];
|
|
3638
|
-
|
|
5316
|
+
optimizationCounts.keyedIdentityTargets += blockPlans.reduce(
|
|
5317
|
+
(count, plan) => count + (plan.kind === "keyed-rows" ? plan.bindings.filter((binding) => binding.identityTarget !== void 0).length : 0),
|
|
5318
|
+
0
|
|
5319
|
+
);
|
|
5320
|
+
optimizationCounts.keyedMembershipTargets += blockPlans.reduce(
|
|
5321
|
+
(count, plan) => count + (plan.kind === "keyed-rows" ? plan.bindings.filter((binding) => binding.membershipTarget !== void 0).length : 0),
|
|
5322
|
+
0
|
|
5323
|
+
);
|
|
5324
|
+
optimizationCounts.keyedMapLookupTargets += blockPlans.reduce(
|
|
5325
|
+
(count, plan) => count + (plan.kind === "keyed-rows" ? plan.bindings.filter((binding) => binding.mapLookupTarget !== void 0).length : 0),
|
|
5326
|
+
0
|
|
5327
|
+
);
|
|
5328
|
+
const hasKeyedUpdateHints = appliedKeyedMapUpdateHints > 0 || appliedKeyedArrayAppendHints > 0 || appliedKeyedArrayFilterHints > 0 || appliedKeyedArrayPrependHints > 0 || appliedKeyedArrayPositionHints > 0 || appliedKeyedArrayReorderHints > 0 || appliedKeyedArrayRollingWindowHints > 0 || appliedKeyedArraySliceHints > 0;
|
|
5329
|
+
const hasKeyedArrayRemovalHints = appliedKeyedArrayFilterHints > 0 || appliedKeyedArrayRollingWindowHints > 0 || appliedKeyedArraySliceHints > 0;
|
|
5330
|
+
const runtimeFeatures = runtimeFeaturesForPlans(
|
|
5331
|
+
blockPlans,
|
|
5332
|
+
hasKeyedUpdateHints,
|
|
5333
|
+
hasKeyedArrayRemovalHints,
|
|
5334
|
+
appliedKeyedArrayPrependHints > 0,
|
|
5335
|
+
appliedKeyedArrayPositionHints > 0,
|
|
5336
|
+
appliedKeyedArrayReorderHints > 0,
|
|
5337
|
+
appliedKeyedArrayRollingWindowHints > 0
|
|
5338
|
+
);
|
|
3639
5339
|
markShortCircuitBindings(analysis.bindings || []);
|
|
3640
5340
|
assignStableBindingTargets(analysis.bindings || []);
|
|
3641
5341
|
const stateParameter = path.scope.generateUidIdentifier("farmState");
|
|
@@ -3648,11 +5348,21 @@ function compileCandidate(candidate, createComponentIdentifier, runtimeFeatureId
|
|
|
3648
5348
|
blockParameter,
|
|
3649
5349
|
blockAnalysis.ownedElements || /* @__PURE__ */ new Set()
|
|
3650
5350
|
);
|
|
5351
|
+
const appliedRemovalHintedStateIndices = /* @__PURE__ */ new Set([
|
|
5352
|
+
...appliedFilterHintedStateIndices,
|
|
5353
|
+
...appliedRollingWindowHintedStateIndices,
|
|
5354
|
+
...appliedSliceHintedStateIndices
|
|
5355
|
+
]);
|
|
3651
5356
|
const rootWithBlocks = lowerComposableBlocks(
|
|
3652
5357
|
rootWithTargets,
|
|
3653
5358
|
blockPlans,
|
|
3654
5359
|
blockParameter,
|
|
3655
|
-
listNames
|
|
5360
|
+
listNames,
|
|
5361
|
+
hasKeyedUpdateHints,
|
|
5362
|
+
appliedRemovalHintedStateIndices,
|
|
5363
|
+
appliedPrependHintedStateIndices,
|
|
5364
|
+
appliedPositionHintedStateIndices,
|
|
5365
|
+
appliedReorderHintedStateIndices
|
|
3656
5366
|
);
|
|
3657
5367
|
const rewrittenRoot = rewriteStateAccess(
|
|
3658
5368
|
rootWithBlocks,
|
|
@@ -3790,6 +5500,20 @@ function collectCandidates(programPath) {
|
|
|
3790
5500
|
async function compileReactModule(code, id, options) {
|
|
3791
5501
|
const compiled = [];
|
|
3792
5502
|
const diagnostics = [];
|
|
5503
|
+
const optimizationCounts = {
|
|
5504
|
+
keyedArrayAppendHints: 0,
|
|
5505
|
+
keyedArrayFilterHints: 0,
|
|
5506
|
+
keyedArrayPrependHints: 0,
|
|
5507
|
+
keyedArrayPositionHints: 0,
|
|
5508
|
+
keyedArrayReorderHints: 0,
|
|
5509
|
+
keyedArrayRollingWindowHints: 0,
|
|
5510
|
+
keyedArraySliceHints: 0,
|
|
5511
|
+
keyedCollectionUpdateHints: 0,
|
|
5512
|
+
keyedIdentityTargets: 0,
|
|
5513
|
+
keyedMapLookupTargets: 0,
|
|
5514
|
+
keyedMembershipTargets: 0,
|
|
5515
|
+
keyedMapUpdateHints: 0
|
|
5516
|
+
};
|
|
3793
5517
|
const plugin = () => ({
|
|
3794
5518
|
name: "farm-react-aot",
|
|
3795
5519
|
visitor: {
|
|
@@ -3819,6 +5543,36 @@ async function compileReactModule(code, id, options) {
|
|
|
3819
5543
|
}
|
|
3820
5544
|
const candidates = collectCandidates(programPath);
|
|
3821
5545
|
const createComponentIdentifier = programPath.scope.generateUidIdentifier("createCompiledComponent");
|
|
5546
|
+
const keyedMapUpdateIdentifier = programPath.scope.generateUidIdentifier(
|
|
5547
|
+
"createCompilerKeyedMapUpdate"
|
|
5548
|
+
);
|
|
5549
|
+
const keyedArrayAppendIdentifier = programPath.scope.generateUidIdentifier(
|
|
5550
|
+
"createCompilerKeyedArrayAppend"
|
|
5551
|
+
);
|
|
5552
|
+
const keyedArrayFilterIdentifier = programPath.scope.generateUidIdentifier(
|
|
5553
|
+
"createCompilerKeyedArrayFilter"
|
|
5554
|
+
);
|
|
5555
|
+
const keyedArrayPrependIdentifier = programPath.scope.generateUidIdentifier(
|
|
5556
|
+
"createCompilerKeyedArrayPrepend"
|
|
5557
|
+
);
|
|
5558
|
+
const keyedArrayPositionIdentifier = programPath.scope.generateUidIdentifier(
|
|
5559
|
+
"createCompilerKeyedArrayPositionUpdate"
|
|
5560
|
+
);
|
|
5561
|
+
const keyedArrayReorderIdentifier = programPath.scope.generateUidIdentifier(
|
|
5562
|
+
"createCompilerKeyedArrayReorder"
|
|
5563
|
+
);
|
|
5564
|
+
const keyedArrayRollingWindowIdentifier = programPath.scope.generateUidIdentifier(
|
|
5565
|
+
"createCompilerKeyedArrayRollingWindow"
|
|
5566
|
+
);
|
|
5567
|
+
const keyedArraySliceIdentifier = programPath.scope.generateUidIdentifier(
|
|
5568
|
+
"createCompilerKeyedArraySlice"
|
|
5569
|
+
);
|
|
5570
|
+
const keyedCollectionUpdateIdentifier = programPath.scope.generateUidIdentifier(
|
|
5571
|
+
"createCompilerKeyedCollectionUpdate"
|
|
5572
|
+
);
|
|
5573
|
+
const keyedCollectionMutationIdentifier = programPath.scope.generateUidIdentifier(
|
|
5574
|
+
"applyCompilerKeyedCollectionMutation"
|
|
5575
|
+
);
|
|
3822
5576
|
const runtimeFeatureIdentifiers = new Map(
|
|
3823
5577
|
Object.entries(COMPILER_RUNTIME_FEATURE_EXPORTS).map(([feature, exportName]) => [
|
|
3824
5578
|
feature,
|
|
@@ -3836,8 +5590,19 @@ async function compileReactModule(code, id, options) {
|
|
|
3836
5590
|
const reason = compileCandidate(
|
|
3837
5591
|
candidate,
|
|
3838
5592
|
createComponentIdentifier,
|
|
5593
|
+
keyedMapUpdateIdentifier,
|
|
5594
|
+
keyedArrayAppendIdentifier,
|
|
5595
|
+
keyedArrayFilterIdentifier,
|
|
5596
|
+
keyedArrayPrependIdentifier,
|
|
5597
|
+
keyedArrayPositionIdentifier,
|
|
5598
|
+
keyedArrayReorderIdentifier,
|
|
5599
|
+
keyedArrayRollingWindowIdentifier,
|
|
5600
|
+
keyedArraySliceIdentifier,
|
|
5601
|
+
keyedCollectionUpdateIdentifier,
|
|
5602
|
+
keyedCollectionMutationIdentifier,
|
|
3839
5603
|
runtimeFeatureIdentifiers,
|
|
3840
5604
|
usedRuntimeFeatures,
|
|
5605
|
+
optimizationCounts,
|
|
3841
5606
|
useStateNames,
|
|
3842
5607
|
reactNames,
|
|
3843
5608
|
listNames,
|
|
@@ -3863,6 +5628,64 @@ async function compileReactModule(code, id, options) {
|
|
|
3863
5628
|
createComponentIdentifier,
|
|
3864
5629
|
types.identifier("createCompiledComponentWithFeatures")
|
|
3865
5630
|
),
|
|
5631
|
+
...optimizationCounts.keyedMapUpdateHints > 0 ? [
|
|
5632
|
+
types.importSpecifier(
|
|
5633
|
+
keyedMapUpdateIdentifier,
|
|
5634
|
+
types.identifier("createCompilerKeyedMapUpdate")
|
|
5635
|
+
)
|
|
5636
|
+
] : [],
|
|
5637
|
+
...optimizationCounts.keyedArrayAppendHints > 0 ? [
|
|
5638
|
+
types.importSpecifier(
|
|
5639
|
+
keyedArrayAppendIdentifier,
|
|
5640
|
+
types.identifier("createCompilerKeyedArrayAppend")
|
|
5641
|
+
)
|
|
5642
|
+
] : [],
|
|
5643
|
+
...optimizationCounts.keyedArrayFilterHints > 0 ? [
|
|
5644
|
+
types.importSpecifier(
|
|
5645
|
+
keyedArrayFilterIdentifier,
|
|
5646
|
+
types.identifier("createCompilerKeyedArrayFilter")
|
|
5647
|
+
)
|
|
5648
|
+
] : [],
|
|
5649
|
+
...optimizationCounts.keyedArrayPrependHints > 0 ? [
|
|
5650
|
+
types.importSpecifier(
|
|
5651
|
+
keyedArrayPrependIdentifier,
|
|
5652
|
+
types.identifier("createCompilerKeyedArrayPrepend")
|
|
5653
|
+
)
|
|
5654
|
+
] : [],
|
|
5655
|
+
...optimizationCounts.keyedArrayPositionHints > 0 ? [
|
|
5656
|
+
types.importSpecifier(
|
|
5657
|
+
keyedArrayPositionIdentifier,
|
|
5658
|
+
types.identifier("createCompilerKeyedArrayPositionUpdate")
|
|
5659
|
+
)
|
|
5660
|
+
] : [],
|
|
5661
|
+
...optimizationCounts.keyedArrayReorderHints > 0 ? [
|
|
5662
|
+
types.importSpecifier(
|
|
5663
|
+
keyedArrayReorderIdentifier,
|
|
5664
|
+
types.identifier("createCompilerKeyedArrayReorder")
|
|
5665
|
+
)
|
|
5666
|
+
] : [],
|
|
5667
|
+
...optimizationCounts.keyedArrayRollingWindowHints > 0 ? [
|
|
5668
|
+
types.importSpecifier(
|
|
5669
|
+
keyedArrayRollingWindowIdentifier,
|
|
5670
|
+
types.identifier("createCompilerKeyedArrayRollingWindow")
|
|
5671
|
+
)
|
|
5672
|
+
] : [],
|
|
5673
|
+
...optimizationCounts.keyedArraySliceHints > 0 || optimizationCounts.keyedArrayRollingWindowHints > 0 ? [
|
|
5674
|
+
types.importSpecifier(
|
|
5675
|
+
keyedArraySliceIdentifier,
|
|
5676
|
+
types.identifier("createCompilerKeyedArraySlice")
|
|
5677
|
+
)
|
|
5678
|
+
] : [],
|
|
5679
|
+
...optimizationCounts.keyedCollectionUpdateHints > 0 ? [
|
|
5680
|
+
types.importSpecifier(
|
|
5681
|
+
keyedCollectionUpdateIdentifier,
|
|
5682
|
+
types.identifier("createCompilerKeyedCollectionUpdate")
|
|
5683
|
+
),
|
|
5684
|
+
types.importSpecifier(
|
|
5685
|
+
keyedCollectionMutationIdentifier,
|
|
5686
|
+
types.identifier("applyCompilerKeyedCollectionMutation")
|
|
5687
|
+
)
|
|
5688
|
+
] : [],
|
|
3866
5689
|
...[...usedRuntimeFeatures].sort().map(
|
|
3867
5690
|
(feature) => types.importSpecifier(
|
|
3868
5691
|
types.cloneNode(runtimeFeatureIdentifiers.get(feature)),
|
|
@@ -3899,7 +5722,8 @@ async function compileReactModule(code, id, options) {
|
|
|
3899
5722
|
code: result?.code || code,
|
|
3900
5723
|
map: result?.map || null,
|
|
3901
5724
|
compiled,
|
|
3902
|
-
diagnostics
|
|
5725
|
+
diagnostics,
|
|
5726
|
+
optimizations: optimizationCounts
|
|
3903
5727
|
};
|
|
3904
5728
|
}
|
|
3905
5729
|
function projectRelativeId(projectRoot, id) {
|
|
@@ -3910,10 +5734,34 @@ function createReactCompilerReport(projectRoot, observations) {
|
|
|
3910
5734
|
let componentsConsidered = 0;
|
|
3911
5735
|
let compiled = 0;
|
|
3912
5736
|
let fallback = 0;
|
|
5737
|
+
let keyedArrayAppendHints = 0;
|
|
5738
|
+
let keyedArrayFilterHints = 0;
|
|
5739
|
+
let keyedArrayPrependHints = 0;
|
|
5740
|
+
let keyedArrayPositionHints = 0;
|
|
5741
|
+
let keyedArrayReorderHints = 0;
|
|
5742
|
+
let keyedArrayRollingWindowHints = 0;
|
|
5743
|
+
let keyedArraySliceHints = 0;
|
|
5744
|
+
let keyedCollectionUpdateHints = 0;
|
|
5745
|
+
let keyedIdentityTargets = 0;
|
|
5746
|
+
let keyedMapLookupTargets = 0;
|
|
5747
|
+
let keyedMembershipTargets = 0;
|
|
5748
|
+
let keyedMapUpdateHints = 0;
|
|
3913
5749
|
const modules = [...observations].map(({ id, result }) => {
|
|
3914
5750
|
componentsConsidered += result.compiled.length + result.diagnostics.length;
|
|
3915
5751
|
compiled += result.compiled.length;
|
|
3916
5752
|
fallback += result.diagnostics.length;
|
|
5753
|
+
keyedArrayAppendHints += result.optimizations.keyedArrayAppendHints || 0;
|
|
5754
|
+
keyedArrayFilterHints += result.optimizations.keyedArrayFilterHints || 0;
|
|
5755
|
+
keyedArrayPrependHints += result.optimizations.keyedArrayPrependHints || 0;
|
|
5756
|
+
keyedArrayPositionHints += result.optimizations.keyedArrayPositionHints || 0;
|
|
5757
|
+
keyedArrayReorderHints += result.optimizations.keyedArrayReorderHints || 0;
|
|
5758
|
+
keyedArrayRollingWindowHints += result.optimizations.keyedArrayRollingWindowHints || 0;
|
|
5759
|
+
keyedArraySliceHints += result.optimizations.keyedArraySliceHints || 0;
|
|
5760
|
+
keyedCollectionUpdateHints += result.optimizations.keyedCollectionUpdateHints || 0;
|
|
5761
|
+
keyedIdentityTargets += result.optimizations.keyedIdentityTargets || 0;
|
|
5762
|
+
keyedMapLookupTargets += result.optimizations.keyedMapLookupTargets || 0;
|
|
5763
|
+
keyedMembershipTargets += result.optimizations.keyedMembershipTargets || 0;
|
|
5764
|
+
keyedMapUpdateHints += result.optimizations.keyedMapUpdateHints;
|
|
3917
5765
|
const moduleId = projectRelativeId(projectRoot, id);
|
|
3918
5766
|
const fallbacks = result.diagnostics.map((diagnostic) => {
|
|
3919
5767
|
reasonCounts.set(diagnostic.reason, (reasonCounts.get(diagnostic.reason) || 0) + 1);
|
|
@@ -3922,6 +5770,7 @@ function createReactCompilerReport(projectRoot, observations) {
|
|
|
3922
5770
|
return {
|
|
3923
5771
|
id: moduleId,
|
|
3924
5772
|
compiled: [...result.compiled].sort(),
|
|
5773
|
+
optimizations: result.optimizations,
|
|
3925
5774
|
fallbacks
|
|
3926
5775
|
};
|
|
3927
5776
|
}).sort((left, right) => left.id.localeCompare(right.id));
|
|
@@ -3932,7 +5781,19 @@ function createReactCompilerReport(projectRoot, observations) {
|
|
|
3932
5781
|
modules: modules.length,
|
|
3933
5782
|
componentsConsidered,
|
|
3934
5783
|
compiled,
|
|
3935
|
-
fallback
|
|
5784
|
+
fallback,
|
|
5785
|
+
keyedArrayAppendHints,
|
|
5786
|
+
keyedArrayFilterHints,
|
|
5787
|
+
keyedArrayPrependHints,
|
|
5788
|
+
keyedArrayPositionHints,
|
|
5789
|
+
keyedArrayReorderHints,
|
|
5790
|
+
keyedArrayRollingWindowHints,
|
|
5791
|
+
keyedArraySliceHints,
|
|
5792
|
+
keyedCollectionUpdateHints,
|
|
5793
|
+
keyedIdentityTargets,
|
|
5794
|
+
keyedMapLookupTargets,
|
|
5795
|
+
keyedMembershipTargets,
|
|
5796
|
+
keyedMapUpdateHints
|
|
3936
5797
|
},
|
|
3937
5798
|
fallbackReasons,
|
|
3938
5799
|
modules
|