@farm.js/react 0.1.0-beta.4 → 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 +213 -1
- package/dist/compiler-runtime.cjs +1892 -65
- package/dist/compiler-runtime.cjs.map +1 -1
- package/dist/compiler-runtime.d.mts +112 -4
- package/dist/compiler-runtime.d.ts +112 -4
- package/dist/compiler-runtime.mjs +1839 -66
- package/dist/compiler-runtime.mjs.map +1 -1
- package/dist/vite.cjs +1959 -44
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.mjs +1959 -44
- package/dist/vite.mjs.map +1 -1
- package/package.json +6 -4
package/dist/vite.mjs
CHANGED
|
@@ -60,6 +60,73 @@ function canDelegateKeyedRowEvents(plan) {
|
|
|
60
60
|
(event) => DELEGATABLE_KEYED_ROW_EVENTS.has(event.name.replace(/Capture$/, ""))
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
|
+
var COMPILER_RUNTIME_FEATURE_EXPORTS = {
|
|
64
|
+
conditional: "conditionalRuntimeFeature",
|
|
65
|
+
"host-conditional": "hostConditionalRuntimeFeature",
|
|
66
|
+
"conditional-ranges": "conditionalRangesRuntimeFeature",
|
|
67
|
+
"keyed-list": "keyedListRuntimeFeature",
|
|
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",
|
|
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",
|
|
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",
|
|
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",
|
|
104
|
+
"keyed-ranges": "keyedRangesRuntimeFeature",
|
|
105
|
+
"mixed-ranges": "mixedRangesRuntimeFeature",
|
|
106
|
+
component: "componentRuntimeFeature"
|
|
107
|
+
};
|
|
108
|
+
function runtimeFeaturesForPlans(plans, keyedMapUpdateHints, keyedArrayFilterHints, keyedArrayPrependHints, keyedArrayPositionHints, keyedArrayReorderHints, keyedArrayRollingWindowHints) {
|
|
109
|
+
const features = /* @__PURE__ */ new Set();
|
|
110
|
+
let keyedRowsHaveConditionals = false;
|
|
111
|
+
let keyedRowsHaveHostBlocks = false;
|
|
112
|
+
for (const plan of plans) {
|
|
113
|
+
if (plan.kind === "keyed-rows") {
|
|
114
|
+
keyedRowsHaveConditionals || (keyedRowsHaveConditionals = plan.conditionals.length > 0);
|
|
115
|
+
keyedRowsHaveHostBlocks || (keyedRowsHaveHostBlocks = Boolean(plan.descriptorBlocks?.size));
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (plan.kind in COMPILER_RUNTIME_FEATURE_EXPORTS) {
|
|
119
|
+
features.add(plan.kind);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (plans.some((plan) => plan.kind === "keyed-rows")) {
|
|
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}`);
|
|
127
|
+
}
|
|
128
|
+
return [...features].sort();
|
|
129
|
+
}
|
|
63
130
|
var SAFE_GLOBAL_CALLS = /* @__PURE__ */ new Set(["Boolean", "Number", "String"]);
|
|
64
131
|
var SAFE_MATH_CALLS = /* @__PURE__ */ new Set(["abs", "ceil", "floor", "max", "min", "round", "sign", "trunc"]);
|
|
65
132
|
function isComponentName(name) {
|
|
@@ -105,6 +172,174 @@ function referencesIdentifier(expression, name) {
|
|
|
105
172
|
});
|
|
106
173
|
return referenced;
|
|
107
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
|
+
}
|
|
108
343
|
function collectReferencedLocals(expression, names) {
|
|
109
344
|
const references = /* @__PURE__ */ new Set();
|
|
110
345
|
traverse(expressionFile(cloneExpression(expression)), {
|
|
@@ -205,7 +440,9 @@ function rewriteHandlerAccess(root, handlersByName) {
|
|
|
205
440
|
path.skip();
|
|
206
441
|
}
|
|
207
442
|
});
|
|
208
|
-
return reason ? { reason } : {
|
|
443
|
+
return reason ? { reason } : {
|
|
444
|
+
root: file.program.body[0].expression
|
|
445
|
+
};
|
|
209
446
|
}
|
|
210
447
|
function isSafeCompilerCall(expression, safeGlobals) {
|
|
211
448
|
if (types.isIdentifier(expression.callee)) {
|
|
@@ -213,7 +450,7 @@ function isSafeCompilerCall(expression, safeGlobals) {
|
|
|
213
450
|
}
|
|
214
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);
|
|
215
452
|
}
|
|
216
|
-
function validateDerivedExpression(expression, safeGlobals) {
|
|
453
|
+
function validateDerivedExpression(expression, safeGlobals, additionalSafeCall) {
|
|
217
454
|
let unsupported;
|
|
218
455
|
const reject = (reason, path) => {
|
|
219
456
|
unsupported = reason;
|
|
@@ -224,7 +461,9 @@ function validateDerivedExpression(expression, safeGlobals) {
|
|
|
224
461
|
AssignmentExpression: (path) => reject("assignments", path),
|
|
225
462
|
AwaitExpression: (path) => reject("await expressions", path),
|
|
226
463
|
CallExpression(path) {
|
|
227
|
-
if (!isSafeCompilerCall(path.node, safeGlobals)
|
|
464
|
+
if (!isSafeCompilerCall(path.node, safeGlobals) && !additionalSafeCall?.(path.node)) {
|
|
465
|
+
reject("function calls", path);
|
|
466
|
+
}
|
|
228
467
|
},
|
|
229
468
|
ClassExpression: (path) => reject("class expressions", path),
|
|
230
469
|
Function: (path) => reject("function expressions", path),
|
|
@@ -264,6 +503,879 @@ function validateSetterUsage(root, statesBySetter) {
|
|
|
264
503
|
});
|
|
265
504
|
return reason;
|
|
266
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
|
+
}
|
|
267
1379
|
function rewriteStateAccess(expression, stateParameter, statesByValue, statesBySetter) {
|
|
268
1380
|
const file = expressionFile(cloneExpression(expression));
|
|
269
1381
|
traverse(file, {
|
|
@@ -514,21 +1626,28 @@ function analyzeMapList(expression, statesByValue, safeGlobals) {
|
|
|
514
1626
|
const collection = callee.object;
|
|
515
1627
|
const collectionUnsupported = validateCollectionPipeline(collection, safeGlobals);
|
|
516
1628
|
if (collectionUnsupported) {
|
|
517
|
-
return {
|
|
1629
|
+
return {
|
|
1630
|
+
reason: `keyed list collection cannot use ${collectionUnsupported}`
|
|
1631
|
+
};
|
|
518
1632
|
}
|
|
519
1633
|
if (expression.arguments.length !== 1 || !types.isArrowFunctionExpression(expression.arguments[0]) && !types.isFunctionExpression(expression.arguments[0])) {
|
|
520
1634
|
return { reason: "keyed list map must use one inline render callback" };
|
|
521
1635
|
}
|
|
522
1636
|
const callback = expression.arguments[0];
|
|
523
1637
|
if (containsDirectHookCall(callback)) {
|
|
524
|
-
return {
|
|
1638
|
+
return {
|
|
1639
|
+
reason: "Hooks cannot be called directly inside a keyed list callback"
|
|
1640
|
+
};
|
|
525
1641
|
}
|
|
526
1642
|
const row = returnedExpression(callback);
|
|
527
1643
|
if (!row || !types.isJSXElement(row)) {
|
|
528
1644
|
return { reason: "keyed list map callbacks must return one React element" };
|
|
529
1645
|
}
|
|
530
1646
|
const key = jsxKeyExpression(row);
|
|
531
|
-
if (!key)
|
|
1647
|
+
if (!key)
|
|
1648
|
+
return {
|
|
1649
|
+
reason: "automatically compiled lists require an explicit item key"
|
|
1650
|
+
};
|
|
532
1651
|
const keyReason = validateKeyFunction(callback, key, safeGlobals);
|
|
533
1652
|
if (keyReason) return { reason: keyReason };
|
|
534
1653
|
return { dependencies: collectStateDependencies(expression, statesByValue) };
|
|
@@ -543,7 +1662,9 @@ function listAttributeExpression(element, name) {
|
|
|
543
1662
|
}
|
|
544
1663
|
function analyzePublicList(element, statesByValue, safeGlobals) {
|
|
545
1664
|
if (element.openingElement.attributes.some((attribute) => types.isJSXSpreadAttribute(attribute))) {
|
|
546
|
-
return {
|
|
1665
|
+
return {
|
|
1666
|
+
reason: "compiled List boundaries do not support JSX attribute spreads"
|
|
1667
|
+
};
|
|
547
1668
|
}
|
|
548
1669
|
const each = listAttributeExpression(element, "each");
|
|
549
1670
|
const by = listAttributeExpression(element, "by");
|
|
@@ -561,7 +1682,9 @@ function analyzePublicList(element, statesByValue, safeGlobals) {
|
|
|
561
1682
|
if (keyReason) return { reason: keyReason };
|
|
562
1683
|
const children = meaningfulJsxChildren(element);
|
|
563
1684
|
if (children.length !== 1 || !types.isJSXExpressionContainer(children[0]) || types.isJSXEmptyExpression(children[0].expression) || !types.isArrowFunctionExpression(children[0].expression) && !types.isFunctionExpression(children[0].expression)) {
|
|
564
|
-
return {
|
|
1685
|
+
return {
|
|
1686
|
+
reason: "compiled List children must use one inline render function"
|
|
1687
|
+
};
|
|
565
1688
|
}
|
|
566
1689
|
const render = children[0].expression;
|
|
567
1690
|
if (!returnedExpression(render)) {
|
|
@@ -675,13 +1798,20 @@ function stabilizeDeferredEventCurrentTargets(root, compilerSetters) {
|
|
|
675
1798
|
const expression = file.program.body[0].expression;
|
|
676
1799
|
return types.isJSXElement(expression) ? expression : types.cloneNode(root, true);
|
|
677
1800
|
}
|
|
678
|
-
function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters) {
|
|
1801
|
+
function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters, keyedTargetReactiveByValue) {
|
|
679
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])) {
|
|
680
|
-
return {
|
|
1803
|
+
return {
|
|
1804
|
+
reason: "compiled keyed rows require item and optional index identifiers"
|
|
1805
|
+
};
|
|
681
1806
|
}
|
|
682
1807
|
const bindings = [];
|
|
683
1808
|
const events = [];
|
|
684
1809
|
const conditionals = [];
|
|
1810
|
+
const validateBindingExpression = (expression) => validateDerivedExpression(
|
|
1811
|
+
expression,
|
|
1812
|
+
safeGlobals,
|
|
1813
|
+
keyedTargetReactiveByValue ? (call) => isPotentialKeyedMembershipCall(call, keyedTargetReactiveByValue) || isPotentialKeyedMapLookupCall(call, keyedTargetReactiveByValue) : void 0
|
|
1814
|
+
);
|
|
685
1815
|
const visit = (element, path) => {
|
|
686
1816
|
const tag = element.openingElement.name;
|
|
687
1817
|
if (!types.isJSXIdentifier(tag) || !/^[a-z]/.test(tag.name)) {
|
|
@@ -760,7 +1890,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
760
1890
|
if (!propertyName || propertyName.includes("-") && !propertyName.startsWith("--")) {
|
|
761
1891
|
return "compiled keyed row style names must use camelCase or a CSS custom property";
|
|
762
1892
|
}
|
|
763
|
-
const unsupported2 =
|
|
1893
|
+
const unsupported2 = validateBindingExpression(property.value);
|
|
764
1894
|
if (unsupported2) {
|
|
765
1895
|
return `compiled keyed row style ${propertyName} cannot use ${unsupported2}`;
|
|
766
1896
|
}
|
|
@@ -774,7 +1904,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
774
1904
|
continue;
|
|
775
1905
|
}
|
|
776
1906
|
if (name === "children") return "compiled keyed row children props are not supported yet";
|
|
777
|
-
const unsupported =
|
|
1907
|
+
const unsupported = validateBindingExpression(expression);
|
|
778
1908
|
if (unsupported) return `compiled keyed row ${name} cannot use ${unsupported}`;
|
|
779
1909
|
bindings.push({
|
|
780
1910
|
kind: "attribute",
|
|
@@ -824,7 +1954,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
824
1954
|
(child) => types.isJSXExpressionContainer(child) && !types.isJSXEmptyExpression(child.expression)
|
|
825
1955
|
);
|
|
826
1956
|
for (const child of expressions) {
|
|
827
|
-
const unsupported =
|
|
1957
|
+
const unsupported = validateBindingExpression(child.expression);
|
|
828
1958
|
if (unsupported) return `compiled keyed row text cannot use ${unsupported}`;
|
|
829
1959
|
}
|
|
830
1960
|
if (nestedElements.length > 0 && expressions.length > 0) {
|
|
@@ -840,7 +1970,11 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
840
1970
|
parts.push(cloneExpression(child.expression));
|
|
841
1971
|
}
|
|
842
1972
|
}
|
|
843
|
-
bindings.push({
|
|
1973
|
+
bindings.push({
|
|
1974
|
+
kind: "text",
|
|
1975
|
+
path: [...path],
|
|
1976
|
+
value: types.arrayExpression(parts)
|
|
1977
|
+
});
|
|
844
1978
|
}
|
|
845
1979
|
let elementIndex = 0;
|
|
846
1980
|
for (const child of element.children) {
|
|
@@ -854,7 +1988,7 @@ function analyzeKeyedRowTree(row, renderCallback, safeGlobals, compilerSetters)
|
|
|
854
1988
|
const reason = visit(row, []);
|
|
855
1989
|
return reason ? { reason } : { bindings, events, conditionals };
|
|
856
1990
|
}
|
|
857
|
-
function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acceptUnsupportedRow = false) {
|
|
1991
|
+
function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acceptUnsupportedRow = false, allowMembershipTargets = false) {
|
|
858
1992
|
let collection;
|
|
859
1993
|
let keyCallback;
|
|
860
1994
|
let renderCallback;
|
|
@@ -907,7 +2041,8 @@ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acce
|
|
|
907
2041
|
row,
|
|
908
2042
|
renderCallback,
|
|
909
2043
|
safeGlobals,
|
|
910
|
-
new Set([...statesByValue.values()].map((state) => state.setterName))
|
|
2044
|
+
new Set([...statesByValue.values()].map((state) => state.setterName)),
|
|
2045
|
+
allowMembershipTargets ? statesByValue : void 0
|
|
911
2046
|
);
|
|
912
2047
|
if (rowAnalysis.reason && !acceptUnsupportedRow) return void 0;
|
|
913
2048
|
const keyExpression = returnedExpression(keyCallback);
|
|
@@ -920,6 +2055,7 @@ function analyzeKeyedRowChild(child, statesByValue, safeGlobals, listNames, acce
|
|
|
920
2055
|
return {
|
|
921
2056
|
source,
|
|
922
2057
|
collection,
|
|
2058
|
+
collectionDependency: types.isIdentifier(collection) ? statesByValue.get(collection.name)?.index : void 0,
|
|
923
2059
|
structureDependencies: [...structureDependencies].sort((left, right) => left - right),
|
|
924
2060
|
keyCallback,
|
|
925
2061
|
renderCallback,
|
|
@@ -948,7 +2084,74 @@ function analyzeKeyedRowsContainer(container, statesByValue, safeGlobals, listNa
|
|
|
948
2084
|
}
|
|
949
2085
|
const children = meaningfulJsxChildren(container);
|
|
950
2086
|
if (children.length !== 1) return void 0;
|
|
951
|
-
|
|
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
|
+
};
|
|
952
2155
|
}
|
|
953
2156
|
function analyzeKeyedRangesContainer(container, statesByValue, safeGlobals, listNames, allowSingleRange = false) {
|
|
954
2157
|
if (container.openingElement.attributes.some(
|
|
@@ -1104,7 +2307,11 @@ function analyzeHostConditionalTree(branch, safeGlobals, allowStaticEvents = fal
|
|
|
1104
2307
|
parts.push(cloneExpression(child.expression));
|
|
1105
2308
|
}
|
|
1106
2309
|
}
|
|
1107
|
-
bindings.push({
|
|
2310
|
+
bindings.push({
|
|
2311
|
+
kind: "text",
|
|
2312
|
+
path: [...path],
|
|
2313
|
+
value: types.arrayExpression(parts)
|
|
2314
|
+
});
|
|
1108
2315
|
}
|
|
1109
2316
|
let elementIndex = 0;
|
|
1110
2317
|
for (const child of element.children) {
|
|
@@ -1276,7 +2483,11 @@ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames,
|
|
|
1276
2483
|
listNames,
|
|
1277
2484
|
id,
|
|
1278
2485
|
allocateId
|
|
1279
|
-
) : {
|
|
2486
|
+
) : {
|
|
2487
|
+
bindings: [],
|
|
2488
|
+
plans: [],
|
|
2489
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2490
|
+
};
|
|
1280
2491
|
const falsy = shape.falsy ? analyzeRecursiveHostTree(
|
|
1281
2492
|
shape.falsy,
|
|
1282
2493
|
statesByValue,
|
|
@@ -1284,7 +2495,11 @@ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames,
|
|
|
1284
2495
|
listNames,
|
|
1285
2496
|
id,
|
|
1286
2497
|
allocateId
|
|
1287
|
-
) : {
|
|
2498
|
+
) : {
|
|
2499
|
+
bindings: [],
|
|
2500
|
+
plans: [],
|
|
2501
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2502
|
+
};
|
|
1288
2503
|
if (truthy.reason) return truthy.reason;
|
|
1289
2504
|
if (falsy.reason) return falsy.reason;
|
|
1290
2505
|
plans.push(...truthy.plans, ...falsy.plans);
|
|
@@ -1442,7 +2657,11 @@ function analyzeRecursiveHostTree(branch, statesByValue, safeGlobals, listNames,
|
|
|
1442
2657
|
parts.push(cloneExpression(child.expression));
|
|
1443
2658
|
}
|
|
1444
2659
|
}
|
|
1445
|
-
bindings.push({
|
|
2660
|
+
bindings.push({
|
|
2661
|
+
kind: "text",
|
|
2662
|
+
path: [...path],
|
|
2663
|
+
value: types.arrayExpression(parts)
|
|
2664
|
+
});
|
|
1446
2665
|
}
|
|
1447
2666
|
let elementIndex = 0;
|
|
1448
2667
|
for (const child of element.children) {
|
|
@@ -1509,7 +2728,11 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals,
|
|
|
1509
2728
|
listNames,
|
|
1510
2729
|
parent,
|
|
1511
2730
|
allocateId
|
|
1512
|
-
) : {
|
|
2731
|
+
) : {
|
|
2732
|
+
bindings: [],
|
|
2733
|
+
plans: [],
|
|
2734
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2735
|
+
};
|
|
1513
2736
|
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1514
2737
|
shape.falsy,
|
|
1515
2738
|
statesByValue,
|
|
@@ -1517,7 +2740,11 @@ function analyzeHostConditionalContainer(container, statesByValue, safeGlobals,
|
|
|
1517
2740
|
listNames,
|
|
1518
2741
|
parent,
|
|
1519
2742
|
allocateId
|
|
1520
|
-
) : {
|
|
2743
|
+
) : {
|
|
2744
|
+
bindings: [],
|
|
2745
|
+
plans: [],
|
|
2746
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2747
|
+
};
|
|
1521
2748
|
if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
|
|
1522
2749
|
const dependencies = new Set(collectStateDependencies(shape.test, statesByValue));
|
|
1523
2750
|
for (const binding of [...truthyAnalysis.bindings || [], ...falsyAnalysis.bindings || []]) {
|
|
@@ -1563,7 +2790,11 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
|
|
|
1563
2790
|
listNames,
|
|
1564
2791
|
parent,
|
|
1565
2792
|
allocateId
|
|
1566
|
-
) : {
|
|
2793
|
+
) : {
|
|
2794
|
+
bindings: [],
|
|
2795
|
+
plans: [],
|
|
2796
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2797
|
+
};
|
|
1567
2798
|
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1568
2799
|
shape.falsy,
|
|
1569
2800
|
statesByValue,
|
|
@@ -1571,7 +2802,11 @@ function analyzeConditionalRangesContainer(container, statesByValue, safeGlobals
|
|
|
1571
2802
|
listNames,
|
|
1572
2803
|
parent,
|
|
1573
2804
|
allocateId
|
|
1574
|
-
) : {
|
|
2805
|
+
) : {
|
|
2806
|
+
bindings: [],
|
|
2807
|
+
plans: [],
|
|
2808
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2809
|
+
};
|
|
1575
2810
|
if (truthyAnalysis.reason || falsyAnalysis.reason) return void 0;
|
|
1576
2811
|
nestedPlans.push(...truthyAnalysis.plans, ...falsyAnalysis.plans);
|
|
1577
2812
|
for (const [element, plan] of truthyAnalysis.blocks) descriptorBlocks.set(element, plan);
|
|
@@ -1664,7 +2899,11 @@ function analyzeMixedRangesContainer(container, statesByValue, safeGlobals, list
|
|
|
1664
2899
|
listNames,
|
|
1665
2900
|
parent,
|
|
1666
2901
|
allocateId
|
|
1667
|
-
) : {
|
|
2902
|
+
) : {
|
|
2903
|
+
bindings: [],
|
|
2904
|
+
plans: [],
|
|
2905
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2906
|
+
};
|
|
1668
2907
|
const falsyAnalysis = shape.falsy ? analyzeRecursiveHostTree(
|
|
1669
2908
|
shape.falsy,
|
|
1670
2909
|
statesByValue,
|
|
@@ -1672,7 +2911,11 @@ function analyzeMixedRangesContainer(container, statesByValue, safeGlobals, list
|
|
|
1672
2911
|
listNames,
|
|
1673
2912
|
parent,
|
|
1674
2913
|
allocateId
|
|
1675
|
-
) : {
|
|
2914
|
+
) : {
|
|
2915
|
+
bindings: [],
|
|
2916
|
+
plans: [],
|
|
2917
|
+
blocks: /* @__PURE__ */ new Map()
|
|
2918
|
+
};
|
|
1676
2919
|
if (!mergeAnalysis(truthyAnalysis) || !mergeAnalysis(falsyAnalysis)) return void 0;
|
|
1677
2920
|
for (const dependency of collectStateDependencies(shape.test, statesByValue)) {
|
|
1678
2921
|
dependencies.add(dependency);
|
|
@@ -1913,6 +3156,57 @@ function keyedRowBindingObject(binding, parameters) {
|
|
|
1913
3156
|
if (binding.name) {
|
|
1914
3157
|
properties.push(types.objectProperty(types.identifier("name"), types.stringLiteral(binding.name)));
|
|
1915
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
|
+
}
|
|
1916
3210
|
properties.push(
|
|
1917
3211
|
types.objectProperty(
|
|
1918
3212
|
types.identifier("read"),
|
|
@@ -2107,7 +3401,7 @@ function keyedRowConditionalObject(conditional, parameters) {
|
|
|
2107
3401
|
}
|
|
2108
3402
|
return types.objectExpression(properties);
|
|
2109
3403
|
}
|
|
2110
|
-
function keyedRowsBoundary(blockRuntime, plan) {
|
|
3404
|
+
function keyedRowsBoundary(blockRuntime, plan, keyedMapUpdateHints, keyedArrayFilterHintedStateIndices, keyedArrayPrependHintedStateIndices, keyedArrayPositionHintedStateIndices, keyedArrayReorderHintedStateIndices) {
|
|
2111
3405
|
const name = types.jsxMemberExpression(
|
|
2112
3406
|
types.jsxIdentifier(blockRuntime.name),
|
|
2113
3407
|
types.jsxIdentifier("KeyedRows")
|
|
@@ -2141,6 +3435,16 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
2141
3435
|
types.jsxIdentifier("items"),
|
|
2142
3436
|
types.jsxExpressionContainer(types.arrowFunctionExpression([], cloneExpression(plan.collection)))
|
|
2143
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
|
+
] : [],
|
|
2144
3448
|
types.jsxAttribute(
|
|
2145
3449
|
types.jsxIdentifier("structureDependencies"),
|
|
2146
3450
|
types.jsxExpressionContainer(
|
|
@@ -2149,6 +3453,36 @@ function keyedRowsBoundary(blockRuntime, plan) {
|
|
|
2149
3453
|
)
|
|
2150
3454
|
)
|
|
2151
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
|
+
] : [],
|
|
2152
3486
|
types.jsxAttribute(
|
|
2153
3487
|
types.jsxIdentifier("rowKey"),
|
|
2154
3488
|
types.jsxExpressionContainer(types.cloneNode(plan.keyCallback, true))
|
|
@@ -2475,7 +3809,9 @@ function conditionalRangesBoundary(blockRuntime, plan) {
|
|
|
2475
3809
|
function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allowedComponentNames) {
|
|
2476
3810
|
const name = element.openingElement.name;
|
|
2477
3811
|
if (!types.isJSXIdentifier(name) || !isComponentName(name.name)) {
|
|
2478
|
-
return {
|
|
3812
|
+
return {
|
|
3813
|
+
reason: "component islands require a direct component identifier"
|
|
3814
|
+
};
|
|
2479
3815
|
}
|
|
2480
3816
|
if (!allowedComponentNames.has(name.name)) {
|
|
2481
3817
|
return {
|
|
@@ -2483,19 +3819,27 @@ function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allo
|
|
|
2483
3819
|
};
|
|
2484
3820
|
}
|
|
2485
3821
|
if (meaningfulJsxChildren(element).length > 0) {
|
|
2486
|
-
return {
|
|
3822
|
+
return {
|
|
3823
|
+
reason: `component island ${name.name} does not support children yet`
|
|
3824
|
+
};
|
|
2487
3825
|
}
|
|
2488
3826
|
const dependencies = /* @__PURE__ */ new Set();
|
|
2489
3827
|
for (const attribute of element.openingElement.attributes) {
|
|
2490
3828
|
if (types.isJSXSpreadAttribute(attribute)) {
|
|
2491
|
-
return {
|
|
3829
|
+
return {
|
|
3830
|
+
reason: `component island ${name.name} does not support JSX attribute spreads`
|
|
3831
|
+
};
|
|
2492
3832
|
}
|
|
2493
3833
|
const attributeName = jsxAttributeName(attribute);
|
|
2494
3834
|
if (!attributeName) {
|
|
2495
|
-
return {
|
|
3835
|
+
return {
|
|
3836
|
+
reason: `component island ${name.name} does not support namespaced JSX attributes`
|
|
3837
|
+
};
|
|
2496
3838
|
}
|
|
2497
3839
|
if (attributeName === "ref" || attributeName === "key" || attributeName === "children") {
|
|
2498
|
-
return {
|
|
3840
|
+
return {
|
|
3841
|
+
reason: `component island ${name.name} does not support ${attributeName} yet`
|
|
3842
|
+
};
|
|
2499
3843
|
}
|
|
2500
3844
|
if (!types.isJSXExpressionContainer(attribute.value) || types.isJSXEmptyExpression(attribute.value.expression)) {
|
|
2501
3845
|
continue;
|
|
@@ -2514,7 +3858,9 @@ function analyzeComponentIslandElement(element, statesByValue, safeGlobals, allo
|
|
|
2514
3858
|
(dependency) => dependencies.add(dependency)
|
|
2515
3859
|
);
|
|
2516
3860
|
}
|
|
2517
|
-
return {
|
|
3861
|
+
return {
|
|
3862
|
+
dependencies: [...dependencies].sort((left, right) => left - right)
|
|
3863
|
+
};
|
|
2518
3864
|
}
|
|
2519
3865
|
function componentIslandBoundary(blockRuntime, plan, source) {
|
|
2520
3866
|
const name = types.jsxMemberExpression(
|
|
@@ -2771,6 +4117,7 @@ function analyzeComposableBlocks(root, statesByValue, safeGlobals, listNames, al
|
|
|
2771
4117
|
dependencies: keyedRows.dependencies,
|
|
2772
4118
|
source: child,
|
|
2773
4119
|
collection: keyedRows.collection,
|
|
4120
|
+
collectionDependency: keyedRows.collectionDependency,
|
|
2774
4121
|
structureDependencies: keyedRows.structureDependencies,
|
|
2775
4122
|
keyCallback: keyedRows.keyCallback,
|
|
2776
4123
|
renderCallback: keyedRows.renderCallback,
|
|
@@ -3012,7 +4359,7 @@ function conditionalBlockBoundary(blockRuntime, plan, source) {
|
|
|
3012
4359
|
true
|
|
3013
4360
|
);
|
|
3014
4361
|
}
|
|
3015
|
-
function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
|
|
4362
|
+
function lowerComposableBlocks(root, plans, blockRuntime, listNames, keyedMapUpdateHints, keyedArrayFilterHintedStateIndices, keyedArrayPrependHintedStateIndices, keyedArrayPositionHintedStateIndices, keyedArrayReorderHintedStateIndices) {
|
|
3016
4363
|
const planBySource = new Map(
|
|
3017
4364
|
plans.map((plan) => [plan.source, plan])
|
|
3018
4365
|
);
|
|
@@ -3037,7 +4384,15 @@ function lowerComposableBlocks(root, plans, blockRuntime, listNames) {
|
|
|
3037
4384
|
return mixedRangesBoundary(blockRuntime, plan2);
|
|
3038
4385
|
}
|
|
3039
4386
|
if (plan2?.kind === "keyed-rows") {
|
|
3040
|
-
return keyedRowsBoundary(
|
|
4387
|
+
return keyedRowsBoundary(
|
|
4388
|
+
blockRuntime,
|
|
4389
|
+
plan2,
|
|
4390
|
+
keyedMapUpdateHints,
|
|
4391
|
+
keyedArrayFilterHintedStateIndices,
|
|
4392
|
+
keyedArrayPrependHintedStateIndices,
|
|
4393
|
+
keyedArrayPositionHintedStateIndices,
|
|
4394
|
+
keyedArrayReorderHintedStateIndices
|
|
4395
|
+
);
|
|
3041
4396
|
}
|
|
3042
4397
|
if (plan2?.kind === "keyed-ranges") {
|
|
3043
4398
|
return keyedRangesBoundary(blockRuntime, plan2);
|
|
@@ -3400,7 +4755,7 @@ function wrapperElement(definitionIdentifier, props) {
|
|
|
3400
4755
|
const attributes = props ? [types.jsxSpreadAttribute(types.cloneNode(props))] : [];
|
|
3401
4756
|
return types.jsxElement(types.jsxOpeningElement(name, attributes, true), null, [], true);
|
|
3402
4757
|
}
|
|
3403
|
-
function compileCandidate(candidate, createComponentIdentifier, 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) {
|
|
3404
4759
|
const { path, name, statementPath } = candidate;
|
|
3405
4760
|
if (path.node.async || path.node.generator)
|
|
3406
4761
|
return "async and generator components are not supported";
|
|
@@ -3412,6 +4767,7 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
3412
4767
|
const safeGlobals = new Set(
|
|
3413
4768
|
[...SAFE_GLOBAL_CALLS, "Math"].filter((name2) => !path.scope.getBinding(name2))
|
|
3414
4769
|
);
|
|
4770
|
+
const globalCollections = new Set(["Set", "Map"].filter((name2) => !path.scope.getBinding(name2)));
|
|
3415
4771
|
const states = [];
|
|
3416
4772
|
const locals = [];
|
|
3417
4773
|
let returned;
|
|
@@ -3459,9 +4815,17 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
3459
4815
|
if (declaration.init.async || declaration.init.generator) {
|
|
3460
4816
|
return `event handler ${declaration.id.name} must be synchronous`;
|
|
3461
4817
|
}
|
|
3462
|
-
locals.push({
|
|
4818
|
+
locals.push({
|
|
4819
|
+
kind: "handler",
|
|
4820
|
+
name: declaration.id.name,
|
|
4821
|
+
value: declaration.init
|
|
4822
|
+
});
|
|
3463
4823
|
} else {
|
|
3464
|
-
locals.push({
|
|
4824
|
+
locals.push({
|
|
4825
|
+
kind: "derived",
|
|
4826
|
+
name: declaration.id.name,
|
|
4827
|
+
value: declaration.init
|
|
4828
|
+
});
|
|
3465
4829
|
}
|
|
3466
4830
|
}
|
|
3467
4831
|
if (states.length === 0) return "no local useState binding was found";
|
|
@@ -3600,7 +4964,378 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
3600
4964
|
}
|
|
3601
4965
|
if (blockAnalysis.reason) return blockAnalysis.reason;
|
|
3602
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
|
+
}
|
|
3603
5315
|
const blockPlans = blockAnalysis.plans || [];
|
|
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
|
+
);
|
|
3604
5339
|
markShortCircuitBindings(analysis.bindings || []);
|
|
3605
5340
|
assignStableBindingTargets(analysis.bindings || []);
|
|
3606
5341
|
const stateParameter = path.scope.generateUidIdentifier("farmState");
|
|
@@ -3613,11 +5348,21 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
3613
5348
|
blockParameter,
|
|
3614
5349
|
blockAnalysis.ownedElements || /* @__PURE__ */ new Set()
|
|
3615
5350
|
);
|
|
5351
|
+
const appliedRemovalHintedStateIndices = /* @__PURE__ */ new Set([
|
|
5352
|
+
...appliedFilterHintedStateIndices,
|
|
5353
|
+
...appliedRollingWindowHintedStateIndices,
|
|
5354
|
+
...appliedSliceHintedStateIndices
|
|
5355
|
+
]);
|
|
3616
5356
|
const rootWithBlocks = lowerComposableBlocks(
|
|
3617
5357
|
rootWithTargets,
|
|
3618
5358
|
blockPlans,
|
|
3619
5359
|
blockParameter,
|
|
3620
|
-
listNames
|
|
5360
|
+
listNames,
|
|
5361
|
+
hasKeyedUpdateHints,
|
|
5362
|
+
appliedRemovalHintedStateIndices,
|
|
5363
|
+
appliedPrependHintedStateIndices,
|
|
5364
|
+
appliedPositionHintedStateIndices,
|
|
5365
|
+
appliedReorderHintedStateIndices
|
|
3621
5366
|
);
|
|
3622
5367
|
const rewrittenRoot = rewriteStateAccess(
|
|
3623
5368
|
rootWithBlocks,
|
|
@@ -3703,7 +5448,10 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
3703
5448
|
)
|
|
3704
5449
|
)
|
|
3705
5450
|
)
|
|
3706
|
-
])
|
|
5451
|
+
]),
|
|
5452
|
+
types.arrayExpression(
|
|
5453
|
+
runtimeFeatures.map((feature) => types.cloneNode(runtimeFeatureIdentifiers.get(feature)))
|
|
5454
|
+
)
|
|
3707
5455
|
]);
|
|
3708
5456
|
path.get("body").replaceWith(
|
|
3709
5457
|
types.blockStatement([
|
|
@@ -3713,6 +5461,7 @@ function compileCandidate(candidate, createComponentIdentifier, useStateNames, r
|
|
|
3713
5461
|
statementPath.insertAfter(
|
|
3714
5462
|
types.variableDeclaration("const", [types.variableDeclarator(definitionIdentifier, definition)])
|
|
3715
5463
|
);
|
|
5464
|
+
for (const feature of runtimeFeatures) usedRuntimeFeatures.add(feature);
|
|
3716
5465
|
return void 0;
|
|
3717
5466
|
}
|
|
3718
5467
|
function collectCandidates(programPath) {
|
|
@@ -3751,6 +5500,20 @@ function collectCandidates(programPath) {
|
|
|
3751
5500
|
async function compileReactModule(code, id, options) {
|
|
3752
5501
|
const compiled = [];
|
|
3753
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
|
+
};
|
|
3754
5517
|
const plugin = () => ({
|
|
3755
5518
|
name: "farm-react-aot",
|
|
3756
5519
|
visitor: {
|
|
@@ -3780,6 +5543,43 @@ async function compileReactModule(code, id, options) {
|
|
|
3780
5543
|
}
|
|
3781
5544
|
const candidates = collectCandidates(programPath);
|
|
3782
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
|
+
);
|
|
5576
|
+
const runtimeFeatureIdentifiers = new Map(
|
|
5577
|
+
Object.entries(COMPILER_RUNTIME_FEATURE_EXPORTS).map(([feature, exportName]) => [
|
|
5578
|
+
feature,
|
|
5579
|
+
programPath.scope.generateUidIdentifier(exportName)
|
|
5580
|
+
])
|
|
5581
|
+
);
|
|
5582
|
+
const usedRuntimeFeatures = /* @__PURE__ */ new Set();
|
|
3783
5583
|
for (const candidate of candidates) {
|
|
3784
5584
|
const functionDirectives = new Set(
|
|
3785
5585
|
types.isBlockStatement(candidate.path.node.body) ? directiveValues(candidate.path.node.body) : []
|
|
@@ -3790,6 +5590,19 @@ async function compileReactModule(code, id, options) {
|
|
|
3790
5590
|
const reason = compileCandidate(
|
|
3791
5591
|
candidate,
|
|
3792
5592
|
createComponentIdentifier,
|
|
5593
|
+
keyedMapUpdateIdentifier,
|
|
5594
|
+
keyedArrayAppendIdentifier,
|
|
5595
|
+
keyedArrayFilterIdentifier,
|
|
5596
|
+
keyedArrayPrependIdentifier,
|
|
5597
|
+
keyedArrayPositionIdentifier,
|
|
5598
|
+
keyedArrayReorderIdentifier,
|
|
5599
|
+
keyedArrayRollingWindowIdentifier,
|
|
5600
|
+
keyedArraySliceIdentifier,
|
|
5601
|
+
keyedCollectionUpdateIdentifier,
|
|
5602
|
+
keyedCollectionMutationIdentifier,
|
|
5603
|
+
runtimeFeatureIdentifiers,
|
|
5604
|
+
usedRuntimeFeatures,
|
|
5605
|
+
optimizationCounts,
|
|
3793
5606
|
useStateNames,
|
|
3794
5607
|
reactNames,
|
|
3795
5608
|
listNames,
|
|
@@ -3813,7 +5626,71 @@ async function compileReactModule(code, id, options) {
|
|
|
3813
5626
|
[
|
|
3814
5627
|
types.importSpecifier(
|
|
3815
5628
|
createComponentIdentifier,
|
|
3816
|
-
types.identifier("
|
|
5629
|
+
types.identifier("createCompiledComponentWithFeatures")
|
|
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
|
+
] : [],
|
|
5689
|
+
...[...usedRuntimeFeatures].sort().map(
|
|
5690
|
+
(feature) => types.importSpecifier(
|
|
5691
|
+
types.cloneNode(runtimeFeatureIdentifiers.get(feature)),
|
|
5692
|
+
types.identifier(COMPILER_RUNTIME_FEATURE_EXPORTS[feature])
|
|
5693
|
+
)
|
|
3817
5694
|
)
|
|
3818
5695
|
],
|
|
3819
5696
|
types.stringLiteral("@farm.js/react/compiler-runtime")
|
|
@@ -3845,7 +5722,8 @@ async function compileReactModule(code, id, options) {
|
|
|
3845
5722
|
code: result?.code || code,
|
|
3846
5723
|
map: result?.map || null,
|
|
3847
5724
|
compiled,
|
|
3848
|
-
diagnostics
|
|
5725
|
+
diagnostics,
|
|
5726
|
+
optimizations: optimizationCounts
|
|
3849
5727
|
};
|
|
3850
5728
|
}
|
|
3851
5729
|
function projectRelativeId(projectRoot, id) {
|
|
@@ -3856,10 +5734,34 @@ function createReactCompilerReport(projectRoot, observations) {
|
|
|
3856
5734
|
let componentsConsidered = 0;
|
|
3857
5735
|
let compiled = 0;
|
|
3858
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;
|
|
3859
5749
|
const modules = [...observations].map(({ id, result }) => {
|
|
3860
5750
|
componentsConsidered += result.compiled.length + result.diagnostics.length;
|
|
3861
5751
|
compiled += result.compiled.length;
|
|
3862
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;
|
|
3863
5765
|
const moduleId = projectRelativeId(projectRoot, id);
|
|
3864
5766
|
const fallbacks = result.diagnostics.map((diagnostic) => {
|
|
3865
5767
|
reasonCounts.set(diagnostic.reason, (reasonCounts.get(diagnostic.reason) || 0) + 1);
|
|
@@ -3868,6 +5770,7 @@ function createReactCompilerReport(projectRoot, observations) {
|
|
|
3868
5770
|
return {
|
|
3869
5771
|
id: moduleId,
|
|
3870
5772
|
compiled: [...result.compiled].sort(),
|
|
5773
|
+
optimizations: result.optimizations,
|
|
3871
5774
|
fallbacks
|
|
3872
5775
|
};
|
|
3873
5776
|
}).sort((left, right) => left.id.localeCompare(right.id));
|
|
@@ -3878,7 +5781,19 @@ function createReactCompilerReport(projectRoot, observations) {
|
|
|
3878
5781
|
modules: modules.length,
|
|
3879
5782
|
componentsConsidered,
|
|
3880
5783
|
compiled,
|
|
3881
|
-
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
|
|
3882
5797
|
},
|
|
3883
5798
|
fallbackReasons,
|
|
3884
5799
|
modules
|