@fictjs/compiler 0.8.0 → 0.10.0
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 +19 -0
- package/dist/index.cjs +1052 -222
- package/dist/index.d.cts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +1052 -222
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -14241,6 +14241,9 @@ var RUNTIME_ALIASES = {
|
|
|
14241
14241
|
hydrateComponent: "hydrateComponent",
|
|
14242
14242
|
registerResume: "__fictRegisterResume"
|
|
14243
14243
|
};
|
|
14244
|
+
var RUNTIME_HELPER_MODULES = {
|
|
14245
|
+
keyedList: "@fictjs/runtime/internal/list"
|
|
14246
|
+
};
|
|
14244
14247
|
var DelegatedEvents = /* @__PURE__ */ new Set([...DelegatedEventNames]);
|
|
14245
14248
|
var SAFE_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
14246
14249
|
// Console methods
|
|
@@ -19939,15 +19942,38 @@ function buildEffectCall(ctx, t4, effectFn, options) {
|
|
|
19939
19942
|
}
|
|
19940
19943
|
return t4.callExpression(t4.identifier(RUNTIME_ALIASES.useEffect), args);
|
|
19941
19944
|
}
|
|
19942
|
-
function buildMemoCall(ctx, t4, memoFn,
|
|
19945
|
+
function buildMemoCall(ctx, t4, memoFn, options) {
|
|
19946
|
+
const slot = options?.slot;
|
|
19947
|
+
const memoOptionsProperties = [];
|
|
19948
|
+
if (options?.name) {
|
|
19949
|
+
memoOptionsProperties.push(
|
|
19950
|
+
t4.objectProperty(t4.identifier("name"), t4.stringLiteral(options.name))
|
|
19951
|
+
);
|
|
19952
|
+
}
|
|
19953
|
+
if (options?.source) {
|
|
19954
|
+
memoOptionsProperties.push(
|
|
19955
|
+
t4.objectProperty(t4.identifier("devToolsSource"), t4.stringLiteral(options.source))
|
|
19956
|
+
);
|
|
19957
|
+
}
|
|
19958
|
+
if (options?.internal) {
|
|
19959
|
+
memoOptionsProperties.push(t4.objectProperty(t4.identifier("internal"), t4.booleanLiteral(true)));
|
|
19960
|
+
}
|
|
19961
|
+
const memoOptions = memoOptionsProperties.length > 0 ? t4.objectExpression(memoOptionsProperties) : null;
|
|
19943
19962
|
if (ctx.inModule) {
|
|
19944
19963
|
ctx.helpersUsed.add("memo");
|
|
19945
|
-
|
|
19964
|
+
const args2 = [memoFn];
|
|
19965
|
+
if (memoOptions) args2.push(memoOptions);
|
|
19966
|
+
return t4.callExpression(t4.identifier(RUNTIME_ALIASES.memo), args2);
|
|
19946
19967
|
}
|
|
19947
19968
|
ctx.helpersUsed.add("useMemo");
|
|
19948
19969
|
ctx.needsCtx = true;
|
|
19949
19970
|
const args = [t4.identifier("__fictCtx"), memoFn];
|
|
19950
|
-
if (
|
|
19971
|
+
if (memoOptions) {
|
|
19972
|
+
args.push(memoOptions);
|
|
19973
|
+
if (slot !== void 0 && slot >= 0) {
|
|
19974
|
+
args.push(t4.numericLiteral(slot));
|
|
19975
|
+
}
|
|
19976
|
+
} else if (slot !== void 0 && slot >= 0) {
|
|
19951
19977
|
args.push(t4.numericLiteral(slot));
|
|
19952
19978
|
}
|
|
19953
19979
|
return t4.callExpression(t4.identifier(RUNTIME_ALIASES.useMemo), args);
|
|
@@ -21208,7 +21234,10 @@ function wrapInMemo(region, t4, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
21208
21234
|
const returnObj = t4.objectExpression(uniqueOutputNames.map((name) => buildOutputProperty(name)));
|
|
21209
21235
|
const memoBody = t4.blockStatement([...bodyStatements, t4.returnStatement(returnObj)]);
|
|
21210
21236
|
const slot = ctx.inModule ? void 0 : reserveHookSlot(ctx);
|
|
21211
|
-
const memoCall = buildMemoCall(ctx, t4, t4.arrowFunctionExpression([], memoBody),
|
|
21237
|
+
const memoCall = buildMemoCall(ctx, t4, t4.arrowFunctionExpression([], memoBody), {
|
|
21238
|
+
slot,
|
|
21239
|
+
internal: true
|
|
21240
|
+
});
|
|
21212
21241
|
const regionVarName = `__region_${region.id}`;
|
|
21213
21242
|
statements.push(
|
|
21214
21243
|
t4.variableDeclaration("const", [t4.variableDeclarator(t4.identifier(regionVarName), memoCall)])
|
|
@@ -21467,7 +21496,10 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
|
|
|
21467
21496
|
ctx,
|
|
21468
21497
|
t4,
|
|
21469
21498
|
t4.arrowFunctionExpression([], t4.blockStatement(memoBody)),
|
|
21470
|
-
|
|
21499
|
+
{
|
|
21500
|
+
slot: ctx.inModule ? void 0 : reserveHookSlot(ctx),
|
|
21501
|
+
internal: true
|
|
21502
|
+
}
|
|
21471
21503
|
);
|
|
21472
21504
|
statements.push(
|
|
21473
21505
|
t4.variableDeclaration("const", [t4.variableDeclarator(t4.identifier(regionVarName), memoCall)])
|
|
@@ -21580,7 +21612,12 @@ Context: ${location}`
|
|
|
21580
21612
|
};
|
|
21581
21613
|
const buildDerivedMemoCall = (expr) => {
|
|
21582
21614
|
const slot = !ctx.inModule && inRegionMemo ? reserveHookSlot(ctx) : void 0;
|
|
21583
|
-
|
|
21615
|
+
const source = ctx.options?.dev !== false && instr.loc ? `${ctx.options?.filename ?? ""}:${instr.loc.start.line}:${instr.loc.start.column}` : void 0;
|
|
21616
|
+
return buildMemoCall(ctx, t4, t4.arrowFunctionExpression([], expr), {
|
|
21617
|
+
slot,
|
|
21618
|
+
name: baseName2,
|
|
21619
|
+
source
|
|
21620
|
+
});
|
|
21584
21621
|
};
|
|
21585
21622
|
if (isShadowDeclaration && declKind) {
|
|
21586
21623
|
ctx.trackedVars.delete(baseName2);
|
|
@@ -22942,7 +22979,7 @@ function expressionUsesIdentifier(expr, name, t4) {
|
|
|
22942
22979
|
visit(expr);
|
|
22943
22980
|
return found;
|
|
22944
22981
|
}
|
|
22945
|
-
function extractDelegatedEventData(expr, t4) {
|
|
22982
|
+
function extractDelegatedEventData(expr, t4, options) {
|
|
22946
22983
|
const isSimpleHandler = t4.isIdentifier(expr) || t4.isMemberExpression(expr);
|
|
22947
22984
|
if (isSimpleHandler) {
|
|
22948
22985
|
return { handler: expr };
|
|
@@ -22955,6 +22992,9 @@ function extractDelegatedEventData(expr, t4) {
|
|
|
22955
22992
|
if (!bodyExpr || !t4.isCallExpression(bodyExpr)) return null;
|
|
22956
22993
|
if (paramNames.some((name) => expressionUsesIdentifier(bodyExpr, name, t4))) return null;
|
|
22957
22994
|
if (!t4.isIdentifier(bodyExpr.callee)) return null;
|
|
22995
|
+
if (options?.isKnownHandlerIdentifier && !options.isKnownHandlerIdentifier(bodyExpr.callee.name)) {
|
|
22996
|
+
return null;
|
|
22997
|
+
}
|
|
22958
22998
|
if (bodyExpr.arguments.length === 0) return null;
|
|
22959
22999
|
if (bodyExpr.arguments.length > 1) return null;
|
|
22960
23000
|
const dataArg = bodyExpr.arguments[0];
|
|
@@ -23017,6 +23057,10 @@ function extractDelegatedEventDataFromHIR(expr, ctx) {
|
|
|
23017
23057
|
return null;
|
|
23018
23058
|
}
|
|
23019
23059
|
const handlerName = callee.name;
|
|
23060
|
+
const normalizedHandlerName = deSSAVarName(handlerName);
|
|
23061
|
+
if (!ctx.functionVars?.has(normalizedHandlerName)) {
|
|
23062
|
+
return null;
|
|
23063
|
+
}
|
|
23020
23064
|
if (ctx.signalVars?.has(handlerName) || ctx.memoVars?.has(handlerName) || ctx.aliasVars?.has(handlerName) || ctx.storeVars?.has(handlerName) || ctx.trackedVars.has(handlerName)) {
|
|
23021
23065
|
return null;
|
|
23022
23066
|
}
|
|
@@ -23027,7 +23071,10 @@ function extractDelegatedEventDataFromHIR(expr, ctx) {
|
|
|
23027
23071
|
if (isTrackedAccessor) {
|
|
23028
23072
|
return null;
|
|
23029
23073
|
}
|
|
23030
|
-
const paramNames = new Set(expr.params.map((p) => p.name));
|
|
23074
|
+
const paramNames = new Set(expr.params.map((p) => deSSAVarName(p.name)));
|
|
23075
|
+
if (paramNames.has(deSSAVarName(callee.name))) {
|
|
23076
|
+
return null;
|
|
23077
|
+
}
|
|
23031
23078
|
const dataExpr = bodyExpr.arguments[0];
|
|
23032
23079
|
if (!dataExpr) {
|
|
23033
23080
|
return null;
|
|
@@ -24066,17 +24113,19 @@ function collectDeclaredNames(body, t4) {
|
|
|
24066
24113
|
function attachHelperImports(ctx, body, t4) {
|
|
24067
24114
|
if (ctx.helpersUsed.size === 0) return body;
|
|
24068
24115
|
const declared = collectDeclaredNames(body, t4);
|
|
24069
|
-
const
|
|
24116
|
+
const specifiersByModule = /* @__PURE__ */ new Map();
|
|
24070
24117
|
for (const name of ctx.helpersUsed) {
|
|
24071
24118
|
const alias = RUNTIME_ALIASES[name];
|
|
24072
24119
|
const helper = RUNTIME_HELPERS[name];
|
|
24073
24120
|
if (alias && helper) {
|
|
24074
24121
|
if (declared.has(alias)) continue;
|
|
24075
|
-
|
|
24122
|
+
const modulePath = RUNTIME_HELPER_MODULES[name] ?? RUNTIME_MODULE;
|
|
24123
|
+
const moduleSpecifiers = specifiersByModule.get(modulePath) ?? [];
|
|
24124
|
+
moduleSpecifiers.push(t4.importSpecifier(t4.identifier(alias), t4.identifier(helper)));
|
|
24125
|
+
specifiersByModule.set(modulePath, moduleSpecifiers);
|
|
24076
24126
|
}
|
|
24077
24127
|
}
|
|
24078
|
-
if (
|
|
24079
|
-
const importDecl = t4.importDeclaration(specifiers, t4.stringLiteral(RUNTIME_MODULE));
|
|
24128
|
+
if (specifiersByModule.size === 0) return body;
|
|
24080
24129
|
const helpers = [];
|
|
24081
24130
|
if (ctx.needsForOfHelper) {
|
|
24082
24131
|
const itemId = t4.identifier("item");
|
|
@@ -24114,7 +24163,15 @@ function attachHelperImports(ctx, body, t4) {
|
|
|
24114
24163
|
)
|
|
24115
24164
|
);
|
|
24116
24165
|
}
|
|
24117
|
-
|
|
24166
|
+
const modulePaths = Array.from(specifiersByModule.keys()).sort((a, b) => {
|
|
24167
|
+
if (a === RUNTIME_MODULE) return -1;
|
|
24168
|
+
if (b === RUNTIME_MODULE) return 1;
|
|
24169
|
+
return a.localeCompare(b);
|
|
24170
|
+
});
|
|
24171
|
+
const importDecls = modulePaths.map(
|
|
24172
|
+
(modulePath) => t4.importDeclaration(specifiersByModule.get(modulePath) ?? [], t4.stringLiteral(modulePath))
|
|
24173
|
+
);
|
|
24174
|
+
return [...importDecls, ...helpers, ...body];
|
|
24118
24175
|
}
|
|
24119
24176
|
|
|
24120
24177
|
// src/ir/codegen-jsx-keys.ts
|
|
@@ -24184,8 +24241,8 @@ function getDependencyPathFromNode(node, t4) {
|
|
|
24184
24241
|
}
|
|
24185
24242
|
return null;
|
|
24186
24243
|
}
|
|
24187
|
-
function replaceIdentifiersWithOverrides(node, overrides, t4, parentKind, parentKey, skipCurrentNode = false) {
|
|
24188
|
-
const isCallTarget = parentKey === "callee" && (parentKind === "CallExpression" || parentKind === "OptionalCallExpression");
|
|
24244
|
+
function replaceIdentifiersWithOverrides(node, overrides, t4, parentKind, parentKey, skipCurrentNode = false, allowCallCalleeReplacement = false) {
|
|
24245
|
+
const isCallTarget = !allowCallCalleeReplacement && parentKey === "callee" && (parentKind === "CallExpression" || parentKind === "OptionalCallExpression");
|
|
24189
24246
|
if (parentKind === "VariableDeclarator" && parentKey === "id") {
|
|
24190
24247
|
return;
|
|
24191
24248
|
}
|
|
@@ -24257,9 +24314,25 @@ function replaceIdentifiersWithOverrides(node, overrides, t4, parentKind, parent
|
|
|
24257
24314
|
}
|
|
24258
24315
|
}
|
|
24259
24316
|
if (t4.isBlockStatement(node.body)) {
|
|
24260
|
-
replaceIdentifiersWithOverrides(
|
|
24317
|
+
replaceIdentifiersWithOverrides(
|
|
24318
|
+
node.body,
|
|
24319
|
+
scopedOverrides,
|
|
24320
|
+
t4,
|
|
24321
|
+
node.type,
|
|
24322
|
+
"body",
|
|
24323
|
+
false,
|
|
24324
|
+
allowCallCalleeReplacement
|
|
24325
|
+
);
|
|
24261
24326
|
} else {
|
|
24262
|
-
replaceIdentifiersWithOverrides(
|
|
24327
|
+
replaceIdentifiersWithOverrides(
|
|
24328
|
+
node.body,
|
|
24329
|
+
scopedOverrides,
|
|
24330
|
+
t4,
|
|
24331
|
+
node.type,
|
|
24332
|
+
"body",
|
|
24333
|
+
false,
|
|
24334
|
+
allowCallCalleeReplacement
|
|
24335
|
+
);
|
|
24263
24336
|
}
|
|
24264
24337
|
return;
|
|
24265
24338
|
}
|
|
@@ -24287,12 +24360,21 @@ function replaceIdentifiersWithOverrides(node, overrides, t4, parentKind, parent
|
|
|
24287
24360
|
t4,
|
|
24288
24361
|
node.type,
|
|
24289
24362
|
key,
|
|
24290
|
-
false
|
|
24363
|
+
false,
|
|
24364
|
+
allowCallCalleeReplacement
|
|
24291
24365
|
);
|
|
24292
24366
|
}
|
|
24293
24367
|
}
|
|
24294
24368
|
} else if (value && typeof value === "object" && "type" in value) {
|
|
24295
|
-
replaceIdentifiersWithOverrides(
|
|
24369
|
+
replaceIdentifiersWithOverrides(
|
|
24370
|
+
value,
|
|
24371
|
+
overrides,
|
|
24372
|
+
t4,
|
|
24373
|
+
node.type,
|
|
24374
|
+
key,
|
|
24375
|
+
false,
|
|
24376
|
+
allowCallCalleeReplacement
|
|
24377
|
+
);
|
|
24296
24378
|
}
|
|
24297
24379
|
}
|
|
24298
24380
|
}
|
|
@@ -24565,6 +24647,124 @@ function applySelectorHoist(callbackExpr, itemParamName, keyParamName, statement
|
|
|
24565
24647
|
}
|
|
24566
24648
|
|
|
24567
24649
|
// src/ir/codegen-list-child.ts
|
|
24650
|
+
function getCallbackBlocks(callback) {
|
|
24651
|
+
if (callback.kind === "FunctionExpression") {
|
|
24652
|
+
return callback.body;
|
|
24653
|
+
}
|
|
24654
|
+
if (callback.kind === "ArrowFunction" && Array.isArray(callback.body)) {
|
|
24655
|
+
return callback.body;
|
|
24656
|
+
}
|
|
24657
|
+
return [];
|
|
24658
|
+
}
|
|
24659
|
+
function collectMapCallbackAliasDeclarations(callback) {
|
|
24660
|
+
const blocks = getCallbackBlocks(callback);
|
|
24661
|
+
if (blocks.length === 0) {
|
|
24662
|
+
return /* @__PURE__ */ new Map();
|
|
24663
|
+
}
|
|
24664
|
+
const paramNames = callback.kind === "ArrowFunction" || callback.kind === "FunctionExpression" ? new Set(callback.params.map((param) => param.name)) : /* @__PURE__ */ new Set();
|
|
24665
|
+
const declarationState = /* @__PURE__ */ new Map();
|
|
24666
|
+
for (const block of blocks) {
|
|
24667
|
+
for (const instr of block.instructions) {
|
|
24668
|
+
if (instr.kind !== "Assign" || instr.target.kind !== "Identifier") {
|
|
24669
|
+
continue;
|
|
24670
|
+
}
|
|
24671
|
+
const name = instr.target.name;
|
|
24672
|
+
if (paramNames.has(name)) continue;
|
|
24673
|
+
const isDeclaration = !!instr.declarationKind;
|
|
24674
|
+
const previous = declarationState.get(name);
|
|
24675
|
+
if (previous) {
|
|
24676
|
+
declarationState.set(name, {
|
|
24677
|
+
declarationCount: previous.declarationCount + (isDeclaration ? 1 : 0),
|
|
24678
|
+
hasNonDeclarationWrite: previous.hasNonDeclarationWrite || !isDeclaration,
|
|
24679
|
+
declarationValue: previous.declarationValue,
|
|
24680
|
+
lastAssignedValue: instr.value
|
|
24681
|
+
});
|
|
24682
|
+
} else {
|
|
24683
|
+
declarationState.set(name, {
|
|
24684
|
+
declarationCount: isDeclaration ? 1 : 0,
|
|
24685
|
+
hasNonDeclarationWrite: !isDeclaration,
|
|
24686
|
+
declarationValue: isDeclaration ? instr.value : null,
|
|
24687
|
+
lastAssignedValue: instr.value
|
|
24688
|
+
});
|
|
24689
|
+
}
|
|
24690
|
+
}
|
|
24691
|
+
}
|
|
24692
|
+
const aliasMap = /* @__PURE__ */ new Map();
|
|
24693
|
+
const effectiveBlocks = blocks.filter(
|
|
24694
|
+
(block) => block.instructions.length > 0 || block.terminator.kind !== "Unreachable"
|
|
24695
|
+
);
|
|
24696
|
+
const isSingleLinearBlock = effectiveBlocks.length === 1 && effectiveBlocks[0].terminator.kind === "Return";
|
|
24697
|
+
for (const [name, state] of declarationState) {
|
|
24698
|
+
if (isSingleLinearBlock) {
|
|
24699
|
+
if (state.declarationCount <= 1) {
|
|
24700
|
+
aliasMap.set(name, state.lastAssignedValue);
|
|
24701
|
+
}
|
|
24702
|
+
continue;
|
|
24703
|
+
}
|
|
24704
|
+
if (state.declarationCount === 1 && !state.hasNonDeclarationWrite && state.declarationValue) {
|
|
24705
|
+
aliasMap.set(name, state.declarationValue);
|
|
24706
|
+
}
|
|
24707
|
+
}
|
|
24708
|
+
return aliasMap;
|
|
24709
|
+
}
|
|
24710
|
+
function resolveMapCallbackKeyExpression(keyExpr, callback) {
|
|
24711
|
+
if (keyExpr.kind !== "Identifier") {
|
|
24712
|
+
return keyExpr;
|
|
24713
|
+
}
|
|
24714
|
+
const aliasMap = collectMapCallbackAliasDeclarations(callback);
|
|
24715
|
+
if (aliasMap.size === 0) {
|
|
24716
|
+
return keyExpr;
|
|
24717
|
+
}
|
|
24718
|
+
let resolved = keyExpr;
|
|
24719
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24720
|
+
while (resolved.kind === "Identifier") {
|
|
24721
|
+
const next = aliasMap.get(resolved.name);
|
|
24722
|
+
if (!next || seen.has(resolved.name)) break;
|
|
24723
|
+
seen.add(resolved.name);
|
|
24724
|
+
resolved = next;
|
|
24725
|
+
}
|
|
24726
|
+
return resolved;
|
|
24727
|
+
}
|
|
24728
|
+
function collectMapCallbackLocalNames(callback) {
|
|
24729
|
+
const blocks = getCallbackBlocks(callback);
|
|
24730
|
+
if (blocks.length === 0) {
|
|
24731
|
+
return /* @__PURE__ */ new Set();
|
|
24732
|
+
}
|
|
24733
|
+
const paramNames = callback.kind === "ArrowFunction" || callback.kind === "FunctionExpression" ? new Set(callback.params.map((param) => deSSAVarName(param.name))) : /* @__PURE__ */ new Set();
|
|
24734
|
+
const locals = /* @__PURE__ */ new Set();
|
|
24735
|
+
for (const block of blocks) {
|
|
24736
|
+
for (const instr of block.instructions) {
|
|
24737
|
+
if (instr.kind === "Assign" && instr.target.kind === "Identifier") {
|
|
24738
|
+
const name = deSSAVarName(instr.target.name);
|
|
24739
|
+
if (!paramNames.has(name)) locals.add(name);
|
|
24740
|
+
}
|
|
24741
|
+
if (instr.kind === "Phi" && instr.target.kind === "Identifier") {
|
|
24742
|
+
const name = deSSAVarName(instr.target.name);
|
|
24743
|
+
if (!paramNames.has(name)) locals.add(name);
|
|
24744
|
+
}
|
|
24745
|
+
}
|
|
24746
|
+
}
|
|
24747
|
+
return locals;
|
|
24748
|
+
}
|
|
24749
|
+
function hasUnresolvedCallbackLocalKeyDependencies(keyExpr, callback, keyAliasDeclarations) {
|
|
24750
|
+
const callbackLocals = collectMapCallbackLocalNames(callback);
|
|
24751
|
+
if (callbackLocals.size === 0) {
|
|
24752
|
+
return false;
|
|
24753
|
+
}
|
|
24754
|
+
const resolvableAliases = new Set(
|
|
24755
|
+
Array.from(keyAliasDeclarations.keys()).map((name) => deSSAVarName(name))
|
|
24756
|
+
);
|
|
24757
|
+
const deps = /* @__PURE__ */ new Set();
|
|
24758
|
+
collectExpressionDependencies(keyExpr, deps);
|
|
24759
|
+
for (const dep of deps) {
|
|
24760
|
+
const base = dep.split(".")[0] ?? dep;
|
|
24761
|
+
if (!base) continue;
|
|
24762
|
+
if (callbackLocals.has(base) && !resolvableAliases.has(base)) {
|
|
24763
|
+
return true;
|
|
24764
|
+
}
|
|
24765
|
+
}
|
|
24766
|
+
return false;
|
|
24767
|
+
}
|
|
24568
24768
|
function buildListCallExpression(expr, statements, ctx, ops) {
|
|
24569
24769
|
const { t: t4 } = ctx;
|
|
24570
24770
|
if (expr.kind !== "CallExpression" && expr.kind !== "OptionalCallExpression") {
|
|
@@ -24583,7 +24783,8 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24583
24783
|
if (!mapCallback) {
|
|
24584
24784
|
throw new Error("map callback is required");
|
|
24585
24785
|
}
|
|
24586
|
-
const
|
|
24786
|
+
const extractedKeyExpr = extractKeyFromMapCallback(mapCallback);
|
|
24787
|
+
const keyExpr = extractedKeyExpr ? resolveMapCallbackKeyExpression(extractedKeyExpr, mapCallback) : void 0;
|
|
24587
24788
|
const isKeyed = !!keyExpr;
|
|
24588
24789
|
const hasRestParam = (mapCallback.kind === "ArrowFunction" || mapCallback.kind === "FunctionExpression") && Array.isArray(mapCallback.rawParams) && mapCallback.rawParams.some((param) => t4.isRestElement(param));
|
|
24589
24790
|
const canConstifyKey = isKeyed && keyExpr && !hasRestParam;
|
|
@@ -24634,7 +24835,7 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24634
24835
|
if (Object.keys(overrides).length > 0) {
|
|
24635
24836
|
if (t4.isBlockStatement(callbackExpr.body)) {
|
|
24636
24837
|
for (const stmt of callbackExpr.body.body) {
|
|
24637
|
-
if (!t4.isVariableDeclaration(stmt)) continue;
|
|
24838
|
+
if (!t4.isVariableDeclaration(stmt) || stmt.kind !== "const") continue;
|
|
24638
24839
|
for (const decl of stmt.declarations) {
|
|
24639
24840
|
if (!t4.isIdentifier(decl.id) || !decl.init) continue;
|
|
24640
24841
|
const replacement = t4.cloneNode(decl.init, true);
|
|
@@ -24664,7 +24865,32 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24664
24865
|
}
|
|
24665
24866
|
let listCall;
|
|
24666
24867
|
if (isKeyed && keyExpr) {
|
|
24868
|
+
const keyAliasDeclarations = collectMapCallbackAliasDeclarations(mapCallback);
|
|
24869
|
+
const hasUnresolvedLocalKeyDeps = hasUnresolvedCallbackLocalKeyDependencies(
|
|
24870
|
+
keyExpr,
|
|
24871
|
+
mapCallback,
|
|
24872
|
+
keyAliasDeclarations
|
|
24873
|
+
);
|
|
24667
24874
|
let keyExprAst = ops.lowerExpression(keyExpr, ctx);
|
|
24875
|
+
if (keyAliasDeclarations.size > 0) {
|
|
24876
|
+
const keyOverrides = {};
|
|
24877
|
+
for (const [name, value] of keyAliasDeclarations) {
|
|
24878
|
+
const replacement = ops.lowerExpression(value, ctx);
|
|
24879
|
+
replaceIdentifiersWithOverrides(replacement, keyOverrides, t4);
|
|
24880
|
+
keyOverrides[name] = () => t4.cloneNode(replacement, true);
|
|
24881
|
+
}
|
|
24882
|
+
if (Object.keys(keyOverrides).length > 0) {
|
|
24883
|
+
replaceIdentifiersWithOverrides(
|
|
24884
|
+
keyExprAst,
|
|
24885
|
+
keyOverrides,
|
|
24886
|
+
t4,
|
|
24887
|
+
void 0,
|
|
24888
|
+
void 0,
|
|
24889
|
+
false,
|
|
24890
|
+
true
|
|
24891
|
+
);
|
|
24892
|
+
}
|
|
24893
|
+
}
|
|
24668
24894
|
if (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) {
|
|
24669
24895
|
const itemParam = callbackExpr.params[0];
|
|
24670
24896
|
const indexParam = callbackExpr.params[1];
|
|
@@ -24678,6 +24904,9 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24678
24904
|
}
|
|
24679
24905
|
const itemParamName = t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr) ? callbackExpr.params[0] : null;
|
|
24680
24906
|
const indexParamName = t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr) ? callbackExpr.params[1] : null;
|
|
24907
|
+
if (hasUnresolvedLocalKeyDeps) {
|
|
24908
|
+
keyExprAst = t4.identifier(t4.isIdentifier(indexParamName) ? indexParamName.name : "__index");
|
|
24909
|
+
}
|
|
24681
24910
|
const keyFn = t4.arrowFunctionExpression(
|
|
24682
24911
|
[
|
|
24683
24912
|
t4.isIdentifier(itemParamName) ? itemParamName : t4.identifier("__item"),
|
|
@@ -25119,33 +25348,42 @@ function dependencyCoveredByDeclarations(dep, region) {
|
|
|
25119
25348
|
|
|
25120
25349
|
// src/ir/codegen-resumable-utils.ts
|
|
25121
25350
|
var import_node_url2 = require("url");
|
|
25122
|
-
|
|
25123
|
-
|
|
25124
|
-
|
|
25125
|
-
|
|
25126
|
-
|
|
25127
|
-
|
|
25128
|
-
|
|
25129
|
-
|
|
25130
|
-
|
|
25131
|
-
|
|
25132
|
-
|
|
25133
|
-
|
|
25134
|
-
|
|
25135
|
-
|
|
25136
|
-
}
|
|
25137
|
-
const value = n[key];
|
|
25138
|
-
if (Array.isArray(value)) {
|
|
25139
|
-
for (const item of value) {
|
|
25140
|
-
visit(item);
|
|
25141
|
-
}
|
|
25142
|
-
} else if (value && typeof value === "object") {
|
|
25143
|
-
visit(value);
|
|
25351
|
+
var import_traverse2 = __toESM(require("@babel/traverse"), 1);
|
|
25352
|
+
function renameIdentifiersInExpr(expr, renames, t4) {
|
|
25353
|
+
const traverse = import_traverse2.default.default ?? import_traverse2.default;
|
|
25354
|
+
const cloned = t4.cloneNode(expr, true);
|
|
25355
|
+
const file = t4.file(t4.program([t4.expressionStatement(cloned)]));
|
|
25356
|
+
traverse(file, {
|
|
25357
|
+
Identifier(path2) {
|
|
25358
|
+
const oldName = path2.node.name;
|
|
25359
|
+
const nextName = renames.get(oldName);
|
|
25360
|
+
if (!nextName) return;
|
|
25361
|
+
if (path2.parentPath.isObjectProperty() && path2.parentPath.node.shorthand && path2.parentPath.node.value === path2.node && t4.isIdentifier(path2.parentPath.node.key)) {
|
|
25362
|
+
path2.parentPath.node.shorthand = false;
|
|
25363
|
+
path2.parentPath.node.value = t4.identifier(nextName);
|
|
25364
|
+
return;
|
|
25144
25365
|
}
|
|
25366
|
+
if (!path2.isReferencedIdentifier()) return;
|
|
25367
|
+
const binding = path2.scope.getBinding(oldName);
|
|
25368
|
+
if (binding && binding.scope !== path2.scope.getProgramParent()) return;
|
|
25369
|
+
path2.node.name = nextName;
|
|
25145
25370
|
}
|
|
25146
|
-
}
|
|
25147
|
-
|
|
25148
|
-
return cloned;
|
|
25371
|
+
});
|
|
25372
|
+
const first = file.program.body[0];
|
|
25373
|
+
return t4.isExpressionStatement(first) ? first.expression : cloned;
|
|
25374
|
+
}
|
|
25375
|
+
function collectFreeIdentifiersInExpr(expr, t4) {
|
|
25376
|
+
const traverse = import_traverse2.default.default ?? import_traverse2.default;
|
|
25377
|
+
const file = t4.file(t4.program([t4.expressionStatement(t4.cloneNode(expr, true))]));
|
|
25378
|
+
const names = /* @__PURE__ */ new Set();
|
|
25379
|
+
traverse(file, {
|
|
25380
|
+
ReferencedIdentifier(path2) {
|
|
25381
|
+
const name = path2.node.name;
|
|
25382
|
+
if (path2.scope.getBinding(name)) return;
|
|
25383
|
+
names.add(name);
|
|
25384
|
+
}
|
|
25385
|
+
});
|
|
25386
|
+
return names;
|
|
25149
25387
|
}
|
|
25150
25388
|
function genModuleUrlExpr(ctx) {
|
|
25151
25389
|
const { t: t4 } = ctx;
|
|
@@ -25282,10 +25520,10 @@ function registerResumableComponent(componentName, ctx) {
|
|
|
25282
25520
|
}
|
|
25283
25521
|
|
|
25284
25522
|
// src/ir/codegen-resumable-events.ts
|
|
25285
|
-
function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, containingRegion, ops) {
|
|
25523
|
+
function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, containingRegion, ops, options) {
|
|
25286
25524
|
const { t: t4 } = ctx;
|
|
25287
25525
|
if (!ctx.resumableEnabled) {
|
|
25288
|
-
return;
|
|
25526
|
+
return false;
|
|
25289
25527
|
}
|
|
25290
25528
|
const prevWrapTracked = ctx.wrapTrackedExpressions;
|
|
25291
25529
|
ctx.wrapTrackedExpressions = false;
|
|
@@ -25299,53 +25537,88 @@ function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, c
|
|
|
25299
25537
|
const scopeParam = t4.identifier("scopeId");
|
|
25300
25538
|
const ensureHandlerParam = (fn) => {
|
|
25301
25539
|
if (t4.isArrowFunctionExpression(fn)) {
|
|
25302
|
-
|
|
25303
|
-
return t4.arrowFunctionExpression([eventParam], fn.body, fn.async);
|
|
25540
|
+
return fn;
|
|
25304
25541
|
}
|
|
25305
25542
|
if (t4.isFunctionExpression(fn)) {
|
|
25306
|
-
|
|
25307
|
-
return t4.functionExpression(fn.id, [eventParam], fn.body, fn.generator, fn.async);
|
|
25543
|
+
return fn;
|
|
25308
25544
|
}
|
|
25309
25545
|
if (t4.isIdentifier(fn) || t4.isMemberExpression(fn)) {
|
|
25310
25546
|
return fn;
|
|
25311
25547
|
}
|
|
25312
|
-
if (t4.isCallExpression(fn) && fn.arguments.length === 0 && (t4.isIdentifier(fn.callee) || t4.isMemberExpression(fn.callee))) {
|
|
25313
|
-
return fn.callee;
|
|
25314
|
-
}
|
|
25315
25548
|
return t4.functionExpression(
|
|
25316
25549
|
null,
|
|
25317
|
-
[
|
|
25318
|
-
t4.blockStatement([
|
|
25319
|
-
t4.returnStatement(
|
|
25320
|
-
t4.callExpression(
|
|
25321
|
-
t4.memberExpression(fn, t4.identifier("call")),
|
|
25322
|
-
[t4.thisExpression(), eventParam]
|
|
25323
|
-
)
|
|
25324
|
-
)
|
|
25325
|
-
])
|
|
25550
|
+
[],
|
|
25551
|
+
t4.blockStatement([t4.returnStatement(fn)])
|
|
25326
25552
|
);
|
|
25327
25553
|
};
|
|
25328
25554
|
const handlerExpr = ensureHandlerParam(valueExpr);
|
|
25329
25555
|
const handlerId = t4.identifier(`__fict_e${ctx.resumableHandlerCounter ?? 0}`);
|
|
25330
25556
|
ctx.resumableHandlerCounter = (ctx.resumableHandlerCounter ?? 0) + 1;
|
|
25331
|
-
const captured =
|
|
25332
|
-
collectExpressionIdentifiersDeep(expr, captured);
|
|
25557
|
+
const captured = collectFreeIdentifiersInExpr(handlerExpr, t4);
|
|
25333
25558
|
const lexicalNames = Array.from(captured).filter((name) => ctx.signalVars?.has(name));
|
|
25334
25559
|
const propsName = ctx.propsParamName && captured.has(ctx.propsParamName) ? ctx.propsParamName : null;
|
|
25560
|
+
const unsupportedLocals = Array.from(captured).filter((name) => {
|
|
25561
|
+
if (ctx.inListRender && ctx.listKeyParamName && name === ctx.listKeyParamName) return true;
|
|
25562
|
+
if (!ctx.localDeclaredNames?.has(name)) return false;
|
|
25563
|
+
if (ctx.signalVars?.has(name)) return false;
|
|
25564
|
+
if (ctx.functionVars?.has(name)) return false;
|
|
25565
|
+
if (propsName && name === propsName) return false;
|
|
25566
|
+
return true;
|
|
25567
|
+
});
|
|
25568
|
+
const loweredFunctionDeps = /* @__PURE__ */ new Map();
|
|
25569
|
+
const unsafeFunctionCaptures = [];
|
|
25570
|
+
for (const name of captured) {
|
|
25571
|
+
if (!ctx.functionVars?.has(name) || ctx.signalVars?.has(name)) continue;
|
|
25572
|
+
if (ctx.hoistedFunctionDepNames?.has(name)) continue;
|
|
25573
|
+
const hirDef = ctx.componentFunctionDefs?.get(name);
|
|
25574
|
+
if (!hirDef) {
|
|
25575
|
+
if (ctx.localDeclaredNames?.has(name)) {
|
|
25576
|
+
unsafeFunctionCaptures.push(`${name} -> <unhoistable>`);
|
|
25577
|
+
}
|
|
25578
|
+
continue;
|
|
25579
|
+
}
|
|
25580
|
+
const loweredFn = ops.lowerDomExpression(hirDef, ctx, null, {
|
|
25581
|
+
skipHookAccessors: true,
|
|
25582
|
+
skipRegionRootOverride: true
|
|
25583
|
+
});
|
|
25584
|
+
const fnCaptured = collectFreeIdentifiersInExpr(loweredFn, t4);
|
|
25585
|
+
const localFnCaptures = Array.from(fnCaptured).filter((dep) => ctx.localDeclaredNames?.has(dep)).sort();
|
|
25586
|
+
if (localFnCaptures.length > 0) {
|
|
25587
|
+
unsafeFunctionCaptures.push(`${name} -> ${localFnCaptures.join(", ")}`);
|
|
25588
|
+
continue;
|
|
25589
|
+
}
|
|
25590
|
+
loweredFunctionDeps.set(name, loweredFn);
|
|
25591
|
+
}
|
|
25592
|
+
if (unsupportedLocals.length > 0 || unsafeFunctionCaptures.length > 0) {
|
|
25593
|
+
const detailParts = [];
|
|
25594
|
+
if (unsupportedLocals.length > 0) {
|
|
25595
|
+
detailParts.push(`direct: ${unsupportedLocals.sort().join(", ")}`);
|
|
25596
|
+
}
|
|
25597
|
+
if (unsafeFunctionCaptures.length > 0) {
|
|
25598
|
+
detailParts.push(`function deps: ${unsafeFunctionCaptures.sort().join("; ")}`);
|
|
25599
|
+
}
|
|
25600
|
+
const detail = `Resumable handlers cannot capture non-serializable local variables (${detailParts.join(" | ")}).`;
|
|
25601
|
+
if (options?.explicit) {
|
|
25602
|
+
const loc = expr.loc?.start;
|
|
25603
|
+
const fileName = ctx.options?.filename ?? "<unknown>";
|
|
25604
|
+
const location = loc ? `${fileName}:${loc.line}:${loc.column + 1}` : fileName;
|
|
25605
|
+
throw new Error(
|
|
25606
|
+
`${detail} Use signals/props/function references or remove '$' suffix.
|
|
25607
|
+
at ${location}`
|
|
25608
|
+
);
|
|
25609
|
+
}
|
|
25610
|
+
return false;
|
|
25611
|
+
}
|
|
25335
25612
|
const functionDepRenames = /* @__PURE__ */ new Map();
|
|
25336
25613
|
for (const name of captured) {
|
|
25337
25614
|
if (ctx.functionVars?.has(name) && !ctx.signalVars?.has(name)) {
|
|
25338
|
-
const hirDef = ctx.componentFunctionDefs?.get(name);
|
|
25339
|
-
if (!hirDef) continue;
|
|
25340
25615
|
let hoistedName = ctx.hoistedFunctionDepNames?.get(name);
|
|
25341
25616
|
if (!hoistedName) {
|
|
25617
|
+
const loweredFn = loweredFunctionDeps.get(name);
|
|
25618
|
+
if (!loweredFn) continue;
|
|
25342
25619
|
hoistedName = `__fict_fn_${name}_${ctx.hoistedFunctionDepCounter ?? 0}`;
|
|
25343
25620
|
ctx.hoistedFunctionDepCounter = (ctx.hoistedFunctionDepCounter ?? 0) + 1;
|
|
25344
25621
|
ctx.hoistedFunctionDepNames?.set(name, hoistedName);
|
|
25345
|
-
const loweredFn = ops.lowerDomExpression(hirDef, ctx, null, {
|
|
25346
|
-
skipHookAccessors: true,
|
|
25347
|
-
skipRegionRootOverride: true
|
|
25348
|
-
});
|
|
25349
25622
|
const hoistedDecl = t4.variableDeclaration("const", [
|
|
25350
25623
|
t4.variableDeclarator(t4.identifier(hoistedName), loweredFn)
|
|
25351
25624
|
]);
|
|
@@ -25357,7 +25630,7 @@ function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, c
|
|
|
25357
25630
|
}
|
|
25358
25631
|
let finalHandlerExpr = handlerExpr;
|
|
25359
25632
|
if (functionDepRenames.size > 0) {
|
|
25360
|
-
finalHandlerExpr = renameIdentifiersInExpr(handlerExpr, functionDepRenames);
|
|
25633
|
+
finalHandlerExpr = renameIdentifiersInExpr(handlerExpr, functionDepRenames, t4);
|
|
25361
25634
|
}
|
|
25362
25635
|
const bodyStatements = [];
|
|
25363
25636
|
if (lexicalNames.length > 0) {
|
|
@@ -25390,12 +25663,97 @@ function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, c
|
|
|
25390
25663
|
);
|
|
25391
25664
|
}
|
|
25392
25665
|
const handlerVar = t4.identifier("__handler");
|
|
25666
|
+
const resultVar = t4.identifier("__result");
|
|
25393
25667
|
bodyStatements.push(
|
|
25394
25668
|
t4.variableDeclaration("const", [t4.variableDeclarator(handlerVar, finalHandlerExpr)])
|
|
25395
25669
|
);
|
|
25396
25670
|
bodyStatements.push(
|
|
25397
|
-
t4.
|
|
25398
|
-
t4.
|
|
25671
|
+
t4.ifStatement(
|
|
25672
|
+
t4.binaryExpression(
|
|
25673
|
+
"===",
|
|
25674
|
+
t4.unaryExpression("typeof", handlerVar),
|
|
25675
|
+
t4.stringLiteral("function")
|
|
25676
|
+
),
|
|
25677
|
+
t4.blockStatement([
|
|
25678
|
+
t4.variableDeclaration("const", [
|
|
25679
|
+
t4.variableDeclarator(
|
|
25680
|
+
resultVar,
|
|
25681
|
+
t4.callExpression(t4.memberExpression(handlerVar, t4.identifier("call")), [
|
|
25682
|
+
elParam,
|
|
25683
|
+
eventParam
|
|
25684
|
+
])
|
|
25685
|
+
)
|
|
25686
|
+
]),
|
|
25687
|
+
t4.ifStatement(
|
|
25688
|
+
t4.logicalExpression(
|
|
25689
|
+
"&&",
|
|
25690
|
+
t4.binaryExpression(
|
|
25691
|
+
"===",
|
|
25692
|
+
t4.unaryExpression("typeof", resultVar),
|
|
25693
|
+
t4.stringLiteral("function")
|
|
25694
|
+
),
|
|
25695
|
+
t4.binaryExpression("!==", resultVar, handlerVar)
|
|
25696
|
+
),
|
|
25697
|
+
t4.blockStatement([
|
|
25698
|
+
t4.returnStatement(
|
|
25699
|
+
t4.callExpression(t4.memberExpression(resultVar, t4.identifier("call")), [
|
|
25700
|
+
elParam,
|
|
25701
|
+
eventParam
|
|
25702
|
+
])
|
|
25703
|
+
)
|
|
25704
|
+
])
|
|
25705
|
+
),
|
|
25706
|
+
t4.ifStatement(
|
|
25707
|
+
t4.logicalExpression(
|
|
25708
|
+
"&&",
|
|
25709
|
+
resultVar,
|
|
25710
|
+
t4.binaryExpression(
|
|
25711
|
+
"===",
|
|
25712
|
+
t4.unaryExpression(
|
|
25713
|
+
"typeof",
|
|
25714
|
+
t4.memberExpression(resultVar, t4.identifier("handleEvent"))
|
|
25715
|
+
),
|
|
25716
|
+
t4.stringLiteral("function")
|
|
25717
|
+
)
|
|
25718
|
+
),
|
|
25719
|
+
t4.blockStatement([
|
|
25720
|
+
t4.returnStatement(
|
|
25721
|
+
t4.callExpression(
|
|
25722
|
+
t4.memberExpression(
|
|
25723
|
+
t4.memberExpression(resultVar, t4.identifier("handleEvent")),
|
|
25724
|
+
t4.identifier("call")
|
|
25725
|
+
),
|
|
25726
|
+
[resultVar, eventParam]
|
|
25727
|
+
)
|
|
25728
|
+
)
|
|
25729
|
+
])
|
|
25730
|
+
),
|
|
25731
|
+
t4.returnStatement(resultVar)
|
|
25732
|
+
])
|
|
25733
|
+
)
|
|
25734
|
+
);
|
|
25735
|
+
bodyStatements.push(
|
|
25736
|
+
t4.ifStatement(
|
|
25737
|
+
t4.logicalExpression(
|
|
25738
|
+
"&&",
|
|
25739
|
+
handlerVar,
|
|
25740
|
+
t4.binaryExpression(
|
|
25741
|
+
"===",
|
|
25742
|
+
t4.unaryExpression("typeof", t4.memberExpression(handlerVar, t4.identifier("handleEvent"))),
|
|
25743
|
+
t4.stringLiteral("function")
|
|
25744
|
+
)
|
|
25745
|
+
),
|
|
25746
|
+
t4.blockStatement([
|
|
25747
|
+
t4.returnStatement(
|
|
25748
|
+
t4.callExpression(
|
|
25749
|
+
t4.memberExpression(
|
|
25750
|
+
t4.memberExpression(handlerVar, t4.identifier("handleEvent")),
|
|
25751
|
+
t4.identifier("call")
|
|
25752
|
+
),
|
|
25753
|
+
[handlerVar, eventParam]
|
|
25754
|
+
)
|
|
25755
|
+
)
|
|
25756
|
+
])
|
|
25399
25757
|
)
|
|
25400
25758
|
);
|
|
25401
25759
|
const exportedHandler = t4.exportNamedDeclaration(
|
|
@@ -25424,11 +25782,13 @@ function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, c
|
|
|
25424
25782
|
])
|
|
25425
25783
|
)
|
|
25426
25784
|
);
|
|
25785
|
+
return true;
|
|
25427
25786
|
}
|
|
25428
25787
|
|
|
25429
25788
|
// src/ir/codegen-runtime-imports.ts
|
|
25430
25789
|
var RUNTIME_IMPORT_MODULES = /* @__PURE__ */ new Set([
|
|
25431
25790
|
RUNTIME_MODULE,
|
|
25791
|
+
...Object.values(RUNTIME_HELPER_MODULES),
|
|
25432
25792
|
"@fictjs/runtime",
|
|
25433
25793
|
"@fictjs/runtime/advanced",
|
|
25434
25794
|
"fict",
|
|
@@ -25807,7 +26167,8 @@ function extractHIRStaticHtml(jsx, ctx, ops, parentPath = [], namespace = null)
|
|
|
25807
26167
|
name: eventName.toLowerCase(),
|
|
25808
26168
|
expr: attr.value ?? void 0,
|
|
25809
26169
|
eventOptions: { capture, passive, once },
|
|
25810
|
-
resumable: shouldBeResumable
|
|
26170
|
+
resumable: shouldBeResumable,
|
|
26171
|
+
resumableExplicit: isResumableEvent
|
|
25811
26172
|
});
|
|
25812
26173
|
continue;
|
|
25813
26174
|
}
|
|
@@ -26380,7 +26741,7 @@ function buildOutputParams(fn, t4) {
|
|
|
26380
26741
|
}
|
|
26381
26742
|
return fn.params.map((p) => t4.identifier(deSSAVarName(p.name)));
|
|
26382
26743
|
}
|
|
26383
|
-
function lowerTrackedExpression(expr, ctx) {
|
|
26744
|
+
function lowerTrackedExpression(expr, ctx, valueUsed = true) {
|
|
26384
26745
|
const regionOverride = ctx.inReturn && ctx.currentFnIsHook ? null : ctx.currentRegion ?? (ctx.trackedVars.size ? {
|
|
26385
26746
|
id: -1,
|
|
26386
26747
|
dependencies: new Set(ctx.trackedVars),
|
|
@@ -26388,7 +26749,7 @@ function lowerTrackedExpression(expr, ctx) {
|
|
|
26388
26749
|
hasControlFlow: false,
|
|
26389
26750
|
hasReactiveWrites: false
|
|
26390
26751
|
} : null);
|
|
26391
|
-
const lowered = lowerExpression2(expr, ctx);
|
|
26752
|
+
const lowered = lowerExpression2(expr, ctx, valueUsed);
|
|
26392
26753
|
if (ctx.t.isAssignmentExpression(lowered)) {
|
|
26393
26754
|
const right = applyRegionMetadataToExpression2(lowered.right, ctx, regionOverride ?? void 0);
|
|
26394
26755
|
return ctx.t.assignmentExpression(lowered.operator, lowered.left, right);
|
|
@@ -26510,7 +26871,7 @@ function lowerInstruction(instr, ctx) {
|
|
|
26510
26871
|
);
|
|
26511
26872
|
}
|
|
26512
26873
|
if (instr.kind === "Expression") {
|
|
26513
|
-
return applyLoc(t4.expressionStatement(lowerTrackedExpression(instr.value, ctx)));
|
|
26874
|
+
return applyLoc(t4.expressionStatement(lowerTrackedExpression(instr.value, ctx, false)));
|
|
26514
26875
|
}
|
|
26515
26876
|
if (instr.kind === "Phi") {
|
|
26516
26877
|
return null;
|
|
@@ -26674,7 +27035,7 @@ function collectLocalDeclaredNames(params, blocks, t4) {
|
|
|
26674
27035
|
}
|
|
26675
27036
|
return declared;
|
|
26676
27037
|
}
|
|
26677
|
-
function lowerExpression2(expr, ctx,
|
|
27038
|
+
function lowerExpression2(expr, ctx, valueUsed = true) {
|
|
26678
27039
|
const depth = (ctx.expressionDepth ?? 0) + 1;
|
|
26679
27040
|
const maxDepth = ctx.maxExpressionDepth ?? 500;
|
|
26680
27041
|
if (depth > maxDepth) {
|
|
@@ -26685,12 +27046,12 @@ function lowerExpression2(expr, ctx, isAssigned = false) {
|
|
|
26685
27046
|
}
|
|
26686
27047
|
ctx.expressionDepth = depth;
|
|
26687
27048
|
try {
|
|
26688
|
-
return setNodeLoc(lowerExpressionImpl(expr, ctx,
|
|
27049
|
+
return setNodeLoc(lowerExpressionImpl(expr, ctx, valueUsed), expr.loc);
|
|
26689
27050
|
} finally {
|
|
26690
27051
|
ctx.expressionDepth = depth - 1;
|
|
26691
27052
|
}
|
|
26692
27053
|
}
|
|
26693
|
-
function lowerExpressionImpl(expr, ctx,
|
|
27054
|
+
function lowerExpressionImpl(expr, ctx, valueUsed = true) {
|
|
26694
27055
|
const { t: t4 } = ctx;
|
|
26695
27056
|
const mapParams = (params) => params.map((p) => t4.identifier(deSSAVarName(p.name)));
|
|
26696
27057
|
const lowerArgsAsExpressions = (args) => args.map(
|
|
@@ -26731,6 +27092,152 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
26731
27092
|
ctx.localDeclaredNames = prevLocalDeclared;
|
|
26732
27093
|
return result;
|
|
26733
27094
|
};
|
|
27095
|
+
const lowerTrackedWriteCall = (callee, nextValue) => {
|
|
27096
|
+
if (!valueUsed) {
|
|
27097
|
+
return t4.callExpression(t4.cloneNode(callee, true), [nextValue]);
|
|
27098
|
+
}
|
|
27099
|
+
const nextId = genTemp3(ctx, "next");
|
|
27100
|
+
const nextRef = t4.identifier(nextId.name);
|
|
27101
|
+
return t4.callExpression(
|
|
27102
|
+
t4.arrowFunctionExpression(
|
|
27103
|
+
[t4.cloneNode(nextId, true)],
|
|
27104
|
+
t4.sequenceExpression([
|
|
27105
|
+
t4.callExpression(t4.cloneNode(callee, true), [nextRef]),
|
|
27106
|
+
t4.identifier(nextId.name)
|
|
27107
|
+
])
|
|
27108
|
+
),
|
|
27109
|
+
[nextValue]
|
|
27110
|
+
);
|
|
27111
|
+
};
|
|
27112
|
+
const buildTrackedAssignmentNext = (operator, current, right) => {
|
|
27113
|
+
switch (operator) {
|
|
27114
|
+
case "=":
|
|
27115
|
+
return right;
|
|
27116
|
+
case "+=":
|
|
27117
|
+
return t4.binaryExpression("+", current, right);
|
|
27118
|
+
case "-=":
|
|
27119
|
+
return t4.binaryExpression("-", current, right);
|
|
27120
|
+
case "*=":
|
|
27121
|
+
return t4.binaryExpression("*", current, right);
|
|
27122
|
+
case "/=":
|
|
27123
|
+
return t4.binaryExpression("/", current, right);
|
|
27124
|
+
case "%=":
|
|
27125
|
+
return t4.binaryExpression("%", current, right);
|
|
27126
|
+
case "**=":
|
|
27127
|
+
return t4.binaryExpression("**", current, right);
|
|
27128
|
+
case "<<=":
|
|
27129
|
+
return t4.binaryExpression("<<", current, right);
|
|
27130
|
+
case ">>=":
|
|
27131
|
+
return t4.binaryExpression(">>", current, right);
|
|
27132
|
+
case ">>>=":
|
|
27133
|
+
return t4.binaryExpression(">>>", current, right);
|
|
27134
|
+
case "|=":
|
|
27135
|
+
return t4.binaryExpression("|", current, right);
|
|
27136
|
+
case "^=":
|
|
27137
|
+
return t4.binaryExpression("^", current, right);
|
|
27138
|
+
case "&=":
|
|
27139
|
+
return t4.binaryExpression("&", current, right);
|
|
27140
|
+
case "&&=":
|
|
27141
|
+
return t4.logicalExpression("&&", current, right);
|
|
27142
|
+
case "||=":
|
|
27143
|
+
return t4.logicalExpression("||", current, right);
|
|
27144
|
+
case "??=":
|
|
27145
|
+
return t4.logicalExpression("??", current, right);
|
|
27146
|
+
default:
|
|
27147
|
+
return right;
|
|
27148
|
+
}
|
|
27149
|
+
};
|
|
27150
|
+
const buildStaticSignalKeyTest = (keyRef, keys) => {
|
|
27151
|
+
if (keys.length === 0) return null;
|
|
27152
|
+
let test = null;
|
|
27153
|
+
for (const key of keys) {
|
|
27154
|
+
const literal = typeof key === "number" ? t4.numericLiteral(key) : t4.stringLiteral(String(key));
|
|
27155
|
+
const eq = t4.binaryExpression("===", t4.cloneNode(keyRef, true), literal);
|
|
27156
|
+
test = test ? t4.logicalExpression("||", test, eq) : eq;
|
|
27157
|
+
}
|
|
27158
|
+
return test;
|
|
27159
|
+
};
|
|
27160
|
+
const lowerComputedHookSignalAssignment = (objectName, keyExpr, signalKeys, operator, rightExpr) => {
|
|
27161
|
+
const keyTestKeys = signalKeys.filter(
|
|
27162
|
+
(key) => typeof key === "number" && Number.isFinite(key) || typeof key === "string"
|
|
27163
|
+
);
|
|
27164
|
+
if (keyTestKeys.length === 0) return null;
|
|
27165
|
+
const keyId = genTemp3(ctx, "key");
|
|
27166
|
+
const keyRef = t4.identifier(keyId.name);
|
|
27167
|
+
const memberForAccessor = t4.memberExpression(
|
|
27168
|
+
t4.identifier(objectName),
|
|
27169
|
+
t4.identifier(keyId.name),
|
|
27170
|
+
true
|
|
27171
|
+
);
|
|
27172
|
+
const current = t4.callExpression(t4.cloneNode(memberForAccessor, true), []);
|
|
27173
|
+
const right = lowerExpression2(rightExpr, ctx);
|
|
27174
|
+
const signalWrite = lowerTrackedWriteCall(
|
|
27175
|
+
memberForAccessor,
|
|
27176
|
+
buildTrackedAssignmentNext(operator, current, t4.cloneNode(right, true))
|
|
27177
|
+
);
|
|
27178
|
+
const fallback = t4.assignmentExpression(
|
|
27179
|
+
operator,
|
|
27180
|
+
t4.memberExpression(t4.identifier(objectName), t4.identifier(keyId.name), true),
|
|
27181
|
+
right
|
|
27182
|
+
);
|
|
27183
|
+
const keyTest = buildStaticSignalKeyTest(keyRef, keyTestKeys);
|
|
27184
|
+
if (!keyTest) return null;
|
|
27185
|
+
return t4.callExpression(
|
|
27186
|
+
t4.arrowFunctionExpression(
|
|
27187
|
+
[t4.cloneNode(keyId, true)],
|
|
27188
|
+
t4.conditionalExpression(keyTest, signalWrite, fallback)
|
|
27189
|
+
),
|
|
27190
|
+
[lowerExpression2(keyExpr, ctx)]
|
|
27191
|
+
);
|
|
27192
|
+
};
|
|
27193
|
+
const lowerComputedHookSignalUpdate = (objectName, keyExpr, signalKeys, operator, prefix) => {
|
|
27194
|
+
const keyTestKeys = signalKeys.filter(
|
|
27195
|
+
(key) => typeof key === "number" && Number.isFinite(key) || typeof key === "string"
|
|
27196
|
+
);
|
|
27197
|
+
if (keyTestKeys.length === 0) return null;
|
|
27198
|
+
const keyId = genTemp3(ctx, "key");
|
|
27199
|
+
const keyRef = t4.identifier(keyId.name);
|
|
27200
|
+
const signalUpdate = lowerTrackedUpdateCall(
|
|
27201
|
+
t4.memberExpression(t4.identifier(objectName), t4.identifier(keyId.name), true),
|
|
27202
|
+
operator,
|
|
27203
|
+
prefix
|
|
27204
|
+
);
|
|
27205
|
+
const fallback = t4.updateExpression(
|
|
27206
|
+
operator,
|
|
27207
|
+
t4.memberExpression(t4.identifier(objectName), t4.identifier(keyId.name), true),
|
|
27208
|
+
prefix
|
|
27209
|
+
);
|
|
27210
|
+
const keyTest = buildStaticSignalKeyTest(keyRef, keyTestKeys);
|
|
27211
|
+
if (!keyTest) return null;
|
|
27212
|
+
return t4.callExpression(
|
|
27213
|
+
t4.arrowFunctionExpression(
|
|
27214
|
+
[t4.cloneNode(keyId, true)],
|
|
27215
|
+
t4.conditionalExpression(keyTest, signalUpdate, fallback)
|
|
27216
|
+
),
|
|
27217
|
+
[lowerExpression2(keyExpr, ctx)]
|
|
27218
|
+
);
|
|
27219
|
+
};
|
|
27220
|
+
const lowerTrackedUpdateCall = (callee, operator, prefix) => {
|
|
27221
|
+
const op = operator === "++" ? "+" : "-";
|
|
27222
|
+
const delta = t4.numericLiteral(1);
|
|
27223
|
+
const current = t4.callExpression(t4.cloneNode(callee, true), []);
|
|
27224
|
+
if (!valueUsed) {
|
|
27225
|
+
return t4.callExpression(t4.cloneNode(callee, true), [t4.binaryExpression(op, current, delta)]);
|
|
27226
|
+
}
|
|
27227
|
+
const prevId = genTemp3(ctx, "prev");
|
|
27228
|
+
const prevForSet = t4.identifier(prevId.name);
|
|
27229
|
+
const prevForResult = t4.identifier(prevId.name);
|
|
27230
|
+
return t4.callExpression(
|
|
27231
|
+
t4.arrowFunctionExpression(
|
|
27232
|
+
[t4.cloneNode(prevId, true)],
|
|
27233
|
+
t4.sequenceExpression([
|
|
27234
|
+
t4.callExpression(t4.cloneNode(callee, true), [t4.binaryExpression(op, prevForSet, delta)]),
|
|
27235
|
+
prefix ? t4.binaryExpression(op, prevForResult, t4.numericLiteral(1)) : prevForResult
|
|
27236
|
+
])
|
|
27237
|
+
),
|
|
27238
|
+
[current]
|
|
27239
|
+
);
|
|
27240
|
+
};
|
|
26734
27241
|
const lowerBlocksToStatements = (blocks) => {
|
|
26735
27242
|
const stmts = [];
|
|
26736
27243
|
for (const block of blocks) {
|
|
@@ -26900,6 +27407,24 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
26900
27407
|
expr.arguments,
|
|
26901
27408
|
(arg) => arg.kind === "ArrowFunction" || arg.kind === "FunctionExpression" ? withNonReactiveScope(ctx, () => lowerExpression2(arg, ctx)) : lowerExpression2(arg, ctx)
|
|
26902
27409
|
);
|
|
27410
|
+
const includeDevtools = ctx.options?.dev !== false;
|
|
27411
|
+
if (includeDevtools && expr.loc) {
|
|
27412
|
+
const source = `${ctx.options?.filename ?? ""}:${expr.loc.start.line}:${expr.loc.start.column}`;
|
|
27413
|
+
const sourceProp = t4.objectProperty(
|
|
27414
|
+
t4.identifier("devToolsSource"),
|
|
27415
|
+
t4.stringLiteral(source)
|
|
27416
|
+
);
|
|
27417
|
+
if (args.length === 1) {
|
|
27418
|
+
args.push(t4.objectExpression([sourceProp]));
|
|
27419
|
+
} else if (args.length > 1 && t4.isObjectExpression(args[1])) {
|
|
27420
|
+
const hasSourceProp = args[1].properties.some(
|
|
27421
|
+
(prop) => t4.isObjectProperty(prop) && t4.isIdentifier(prop.key) && prop.key.name === "devToolsSource"
|
|
27422
|
+
);
|
|
27423
|
+
if (!hasSourceProp) {
|
|
27424
|
+
args[1].properties.push(sourceProp);
|
|
27425
|
+
}
|
|
27426
|
+
}
|
|
27427
|
+
}
|
|
26903
27428
|
if (ctx.inModule) {
|
|
26904
27429
|
ctx.helpersUsed.add("effect");
|
|
26905
27430
|
return t4.callExpression(t4.identifier(RUNTIME_ALIASES.effect), args);
|
|
@@ -27207,59 +27732,42 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
27207
27732
|
expr.left.computed,
|
|
27208
27733
|
expr.left.optional
|
|
27209
27734
|
);
|
|
27210
|
-
const current = t4.callExpression(member, []);
|
|
27735
|
+
const current = t4.callExpression(t4.cloneNode(member, true), []);
|
|
27211
27736
|
const right = lowerExpression2(expr.right, ctx);
|
|
27212
|
-
|
|
27213
|
-
|
|
27214
|
-
|
|
27215
|
-
|
|
27216
|
-
|
|
27217
|
-
|
|
27218
|
-
|
|
27219
|
-
|
|
27220
|
-
|
|
27221
|
-
next = t4.binaryExpression("-", current, right);
|
|
27222
|
-
break;
|
|
27223
|
-
case "*=":
|
|
27224
|
-
next = t4.binaryExpression("*", current, right);
|
|
27225
|
-
break;
|
|
27226
|
-
case "/=":
|
|
27227
|
-
next = t4.binaryExpression("/", current, right);
|
|
27228
|
-
break;
|
|
27229
|
-
default:
|
|
27230
|
-
next = right;
|
|
27737
|
+
const next = buildTrackedAssignmentNext(expr.operator, current, right);
|
|
27738
|
+
return lowerTrackedWriteCall(member, next);
|
|
27739
|
+
}
|
|
27740
|
+
if (expr.left.computed) {
|
|
27741
|
+
const signalKeys = [];
|
|
27742
|
+
if (info?.objectProps) {
|
|
27743
|
+
for (const [key, accessorKind] of info.objectProps.entries()) {
|
|
27744
|
+
if (accessorKind === "signal") signalKeys.push(key);
|
|
27745
|
+
}
|
|
27231
27746
|
}
|
|
27232
|
-
|
|
27747
|
+
if (info?.arrayProps) {
|
|
27748
|
+
for (const [key, accessorKind] of info.arrayProps.entries()) {
|
|
27749
|
+
if (accessorKind === "signal") signalKeys.push(key);
|
|
27750
|
+
}
|
|
27751
|
+
}
|
|
27752
|
+
const lowered = lowerComputedHookSignalAssignment(
|
|
27753
|
+
deSSAVarName(expr.left.object.name),
|
|
27754
|
+
expr.left.property,
|
|
27755
|
+
signalKeys,
|
|
27756
|
+
expr.operator,
|
|
27757
|
+
expr.right
|
|
27758
|
+
);
|
|
27759
|
+
if (lowered) return lowered;
|
|
27233
27760
|
}
|
|
27234
27761
|
}
|
|
27235
27762
|
}
|
|
27236
27763
|
if (expr.left.kind === "Identifier") {
|
|
27237
27764
|
const baseName2 = deSSAVarName(expr.left.name);
|
|
27238
27765
|
if (ctx.trackedVars.has(baseName2)) {
|
|
27239
|
-
const
|
|
27766
|
+
const callee = t4.identifier(baseName2);
|
|
27240
27767
|
const current = t4.callExpression(t4.identifier(baseName2), []);
|
|
27241
27768
|
const right = lowerExpression2(expr.right, ctx);
|
|
27242
|
-
|
|
27243
|
-
|
|
27244
|
-
case "=":
|
|
27245
|
-
next = right;
|
|
27246
|
-
break;
|
|
27247
|
-
case "+=":
|
|
27248
|
-
next = t4.binaryExpression("+", current, right);
|
|
27249
|
-
break;
|
|
27250
|
-
case "-=":
|
|
27251
|
-
next = t4.binaryExpression("-", current, right);
|
|
27252
|
-
break;
|
|
27253
|
-
case "*=":
|
|
27254
|
-
next = t4.binaryExpression("*", current, right);
|
|
27255
|
-
break;
|
|
27256
|
-
case "/=":
|
|
27257
|
-
next = t4.binaryExpression("/", current, right);
|
|
27258
|
-
break;
|
|
27259
|
-
default:
|
|
27260
|
-
next = right;
|
|
27261
|
-
}
|
|
27262
|
-
return t4.callExpression(id, [next]);
|
|
27769
|
+
const next = buildTrackedAssignmentNext(expr.operator, current, right);
|
|
27770
|
+
return lowerTrackedWriteCall(callee, next);
|
|
27263
27771
|
}
|
|
27264
27772
|
}
|
|
27265
27773
|
return t4.assignmentExpression(
|
|
@@ -27291,21 +27799,35 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
27291
27799
|
expr.argument.computed,
|
|
27292
27800
|
expr.argument.optional
|
|
27293
27801
|
);
|
|
27294
|
-
|
|
27295
|
-
|
|
27296
|
-
|
|
27297
|
-
|
|
27802
|
+
return lowerTrackedUpdateCall(member, expr.operator, expr.prefix);
|
|
27803
|
+
}
|
|
27804
|
+
if (expr.argument.computed) {
|
|
27805
|
+
const signalKeys = [];
|
|
27806
|
+
if (info?.objectProps) {
|
|
27807
|
+
for (const [key, accessorKind] of info.objectProps.entries()) {
|
|
27808
|
+
if (accessorKind === "signal") signalKeys.push(key);
|
|
27809
|
+
}
|
|
27810
|
+
}
|
|
27811
|
+
if (info?.arrayProps) {
|
|
27812
|
+
for (const [key, accessorKind] of info.arrayProps.entries()) {
|
|
27813
|
+
if (accessorKind === "signal") signalKeys.push(key);
|
|
27814
|
+
}
|
|
27815
|
+
}
|
|
27816
|
+
const lowered = lowerComputedHookSignalUpdate(
|
|
27817
|
+
deSSAVarName(expr.argument.object.name),
|
|
27818
|
+
expr.argument.property,
|
|
27819
|
+
signalKeys,
|
|
27820
|
+
expr.operator,
|
|
27821
|
+
expr.prefix
|
|
27822
|
+
);
|
|
27823
|
+
if (lowered) return lowered;
|
|
27298
27824
|
}
|
|
27299
27825
|
}
|
|
27300
27826
|
}
|
|
27301
27827
|
if (expr.argument.kind === "Identifier") {
|
|
27302
27828
|
const baseName2 = deSSAVarName(expr.argument.name);
|
|
27303
27829
|
if (ctx.trackedVars.has(baseName2)) {
|
|
27304
|
-
|
|
27305
|
-
const current = t4.callExpression(t4.identifier(baseName2), []);
|
|
27306
|
-
const delta = t4.numericLiteral(1);
|
|
27307
|
-
const next = expr.operator === "++" ? t4.binaryExpression("+", current, delta) : t4.binaryExpression("-", current, delta);
|
|
27308
|
-
return t4.callExpression(id, [next]);
|
|
27830
|
+
return lowerTrackedUpdateCall(t4.identifier(baseName2), expr.operator, expr.prefix);
|
|
27309
27831
|
}
|
|
27310
27832
|
}
|
|
27311
27833
|
return t4.updateExpression(
|
|
@@ -27327,7 +27849,11 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
27327
27849
|
case "NewExpression":
|
|
27328
27850
|
return t4.newExpression(lowerExpression2(expr.callee, ctx), lowerCallArguments(expr.arguments));
|
|
27329
27851
|
case "SequenceExpression":
|
|
27330
|
-
return t4.sequenceExpression(
|
|
27852
|
+
return t4.sequenceExpression(
|
|
27853
|
+
expr.expressions.map(
|
|
27854
|
+
(e, index) => lowerExpression2(e, ctx, index === expr.expressions.length - 1 ? valueUsed : false)
|
|
27855
|
+
)
|
|
27856
|
+
);
|
|
27331
27857
|
case "YieldExpression":
|
|
27332
27858
|
return t4.yieldExpression(
|
|
27333
27859
|
expr.argument ? lowerExpression2(expr.argument, ctx) : null,
|
|
@@ -27785,16 +28311,17 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
27785
28311
|
const hasEventOptions = binding.eventOptions && (binding.eventOptions.capture || binding.eventOptions.passive || binding.eventOptions.once);
|
|
27786
28312
|
const isDelegated = DelegatedEvents.has(eventName) && !hasEventOptions;
|
|
27787
28313
|
if (binding.resumable && !hasEventOptions) {
|
|
27788
|
-
emitResumableEventBinding(
|
|
28314
|
+
const emitted = emitResumableEventBinding(
|
|
27789
28315
|
targetId,
|
|
27790
28316
|
eventName,
|
|
27791
28317
|
binding.expr,
|
|
27792
28318
|
statements,
|
|
27793
28319
|
ctx,
|
|
27794
28320
|
containingRegion,
|
|
27795
|
-
createResumableEventBindingOps()
|
|
28321
|
+
createResumableEventBindingOps(),
|
|
28322
|
+
{ explicit: binding.resumableExplicit === true }
|
|
27796
28323
|
);
|
|
27797
|
-
continue;
|
|
28324
|
+
if (emitted) continue;
|
|
27798
28325
|
}
|
|
27799
28326
|
const hirDataBinding = isDelegated && binding.expr ? extractDelegatedEventDataFromHIR(binding.expr, ctx) : null;
|
|
27800
28327
|
if (hirDataBinding) {
|
|
@@ -27836,34 +28363,24 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
27836
28363
|
const isFn = t4.isArrowFunctionExpression(valueExpr) || t4.isFunctionExpression(valueExpr);
|
|
27837
28364
|
const ensureHandlerParam = (fn) => {
|
|
27838
28365
|
if (t4.isArrowFunctionExpression(fn)) {
|
|
27839
|
-
|
|
27840
|
-
return t4.arrowFunctionExpression([eventParam], fn.body, fn.async);
|
|
28366
|
+
return fn;
|
|
27841
28367
|
}
|
|
27842
28368
|
if (t4.isFunctionExpression(fn)) {
|
|
27843
|
-
|
|
27844
|
-
return t4.functionExpression(fn.id, [eventParam], fn.body, fn.generator, fn.async);
|
|
28369
|
+
return fn;
|
|
27845
28370
|
}
|
|
27846
28371
|
if (t4.isIdentifier(fn) || t4.isMemberExpression(fn)) {
|
|
27847
28372
|
return fn;
|
|
27848
28373
|
}
|
|
27849
|
-
if (t4.isCallExpression(fn) && fn.arguments.length === 0 && (t4.isIdentifier(fn.callee) || t4.isMemberExpression(fn.callee))) {
|
|
27850
|
-
return fn.callee;
|
|
27851
|
-
}
|
|
27852
28374
|
return t4.functionExpression(
|
|
27853
28375
|
null,
|
|
27854
|
-
[
|
|
27855
|
-
t4.blockStatement([
|
|
27856
|
-
t4.returnStatement(
|
|
27857
|
-
t4.callExpression(
|
|
27858
|
-
t4.memberExpression(fn, t4.identifier("call")),
|
|
27859
|
-
[t4.thisExpression(), eventParam]
|
|
27860
|
-
)
|
|
27861
|
-
)
|
|
27862
|
-
])
|
|
28376
|
+
[],
|
|
28377
|
+
t4.blockStatement([t4.returnStatement(fn)])
|
|
27863
28378
|
);
|
|
27864
28379
|
};
|
|
27865
28380
|
const handlerExpr = !isFn && shouldWrapHandler ? t4.arrowFunctionExpression([], valueExpr) : ensureHandlerParam(valueExpr);
|
|
27866
|
-
let dataBinding = isDelegated && !shouldWrapHandler ? extractDelegatedEventData(valueExpr, t4
|
|
28381
|
+
let dataBinding = isDelegated && !shouldWrapHandler ? extractDelegatedEventData(valueExpr, t4, {
|
|
28382
|
+
isKnownHandlerIdentifier: (name) => ctx.functionVars?.has(deSSAVarName(name)) ?? false
|
|
28383
|
+
}) : null;
|
|
27867
28384
|
if (dataBinding && t4.isIdentifier(dataBinding.handler)) {
|
|
27868
28385
|
const handlerName = dataBinding.handler.name;
|
|
27869
28386
|
if (ctx.signalVars?.has(handlerName) || ctx.memoVars?.has(handlerName) || ctx.aliasVars?.has(handlerName) || ctx.storeVars?.has(handlerName) || ctx.trackedVars.has(handlerName)) {
|
|
@@ -27875,8 +28392,6 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
27875
28392
|
let handlerName = null;
|
|
27876
28393
|
if (t4.isIdentifier(valueExpr)) {
|
|
27877
28394
|
handlerName = valueExpr.name;
|
|
27878
|
-
} else if (t4.isCallExpression(valueExpr) && valueExpr.arguments.length === 0 && t4.isIdentifier(valueExpr.callee)) {
|
|
27879
|
-
handlerName = valueExpr.callee.name;
|
|
27880
28395
|
}
|
|
27881
28396
|
const handlerForCall = handlerName ? t4.identifier(handlerName) : t4.cloneNode(valueExpr, true);
|
|
27882
28397
|
const finalHandler = !isFn && shouldWrapHandler ? t4.functionExpression(
|
|
@@ -27892,9 +28407,6 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
27892
28407
|
])
|
|
27893
28408
|
) : handlerExpr;
|
|
27894
28409
|
const normalizeHandler = (expr) => {
|
|
27895
|
-
if (t4.isCallExpression(expr) && (t4.isIdentifier(expr.callee) || t4.isMemberExpression(expr.callee))) {
|
|
27896
|
-
return expr.callee;
|
|
27897
|
-
}
|
|
27898
28410
|
return expr;
|
|
27899
28411
|
};
|
|
27900
28412
|
const normalizedDataHandler = dataBinding !== null ? normalizeHandler(
|
|
@@ -28568,10 +29080,13 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28568
29080
|
}
|
|
28569
29081
|
return false;
|
|
28570
29082
|
};
|
|
28571
|
-
function hasNodeMatch(nodes, predicate) {
|
|
29083
|
+
function hasNodeMatch(nodes, predicate, options) {
|
|
28572
29084
|
let found = false;
|
|
28573
|
-
const visit = (node) => {
|
|
29085
|
+
const visit = (node, isRoot = false) => {
|
|
28574
29086
|
if (!node || found) return;
|
|
29087
|
+
if (!isRoot && options?.skipNestedFunctions && (t4.isFunctionExpression(node) || t4.isArrowFunctionExpression(node) || t4.isFunctionDeclaration(node) || t4.isObjectMethod(node) || t4.isClassMethod(node))) {
|
|
29088
|
+
return;
|
|
29089
|
+
}
|
|
28575
29090
|
if (predicate(node)) {
|
|
28576
29091
|
found = true;
|
|
28577
29092
|
return;
|
|
@@ -28594,17 +29109,134 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28594
29109
|
}
|
|
28595
29110
|
};
|
|
28596
29111
|
for (const node of nodes) {
|
|
28597
|
-
visit(node);
|
|
29112
|
+
visit(node, true);
|
|
28598
29113
|
if (found) return true;
|
|
28599
29114
|
}
|
|
28600
29115
|
return found;
|
|
28601
29116
|
}
|
|
28602
29117
|
const containsReturnStatement = (nodes) => hasNodeMatch(nodes, (node) => t4.isReturnStatement(node));
|
|
28603
|
-
const
|
|
28604
|
-
|
|
28605
|
-
|
|
28606
|
-
|
|
28607
|
-
|
|
29118
|
+
const getMemberRootIdentifier = (expr) => {
|
|
29119
|
+
let current = expr.object;
|
|
29120
|
+
while (t4.isMemberExpression(current) || t4.isOptionalMemberExpression(current)) {
|
|
29121
|
+
current = current.object;
|
|
29122
|
+
}
|
|
29123
|
+
return t4.isIdentifier(current) ? current : null;
|
|
29124
|
+
};
|
|
29125
|
+
const containsReactiveAccessorRead = (nodes, options) => hasNodeMatch(
|
|
29126
|
+
nodes,
|
|
29127
|
+
(node) => {
|
|
29128
|
+
if (t4.isCallExpression(node) || t4.isOptionalCallExpression(node)) {
|
|
29129
|
+
const callee = node.callee;
|
|
29130
|
+
return t4.isIdentifier(callee) && reactiveAccessorNames.has(callee.name);
|
|
29131
|
+
}
|
|
29132
|
+
if (t4.isMemberExpression(node) || t4.isOptionalMemberExpression(node)) {
|
|
29133
|
+
const root = getMemberRootIdentifier(node);
|
|
29134
|
+
return !!(root && reactiveAccessorNames.has(root.name));
|
|
29135
|
+
}
|
|
29136
|
+
return false;
|
|
29137
|
+
},
|
|
29138
|
+
options
|
|
29139
|
+
);
|
|
29140
|
+
const containsReactiveControlFlowRead = (nodes) => hasNodeMatch(
|
|
29141
|
+
nodes,
|
|
29142
|
+
(node) => {
|
|
29143
|
+
if (t4.isIfStatement(node)) {
|
|
29144
|
+
return containsReactiveAccessorRead([node.test], { skipNestedFunctions: true });
|
|
29145
|
+
}
|
|
29146
|
+
if (t4.isSwitchStatement(node)) {
|
|
29147
|
+
return containsReactiveAccessorRead([node.discriminant], { skipNestedFunctions: true });
|
|
29148
|
+
}
|
|
29149
|
+
if (t4.isConditionalExpression(node)) {
|
|
29150
|
+
return containsReactiveAccessorRead([node.test], { skipNestedFunctions: true });
|
|
29151
|
+
}
|
|
29152
|
+
if (t4.isWhileStatement(node) || t4.isDoWhileStatement(node)) {
|
|
29153
|
+
return containsReactiveAccessorRead([node.test], { skipNestedFunctions: true });
|
|
29154
|
+
}
|
|
29155
|
+
if (t4.isForStatement(node)) {
|
|
29156
|
+
const parts = [];
|
|
29157
|
+
if (node.init) parts.push(node.init);
|
|
29158
|
+
if (node.test) parts.push(node.test);
|
|
29159
|
+
if (node.update) parts.push(node.update);
|
|
29160
|
+
return parts.length > 0 && containsReactiveAccessorRead(parts, { skipNestedFunctions: true });
|
|
29161
|
+
}
|
|
29162
|
+
if (t4.isForOfStatement(node) || t4.isForInStatement(node)) {
|
|
29163
|
+
return containsReactiveAccessorRead([node.right], { skipNestedFunctions: true });
|
|
29164
|
+
}
|
|
29165
|
+
return false;
|
|
29166
|
+
},
|
|
29167
|
+
{ skipNestedFunctions: true }
|
|
29168
|
+
);
|
|
29169
|
+
const hasRiskyBranchControlFlow = (stmts) => {
|
|
29170
|
+
if (stmts.length === 0) return false;
|
|
29171
|
+
return containsReactiveControlFlowRead(stmts);
|
|
29172
|
+
};
|
|
29173
|
+
const isJSXLikeNode = (node) => !!node && (t4.isJSXElement(node) || t4.isJSXFragment(node));
|
|
29174
|
+
const isStoreSourceExpression = (expr) => {
|
|
29175
|
+
if (t4.isIdentifier(expr)) {
|
|
29176
|
+
return !!ctx.storeVars?.has(expr.name);
|
|
29177
|
+
}
|
|
29178
|
+
if (t4.isMemberExpression(expr) || t4.isOptionalMemberExpression(expr)) {
|
|
29179
|
+
const root = getMemberRootIdentifier(expr);
|
|
29180
|
+
return !!(root && ctx.storeVars?.has(root.name));
|
|
29181
|
+
}
|
|
29182
|
+
return false;
|
|
29183
|
+
};
|
|
29184
|
+
const hasRiskyStoreDestructureRead = (stmt) => {
|
|
29185
|
+
if (t4.isVariableDeclaration(stmt)) {
|
|
29186
|
+
for (const decl of stmt.declarations) {
|
|
29187
|
+
if (!decl.init) continue;
|
|
29188
|
+
const hasPattern = t4.isObjectPattern(decl.id) || t4.isArrayPattern(decl.id);
|
|
29189
|
+
if (!hasPattern) continue;
|
|
29190
|
+
if (isStoreSourceExpression(decl.init)) {
|
|
29191
|
+
return true;
|
|
29192
|
+
}
|
|
29193
|
+
}
|
|
29194
|
+
return false;
|
|
29195
|
+
}
|
|
29196
|
+
if (t4.isExpressionStatement(stmt) && t4.isAssignmentExpression(stmt.expression)) {
|
|
29197
|
+
const assignment = stmt.expression;
|
|
29198
|
+
const isPatternLhs = t4.isObjectPattern(assignment.left) || t4.isArrayPattern(assignment.left);
|
|
29199
|
+
if (!isPatternLhs) return false;
|
|
29200
|
+
return isStoreSourceExpression(assignment.right);
|
|
29201
|
+
}
|
|
29202
|
+
return false;
|
|
29203
|
+
};
|
|
29204
|
+
const hasRiskyBranchPreludeReads = (stmts) => {
|
|
29205
|
+
for (const stmt of stmts) {
|
|
29206
|
+
if (hasRiskyStoreDestructureRead(stmt)) {
|
|
29207
|
+
return true;
|
|
29208
|
+
}
|
|
29209
|
+
if (t4.isReturnStatement(stmt)) {
|
|
29210
|
+
const arg = stmt.argument;
|
|
29211
|
+
if (!arg || isJSXLikeNode(arg)) continue;
|
|
29212
|
+
if (containsReactiveAccessorRead([arg], { skipNestedFunctions: true })) {
|
|
29213
|
+
return true;
|
|
29214
|
+
}
|
|
29215
|
+
continue;
|
|
29216
|
+
}
|
|
29217
|
+
if (containsReactiveAccessorRead([stmt], { skipNestedFunctions: true })) {
|
|
29218
|
+
return true;
|
|
29219
|
+
}
|
|
29220
|
+
}
|
|
29221
|
+
return false;
|
|
29222
|
+
};
|
|
29223
|
+
const hasRiskyImmediateInvocationReads = (stmts) => hasNodeMatch(
|
|
29224
|
+
stmts,
|
|
29225
|
+
(node) => {
|
|
29226
|
+
if (!t4.isCallExpression(node) && !t4.isOptionalCallExpression(node)) return false;
|
|
29227
|
+
const callee = node.callee;
|
|
29228
|
+
if (!t4.isFunctionExpression(callee) && !t4.isArrowFunctionExpression(callee)) {
|
|
29229
|
+
return false;
|
|
29230
|
+
}
|
|
29231
|
+
const bodyNodes = t4.isBlockStatement(callee.body) ? callee.body.body : [callee.body];
|
|
29232
|
+
return containsReactiveAccessorRead(bodyNodes, { skipNestedFunctions: true });
|
|
29233
|
+
},
|
|
29234
|
+
{ skipNestedFunctions: true }
|
|
29235
|
+
);
|
|
29236
|
+
const needsTrackedBranchReads = (stmts) => {
|
|
29237
|
+
if (stmts.length === 0) return false;
|
|
29238
|
+
return hasRiskyBranchControlFlow(stmts) || hasRiskyBranchPreludeReads(stmts) || hasRiskyImmediateInvocationReads(stmts);
|
|
29239
|
+
};
|
|
28608
29240
|
const emitControlFlowFallbackWarning = (node, kind) => {
|
|
28609
29241
|
const onWarn = ctx.options?.onWarn;
|
|
28610
29242
|
if (!onWarn) return;
|
|
@@ -28673,7 +29305,7 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28673
29305
|
}
|
|
28674
29306
|
return found;
|
|
28675
29307
|
}
|
|
28676
|
-
function buildConditionalBindingExpr(testExpr, trueFn, falseFn) {
|
|
29308
|
+
function buildConditionalBindingExpr(testExpr, trueFn, falseFn, options) {
|
|
28677
29309
|
ctx.helpersUsed.add("conditional");
|
|
28678
29310
|
ctx.helpersUsed.add("createElement");
|
|
28679
29311
|
ctx.helpersUsed.add("onDestroy");
|
|
@@ -28684,6 +29316,16 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28684
29316
|
t4.identifier(RUNTIME_ALIASES.createElement),
|
|
28685
29317
|
falseFn
|
|
28686
29318
|
];
|
|
29319
|
+
if (options?.trackBranchReads) {
|
|
29320
|
+
const undefinedExpr = t4.unaryExpression("void", t4.numericLiteral(0));
|
|
29321
|
+
args.push(
|
|
29322
|
+
undefinedExpr,
|
|
29323
|
+
t4.cloneNode(undefinedExpr),
|
|
29324
|
+
t4.objectExpression([
|
|
29325
|
+
t4.objectProperty(t4.identifier("trackBranchReads"), t4.booleanLiteral(true))
|
|
29326
|
+
])
|
|
29327
|
+
);
|
|
29328
|
+
}
|
|
28687
29329
|
const bindingCall = t4.callExpression(t4.identifier(RUNTIME_ALIASES.conditional), args);
|
|
28688
29330
|
return t4.callExpression(
|
|
28689
29331
|
t4.arrowFunctionExpression(
|
|
@@ -28717,7 +29359,13 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28717
29359
|
const trueFn = buildBranchFunction(consequentStmts);
|
|
28718
29360
|
const falseFn = alternateStmts ? buildBranchFunction(alternateStmts) : null;
|
|
28719
29361
|
if (!trueFn || !falseFn) return null;
|
|
28720
|
-
|
|
29362
|
+
const shouldTrackBranchReads = needsTrackedBranchReads(consequentStmts) || (alternateStmts ? needsTrackedBranchReads(alternateStmts) : false);
|
|
29363
|
+
return buildConditionalBindingExpr(
|
|
29364
|
+
ifStmt.test,
|
|
29365
|
+
trueFn,
|
|
29366
|
+
falseFn,
|
|
29367
|
+
shouldTrackBranchReads ? { trackBranchReads: true } : void 0
|
|
29368
|
+
);
|
|
28721
29369
|
}
|
|
28722
29370
|
function isSupportedSwitchDiscriminant(_expr) {
|
|
28723
29371
|
return true;
|
|
@@ -28810,10 +29458,13 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28810
29458
|
),
|
|
28811
29459
|
[]
|
|
28812
29460
|
);
|
|
29461
|
+
let currentExprNeedsTrackedBranchReads = needsTrackedBranchReads(fallbackStatements);
|
|
28813
29462
|
for (let i = branches.length - 1; i >= 0; i--) {
|
|
28814
29463
|
const branch = branches[i];
|
|
28815
29464
|
const trueFn = buildBranchFunction(branch.statements, { disallowRenderHooks: true });
|
|
28816
29465
|
if (!trueFn) return null;
|
|
29466
|
+
const trueBranchNeedsTrackedBranchReads = needsTrackedBranchReads(branch.statements);
|
|
29467
|
+
const trackBranchReads = trueBranchNeedsTrackedBranchReads || currentExprNeedsTrackedBranchReads;
|
|
28817
29468
|
const falseFn = t4.arrowFunctionExpression(
|
|
28818
29469
|
[],
|
|
28819
29470
|
t4.blockStatement([t4.returnStatement(currentExpr)])
|
|
@@ -28830,7 +29481,13 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28830
29481
|
(acc, expr) => t4.logicalExpression("||", acc, expr),
|
|
28831
29482
|
comparisons[0]
|
|
28832
29483
|
);
|
|
28833
|
-
currentExpr = buildConditionalBindingExpr(
|
|
29484
|
+
currentExpr = buildConditionalBindingExpr(
|
|
29485
|
+
testExpr,
|
|
29486
|
+
trueFn,
|
|
29487
|
+
falseFn,
|
|
29488
|
+
trackBranchReads ? { trackBranchReads: true } : void 0
|
|
29489
|
+
);
|
|
29490
|
+
currentExprNeedsTrackedBranchReads = trackBranchReads;
|
|
28834
29491
|
}
|
|
28835
29492
|
return t4.callExpression(
|
|
28836
29493
|
t4.arrowFunctionExpression(
|
|
@@ -30200,11 +30857,27 @@ function optimizeReactiveBlock(block, reactive, purity, options) {
|
|
|
30200
30857
|
const constArrays = /* @__PURE__ */ new Map();
|
|
30201
30858
|
const cseMap = /* @__PURE__ */ new Map();
|
|
30202
30859
|
const instructions = [];
|
|
30860
|
+
const deleteByBase = (map, name) => {
|
|
30861
|
+
const base = getSSABaseName(name);
|
|
30862
|
+
for (const key of Array.from(map.keys())) {
|
|
30863
|
+
if (getSSABaseName(key) === base) {
|
|
30864
|
+
map.delete(key);
|
|
30865
|
+
}
|
|
30866
|
+
}
|
|
30867
|
+
};
|
|
30203
30868
|
const invalidateCSE = (name) => {
|
|
30869
|
+
const base = getSSABaseName(name);
|
|
30204
30870
|
const toDelete = [];
|
|
30205
30871
|
for (const [hash, entry] of cseMap.entries()) {
|
|
30206
|
-
if (entry.name ===
|
|
30872
|
+
if (getSSABaseName(entry.name) === base) {
|
|
30207
30873
|
toDelete.push(hash);
|
|
30874
|
+
continue;
|
|
30875
|
+
}
|
|
30876
|
+
for (const dep of entry.deps) {
|
|
30877
|
+
if (getSSABaseName(dep) === base) {
|
|
30878
|
+
toDelete.push(hash);
|
|
30879
|
+
break;
|
|
30880
|
+
}
|
|
30208
30881
|
}
|
|
30209
30882
|
}
|
|
30210
30883
|
toDelete.forEach((hash) => cseMap.delete(hash));
|
|
@@ -30214,22 +30887,22 @@ function optimizeReactiveBlock(block, reactive, purity, options) {
|
|
|
30214
30887
|
const target = instr.target.name;
|
|
30215
30888
|
const declKind = instr.declarationKind;
|
|
30216
30889
|
invalidateCSE(target);
|
|
30217
|
-
constants
|
|
30218
|
-
constObjects
|
|
30219
|
-
constArrays
|
|
30890
|
+
deleteByBase(constants, target);
|
|
30891
|
+
deleteByBase(constObjects, target);
|
|
30892
|
+
deleteByBase(constArrays, target);
|
|
30220
30893
|
const sideWrites = collectWriteTargets(instr.value);
|
|
30221
30894
|
for (const name of sideWrites) {
|
|
30222
30895
|
if (name !== target) {
|
|
30223
|
-
constants
|
|
30896
|
+
deleteByBase(constants, name);
|
|
30224
30897
|
invalidateCSE(name);
|
|
30225
30898
|
}
|
|
30226
|
-
constObjects
|
|
30227
|
-
constArrays
|
|
30899
|
+
deleteByBase(constObjects, name);
|
|
30900
|
+
deleteByBase(constArrays, name);
|
|
30228
30901
|
}
|
|
30229
30902
|
const memberCalls = collectMemberCallTargets(instr.value);
|
|
30230
30903
|
for (const name of memberCalls) {
|
|
30231
|
-
constObjects
|
|
30232
|
-
constArrays
|
|
30904
|
+
deleteByBase(constObjects, name);
|
|
30905
|
+
deleteByBase(constArrays, name);
|
|
30233
30906
|
}
|
|
30234
30907
|
const dependsOnReactiveValue = expressionDependsOnReactive(instr.value, reactive);
|
|
30235
30908
|
let value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, options, constObjects, constArrays);
|
|
@@ -30269,15 +30942,15 @@ function optimizeReactiveBlock(block, reactive, purity, options) {
|
|
|
30269
30942
|
if (instr.kind === "Expression") {
|
|
30270
30943
|
const writes = collectWriteTargets(instr.value);
|
|
30271
30944
|
for (const name of writes) {
|
|
30272
|
-
constants
|
|
30945
|
+
deleteByBase(constants, name);
|
|
30273
30946
|
invalidateCSE(name);
|
|
30274
|
-
constObjects
|
|
30275
|
-
constArrays
|
|
30947
|
+
deleteByBase(constObjects, name);
|
|
30948
|
+
deleteByBase(constArrays, name);
|
|
30276
30949
|
}
|
|
30277
30950
|
const memberCalls = collectMemberCallTargets(instr.value);
|
|
30278
30951
|
for (const name of memberCalls) {
|
|
30279
|
-
constObjects
|
|
30280
|
-
constArrays
|
|
30952
|
+
deleteByBase(constObjects, name);
|
|
30953
|
+
deleteByBase(constArrays, name);
|
|
30281
30954
|
}
|
|
30282
30955
|
const dependsOnReactiveValue = expressionDependsOnReactive(instr.value, reactive);
|
|
30283
30956
|
const value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, options, constObjects, constArrays);
|
|
@@ -30927,6 +31600,8 @@ function collectWriteTargets(expr) {
|
|
|
30927
31600
|
} else if (left.kind === "MemberExpression" || left.kind === "OptionalMemberExpression") {
|
|
30928
31601
|
const base = getMemberBaseIdentifier(left);
|
|
30929
31602
|
if (base) writes.add(base.name);
|
|
31603
|
+
visit(left.object);
|
|
31604
|
+
if (left.computed) visit(left.property);
|
|
30930
31605
|
} else {
|
|
30931
31606
|
visit(left);
|
|
30932
31607
|
}
|
|
@@ -30943,8 +31618,10 @@ function collectWriteTargets(expr) {
|
|
|
30943
31618
|
const base = getMemberBaseIdentifier(arg);
|
|
30944
31619
|
if (base) {
|
|
30945
31620
|
writes.add(base.name);
|
|
30946
|
-
return;
|
|
30947
31621
|
}
|
|
31622
|
+
visit(arg.object);
|
|
31623
|
+
if (arg.computed) visit(arg.property);
|
|
31624
|
+
return;
|
|
30948
31625
|
}
|
|
30949
31626
|
visit(arg);
|
|
30950
31627
|
return;
|
|
@@ -31250,6 +31927,16 @@ function propagateConstants(fn, options) {
|
|
|
31250
31927
|
}
|
|
31251
31928
|
function computeConstantMap(fn) {
|
|
31252
31929
|
const constants = /* @__PURE__ */ new Map();
|
|
31930
|
+
const invalidateWrittenName = (writtenName) => {
|
|
31931
|
+
const writtenBase = getSSABaseName(writtenName);
|
|
31932
|
+
let removed = false;
|
|
31933
|
+
for (const constantName of Array.from(constants.keys())) {
|
|
31934
|
+
if (constantName === writtenName || getSSABaseName(constantName) === writtenBase) {
|
|
31935
|
+
removed = constants.delete(constantName) || removed;
|
|
31936
|
+
}
|
|
31937
|
+
}
|
|
31938
|
+
return removed;
|
|
31939
|
+
};
|
|
31253
31940
|
let changed = true;
|
|
31254
31941
|
let iterations = 0;
|
|
31255
31942
|
const maxIterations = 10;
|
|
@@ -31258,6 +31945,14 @@ function computeConstantMap(fn) {
|
|
|
31258
31945
|
changed = false;
|
|
31259
31946
|
for (const block of fn.blocks) {
|
|
31260
31947
|
for (const instr of block.instructions) {
|
|
31948
|
+
if (instr.kind === "Assign" || instr.kind === "Expression") {
|
|
31949
|
+
const writes = collectWriteTargets(instr.value);
|
|
31950
|
+
for (const writtenName of writes) {
|
|
31951
|
+
if (invalidateWrittenName(writtenName)) {
|
|
31952
|
+
changed = true;
|
|
31953
|
+
}
|
|
31954
|
+
}
|
|
31955
|
+
}
|
|
31261
31956
|
if (instr.kind === "Assign") {
|
|
31262
31957
|
const value = evaluateConstant(instr.value, constants);
|
|
31263
31958
|
if (value !== UNKNOWN_CONST) {
|
|
@@ -33179,8 +33874,52 @@ function shouldSuppressWarning(suppressions, code, line) {
|
|
|
33179
33874
|
});
|
|
33180
33875
|
}
|
|
33181
33876
|
var DEFAULT_ERROR_WARNING_CODES = /* @__PURE__ */ new Set(["FICT-R004"]);
|
|
33877
|
+
var STRICT_REACTIVITY_WARNING_CODES = /* @__PURE__ */ new Set(["FICT-R003", "FICT-R006"]);
|
|
33878
|
+
var STRICT_GUARANTEE_WARNING_CODES = /* @__PURE__ */ new Set([
|
|
33879
|
+
"FICT-P001",
|
|
33880
|
+
"FICT-P002",
|
|
33881
|
+
"FICT-P003",
|
|
33882
|
+
"FICT-P004",
|
|
33883
|
+
"FICT-P005",
|
|
33884
|
+
"FICT-J003",
|
|
33885
|
+
"FICT-S002",
|
|
33886
|
+
"FICT-R001",
|
|
33887
|
+
"FICT-R002",
|
|
33888
|
+
"FICT-R003",
|
|
33889
|
+
"FICT-R006"
|
|
33890
|
+
]);
|
|
33891
|
+
function readBooleanEnv(name) {
|
|
33892
|
+
const raw = process.env[name];
|
|
33893
|
+
if (!raw) return void 0;
|
|
33894
|
+
const normalized = raw.trim().toLowerCase();
|
|
33895
|
+
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
33896
|
+
return true;
|
|
33897
|
+
}
|
|
33898
|
+
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
33899
|
+
return false;
|
|
33900
|
+
}
|
|
33901
|
+
return void 0;
|
|
33902
|
+
}
|
|
33903
|
+
function validateStrictGuaranteeConfig(options, suppressions) {
|
|
33904
|
+
if (!options.strictGuarantee) return;
|
|
33905
|
+
if (suppressions.length > 0) {
|
|
33906
|
+
throw new Error(
|
|
33907
|
+
"strictGuarantee does not allow fict-ignore suppression comments. Remove suppressions to keep fail-closed guarantees."
|
|
33908
|
+
);
|
|
33909
|
+
}
|
|
33910
|
+
if (!options.warningLevels) return;
|
|
33911
|
+
for (const [code, level] of Object.entries(options.warningLevels)) {
|
|
33912
|
+
if (!STRICT_GUARANTEE_WARNING_CODES.has(code)) continue;
|
|
33913
|
+
if (level === "error") continue;
|
|
33914
|
+
throw new Error(
|
|
33915
|
+
`strictGuarantee does not allow downgrading ${code} to "${level}". Remove this warningLevels override.`
|
|
33916
|
+
);
|
|
33917
|
+
}
|
|
33918
|
+
}
|
|
33182
33919
|
function hasErrorEscalation(options) {
|
|
33183
33920
|
if (DEFAULT_ERROR_WARNING_CODES.size > 0) return true;
|
|
33921
|
+
if (options.strictGuarantee) return true;
|
|
33922
|
+
if (options.strictReactivity) return true;
|
|
33184
33923
|
if (options.warningsAsErrors === true) return true;
|
|
33185
33924
|
if (Array.isArray(options.warningsAsErrors) && options.warningsAsErrors.length > 0) return true;
|
|
33186
33925
|
if (options.warningLevels) {
|
|
@@ -33189,8 +33928,10 @@ function hasErrorEscalation(options) {
|
|
|
33189
33928
|
return false;
|
|
33190
33929
|
}
|
|
33191
33930
|
function resolveWarningLevel(code, options) {
|
|
33931
|
+
if (options.strictGuarantee && STRICT_GUARANTEE_WARNING_CODES.has(code)) return "error";
|
|
33192
33932
|
const override = options.warningLevels?.[code];
|
|
33193
33933
|
if (override) return override;
|
|
33934
|
+
if (options.strictReactivity && STRICT_REACTIVITY_WARNING_CODES.has(code)) return "error";
|
|
33194
33935
|
if (options.warningsAsErrors === true) return "error";
|
|
33195
33936
|
if (Array.isArray(options.warningsAsErrors) && options.warningsAsErrors.includes(code)) {
|
|
33196
33937
|
return "error";
|
|
@@ -33204,6 +33945,7 @@ function formatWarningAsError(warning) {
|
|
|
33204
33945
|
at ${location}`;
|
|
33205
33946
|
}
|
|
33206
33947
|
function createWarningDispatcher(onWarn, suppressions, options, dev) {
|
|
33948
|
+
validateStrictGuaranteeConfig(options, suppressions);
|
|
33207
33949
|
const hasEscalation = hasErrorEscalation(options);
|
|
33208
33950
|
if (!dev && !hasEscalation) return () => {
|
|
33209
33951
|
};
|
|
@@ -33309,7 +34051,7 @@ function isDynamicPropertyAccess(node, t4) {
|
|
|
33309
34051
|
if (!node.computed) return false;
|
|
33310
34052
|
return !(t4.isStringLiteral(node.property) || t4.isNumericLiteral(node.property));
|
|
33311
34053
|
}
|
|
33312
|
-
function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, reactiveBindingIds, effectMacroNames, warn, fileName, t4) {
|
|
34054
|
+
function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, reactiveBindingIds, stateMacroNames, memoMacroNames, effectMacroNames, warn, fileName, t4) {
|
|
33313
34055
|
const hasTrackedBinding = (path2, name, tracked) => {
|
|
33314
34056
|
const binding = path2.scope.getBinding(name);
|
|
33315
34057
|
return !!(binding && tracked.has(binding.identifier));
|
|
@@ -33324,6 +34066,107 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33324
34066
|
if (!root) return false;
|
|
33325
34067
|
return hasTrackedBinding(path2, root.name, reactiveBindingIds);
|
|
33326
34068
|
};
|
|
34069
|
+
const NON_ESCAPING_CALLBACK_METHODS = /* @__PURE__ */ new Set([
|
|
34070
|
+
"map",
|
|
34071
|
+
"forEach",
|
|
34072
|
+
"filter",
|
|
34073
|
+
"some",
|
|
34074
|
+
"every",
|
|
34075
|
+
"find",
|
|
34076
|
+
"findIndex",
|
|
34077
|
+
"findLast",
|
|
34078
|
+
"findLastIndex",
|
|
34079
|
+
"flatMap",
|
|
34080
|
+
"reduce",
|
|
34081
|
+
"reduceRight",
|
|
34082
|
+
"sort",
|
|
34083
|
+
"toSorted",
|
|
34084
|
+
"then",
|
|
34085
|
+
"catch",
|
|
34086
|
+
"finally"
|
|
34087
|
+
]);
|
|
34088
|
+
const capturedClosureByBinding = /* @__PURE__ */ new Map();
|
|
34089
|
+
const shouldIgnoreIdentifierReference = (idPath) => {
|
|
34090
|
+
if (idPath.parentPath.isMemberExpression({ property: idPath.node }) && !idPath.parent.computed) {
|
|
34091
|
+
return true;
|
|
34092
|
+
}
|
|
34093
|
+
if (idPath.parentPath.isObjectProperty({ key: idPath.node }) && !idPath.parent.computed && !idPath.parent.shorthand) {
|
|
34094
|
+
return true;
|
|
34095
|
+
}
|
|
34096
|
+
return false;
|
|
34097
|
+
};
|
|
34098
|
+
const collectCapturedReactiveNames = (fnPath) => {
|
|
34099
|
+
const captured = /* @__PURE__ */ new Set();
|
|
34100
|
+
fnPath.traverse({
|
|
34101
|
+
Function(inner) {
|
|
34102
|
+
if (inner === fnPath) return;
|
|
34103
|
+
inner.skip();
|
|
34104
|
+
},
|
|
34105
|
+
Identifier(idPath) {
|
|
34106
|
+
if (shouldIgnoreIdentifierReference(idPath)) return;
|
|
34107
|
+
const name = idPath.node.name;
|
|
34108
|
+
const binding = idPath.scope.getBinding(name);
|
|
34109
|
+
if (!binding) return;
|
|
34110
|
+
if (!reactiveBindingIds.has(binding.identifier)) return;
|
|
34111
|
+
if (binding.scope === idPath.scope || binding.scope === fnPath.scope) return;
|
|
34112
|
+
captured.add(name);
|
|
34113
|
+
}
|
|
34114
|
+
});
|
|
34115
|
+
return captured;
|
|
34116
|
+
};
|
|
34117
|
+
const registerClosureCaptureBinding = (fnPath, captured) => {
|
|
34118
|
+
if (captured.size === 0) return;
|
|
34119
|
+
if (fnPath.isFunctionDeclaration() && fnPath.node.id) {
|
|
34120
|
+
const binding = fnPath.parentPath.scope.getBinding(fnPath.node.id.name);
|
|
34121
|
+
if (binding) {
|
|
34122
|
+
capturedClosureByBinding.set(binding.identifier, captured);
|
|
34123
|
+
}
|
|
34124
|
+
return;
|
|
34125
|
+
}
|
|
34126
|
+
if ((fnPath.isFunctionExpression() || fnPath.isArrowFunctionExpression()) && fnPath.parentPath.isVariableDeclarator()) {
|
|
34127
|
+
const id = fnPath.parentPath.node.id;
|
|
34128
|
+
if (!t4.isIdentifier(id)) return;
|
|
34129
|
+
const binding = fnPath.parentPath.scope.getBinding(id.name);
|
|
34130
|
+
if (binding) {
|
|
34131
|
+
capturedClosureByBinding.set(binding.identifier, captured);
|
|
34132
|
+
}
|
|
34133
|
+
return;
|
|
34134
|
+
}
|
|
34135
|
+
if (fnPath.parentPath.isAssignmentExpression({ right: fnPath.node })) {
|
|
34136
|
+
const left = fnPath.parentPath.node.left;
|
|
34137
|
+
if (!t4.isIdentifier(left)) return;
|
|
34138
|
+
const binding = fnPath.parentPath.scope.getBinding(left.name);
|
|
34139
|
+
if (binding) {
|
|
34140
|
+
capturedClosureByBinding.set(binding.identifier, captured);
|
|
34141
|
+
}
|
|
34142
|
+
}
|
|
34143
|
+
};
|
|
34144
|
+
const collectCapturedForArgument = (argPath) => {
|
|
34145
|
+
if (argPath.isArrowFunctionExpression() || argPath.isFunctionExpression()) {
|
|
34146
|
+
const captured2 = collectCapturedReactiveNames(argPath);
|
|
34147
|
+
return captured2.size > 0 ? captured2 : null;
|
|
34148
|
+
}
|
|
34149
|
+
if (!argPath.isIdentifier()) return null;
|
|
34150
|
+
const binding = argPath.scope.getBinding(argPath.node.name);
|
|
34151
|
+
if (!binding) return null;
|
|
34152
|
+
const captured = capturedClosureByBinding.get(binding.identifier);
|
|
34153
|
+
return captured && captured.size > 0 ? captured : null;
|
|
34154
|
+
};
|
|
34155
|
+
const isNonEscapingCallbackHost = (callee) => {
|
|
34156
|
+
const member = t4.isMemberExpression(callee) || t4.isOptionalMemberExpression(callee) ? callee : null;
|
|
34157
|
+
if (!member || member.computed || !t4.isIdentifier(member.property)) return false;
|
|
34158
|
+
return NON_ESCAPING_CALLBACK_METHODS.has(member.property.name);
|
|
34159
|
+
};
|
|
34160
|
+
const emitClosureCaptureWarning = (node, captured) => {
|
|
34161
|
+
const names = Array.from(captured).sort().join(", ");
|
|
34162
|
+
emitWarning(
|
|
34163
|
+
node,
|
|
34164
|
+
"FICT-R005",
|
|
34165
|
+
`Function captures reactive variable(s): ${names}. Pass them as parameters or memoize explicitly to avoid hidden dependencies.`,
|
|
34166
|
+
warn,
|
|
34167
|
+
fileName
|
|
34168
|
+
);
|
|
34169
|
+
};
|
|
33327
34170
|
const argumentHasReactive = (argPath) => {
|
|
33328
34171
|
if (argPath.isSpreadElement()) {
|
|
33329
34172
|
const inner = argPath.get("argument");
|
|
@@ -33346,12 +34189,7 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33346
34189
|
path2.skip();
|
|
33347
34190
|
},
|
|
33348
34191
|
Identifier(idPath) {
|
|
33349
|
-
if (
|
|
33350
|
-
return;
|
|
33351
|
-
}
|
|
33352
|
-
if (idPath.parentPath.isObjectProperty({ key: idPath.node }) && !idPath.parent.computed && !idPath.parent.shorthand) {
|
|
33353
|
-
return;
|
|
33354
|
-
}
|
|
34192
|
+
if (shouldIgnoreIdentifierReference(idPath)) return;
|
|
33355
34193
|
const binding = idPath.scope.getBinding(idPath.node.name);
|
|
33356
34194
|
if (binding && reactiveBindingIds.has(binding.identifier)) {
|
|
33357
34195
|
found = true;
|
|
@@ -33432,36 +34270,14 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33432
34270
|
}
|
|
33433
34271
|
},
|
|
33434
34272
|
Function(path2) {
|
|
33435
|
-
const captured =
|
|
33436
|
-
path2
|
|
33437
|
-
{
|
|
33438
|
-
Function(inner) {
|
|
33439
|
-
if (inner === path2) return;
|
|
33440
|
-
inner.skip();
|
|
33441
|
-
},
|
|
33442
|
-
Identifier(idPath) {
|
|
33443
|
-
const name = idPath.node.name;
|
|
33444
|
-
const binding = idPath.scope.getBinding(name);
|
|
33445
|
-
if (!binding) return;
|
|
33446
|
-
if (!reactiveBindingIds.has(binding.identifier)) return;
|
|
33447
|
-
if (binding.scope === idPath.scope || binding.scope === path2.scope) return;
|
|
33448
|
-
captured.add(name);
|
|
33449
|
-
}
|
|
33450
|
-
},
|
|
33451
|
-
{}
|
|
33452
|
-
);
|
|
33453
|
-
if (captured.size > 0) {
|
|
33454
|
-
emitWarning(
|
|
33455
|
-
path2.node,
|
|
33456
|
-
"FICT-R005",
|
|
33457
|
-
`Function captures reactive variable(s): ${Array.from(captured).join(", ")}. Pass them as parameters or memoize explicitly to avoid hidden dependencies.`,
|
|
33458
|
-
warn,
|
|
33459
|
-
fileName
|
|
33460
|
-
);
|
|
33461
|
-
}
|
|
34273
|
+
const captured = collectCapturedReactiveNames(path2);
|
|
34274
|
+
registerClosureCaptureBinding(path2, captured);
|
|
33462
34275
|
},
|
|
33463
34276
|
CallExpression(path2) {
|
|
33464
|
-
const
|
|
34277
|
+
const callNode = path2.node;
|
|
34278
|
+
if (isStateCall(callNode, t4, stateMacroNames)) return;
|
|
34279
|
+
if (isMemoCall(callNode, t4, memoMacroNames)) return;
|
|
34280
|
+
const isEffect = isEffectCall(callNode, t4, effectMacroNames);
|
|
33465
34281
|
if (isEffect) {
|
|
33466
34282
|
const argPath = path2.get("arguments.0");
|
|
33467
34283
|
if (argPath?.isFunctionExpression() || argPath?.isArrowFunctionExpression()) {
|
|
@@ -33484,7 +34300,7 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33484
34300
|
});
|
|
33485
34301
|
if (!hasReactiveDependency) {
|
|
33486
34302
|
emitWarning(
|
|
33487
|
-
|
|
34303
|
+
callNode,
|
|
33488
34304
|
"FICT-E001",
|
|
33489
34305
|
"Effect has no reactive reads; it will run once. Consider removing $effect or adding dependencies.",
|
|
33490
34306
|
warn,
|
|
@@ -33507,6 +34323,7 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33507
34323
|
const isSafe = calleeName && SAFE_FUNCTIONS.has(calleeName);
|
|
33508
34324
|
if (isSafe) return;
|
|
33509
34325
|
const argPaths = path2.get("arguments");
|
|
34326
|
+
const nonEscapingCallbackHost = isNonEscapingCallbackHost(callee);
|
|
33510
34327
|
for (const argPath of argPaths) {
|
|
33511
34328
|
if (argPath.isIdentifier() && hasTrackedBinding(argPath, argPath.node.name, stateBindingIds)) {
|
|
33512
34329
|
continue;
|
|
@@ -33522,6 +34339,13 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33522
34339
|
break;
|
|
33523
34340
|
}
|
|
33524
34341
|
}
|
|
34342
|
+
if (nonEscapingCallbackHost) return;
|
|
34343
|
+
for (const argPath of argPaths) {
|
|
34344
|
+
const captured = collectCapturedForArgument(argPath);
|
|
34345
|
+
if (!captured) continue;
|
|
34346
|
+
emitClosureCaptureWarning(argPath.node, captured);
|
|
34347
|
+
break;
|
|
34348
|
+
}
|
|
33525
34349
|
},
|
|
33526
34350
|
OptionalMemberExpression(path2) {
|
|
33527
34351
|
if (!path2.node.computed) return;
|
|
@@ -34386,6 +35210,8 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
34386
35210
|
stateBindingIds,
|
|
34387
35211
|
stateRootBindingIds,
|
|
34388
35212
|
reactiveBindingIds,
|
|
35213
|
+
stateMacroNames,
|
|
35214
|
+
memoMacroNames,
|
|
34389
35215
|
effectMacroNames,
|
|
34390
35216
|
warn,
|
|
34391
35217
|
fileName,
|
|
@@ -34430,13 +35256,17 @@ var createFictPlugin = (0, import_helper_plugin_utils.declare)(
|
|
|
34430
35256
|
(api, options = {}) => {
|
|
34431
35257
|
api.assertVersion(7);
|
|
34432
35258
|
const t4 = api.types;
|
|
35259
|
+
const strictGuaranteeFromEnv = readBooleanEnv("FICT_STRICT_GUARANTEE") === true;
|
|
34433
35260
|
const normalizedOptions = {
|
|
34434
35261
|
...options,
|
|
34435
35262
|
fineGrainedDom: options.fineGrainedDom ?? true,
|
|
35263
|
+
lazyConditional: options.lazyConditional ?? true,
|
|
35264
|
+
getterCache: options.getterCache ?? true,
|
|
34436
35265
|
optimize: options.optimize ?? true,
|
|
34437
35266
|
optimizeLevel: options.optimizeLevel ?? "safe",
|
|
34438
35267
|
inlineDerivedMemos: options.inlineDerivedMemos ?? true,
|
|
34439
35268
|
emitModuleMetadata: options.emitModuleMetadata ?? "auto",
|
|
35269
|
+
strictGuarantee: strictGuaranteeFromEnv || options.strictGuarantee !== false,
|
|
34440
35270
|
dev: options.dev ?? (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test")
|
|
34441
35271
|
};
|
|
34442
35272
|
return {
|