@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.js
CHANGED
|
@@ -14226,6 +14226,9 @@ var RUNTIME_ALIASES = {
|
|
|
14226
14226
|
hydrateComponent: "hydrateComponent",
|
|
14227
14227
|
registerResume: "__fictRegisterResume"
|
|
14228
14228
|
};
|
|
14229
|
+
var RUNTIME_HELPER_MODULES = {
|
|
14230
|
+
keyedList: "@fictjs/runtime/internal/list"
|
|
14231
|
+
};
|
|
14229
14232
|
var DelegatedEvents = /* @__PURE__ */ new Set([...DelegatedEventNames]);
|
|
14230
14233
|
var SAFE_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
14231
14234
|
// Console methods
|
|
@@ -19924,15 +19927,38 @@ function buildEffectCall(ctx, t4, effectFn, options) {
|
|
|
19924
19927
|
}
|
|
19925
19928
|
return t4.callExpression(t4.identifier(RUNTIME_ALIASES.useEffect), args);
|
|
19926
19929
|
}
|
|
19927
|
-
function buildMemoCall(ctx, t4, memoFn,
|
|
19930
|
+
function buildMemoCall(ctx, t4, memoFn, options) {
|
|
19931
|
+
const slot = options?.slot;
|
|
19932
|
+
const memoOptionsProperties = [];
|
|
19933
|
+
if (options?.name) {
|
|
19934
|
+
memoOptionsProperties.push(
|
|
19935
|
+
t4.objectProperty(t4.identifier("name"), t4.stringLiteral(options.name))
|
|
19936
|
+
);
|
|
19937
|
+
}
|
|
19938
|
+
if (options?.source) {
|
|
19939
|
+
memoOptionsProperties.push(
|
|
19940
|
+
t4.objectProperty(t4.identifier("devToolsSource"), t4.stringLiteral(options.source))
|
|
19941
|
+
);
|
|
19942
|
+
}
|
|
19943
|
+
if (options?.internal) {
|
|
19944
|
+
memoOptionsProperties.push(t4.objectProperty(t4.identifier("internal"), t4.booleanLiteral(true)));
|
|
19945
|
+
}
|
|
19946
|
+
const memoOptions = memoOptionsProperties.length > 0 ? t4.objectExpression(memoOptionsProperties) : null;
|
|
19928
19947
|
if (ctx.inModule) {
|
|
19929
19948
|
ctx.helpersUsed.add("memo");
|
|
19930
|
-
|
|
19949
|
+
const args2 = [memoFn];
|
|
19950
|
+
if (memoOptions) args2.push(memoOptions);
|
|
19951
|
+
return t4.callExpression(t4.identifier(RUNTIME_ALIASES.memo), args2);
|
|
19931
19952
|
}
|
|
19932
19953
|
ctx.helpersUsed.add("useMemo");
|
|
19933
19954
|
ctx.needsCtx = true;
|
|
19934
19955
|
const args = [t4.identifier("__fictCtx"), memoFn];
|
|
19935
|
-
if (
|
|
19956
|
+
if (memoOptions) {
|
|
19957
|
+
args.push(memoOptions);
|
|
19958
|
+
if (slot !== void 0 && slot >= 0) {
|
|
19959
|
+
args.push(t4.numericLiteral(slot));
|
|
19960
|
+
}
|
|
19961
|
+
} else if (slot !== void 0 && slot >= 0) {
|
|
19936
19962
|
args.push(t4.numericLiteral(slot));
|
|
19937
19963
|
}
|
|
19938
19964
|
return t4.callExpression(t4.identifier(RUNTIME_ALIASES.useMemo), args);
|
|
@@ -21193,7 +21219,10 @@ function wrapInMemo(region, t4, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
21193
21219
|
const returnObj = t4.objectExpression(uniqueOutputNames.map((name) => buildOutputProperty(name)));
|
|
21194
21220
|
const memoBody = t4.blockStatement([...bodyStatements, t4.returnStatement(returnObj)]);
|
|
21195
21221
|
const slot = ctx.inModule ? void 0 : reserveHookSlot(ctx);
|
|
21196
|
-
const memoCall = buildMemoCall(ctx, t4, t4.arrowFunctionExpression([], memoBody),
|
|
21222
|
+
const memoCall = buildMemoCall(ctx, t4, t4.arrowFunctionExpression([], memoBody), {
|
|
21223
|
+
slot,
|
|
21224
|
+
internal: true
|
|
21225
|
+
});
|
|
21197
21226
|
const regionVarName = `__region_${region.id}`;
|
|
21198
21227
|
statements.push(
|
|
21199
21228
|
t4.variableDeclaration("const", [t4.variableDeclarator(t4.identifier(regionVarName), memoCall)])
|
|
@@ -21452,7 +21481,10 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
|
|
|
21452
21481
|
ctx,
|
|
21453
21482
|
t4,
|
|
21454
21483
|
t4.arrowFunctionExpression([], t4.blockStatement(memoBody)),
|
|
21455
|
-
|
|
21484
|
+
{
|
|
21485
|
+
slot: ctx.inModule ? void 0 : reserveHookSlot(ctx),
|
|
21486
|
+
internal: true
|
|
21487
|
+
}
|
|
21456
21488
|
);
|
|
21457
21489
|
statements.push(
|
|
21458
21490
|
t4.variableDeclaration("const", [t4.variableDeclarator(t4.identifier(regionVarName), memoCall)])
|
|
@@ -21565,7 +21597,12 @@ Context: ${location}`
|
|
|
21565
21597
|
};
|
|
21566
21598
|
const buildDerivedMemoCall = (expr) => {
|
|
21567
21599
|
const slot = !ctx.inModule && inRegionMemo ? reserveHookSlot(ctx) : void 0;
|
|
21568
|
-
|
|
21600
|
+
const source = ctx.options?.dev !== false && instr.loc ? `${ctx.options?.filename ?? ""}:${instr.loc.start.line}:${instr.loc.start.column}` : void 0;
|
|
21601
|
+
return buildMemoCall(ctx, t4, t4.arrowFunctionExpression([], expr), {
|
|
21602
|
+
slot,
|
|
21603
|
+
name: baseName2,
|
|
21604
|
+
source
|
|
21605
|
+
});
|
|
21569
21606
|
};
|
|
21570
21607
|
if (isShadowDeclaration && declKind) {
|
|
21571
21608
|
ctx.trackedVars.delete(baseName2);
|
|
@@ -22927,7 +22964,7 @@ function expressionUsesIdentifier(expr, name, t4) {
|
|
|
22927
22964
|
visit(expr);
|
|
22928
22965
|
return found;
|
|
22929
22966
|
}
|
|
22930
|
-
function extractDelegatedEventData(expr, t4) {
|
|
22967
|
+
function extractDelegatedEventData(expr, t4, options) {
|
|
22931
22968
|
const isSimpleHandler = t4.isIdentifier(expr) || t4.isMemberExpression(expr);
|
|
22932
22969
|
if (isSimpleHandler) {
|
|
22933
22970
|
return { handler: expr };
|
|
@@ -22940,6 +22977,9 @@ function extractDelegatedEventData(expr, t4) {
|
|
|
22940
22977
|
if (!bodyExpr || !t4.isCallExpression(bodyExpr)) return null;
|
|
22941
22978
|
if (paramNames.some((name) => expressionUsesIdentifier(bodyExpr, name, t4))) return null;
|
|
22942
22979
|
if (!t4.isIdentifier(bodyExpr.callee)) return null;
|
|
22980
|
+
if (options?.isKnownHandlerIdentifier && !options.isKnownHandlerIdentifier(bodyExpr.callee.name)) {
|
|
22981
|
+
return null;
|
|
22982
|
+
}
|
|
22943
22983
|
if (bodyExpr.arguments.length === 0) return null;
|
|
22944
22984
|
if (bodyExpr.arguments.length > 1) return null;
|
|
22945
22985
|
const dataArg = bodyExpr.arguments[0];
|
|
@@ -23002,6 +23042,10 @@ function extractDelegatedEventDataFromHIR(expr, ctx) {
|
|
|
23002
23042
|
return null;
|
|
23003
23043
|
}
|
|
23004
23044
|
const handlerName = callee.name;
|
|
23045
|
+
const normalizedHandlerName = deSSAVarName(handlerName);
|
|
23046
|
+
if (!ctx.functionVars?.has(normalizedHandlerName)) {
|
|
23047
|
+
return null;
|
|
23048
|
+
}
|
|
23005
23049
|
if (ctx.signalVars?.has(handlerName) || ctx.memoVars?.has(handlerName) || ctx.aliasVars?.has(handlerName) || ctx.storeVars?.has(handlerName) || ctx.trackedVars.has(handlerName)) {
|
|
23006
23050
|
return null;
|
|
23007
23051
|
}
|
|
@@ -23012,7 +23056,10 @@ function extractDelegatedEventDataFromHIR(expr, ctx) {
|
|
|
23012
23056
|
if (isTrackedAccessor) {
|
|
23013
23057
|
return null;
|
|
23014
23058
|
}
|
|
23015
|
-
const paramNames = new Set(expr.params.map((p) => p.name));
|
|
23059
|
+
const paramNames = new Set(expr.params.map((p) => deSSAVarName(p.name)));
|
|
23060
|
+
if (paramNames.has(deSSAVarName(callee.name))) {
|
|
23061
|
+
return null;
|
|
23062
|
+
}
|
|
23016
23063
|
const dataExpr = bodyExpr.arguments[0];
|
|
23017
23064
|
if (!dataExpr) {
|
|
23018
23065
|
return null;
|
|
@@ -24051,17 +24098,19 @@ function collectDeclaredNames(body, t4) {
|
|
|
24051
24098
|
function attachHelperImports(ctx, body, t4) {
|
|
24052
24099
|
if (ctx.helpersUsed.size === 0) return body;
|
|
24053
24100
|
const declared = collectDeclaredNames(body, t4);
|
|
24054
|
-
const
|
|
24101
|
+
const specifiersByModule = /* @__PURE__ */ new Map();
|
|
24055
24102
|
for (const name of ctx.helpersUsed) {
|
|
24056
24103
|
const alias = RUNTIME_ALIASES[name];
|
|
24057
24104
|
const helper = RUNTIME_HELPERS[name];
|
|
24058
24105
|
if (alias && helper) {
|
|
24059
24106
|
if (declared.has(alias)) continue;
|
|
24060
|
-
|
|
24107
|
+
const modulePath = RUNTIME_HELPER_MODULES[name] ?? RUNTIME_MODULE;
|
|
24108
|
+
const moduleSpecifiers = specifiersByModule.get(modulePath) ?? [];
|
|
24109
|
+
moduleSpecifiers.push(t4.importSpecifier(t4.identifier(alias), t4.identifier(helper)));
|
|
24110
|
+
specifiersByModule.set(modulePath, moduleSpecifiers);
|
|
24061
24111
|
}
|
|
24062
24112
|
}
|
|
24063
|
-
if (
|
|
24064
|
-
const importDecl = t4.importDeclaration(specifiers, t4.stringLiteral(RUNTIME_MODULE));
|
|
24113
|
+
if (specifiersByModule.size === 0) return body;
|
|
24065
24114
|
const helpers = [];
|
|
24066
24115
|
if (ctx.needsForOfHelper) {
|
|
24067
24116
|
const itemId = t4.identifier("item");
|
|
@@ -24099,7 +24148,15 @@ function attachHelperImports(ctx, body, t4) {
|
|
|
24099
24148
|
)
|
|
24100
24149
|
);
|
|
24101
24150
|
}
|
|
24102
|
-
|
|
24151
|
+
const modulePaths = Array.from(specifiersByModule.keys()).sort((a, b) => {
|
|
24152
|
+
if (a === RUNTIME_MODULE) return -1;
|
|
24153
|
+
if (b === RUNTIME_MODULE) return 1;
|
|
24154
|
+
return a.localeCompare(b);
|
|
24155
|
+
});
|
|
24156
|
+
const importDecls = modulePaths.map(
|
|
24157
|
+
(modulePath) => t4.importDeclaration(specifiersByModule.get(modulePath) ?? [], t4.stringLiteral(modulePath))
|
|
24158
|
+
);
|
|
24159
|
+
return [...importDecls, ...helpers, ...body];
|
|
24103
24160
|
}
|
|
24104
24161
|
|
|
24105
24162
|
// src/ir/codegen-jsx-keys.ts
|
|
@@ -24169,8 +24226,8 @@ function getDependencyPathFromNode(node, t4) {
|
|
|
24169
24226
|
}
|
|
24170
24227
|
return null;
|
|
24171
24228
|
}
|
|
24172
|
-
function replaceIdentifiersWithOverrides(node, overrides, t4, parentKind, parentKey, skipCurrentNode = false) {
|
|
24173
|
-
const isCallTarget = parentKey === "callee" && (parentKind === "CallExpression" || parentKind === "OptionalCallExpression");
|
|
24229
|
+
function replaceIdentifiersWithOverrides(node, overrides, t4, parentKind, parentKey, skipCurrentNode = false, allowCallCalleeReplacement = false) {
|
|
24230
|
+
const isCallTarget = !allowCallCalleeReplacement && parentKey === "callee" && (parentKind === "CallExpression" || parentKind === "OptionalCallExpression");
|
|
24174
24231
|
if (parentKind === "VariableDeclarator" && parentKey === "id") {
|
|
24175
24232
|
return;
|
|
24176
24233
|
}
|
|
@@ -24242,9 +24299,25 @@ function replaceIdentifiersWithOverrides(node, overrides, t4, parentKind, parent
|
|
|
24242
24299
|
}
|
|
24243
24300
|
}
|
|
24244
24301
|
if (t4.isBlockStatement(node.body)) {
|
|
24245
|
-
replaceIdentifiersWithOverrides(
|
|
24302
|
+
replaceIdentifiersWithOverrides(
|
|
24303
|
+
node.body,
|
|
24304
|
+
scopedOverrides,
|
|
24305
|
+
t4,
|
|
24306
|
+
node.type,
|
|
24307
|
+
"body",
|
|
24308
|
+
false,
|
|
24309
|
+
allowCallCalleeReplacement
|
|
24310
|
+
);
|
|
24246
24311
|
} else {
|
|
24247
|
-
replaceIdentifiersWithOverrides(
|
|
24312
|
+
replaceIdentifiersWithOverrides(
|
|
24313
|
+
node.body,
|
|
24314
|
+
scopedOverrides,
|
|
24315
|
+
t4,
|
|
24316
|
+
node.type,
|
|
24317
|
+
"body",
|
|
24318
|
+
false,
|
|
24319
|
+
allowCallCalleeReplacement
|
|
24320
|
+
);
|
|
24248
24321
|
}
|
|
24249
24322
|
return;
|
|
24250
24323
|
}
|
|
@@ -24272,12 +24345,21 @@ function replaceIdentifiersWithOverrides(node, overrides, t4, parentKind, parent
|
|
|
24272
24345
|
t4,
|
|
24273
24346
|
node.type,
|
|
24274
24347
|
key,
|
|
24275
|
-
false
|
|
24348
|
+
false,
|
|
24349
|
+
allowCallCalleeReplacement
|
|
24276
24350
|
);
|
|
24277
24351
|
}
|
|
24278
24352
|
}
|
|
24279
24353
|
} else if (value && typeof value === "object" && "type" in value) {
|
|
24280
|
-
replaceIdentifiersWithOverrides(
|
|
24354
|
+
replaceIdentifiersWithOverrides(
|
|
24355
|
+
value,
|
|
24356
|
+
overrides,
|
|
24357
|
+
t4,
|
|
24358
|
+
node.type,
|
|
24359
|
+
key,
|
|
24360
|
+
false,
|
|
24361
|
+
allowCallCalleeReplacement
|
|
24362
|
+
);
|
|
24281
24363
|
}
|
|
24282
24364
|
}
|
|
24283
24365
|
}
|
|
@@ -24550,6 +24632,124 @@ function applySelectorHoist(callbackExpr, itemParamName, keyParamName, statement
|
|
|
24550
24632
|
}
|
|
24551
24633
|
|
|
24552
24634
|
// src/ir/codegen-list-child.ts
|
|
24635
|
+
function getCallbackBlocks(callback) {
|
|
24636
|
+
if (callback.kind === "FunctionExpression") {
|
|
24637
|
+
return callback.body;
|
|
24638
|
+
}
|
|
24639
|
+
if (callback.kind === "ArrowFunction" && Array.isArray(callback.body)) {
|
|
24640
|
+
return callback.body;
|
|
24641
|
+
}
|
|
24642
|
+
return [];
|
|
24643
|
+
}
|
|
24644
|
+
function collectMapCallbackAliasDeclarations(callback) {
|
|
24645
|
+
const blocks = getCallbackBlocks(callback);
|
|
24646
|
+
if (blocks.length === 0) {
|
|
24647
|
+
return /* @__PURE__ */ new Map();
|
|
24648
|
+
}
|
|
24649
|
+
const paramNames = callback.kind === "ArrowFunction" || callback.kind === "FunctionExpression" ? new Set(callback.params.map((param) => param.name)) : /* @__PURE__ */ new Set();
|
|
24650
|
+
const declarationState = /* @__PURE__ */ new Map();
|
|
24651
|
+
for (const block of blocks) {
|
|
24652
|
+
for (const instr of block.instructions) {
|
|
24653
|
+
if (instr.kind !== "Assign" || instr.target.kind !== "Identifier") {
|
|
24654
|
+
continue;
|
|
24655
|
+
}
|
|
24656
|
+
const name = instr.target.name;
|
|
24657
|
+
if (paramNames.has(name)) continue;
|
|
24658
|
+
const isDeclaration = !!instr.declarationKind;
|
|
24659
|
+
const previous = declarationState.get(name);
|
|
24660
|
+
if (previous) {
|
|
24661
|
+
declarationState.set(name, {
|
|
24662
|
+
declarationCount: previous.declarationCount + (isDeclaration ? 1 : 0),
|
|
24663
|
+
hasNonDeclarationWrite: previous.hasNonDeclarationWrite || !isDeclaration,
|
|
24664
|
+
declarationValue: previous.declarationValue,
|
|
24665
|
+
lastAssignedValue: instr.value
|
|
24666
|
+
});
|
|
24667
|
+
} else {
|
|
24668
|
+
declarationState.set(name, {
|
|
24669
|
+
declarationCount: isDeclaration ? 1 : 0,
|
|
24670
|
+
hasNonDeclarationWrite: !isDeclaration,
|
|
24671
|
+
declarationValue: isDeclaration ? instr.value : null,
|
|
24672
|
+
lastAssignedValue: instr.value
|
|
24673
|
+
});
|
|
24674
|
+
}
|
|
24675
|
+
}
|
|
24676
|
+
}
|
|
24677
|
+
const aliasMap = /* @__PURE__ */ new Map();
|
|
24678
|
+
const effectiveBlocks = blocks.filter(
|
|
24679
|
+
(block) => block.instructions.length > 0 || block.terminator.kind !== "Unreachable"
|
|
24680
|
+
);
|
|
24681
|
+
const isSingleLinearBlock = effectiveBlocks.length === 1 && effectiveBlocks[0].terminator.kind === "Return";
|
|
24682
|
+
for (const [name, state] of declarationState) {
|
|
24683
|
+
if (isSingleLinearBlock) {
|
|
24684
|
+
if (state.declarationCount <= 1) {
|
|
24685
|
+
aliasMap.set(name, state.lastAssignedValue);
|
|
24686
|
+
}
|
|
24687
|
+
continue;
|
|
24688
|
+
}
|
|
24689
|
+
if (state.declarationCount === 1 && !state.hasNonDeclarationWrite && state.declarationValue) {
|
|
24690
|
+
aliasMap.set(name, state.declarationValue);
|
|
24691
|
+
}
|
|
24692
|
+
}
|
|
24693
|
+
return aliasMap;
|
|
24694
|
+
}
|
|
24695
|
+
function resolveMapCallbackKeyExpression(keyExpr, callback) {
|
|
24696
|
+
if (keyExpr.kind !== "Identifier") {
|
|
24697
|
+
return keyExpr;
|
|
24698
|
+
}
|
|
24699
|
+
const aliasMap = collectMapCallbackAliasDeclarations(callback);
|
|
24700
|
+
if (aliasMap.size === 0) {
|
|
24701
|
+
return keyExpr;
|
|
24702
|
+
}
|
|
24703
|
+
let resolved = keyExpr;
|
|
24704
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24705
|
+
while (resolved.kind === "Identifier") {
|
|
24706
|
+
const next = aliasMap.get(resolved.name);
|
|
24707
|
+
if (!next || seen.has(resolved.name)) break;
|
|
24708
|
+
seen.add(resolved.name);
|
|
24709
|
+
resolved = next;
|
|
24710
|
+
}
|
|
24711
|
+
return resolved;
|
|
24712
|
+
}
|
|
24713
|
+
function collectMapCallbackLocalNames(callback) {
|
|
24714
|
+
const blocks = getCallbackBlocks(callback);
|
|
24715
|
+
if (blocks.length === 0) {
|
|
24716
|
+
return /* @__PURE__ */ new Set();
|
|
24717
|
+
}
|
|
24718
|
+
const paramNames = callback.kind === "ArrowFunction" || callback.kind === "FunctionExpression" ? new Set(callback.params.map((param) => deSSAVarName(param.name))) : /* @__PURE__ */ new Set();
|
|
24719
|
+
const locals = /* @__PURE__ */ new Set();
|
|
24720
|
+
for (const block of blocks) {
|
|
24721
|
+
for (const instr of block.instructions) {
|
|
24722
|
+
if (instr.kind === "Assign" && instr.target.kind === "Identifier") {
|
|
24723
|
+
const name = deSSAVarName(instr.target.name);
|
|
24724
|
+
if (!paramNames.has(name)) locals.add(name);
|
|
24725
|
+
}
|
|
24726
|
+
if (instr.kind === "Phi" && instr.target.kind === "Identifier") {
|
|
24727
|
+
const name = deSSAVarName(instr.target.name);
|
|
24728
|
+
if (!paramNames.has(name)) locals.add(name);
|
|
24729
|
+
}
|
|
24730
|
+
}
|
|
24731
|
+
}
|
|
24732
|
+
return locals;
|
|
24733
|
+
}
|
|
24734
|
+
function hasUnresolvedCallbackLocalKeyDependencies(keyExpr, callback, keyAliasDeclarations) {
|
|
24735
|
+
const callbackLocals = collectMapCallbackLocalNames(callback);
|
|
24736
|
+
if (callbackLocals.size === 0) {
|
|
24737
|
+
return false;
|
|
24738
|
+
}
|
|
24739
|
+
const resolvableAliases = new Set(
|
|
24740
|
+
Array.from(keyAliasDeclarations.keys()).map((name) => deSSAVarName(name))
|
|
24741
|
+
);
|
|
24742
|
+
const deps = /* @__PURE__ */ new Set();
|
|
24743
|
+
collectExpressionDependencies(keyExpr, deps);
|
|
24744
|
+
for (const dep of deps) {
|
|
24745
|
+
const base = dep.split(".")[0] ?? dep;
|
|
24746
|
+
if (!base) continue;
|
|
24747
|
+
if (callbackLocals.has(base) && !resolvableAliases.has(base)) {
|
|
24748
|
+
return true;
|
|
24749
|
+
}
|
|
24750
|
+
}
|
|
24751
|
+
return false;
|
|
24752
|
+
}
|
|
24553
24753
|
function buildListCallExpression(expr, statements, ctx, ops) {
|
|
24554
24754
|
const { t: t4 } = ctx;
|
|
24555
24755
|
if (expr.kind !== "CallExpression" && expr.kind !== "OptionalCallExpression") {
|
|
@@ -24568,7 +24768,8 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24568
24768
|
if (!mapCallback) {
|
|
24569
24769
|
throw new Error("map callback is required");
|
|
24570
24770
|
}
|
|
24571
|
-
const
|
|
24771
|
+
const extractedKeyExpr = extractKeyFromMapCallback(mapCallback);
|
|
24772
|
+
const keyExpr = extractedKeyExpr ? resolveMapCallbackKeyExpression(extractedKeyExpr, mapCallback) : void 0;
|
|
24572
24773
|
const isKeyed = !!keyExpr;
|
|
24573
24774
|
const hasRestParam = (mapCallback.kind === "ArrowFunction" || mapCallback.kind === "FunctionExpression") && Array.isArray(mapCallback.rawParams) && mapCallback.rawParams.some((param) => t4.isRestElement(param));
|
|
24574
24775
|
const canConstifyKey = isKeyed && keyExpr && !hasRestParam;
|
|
@@ -24619,7 +24820,7 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24619
24820
|
if (Object.keys(overrides).length > 0) {
|
|
24620
24821
|
if (t4.isBlockStatement(callbackExpr.body)) {
|
|
24621
24822
|
for (const stmt of callbackExpr.body.body) {
|
|
24622
|
-
if (!t4.isVariableDeclaration(stmt)) continue;
|
|
24823
|
+
if (!t4.isVariableDeclaration(stmt) || stmt.kind !== "const") continue;
|
|
24623
24824
|
for (const decl of stmt.declarations) {
|
|
24624
24825
|
if (!t4.isIdentifier(decl.id) || !decl.init) continue;
|
|
24625
24826
|
const replacement = t4.cloneNode(decl.init, true);
|
|
@@ -24649,7 +24850,32 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24649
24850
|
}
|
|
24650
24851
|
let listCall;
|
|
24651
24852
|
if (isKeyed && keyExpr) {
|
|
24853
|
+
const keyAliasDeclarations = collectMapCallbackAliasDeclarations(mapCallback);
|
|
24854
|
+
const hasUnresolvedLocalKeyDeps = hasUnresolvedCallbackLocalKeyDependencies(
|
|
24855
|
+
keyExpr,
|
|
24856
|
+
mapCallback,
|
|
24857
|
+
keyAliasDeclarations
|
|
24858
|
+
);
|
|
24652
24859
|
let keyExprAst = ops.lowerExpression(keyExpr, ctx);
|
|
24860
|
+
if (keyAliasDeclarations.size > 0) {
|
|
24861
|
+
const keyOverrides = {};
|
|
24862
|
+
for (const [name, value] of keyAliasDeclarations) {
|
|
24863
|
+
const replacement = ops.lowerExpression(value, ctx);
|
|
24864
|
+
replaceIdentifiersWithOverrides(replacement, keyOverrides, t4);
|
|
24865
|
+
keyOverrides[name] = () => t4.cloneNode(replacement, true);
|
|
24866
|
+
}
|
|
24867
|
+
if (Object.keys(keyOverrides).length > 0) {
|
|
24868
|
+
replaceIdentifiersWithOverrides(
|
|
24869
|
+
keyExprAst,
|
|
24870
|
+
keyOverrides,
|
|
24871
|
+
t4,
|
|
24872
|
+
void 0,
|
|
24873
|
+
void 0,
|
|
24874
|
+
false,
|
|
24875
|
+
true
|
|
24876
|
+
);
|
|
24877
|
+
}
|
|
24878
|
+
}
|
|
24653
24879
|
if (t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr)) {
|
|
24654
24880
|
const itemParam = callbackExpr.params[0];
|
|
24655
24881
|
const indexParam = callbackExpr.params[1];
|
|
@@ -24663,6 +24889,9 @@ function buildListCallExpression(expr, statements, ctx, ops) {
|
|
|
24663
24889
|
}
|
|
24664
24890
|
const itemParamName = t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr) ? callbackExpr.params[0] : null;
|
|
24665
24891
|
const indexParamName = t4.isArrowFunctionExpression(callbackExpr) || t4.isFunctionExpression(callbackExpr) ? callbackExpr.params[1] : null;
|
|
24892
|
+
if (hasUnresolvedLocalKeyDeps) {
|
|
24893
|
+
keyExprAst = t4.identifier(t4.isIdentifier(indexParamName) ? indexParamName.name : "__index");
|
|
24894
|
+
}
|
|
24666
24895
|
const keyFn = t4.arrowFunctionExpression(
|
|
24667
24896
|
[
|
|
24668
24897
|
t4.isIdentifier(itemParamName) ? itemParamName : t4.identifier("__item"),
|
|
@@ -25104,33 +25333,42 @@ function dependencyCoveredByDeclarations(dep, region) {
|
|
|
25104
25333
|
|
|
25105
25334
|
// src/ir/codegen-resumable-utils.ts
|
|
25106
25335
|
import { pathToFileURL } from "url";
|
|
25107
|
-
|
|
25108
|
-
|
|
25109
|
-
|
|
25110
|
-
|
|
25111
|
-
|
|
25112
|
-
|
|
25113
|
-
|
|
25114
|
-
|
|
25115
|
-
|
|
25116
|
-
|
|
25117
|
-
|
|
25118
|
-
|
|
25119
|
-
|
|
25120
|
-
|
|
25121
|
-
}
|
|
25122
|
-
const value = n[key];
|
|
25123
|
-
if (Array.isArray(value)) {
|
|
25124
|
-
for (const item of value) {
|
|
25125
|
-
visit(item);
|
|
25126
|
-
}
|
|
25127
|
-
} else if (value && typeof value === "object") {
|
|
25128
|
-
visit(value);
|
|
25336
|
+
import traverseModule2 from "@babel/traverse";
|
|
25337
|
+
function renameIdentifiersInExpr(expr, renames, t4) {
|
|
25338
|
+
const traverse = traverseModule2.default ?? traverseModule2;
|
|
25339
|
+
const cloned = t4.cloneNode(expr, true);
|
|
25340
|
+
const file = t4.file(t4.program([t4.expressionStatement(cloned)]));
|
|
25341
|
+
traverse(file, {
|
|
25342
|
+
Identifier(path2) {
|
|
25343
|
+
const oldName = path2.node.name;
|
|
25344
|
+
const nextName = renames.get(oldName);
|
|
25345
|
+
if (!nextName) return;
|
|
25346
|
+
if (path2.parentPath.isObjectProperty() && path2.parentPath.node.shorthand && path2.parentPath.node.value === path2.node && t4.isIdentifier(path2.parentPath.node.key)) {
|
|
25347
|
+
path2.parentPath.node.shorthand = false;
|
|
25348
|
+
path2.parentPath.node.value = t4.identifier(nextName);
|
|
25349
|
+
return;
|
|
25129
25350
|
}
|
|
25351
|
+
if (!path2.isReferencedIdentifier()) return;
|
|
25352
|
+
const binding = path2.scope.getBinding(oldName);
|
|
25353
|
+
if (binding && binding.scope !== path2.scope.getProgramParent()) return;
|
|
25354
|
+
path2.node.name = nextName;
|
|
25130
25355
|
}
|
|
25131
|
-
}
|
|
25132
|
-
|
|
25133
|
-
return cloned;
|
|
25356
|
+
});
|
|
25357
|
+
const first = file.program.body[0];
|
|
25358
|
+
return t4.isExpressionStatement(first) ? first.expression : cloned;
|
|
25359
|
+
}
|
|
25360
|
+
function collectFreeIdentifiersInExpr(expr, t4) {
|
|
25361
|
+
const traverse = traverseModule2.default ?? traverseModule2;
|
|
25362
|
+
const file = t4.file(t4.program([t4.expressionStatement(t4.cloneNode(expr, true))]));
|
|
25363
|
+
const names = /* @__PURE__ */ new Set();
|
|
25364
|
+
traverse(file, {
|
|
25365
|
+
ReferencedIdentifier(path2) {
|
|
25366
|
+
const name = path2.node.name;
|
|
25367
|
+
if (path2.scope.getBinding(name)) return;
|
|
25368
|
+
names.add(name);
|
|
25369
|
+
}
|
|
25370
|
+
});
|
|
25371
|
+
return names;
|
|
25134
25372
|
}
|
|
25135
25373
|
function genModuleUrlExpr(ctx) {
|
|
25136
25374
|
const { t: t4 } = ctx;
|
|
@@ -25267,10 +25505,10 @@ function registerResumableComponent(componentName, ctx) {
|
|
|
25267
25505
|
}
|
|
25268
25506
|
|
|
25269
25507
|
// src/ir/codegen-resumable-events.ts
|
|
25270
|
-
function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, containingRegion, ops) {
|
|
25508
|
+
function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, containingRegion, ops, options) {
|
|
25271
25509
|
const { t: t4 } = ctx;
|
|
25272
25510
|
if (!ctx.resumableEnabled) {
|
|
25273
|
-
return;
|
|
25511
|
+
return false;
|
|
25274
25512
|
}
|
|
25275
25513
|
const prevWrapTracked = ctx.wrapTrackedExpressions;
|
|
25276
25514
|
ctx.wrapTrackedExpressions = false;
|
|
@@ -25284,53 +25522,88 @@ function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, c
|
|
|
25284
25522
|
const scopeParam = t4.identifier("scopeId");
|
|
25285
25523
|
const ensureHandlerParam = (fn) => {
|
|
25286
25524
|
if (t4.isArrowFunctionExpression(fn)) {
|
|
25287
|
-
|
|
25288
|
-
return t4.arrowFunctionExpression([eventParam], fn.body, fn.async);
|
|
25525
|
+
return fn;
|
|
25289
25526
|
}
|
|
25290
25527
|
if (t4.isFunctionExpression(fn)) {
|
|
25291
|
-
|
|
25292
|
-
return t4.functionExpression(fn.id, [eventParam], fn.body, fn.generator, fn.async);
|
|
25528
|
+
return fn;
|
|
25293
25529
|
}
|
|
25294
25530
|
if (t4.isIdentifier(fn) || t4.isMemberExpression(fn)) {
|
|
25295
25531
|
return fn;
|
|
25296
25532
|
}
|
|
25297
|
-
if (t4.isCallExpression(fn) && fn.arguments.length === 0 && (t4.isIdentifier(fn.callee) || t4.isMemberExpression(fn.callee))) {
|
|
25298
|
-
return fn.callee;
|
|
25299
|
-
}
|
|
25300
25533
|
return t4.functionExpression(
|
|
25301
25534
|
null,
|
|
25302
|
-
[
|
|
25303
|
-
t4.blockStatement([
|
|
25304
|
-
t4.returnStatement(
|
|
25305
|
-
t4.callExpression(
|
|
25306
|
-
t4.memberExpression(fn, t4.identifier("call")),
|
|
25307
|
-
[t4.thisExpression(), eventParam]
|
|
25308
|
-
)
|
|
25309
|
-
)
|
|
25310
|
-
])
|
|
25535
|
+
[],
|
|
25536
|
+
t4.blockStatement([t4.returnStatement(fn)])
|
|
25311
25537
|
);
|
|
25312
25538
|
};
|
|
25313
25539
|
const handlerExpr = ensureHandlerParam(valueExpr);
|
|
25314
25540
|
const handlerId = t4.identifier(`__fict_e${ctx.resumableHandlerCounter ?? 0}`);
|
|
25315
25541
|
ctx.resumableHandlerCounter = (ctx.resumableHandlerCounter ?? 0) + 1;
|
|
25316
|
-
const captured =
|
|
25317
|
-
collectExpressionIdentifiersDeep(expr, captured);
|
|
25542
|
+
const captured = collectFreeIdentifiersInExpr(handlerExpr, t4);
|
|
25318
25543
|
const lexicalNames = Array.from(captured).filter((name) => ctx.signalVars?.has(name));
|
|
25319
25544
|
const propsName = ctx.propsParamName && captured.has(ctx.propsParamName) ? ctx.propsParamName : null;
|
|
25545
|
+
const unsupportedLocals = Array.from(captured).filter((name) => {
|
|
25546
|
+
if (ctx.inListRender && ctx.listKeyParamName && name === ctx.listKeyParamName) return true;
|
|
25547
|
+
if (!ctx.localDeclaredNames?.has(name)) return false;
|
|
25548
|
+
if (ctx.signalVars?.has(name)) return false;
|
|
25549
|
+
if (ctx.functionVars?.has(name)) return false;
|
|
25550
|
+
if (propsName && name === propsName) return false;
|
|
25551
|
+
return true;
|
|
25552
|
+
});
|
|
25553
|
+
const loweredFunctionDeps = /* @__PURE__ */ new Map();
|
|
25554
|
+
const unsafeFunctionCaptures = [];
|
|
25555
|
+
for (const name of captured) {
|
|
25556
|
+
if (!ctx.functionVars?.has(name) || ctx.signalVars?.has(name)) continue;
|
|
25557
|
+
if (ctx.hoistedFunctionDepNames?.has(name)) continue;
|
|
25558
|
+
const hirDef = ctx.componentFunctionDefs?.get(name);
|
|
25559
|
+
if (!hirDef) {
|
|
25560
|
+
if (ctx.localDeclaredNames?.has(name)) {
|
|
25561
|
+
unsafeFunctionCaptures.push(`${name} -> <unhoistable>`);
|
|
25562
|
+
}
|
|
25563
|
+
continue;
|
|
25564
|
+
}
|
|
25565
|
+
const loweredFn = ops.lowerDomExpression(hirDef, ctx, null, {
|
|
25566
|
+
skipHookAccessors: true,
|
|
25567
|
+
skipRegionRootOverride: true
|
|
25568
|
+
});
|
|
25569
|
+
const fnCaptured = collectFreeIdentifiersInExpr(loweredFn, t4);
|
|
25570
|
+
const localFnCaptures = Array.from(fnCaptured).filter((dep) => ctx.localDeclaredNames?.has(dep)).sort();
|
|
25571
|
+
if (localFnCaptures.length > 0) {
|
|
25572
|
+
unsafeFunctionCaptures.push(`${name} -> ${localFnCaptures.join(", ")}`);
|
|
25573
|
+
continue;
|
|
25574
|
+
}
|
|
25575
|
+
loweredFunctionDeps.set(name, loweredFn);
|
|
25576
|
+
}
|
|
25577
|
+
if (unsupportedLocals.length > 0 || unsafeFunctionCaptures.length > 0) {
|
|
25578
|
+
const detailParts = [];
|
|
25579
|
+
if (unsupportedLocals.length > 0) {
|
|
25580
|
+
detailParts.push(`direct: ${unsupportedLocals.sort().join(", ")}`);
|
|
25581
|
+
}
|
|
25582
|
+
if (unsafeFunctionCaptures.length > 0) {
|
|
25583
|
+
detailParts.push(`function deps: ${unsafeFunctionCaptures.sort().join("; ")}`);
|
|
25584
|
+
}
|
|
25585
|
+
const detail = `Resumable handlers cannot capture non-serializable local variables (${detailParts.join(" | ")}).`;
|
|
25586
|
+
if (options?.explicit) {
|
|
25587
|
+
const loc = expr.loc?.start;
|
|
25588
|
+
const fileName = ctx.options?.filename ?? "<unknown>";
|
|
25589
|
+
const location = loc ? `${fileName}:${loc.line}:${loc.column + 1}` : fileName;
|
|
25590
|
+
throw new Error(
|
|
25591
|
+
`${detail} Use signals/props/function references or remove '$' suffix.
|
|
25592
|
+
at ${location}`
|
|
25593
|
+
);
|
|
25594
|
+
}
|
|
25595
|
+
return false;
|
|
25596
|
+
}
|
|
25320
25597
|
const functionDepRenames = /* @__PURE__ */ new Map();
|
|
25321
25598
|
for (const name of captured) {
|
|
25322
25599
|
if (ctx.functionVars?.has(name) && !ctx.signalVars?.has(name)) {
|
|
25323
|
-
const hirDef = ctx.componentFunctionDefs?.get(name);
|
|
25324
|
-
if (!hirDef) continue;
|
|
25325
25600
|
let hoistedName = ctx.hoistedFunctionDepNames?.get(name);
|
|
25326
25601
|
if (!hoistedName) {
|
|
25602
|
+
const loweredFn = loweredFunctionDeps.get(name);
|
|
25603
|
+
if (!loweredFn) continue;
|
|
25327
25604
|
hoistedName = `__fict_fn_${name}_${ctx.hoistedFunctionDepCounter ?? 0}`;
|
|
25328
25605
|
ctx.hoistedFunctionDepCounter = (ctx.hoistedFunctionDepCounter ?? 0) + 1;
|
|
25329
25606
|
ctx.hoistedFunctionDepNames?.set(name, hoistedName);
|
|
25330
|
-
const loweredFn = ops.lowerDomExpression(hirDef, ctx, null, {
|
|
25331
|
-
skipHookAccessors: true,
|
|
25332
|
-
skipRegionRootOverride: true
|
|
25333
|
-
});
|
|
25334
25607
|
const hoistedDecl = t4.variableDeclaration("const", [
|
|
25335
25608
|
t4.variableDeclarator(t4.identifier(hoistedName), loweredFn)
|
|
25336
25609
|
]);
|
|
@@ -25342,7 +25615,7 @@ function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, c
|
|
|
25342
25615
|
}
|
|
25343
25616
|
let finalHandlerExpr = handlerExpr;
|
|
25344
25617
|
if (functionDepRenames.size > 0) {
|
|
25345
|
-
finalHandlerExpr = renameIdentifiersInExpr(handlerExpr, functionDepRenames);
|
|
25618
|
+
finalHandlerExpr = renameIdentifiersInExpr(handlerExpr, functionDepRenames, t4);
|
|
25346
25619
|
}
|
|
25347
25620
|
const bodyStatements = [];
|
|
25348
25621
|
if (lexicalNames.length > 0) {
|
|
@@ -25375,12 +25648,97 @@ function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, c
|
|
|
25375
25648
|
);
|
|
25376
25649
|
}
|
|
25377
25650
|
const handlerVar = t4.identifier("__handler");
|
|
25651
|
+
const resultVar = t4.identifier("__result");
|
|
25378
25652
|
bodyStatements.push(
|
|
25379
25653
|
t4.variableDeclaration("const", [t4.variableDeclarator(handlerVar, finalHandlerExpr)])
|
|
25380
25654
|
);
|
|
25381
25655
|
bodyStatements.push(
|
|
25382
|
-
t4.
|
|
25383
|
-
t4.
|
|
25656
|
+
t4.ifStatement(
|
|
25657
|
+
t4.binaryExpression(
|
|
25658
|
+
"===",
|
|
25659
|
+
t4.unaryExpression("typeof", handlerVar),
|
|
25660
|
+
t4.stringLiteral("function")
|
|
25661
|
+
),
|
|
25662
|
+
t4.blockStatement([
|
|
25663
|
+
t4.variableDeclaration("const", [
|
|
25664
|
+
t4.variableDeclarator(
|
|
25665
|
+
resultVar,
|
|
25666
|
+
t4.callExpression(t4.memberExpression(handlerVar, t4.identifier("call")), [
|
|
25667
|
+
elParam,
|
|
25668
|
+
eventParam
|
|
25669
|
+
])
|
|
25670
|
+
)
|
|
25671
|
+
]),
|
|
25672
|
+
t4.ifStatement(
|
|
25673
|
+
t4.logicalExpression(
|
|
25674
|
+
"&&",
|
|
25675
|
+
t4.binaryExpression(
|
|
25676
|
+
"===",
|
|
25677
|
+
t4.unaryExpression("typeof", resultVar),
|
|
25678
|
+
t4.stringLiteral("function")
|
|
25679
|
+
),
|
|
25680
|
+
t4.binaryExpression("!==", resultVar, handlerVar)
|
|
25681
|
+
),
|
|
25682
|
+
t4.blockStatement([
|
|
25683
|
+
t4.returnStatement(
|
|
25684
|
+
t4.callExpression(t4.memberExpression(resultVar, t4.identifier("call")), [
|
|
25685
|
+
elParam,
|
|
25686
|
+
eventParam
|
|
25687
|
+
])
|
|
25688
|
+
)
|
|
25689
|
+
])
|
|
25690
|
+
),
|
|
25691
|
+
t4.ifStatement(
|
|
25692
|
+
t4.logicalExpression(
|
|
25693
|
+
"&&",
|
|
25694
|
+
resultVar,
|
|
25695
|
+
t4.binaryExpression(
|
|
25696
|
+
"===",
|
|
25697
|
+
t4.unaryExpression(
|
|
25698
|
+
"typeof",
|
|
25699
|
+
t4.memberExpression(resultVar, t4.identifier("handleEvent"))
|
|
25700
|
+
),
|
|
25701
|
+
t4.stringLiteral("function")
|
|
25702
|
+
)
|
|
25703
|
+
),
|
|
25704
|
+
t4.blockStatement([
|
|
25705
|
+
t4.returnStatement(
|
|
25706
|
+
t4.callExpression(
|
|
25707
|
+
t4.memberExpression(
|
|
25708
|
+
t4.memberExpression(resultVar, t4.identifier("handleEvent")),
|
|
25709
|
+
t4.identifier("call")
|
|
25710
|
+
),
|
|
25711
|
+
[resultVar, eventParam]
|
|
25712
|
+
)
|
|
25713
|
+
)
|
|
25714
|
+
])
|
|
25715
|
+
),
|
|
25716
|
+
t4.returnStatement(resultVar)
|
|
25717
|
+
])
|
|
25718
|
+
)
|
|
25719
|
+
);
|
|
25720
|
+
bodyStatements.push(
|
|
25721
|
+
t4.ifStatement(
|
|
25722
|
+
t4.logicalExpression(
|
|
25723
|
+
"&&",
|
|
25724
|
+
handlerVar,
|
|
25725
|
+
t4.binaryExpression(
|
|
25726
|
+
"===",
|
|
25727
|
+
t4.unaryExpression("typeof", t4.memberExpression(handlerVar, t4.identifier("handleEvent"))),
|
|
25728
|
+
t4.stringLiteral("function")
|
|
25729
|
+
)
|
|
25730
|
+
),
|
|
25731
|
+
t4.blockStatement([
|
|
25732
|
+
t4.returnStatement(
|
|
25733
|
+
t4.callExpression(
|
|
25734
|
+
t4.memberExpression(
|
|
25735
|
+
t4.memberExpression(handlerVar, t4.identifier("handleEvent")),
|
|
25736
|
+
t4.identifier("call")
|
|
25737
|
+
),
|
|
25738
|
+
[handlerVar, eventParam]
|
|
25739
|
+
)
|
|
25740
|
+
)
|
|
25741
|
+
])
|
|
25384
25742
|
)
|
|
25385
25743
|
);
|
|
25386
25744
|
const exportedHandler = t4.exportNamedDeclaration(
|
|
@@ -25409,11 +25767,13 @@ function emitResumableEventBinding(targetId, eventName, expr, statements, ctx, c
|
|
|
25409
25767
|
])
|
|
25410
25768
|
)
|
|
25411
25769
|
);
|
|
25770
|
+
return true;
|
|
25412
25771
|
}
|
|
25413
25772
|
|
|
25414
25773
|
// src/ir/codegen-runtime-imports.ts
|
|
25415
25774
|
var RUNTIME_IMPORT_MODULES = /* @__PURE__ */ new Set([
|
|
25416
25775
|
RUNTIME_MODULE,
|
|
25776
|
+
...Object.values(RUNTIME_HELPER_MODULES),
|
|
25417
25777
|
"@fictjs/runtime",
|
|
25418
25778
|
"@fictjs/runtime/advanced",
|
|
25419
25779
|
"fict",
|
|
@@ -25792,7 +26152,8 @@ function extractHIRStaticHtml(jsx, ctx, ops, parentPath = [], namespace = null)
|
|
|
25792
26152
|
name: eventName.toLowerCase(),
|
|
25793
26153
|
expr: attr.value ?? void 0,
|
|
25794
26154
|
eventOptions: { capture, passive, once },
|
|
25795
|
-
resumable: shouldBeResumable
|
|
26155
|
+
resumable: shouldBeResumable,
|
|
26156
|
+
resumableExplicit: isResumableEvent
|
|
25796
26157
|
});
|
|
25797
26158
|
continue;
|
|
25798
26159
|
}
|
|
@@ -26365,7 +26726,7 @@ function buildOutputParams(fn, t4) {
|
|
|
26365
26726
|
}
|
|
26366
26727
|
return fn.params.map((p) => t4.identifier(deSSAVarName(p.name)));
|
|
26367
26728
|
}
|
|
26368
|
-
function lowerTrackedExpression(expr, ctx) {
|
|
26729
|
+
function lowerTrackedExpression(expr, ctx, valueUsed = true) {
|
|
26369
26730
|
const regionOverride = ctx.inReturn && ctx.currentFnIsHook ? null : ctx.currentRegion ?? (ctx.trackedVars.size ? {
|
|
26370
26731
|
id: -1,
|
|
26371
26732
|
dependencies: new Set(ctx.trackedVars),
|
|
@@ -26373,7 +26734,7 @@ function lowerTrackedExpression(expr, ctx) {
|
|
|
26373
26734
|
hasControlFlow: false,
|
|
26374
26735
|
hasReactiveWrites: false
|
|
26375
26736
|
} : null);
|
|
26376
|
-
const lowered = lowerExpression2(expr, ctx);
|
|
26737
|
+
const lowered = lowerExpression2(expr, ctx, valueUsed);
|
|
26377
26738
|
if (ctx.t.isAssignmentExpression(lowered)) {
|
|
26378
26739
|
const right = applyRegionMetadataToExpression2(lowered.right, ctx, regionOverride ?? void 0);
|
|
26379
26740
|
return ctx.t.assignmentExpression(lowered.operator, lowered.left, right);
|
|
@@ -26495,7 +26856,7 @@ function lowerInstruction(instr, ctx) {
|
|
|
26495
26856
|
);
|
|
26496
26857
|
}
|
|
26497
26858
|
if (instr.kind === "Expression") {
|
|
26498
|
-
return applyLoc(t4.expressionStatement(lowerTrackedExpression(instr.value, ctx)));
|
|
26859
|
+
return applyLoc(t4.expressionStatement(lowerTrackedExpression(instr.value, ctx, false)));
|
|
26499
26860
|
}
|
|
26500
26861
|
if (instr.kind === "Phi") {
|
|
26501
26862
|
return null;
|
|
@@ -26659,7 +27020,7 @@ function collectLocalDeclaredNames(params, blocks, t4) {
|
|
|
26659
27020
|
}
|
|
26660
27021
|
return declared;
|
|
26661
27022
|
}
|
|
26662
|
-
function lowerExpression2(expr, ctx,
|
|
27023
|
+
function lowerExpression2(expr, ctx, valueUsed = true) {
|
|
26663
27024
|
const depth = (ctx.expressionDepth ?? 0) + 1;
|
|
26664
27025
|
const maxDepth = ctx.maxExpressionDepth ?? 500;
|
|
26665
27026
|
if (depth > maxDepth) {
|
|
@@ -26670,12 +27031,12 @@ function lowerExpression2(expr, ctx, isAssigned = false) {
|
|
|
26670
27031
|
}
|
|
26671
27032
|
ctx.expressionDepth = depth;
|
|
26672
27033
|
try {
|
|
26673
|
-
return setNodeLoc(lowerExpressionImpl(expr, ctx,
|
|
27034
|
+
return setNodeLoc(lowerExpressionImpl(expr, ctx, valueUsed), expr.loc);
|
|
26674
27035
|
} finally {
|
|
26675
27036
|
ctx.expressionDepth = depth - 1;
|
|
26676
27037
|
}
|
|
26677
27038
|
}
|
|
26678
|
-
function lowerExpressionImpl(expr, ctx,
|
|
27039
|
+
function lowerExpressionImpl(expr, ctx, valueUsed = true) {
|
|
26679
27040
|
const { t: t4 } = ctx;
|
|
26680
27041
|
const mapParams = (params) => params.map((p) => t4.identifier(deSSAVarName(p.name)));
|
|
26681
27042
|
const lowerArgsAsExpressions = (args) => args.map(
|
|
@@ -26716,6 +27077,152 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
26716
27077
|
ctx.localDeclaredNames = prevLocalDeclared;
|
|
26717
27078
|
return result;
|
|
26718
27079
|
};
|
|
27080
|
+
const lowerTrackedWriteCall = (callee, nextValue) => {
|
|
27081
|
+
if (!valueUsed) {
|
|
27082
|
+
return t4.callExpression(t4.cloneNode(callee, true), [nextValue]);
|
|
27083
|
+
}
|
|
27084
|
+
const nextId = genTemp3(ctx, "next");
|
|
27085
|
+
const nextRef = t4.identifier(nextId.name);
|
|
27086
|
+
return t4.callExpression(
|
|
27087
|
+
t4.arrowFunctionExpression(
|
|
27088
|
+
[t4.cloneNode(nextId, true)],
|
|
27089
|
+
t4.sequenceExpression([
|
|
27090
|
+
t4.callExpression(t4.cloneNode(callee, true), [nextRef]),
|
|
27091
|
+
t4.identifier(nextId.name)
|
|
27092
|
+
])
|
|
27093
|
+
),
|
|
27094
|
+
[nextValue]
|
|
27095
|
+
);
|
|
27096
|
+
};
|
|
27097
|
+
const buildTrackedAssignmentNext = (operator, current, right) => {
|
|
27098
|
+
switch (operator) {
|
|
27099
|
+
case "=":
|
|
27100
|
+
return right;
|
|
27101
|
+
case "+=":
|
|
27102
|
+
return t4.binaryExpression("+", current, right);
|
|
27103
|
+
case "-=":
|
|
27104
|
+
return t4.binaryExpression("-", current, right);
|
|
27105
|
+
case "*=":
|
|
27106
|
+
return t4.binaryExpression("*", current, right);
|
|
27107
|
+
case "/=":
|
|
27108
|
+
return t4.binaryExpression("/", current, right);
|
|
27109
|
+
case "%=":
|
|
27110
|
+
return t4.binaryExpression("%", current, right);
|
|
27111
|
+
case "**=":
|
|
27112
|
+
return t4.binaryExpression("**", current, right);
|
|
27113
|
+
case "<<=":
|
|
27114
|
+
return t4.binaryExpression("<<", current, right);
|
|
27115
|
+
case ">>=":
|
|
27116
|
+
return t4.binaryExpression(">>", current, right);
|
|
27117
|
+
case ">>>=":
|
|
27118
|
+
return t4.binaryExpression(">>>", current, right);
|
|
27119
|
+
case "|=":
|
|
27120
|
+
return t4.binaryExpression("|", current, right);
|
|
27121
|
+
case "^=":
|
|
27122
|
+
return t4.binaryExpression("^", current, right);
|
|
27123
|
+
case "&=":
|
|
27124
|
+
return t4.binaryExpression("&", current, right);
|
|
27125
|
+
case "&&=":
|
|
27126
|
+
return t4.logicalExpression("&&", current, right);
|
|
27127
|
+
case "||=":
|
|
27128
|
+
return t4.logicalExpression("||", current, right);
|
|
27129
|
+
case "??=":
|
|
27130
|
+
return t4.logicalExpression("??", current, right);
|
|
27131
|
+
default:
|
|
27132
|
+
return right;
|
|
27133
|
+
}
|
|
27134
|
+
};
|
|
27135
|
+
const buildStaticSignalKeyTest = (keyRef, keys) => {
|
|
27136
|
+
if (keys.length === 0) return null;
|
|
27137
|
+
let test = null;
|
|
27138
|
+
for (const key of keys) {
|
|
27139
|
+
const literal = typeof key === "number" ? t4.numericLiteral(key) : t4.stringLiteral(String(key));
|
|
27140
|
+
const eq = t4.binaryExpression("===", t4.cloneNode(keyRef, true), literal);
|
|
27141
|
+
test = test ? t4.logicalExpression("||", test, eq) : eq;
|
|
27142
|
+
}
|
|
27143
|
+
return test;
|
|
27144
|
+
};
|
|
27145
|
+
const lowerComputedHookSignalAssignment = (objectName, keyExpr, signalKeys, operator, rightExpr) => {
|
|
27146
|
+
const keyTestKeys = signalKeys.filter(
|
|
27147
|
+
(key) => typeof key === "number" && Number.isFinite(key) || typeof key === "string"
|
|
27148
|
+
);
|
|
27149
|
+
if (keyTestKeys.length === 0) return null;
|
|
27150
|
+
const keyId = genTemp3(ctx, "key");
|
|
27151
|
+
const keyRef = t4.identifier(keyId.name);
|
|
27152
|
+
const memberForAccessor = t4.memberExpression(
|
|
27153
|
+
t4.identifier(objectName),
|
|
27154
|
+
t4.identifier(keyId.name),
|
|
27155
|
+
true
|
|
27156
|
+
);
|
|
27157
|
+
const current = t4.callExpression(t4.cloneNode(memberForAccessor, true), []);
|
|
27158
|
+
const right = lowerExpression2(rightExpr, ctx);
|
|
27159
|
+
const signalWrite = lowerTrackedWriteCall(
|
|
27160
|
+
memberForAccessor,
|
|
27161
|
+
buildTrackedAssignmentNext(operator, current, t4.cloneNode(right, true))
|
|
27162
|
+
);
|
|
27163
|
+
const fallback = t4.assignmentExpression(
|
|
27164
|
+
operator,
|
|
27165
|
+
t4.memberExpression(t4.identifier(objectName), t4.identifier(keyId.name), true),
|
|
27166
|
+
right
|
|
27167
|
+
);
|
|
27168
|
+
const keyTest = buildStaticSignalKeyTest(keyRef, keyTestKeys);
|
|
27169
|
+
if (!keyTest) return null;
|
|
27170
|
+
return t4.callExpression(
|
|
27171
|
+
t4.arrowFunctionExpression(
|
|
27172
|
+
[t4.cloneNode(keyId, true)],
|
|
27173
|
+
t4.conditionalExpression(keyTest, signalWrite, fallback)
|
|
27174
|
+
),
|
|
27175
|
+
[lowerExpression2(keyExpr, ctx)]
|
|
27176
|
+
);
|
|
27177
|
+
};
|
|
27178
|
+
const lowerComputedHookSignalUpdate = (objectName, keyExpr, signalKeys, operator, prefix) => {
|
|
27179
|
+
const keyTestKeys = signalKeys.filter(
|
|
27180
|
+
(key) => typeof key === "number" && Number.isFinite(key) || typeof key === "string"
|
|
27181
|
+
);
|
|
27182
|
+
if (keyTestKeys.length === 0) return null;
|
|
27183
|
+
const keyId = genTemp3(ctx, "key");
|
|
27184
|
+
const keyRef = t4.identifier(keyId.name);
|
|
27185
|
+
const signalUpdate = lowerTrackedUpdateCall(
|
|
27186
|
+
t4.memberExpression(t4.identifier(objectName), t4.identifier(keyId.name), true),
|
|
27187
|
+
operator,
|
|
27188
|
+
prefix
|
|
27189
|
+
);
|
|
27190
|
+
const fallback = t4.updateExpression(
|
|
27191
|
+
operator,
|
|
27192
|
+
t4.memberExpression(t4.identifier(objectName), t4.identifier(keyId.name), true),
|
|
27193
|
+
prefix
|
|
27194
|
+
);
|
|
27195
|
+
const keyTest = buildStaticSignalKeyTest(keyRef, keyTestKeys);
|
|
27196
|
+
if (!keyTest) return null;
|
|
27197
|
+
return t4.callExpression(
|
|
27198
|
+
t4.arrowFunctionExpression(
|
|
27199
|
+
[t4.cloneNode(keyId, true)],
|
|
27200
|
+
t4.conditionalExpression(keyTest, signalUpdate, fallback)
|
|
27201
|
+
),
|
|
27202
|
+
[lowerExpression2(keyExpr, ctx)]
|
|
27203
|
+
);
|
|
27204
|
+
};
|
|
27205
|
+
const lowerTrackedUpdateCall = (callee, operator, prefix) => {
|
|
27206
|
+
const op = operator === "++" ? "+" : "-";
|
|
27207
|
+
const delta = t4.numericLiteral(1);
|
|
27208
|
+
const current = t4.callExpression(t4.cloneNode(callee, true), []);
|
|
27209
|
+
if (!valueUsed) {
|
|
27210
|
+
return t4.callExpression(t4.cloneNode(callee, true), [t4.binaryExpression(op, current, delta)]);
|
|
27211
|
+
}
|
|
27212
|
+
const prevId = genTemp3(ctx, "prev");
|
|
27213
|
+
const prevForSet = t4.identifier(prevId.name);
|
|
27214
|
+
const prevForResult = t4.identifier(prevId.name);
|
|
27215
|
+
return t4.callExpression(
|
|
27216
|
+
t4.arrowFunctionExpression(
|
|
27217
|
+
[t4.cloneNode(prevId, true)],
|
|
27218
|
+
t4.sequenceExpression([
|
|
27219
|
+
t4.callExpression(t4.cloneNode(callee, true), [t4.binaryExpression(op, prevForSet, delta)]),
|
|
27220
|
+
prefix ? t4.binaryExpression(op, prevForResult, t4.numericLiteral(1)) : prevForResult
|
|
27221
|
+
])
|
|
27222
|
+
),
|
|
27223
|
+
[current]
|
|
27224
|
+
);
|
|
27225
|
+
};
|
|
26719
27226
|
const lowerBlocksToStatements = (blocks) => {
|
|
26720
27227
|
const stmts = [];
|
|
26721
27228
|
for (const block of blocks) {
|
|
@@ -26885,6 +27392,24 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
26885
27392
|
expr.arguments,
|
|
26886
27393
|
(arg) => arg.kind === "ArrowFunction" || arg.kind === "FunctionExpression" ? withNonReactiveScope(ctx, () => lowerExpression2(arg, ctx)) : lowerExpression2(arg, ctx)
|
|
26887
27394
|
);
|
|
27395
|
+
const includeDevtools = ctx.options?.dev !== false;
|
|
27396
|
+
if (includeDevtools && expr.loc) {
|
|
27397
|
+
const source = `${ctx.options?.filename ?? ""}:${expr.loc.start.line}:${expr.loc.start.column}`;
|
|
27398
|
+
const sourceProp = t4.objectProperty(
|
|
27399
|
+
t4.identifier("devToolsSource"),
|
|
27400
|
+
t4.stringLiteral(source)
|
|
27401
|
+
);
|
|
27402
|
+
if (args.length === 1) {
|
|
27403
|
+
args.push(t4.objectExpression([sourceProp]));
|
|
27404
|
+
} else if (args.length > 1 && t4.isObjectExpression(args[1])) {
|
|
27405
|
+
const hasSourceProp = args[1].properties.some(
|
|
27406
|
+
(prop) => t4.isObjectProperty(prop) && t4.isIdentifier(prop.key) && prop.key.name === "devToolsSource"
|
|
27407
|
+
);
|
|
27408
|
+
if (!hasSourceProp) {
|
|
27409
|
+
args[1].properties.push(sourceProp);
|
|
27410
|
+
}
|
|
27411
|
+
}
|
|
27412
|
+
}
|
|
26888
27413
|
if (ctx.inModule) {
|
|
26889
27414
|
ctx.helpersUsed.add("effect");
|
|
26890
27415
|
return t4.callExpression(t4.identifier(RUNTIME_ALIASES.effect), args);
|
|
@@ -27192,59 +27717,42 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
27192
27717
|
expr.left.computed,
|
|
27193
27718
|
expr.left.optional
|
|
27194
27719
|
);
|
|
27195
|
-
const current = t4.callExpression(member, []);
|
|
27720
|
+
const current = t4.callExpression(t4.cloneNode(member, true), []);
|
|
27196
27721
|
const right = lowerExpression2(expr.right, ctx);
|
|
27197
|
-
|
|
27198
|
-
|
|
27199
|
-
|
|
27200
|
-
|
|
27201
|
-
|
|
27202
|
-
|
|
27203
|
-
|
|
27204
|
-
|
|
27205
|
-
|
|
27206
|
-
next = t4.binaryExpression("-", current, right);
|
|
27207
|
-
break;
|
|
27208
|
-
case "*=":
|
|
27209
|
-
next = t4.binaryExpression("*", current, right);
|
|
27210
|
-
break;
|
|
27211
|
-
case "/=":
|
|
27212
|
-
next = t4.binaryExpression("/", current, right);
|
|
27213
|
-
break;
|
|
27214
|
-
default:
|
|
27215
|
-
next = right;
|
|
27722
|
+
const next = buildTrackedAssignmentNext(expr.operator, current, right);
|
|
27723
|
+
return lowerTrackedWriteCall(member, next);
|
|
27724
|
+
}
|
|
27725
|
+
if (expr.left.computed) {
|
|
27726
|
+
const signalKeys = [];
|
|
27727
|
+
if (info?.objectProps) {
|
|
27728
|
+
for (const [key, accessorKind] of info.objectProps.entries()) {
|
|
27729
|
+
if (accessorKind === "signal") signalKeys.push(key);
|
|
27730
|
+
}
|
|
27216
27731
|
}
|
|
27217
|
-
|
|
27732
|
+
if (info?.arrayProps) {
|
|
27733
|
+
for (const [key, accessorKind] of info.arrayProps.entries()) {
|
|
27734
|
+
if (accessorKind === "signal") signalKeys.push(key);
|
|
27735
|
+
}
|
|
27736
|
+
}
|
|
27737
|
+
const lowered = lowerComputedHookSignalAssignment(
|
|
27738
|
+
deSSAVarName(expr.left.object.name),
|
|
27739
|
+
expr.left.property,
|
|
27740
|
+
signalKeys,
|
|
27741
|
+
expr.operator,
|
|
27742
|
+
expr.right
|
|
27743
|
+
);
|
|
27744
|
+
if (lowered) return lowered;
|
|
27218
27745
|
}
|
|
27219
27746
|
}
|
|
27220
27747
|
}
|
|
27221
27748
|
if (expr.left.kind === "Identifier") {
|
|
27222
27749
|
const baseName2 = deSSAVarName(expr.left.name);
|
|
27223
27750
|
if (ctx.trackedVars.has(baseName2)) {
|
|
27224
|
-
const
|
|
27751
|
+
const callee = t4.identifier(baseName2);
|
|
27225
27752
|
const current = t4.callExpression(t4.identifier(baseName2), []);
|
|
27226
27753
|
const right = lowerExpression2(expr.right, ctx);
|
|
27227
|
-
|
|
27228
|
-
|
|
27229
|
-
case "=":
|
|
27230
|
-
next = right;
|
|
27231
|
-
break;
|
|
27232
|
-
case "+=":
|
|
27233
|
-
next = t4.binaryExpression("+", current, right);
|
|
27234
|
-
break;
|
|
27235
|
-
case "-=":
|
|
27236
|
-
next = t4.binaryExpression("-", current, right);
|
|
27237
|
-
break;
|
|
27238
|
-
case "*=":
|
|
27239
|
-
next = t4.binaryExpression("*", current, right);
|
|
27240
|
-
break;
|
|
27241
|
-
case "/=":
|
|
27242
|
-
next = t4.binaryExpression("/", current, right);
|
|
27243
|
-
break;
|
|
27244
|
-
default:
|
|
27245
|
-
next = right;
|
|
27246
|
-
}
|
|
27247
|
-
return t4.callExpression(id, [next]);
|
|
27754
|
+
const next = buildTrackedAssignmentNext(expr.operator, current, right);
|
|
27755
|
+
return lowerTrackedWriteCall(callee, next);
|
|
27248
27756
|
}
|
|
27249
27757
|
}
|
|
27250
27758
|
return t4.assignmentExpression(
|
|
@@ -27276,21 +27784,35 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
27276
27784
|
expr.argument.computed,
|
|
27277
27785
|
expr.argument.optional
|
|
27278
27786
|
);
|
|
27279
|
-
|
|
27280
|
-
|
|
27281
|
-
|
|
27282
|
-
|
|
27787
|
+
return lowerTrackedUpdateCall(member, expr.operator, expr.prefix);
|
|
27788
|
+
}
|
|
27789
|
+
if (expr.argument.computed) {
|
|
27790
|
+
const signalKeys = [];
|
|
27791
|
+
if (info?.objectProps) {
|
|
27792
|
+
for (const [key, accessorKind] of info.objectProps.entries()) {
|
|
27793
|
+
if (accessorKind === "signal") signalKeys.push(key);
|
|
27794
|
+
}
|
|
27795
|
+
}
|
|
27796
|
+
if (info?.arrayProps) {
|
|
27797
|
+
for (const [key, accessorKind] of info.arrayProps.entries()) {
|
|
27798
|
+
if (accessorKind === "signal") signalKeys.push(key);
|
|
27799
|
+
}
|
|
27800
|
+
}
|
|
27801
|
+
const lowered = lowerComputedHookSignalUpdate(
|
|
27802
|
+
deSSAVarName(expr.argument.object.name),
|
|
27803
|
+
expr.argument.property,
|
|
27804
|
+
signalKeys,
|
|
27805
|
+
expr.operator,
|
|
27806
|
+
expr.prefix
|
|
27807
|
+
);
|
|
27808
|
+
if (lowered) return lowered;
|
|
27283
27809
|
}
|
|
27284
27810
|
}
|
|
27285
27811
|
}
|
|
27286
27812
|
if (expr.argument.kind === "Identifier") {
|
|
27287
27813
|
const baseName2 = deSSAVarName(expr.argument.name);
|
|
27288
27814
|
if (ctx.trackedVars.has(baseName2)) {
|
|
27289
|
-
|
|
27290
|
-
const current = t4.callExpression(t4.identifier(baseName2), []);
|
|
27291
|
-
const delta = t4.numericLiteral(1);
|
|
27292
|
-
const next = expr.operator === "++" ? t4.binaryExpression("+", current, delta) : t4.binaryExpression("-", current, delta);
|
|
27293
|
-
return t4.callExpression(id, [next]);
|
|
27815
|
+
return lowerTrackedUpdateCall(t4.identifier(baseName2), expr.operator, expr.prefix);
|
|
27294
27816
|
}
|
|
27295
27817
|
}
|
|
27296
27818
|
return t4.updateExpression(
|
|
@@ -27312,7 +27834,11 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
27312
27834
|
case "NewExpression":
|
|
27313
27835
|
return t4.newExpression(lowerExpression2(expr.callee, ctx), lowerCallArguments(expr.arguments));
|
|
27314
27836
|
case "SequenceExpression":
|
|
27315
|
-
return t4.sequenceExpression(
|
|
27837
|
+
return t4.sequenceExpression(
|
|
27838
|
+
expr.expressions.map(
|
|
27839
|
+
(e, index) => lowerExpression2(e, ctx, index === expr.expressions.length - 1 ? valueUsed : false)
|
|
27840
|
+
)
|
|
27841
|
+
);
|
|
27316
27842
|
case "YieldExpression":
|
|
27317
27843
|
return t4.yieldExpression(
|
|
27318
27844
|
expr.argument ? lowerExpression2(expr.argument, ctx) : null,
|
|
@@ -27770,16 +28296,17 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
27770
28296
|
const hasEventOptions = binding.eventOptions && (binding.eventOptions.capture || binding.eventOptions.passive || binding.eventOptions.once);
|
|
27771
28297
|
const isDelegated = DelegatedEvents.has(eventName) && !hasEventOptions;
|
|
27772
28298
|
if (binding.resumable && !hasEventOptions) {
|
|
27773
|
-
emitResumableEventBinding(
|
|
28299
|
+
const emitted = emitResumableEventBinding(
|
|
27774
28300
|
targetId,
|
|
27775
28301
|
eventName,
|
|
27776
28302
|
binding.expr,
|
|
27777
28303
|
statements,
|
|
27778
28304
|
ctx,
|
|
27779
28305
|
containingRegion,
|
|
27780
|
-
createResumableEventBindingOps()
|
|
28306
|
+
createResumableEventBindingOps(),
|
|
28307
|
+
{ explicit: binding.resumableExplicit === true }
|
|
27781
28308
|
);
|
|
27782
|
-
continue;
|
|
28309
|
+
if (emitted) continue;
|
|
27783
28310
|
}
|
|
27784
28311
|
const hirDataBinding = isDelegated && binding.expr ? extractDelegatedEventDataFromHIR(binding.expr, ctx) : null;
|
|
27785
28312
|
if (hirDataBinding) {
|
|
@@ -27821,34 +28348,24 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
27821
28348
|
const isFn = t4.isArrowFunctionExpression(valueExpr) || t4.isFunctionExpression(valueExpr);
|
|
27822
28349
|
const ensureHandlerParam = (fn) => {
|
|
27823
28350
|
if (t4.isArrowFunctionExpression(fn)) {
|
|
27824
|
-
|
|
27825
|
-
return t4.arrowFunctionExpression([eventParam], fn.body, fn.async);
|
|
28351
|
+
return fn;
|
|
27826
28352
|
}
|
|
27827
28353
|
if (t4.isFunctionExpression(fn)) {
|
|
27828
|
-
|
|
27829
|
-
return t4.functionExpression(fn.id, [eventParam], fn.body, fn.generator, fn.async);
|
|
28354
|
+
return fn;
|
|
27830
28355
|
}
|
|
27831
28356
|
if (t4.isIdentifier(fn) || t4.isMemberExpression(fn)) {
|
|
27832
28357
|
return fn;
|
|
27833
28358
|
}
|
|
27834
|
-
if (t4.isCallExpression(fn) && fn.arguments.length === 0 && (t4.isIdentifier(fn.callee) || t4.isMemberExpression(fn.callee))) {
|
|
27835
|
-
return fn.callee;
|
|
27836
|
-
}
|
|
27837
28359
|
return t4.functionExpression(
|
|
27838
28360
|
null,
|
|
27839
|
-
[
|
|
27840
|
-
t4.blockStatement([
|
|
27841
|
-
t4.returnStatement(
|
|
27842
|
-
t4.callExpression(
|
|
27843
|
-
t4.memberExpression(fn, t4.identifier("call")),
|
|
27844
|
-
[t4.thisExpression(), eventParam]
|
|
27845
|
-
)
|
|
27846
|
-
)
|
|
27847
|
-
])
|
|
28361
|
+
[],
|
|
28362
|
+
t4.blockStatement([t4.returnStatement(fn)])
|
|
27848
28363
|
);
|
|
27849
28364
|
};
|
|
27850
28365
|
const handlerExpr = !isFn && shouldWrapHandler ? t4.arrowFunctionExpression([], valueExpr) : ensureHandlerParam(valueExpr);
|
|
27851
|
-
let dataBinding = isDelegated && !shouldWrapHandler ? extractDelegatedEventData(valueExpr, t4
|
|
28366
|
+
let dataBinding = isDelegated && !shouldWrapHandler ? extractDelegatedEventData(valueExpr, t4, {
|
|
28367
|
+
isKnownHandlerIdentifier: (name) => ctx.functionVars?.has(deSSAVarName(name)) ?? false
|
|
28368
|
+
}) : null;
|
|
27852
28369
|
if (dataBinding && t4.isIdentifier(dataBinding.handler)) {
|
|
27853
28370
|
const handlerName = dataBinding.handler.name;
|
|
27854
28371
|
if (ctx.signalVars?.has(handlerName) || ctx.memoVars?.has(handlerName) || ctx.aliasVars?.has(handlerName) || ctx.storeVars?.has(handlerName) || ctx.trackedVars.has(handlerName)) {
|
|
@@ -27860,8 +28377,6 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
27860
28377
|
let handlerName = null;
|
|
27861
28378
|
if (t4.isIdentifier(valueExpr)) {
|
|
27862
28379
|
handlerName = valueExpr.name;
|
|
27863
|
-
} else if (t4.isCallExpression(valueExpr) && valueExpr.arguments.length === 0 && t4.isIdentifier(valueExpr.callee)) {
|
|
27864
|
-
handlerName = valueExpr.callee.name;
|
|
27865
28380
|
}
|
|
27866
28381
|
const handlerForCall = handlerName ? t4.identifier(handlerName) : t4.cloneNode(valueExpr, true);
|
|
27867
28382
|
const finalHandler = !isFn && shouldWrapHandler ? t4.functionExpression(
|
|
@@ -27877,9 +28392,6 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
27877
28392
|
])
|
|
27878
28393
|
) : handlerExpr;
|
|
27879
28394
|
const normalizeHandler = (expr) => {
|
|
27880
|
-
if (t4.isCallExpression(expr) && (t4.isIdentifier(expr.callee) || t4.isMemberExpression(expr.callee))) {
|
|
27881
|
-
return expr.callee;
|
|
27882
|
-
}
|
|
27883
28395
|
return expr;
|
|
27884
28396
|
};
|
|
27885
28397
|
const normalizedDataHandler = dataBinding !== null ? normalizeHandler(
|
|
@@ -28553,10 +29065,13 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28553
29065
|
}
|
|
28554
29066
|
return false;
|
|
28555
29067
|
};
|
|
28556
|
-
function hasNodeMatch(nodes, predicate) {
|
|
29068
|
+
function hasNodeMatch(nodes, predicate, options) {
|
|
28557
29069
|
let found = false;
|
|
28558
|
-
const visit = (node) => {
|
|
29070
|
+
const visit = (node, isRoot = false) => {
|
|
28559
29071
|
if (!node || found) return;
|
|
29072
|
+
if (!isRoot && options?.skipNestedFunctions && (t4.isFunctionExpression(node) || t4.isArrowFunctionExpression(node) || t4.isFunctionDeclaration(node) || t4.isObjectMethod(node) || t4.isClassMethod(node))) {
|
|
29073
|
+
return;
|
|
29074
|
+
}
|
|
28560
29075
|
if (predicate(node)) {
|
|
28561
29076
|
found = true;
|
|
28562
29077
|
return;
|
|
@@ -28579,17 +29094,134 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28579
29094
|
}
|
|
28580
29095
|
};
|
|
28581
29096
|
for (const node of nodes) {
|
|
28582
|
-
visit(node);
|
|
29097
|
+
visit(node, true);
|
|
28583
29098
|
if (found) return true;
|
|
28584
29099
|
}
|
|
28585
29100
|
return found;
|
|
28586
29101
|
}
|
|
28587
29102
|
const containsReturnStatement = (nodes) => hasNodeMatch(nodes, (node) => t4.isReturnStatement(node));
|
|
28588
|
-
const
|
|
28589
|
-
|
|
28590
|
-
|
|
28591
|
-
|
|
28592
|
-
|
|
29103
|
+
const getMemberRootIdentifier = (expr) => {
|
|
29104
|
+
let current = expr.object;
|
|
29105
|
+
while (t4.isMemberExpression(current) || t4.isOptionalMemberExpression(current)) {
|
|
29106
|
+
current = current.object;
|
|
29107
|
+
}
|
|
29108
|
+
return t4.isIdentifier(current) ? current : null;
|
|
29109
|
+
};
|
|
29110
|
+
const containsReactiveAccessorRead = (nodes, options) => hasNodeMatch(
|
|
29111
|
+
nodes,
|
|
29112
|
+
(node) => {
|
|
29113
|
+
if (t4.isCallExpression(node) || t4.isOptionalCallExpression(node)) {
|
|
29114
|
+
const callee = node.callee;
|
|
29115
|
+
return t4.isIdentifier(callee) && reactiveAccessorNames.has(callee.name);
|
|
29116
|
+
}
|
|
29117
|
+
if (t4.isMemberExpression(node) || t4.isOptionalMemberExpression(node)) {
|
|
29118
|
+
const root = getMemberRootIdentifier(node);
|
|
29119
|
+
return !!(root && reactiveAccessorNames.has(root.name));
|
|
29120
|
+
}
|
|
29121
|
+
return false;
|
|
29122
|
+
},
|
|
29123
|
+
options
|
|
29124
|
+
);
|
|
29125
|
+
const containsReactiveControlFlowRead = (nodes) => hasNodeMatch(
|
|
29126
|
+
nodes,
|
|
29127
|
+
(node) => {
|
|
29128
|
+
if (t4.isIfStatement(node)) {
|
|
29129
|
+
return containsReactiveAccessorRead([node.test], { skipNestedFunctions: true });
|
|
29130
|
+
}
|
|
29131
|
+
if (t4.isSwitchStatement(node)) {
|
|
29132
|
+
return containsReactiveAccessorRead([node.discriminant], { skipNestedFunctions: true });
|
|
29133
|
+
}
|
|
29134
|
+
if (t4.isConditionalExpression(node)) {
|
|
29135
|
+
return containsReactiveAccessorRead([node.test], { skipNestedFunctions: true });
|
|
29136
|
+
}
|
|
29137
|
+
if (t4.isWhileStatement(node) || t4.isDoWhileStatement(node)) {
|
|
29138
|
+
return containsReactiveAccessorRead([node.test], { skipNestedFunctions: true });
|
|
29139
|
+
}
|
|
29140
|
+
if (t4.isForStatement(node)) {
|
|
29141
|
+
const parts = [];
|
|
29142
|
+
if (node.init) parts.push(node.init);
|
|
29143
|
+
if (node.test) parts.push(node.test);
|
|
29144
|
+
if (node.update) parts.push(node.update);
|
|
29145
|
+
return parts.length > 0 && containsReactiveAccessorRead(parts, { skipNestedFunctions: true });
|
|
29146
|
+
}
|
|
29147
|
+
if (t4.isForOfStatement(node) || t4.isForInStatement(node)) {
|
|
29148
|
+
return containsReactiveAccessorRead([node.right], { skipNestedFunctions: true });
|
|
29149
|
+
}
|
|
29150
|
+
return false;
|
|
29151
|
+
},
|
|
29152
|
+
{ skipNestedFunctions: true }
|
|
29153
|
+
);
|
|
29154
|
+
const hasRiskyBranchControlFlow = (stmts) => {
|
|
29155
|
+
if (stmts.length === 0) return false;
|
|
29156
|
+
return containsReactiveControlFlowRead(stmts);
|
|
29157
|
+
};
|
|
29158
|
+
const isJSXLikeNode = (node) => !!node && (t4.isJSXElement(node) || t4.isJSXFragment(node));
|
|
29159
|
+
const isStoreSourceExpression = (expr) => {
|
|
29160
|
+
if (t4.isIdentifier(expr)) {
|
|
29161
|
+
return !!ctx.storeVars?.has(expr.name);
|
|
29162
|
+
}
|
|
29163
|
+
if (t4.isMemberExpression(expr) || t4.isOptionalMemberExpression(expr)) {
|
|
29164
|
+
const root = getMemberRootIdentifier(expr);
|
|
29165
|
+
return !!(root && ctx.storeVars?.has(root.name));
|
|
29166
|
+
}
|
|
29167
|
+
return false;
|
|
29168
|
+
};
|
|
29169
|
+
const hasRiskyStoreDestructureRead = (stmt) => {
|
|
29170
|
+
if (t4.isVariableDeclaration(stmt)) {
|
|
29171
|
+
for (const decl of stmt.declarations) {
|
|
29172
|
+
if (!decl.init) continue;
|
|
29173
|
+
const hasPattern = t4.isObjectPattern(decl.id) || t4.isArrayPattern(decl.id);
|
|
29174
|
+
if (!hasPattern) continue;
|
|
29175
|
+
if (isStoreSourceExpression(decl.init)) {
|
|
29176
|
+
return true;
|
|
29177
|
+
}
|
|
29178
|
+
}
|
|
29179
|
+
return false;
|
|
29180
|
+
}
|
|
29181
|
+
if (t4.isExpressionStatement(stmt) && t4.isAssignmentExpression(stmt.expression)) {
|
|
29182
|
+
const assignment = stmt.expression;
|
|
29183
|
+
const isPatternLhs = t4.isObjectPattern(assignment.left) || t4.isArrayPattern(assignment.left);
|
|
29184
|
+
if (!isPatternLhs) return false;
|
|
29185
|
+
return isStoreSourceExpression(assignment.right);
|
|
29186
|
+
}
|
|
29187
|
+
return false;
|
|
29188
|
+
};
|
|
29189
|
+
const hasRiskyBranchPreludeReads = (stmts) => {
|
|
29190
|
+
for (const stmt of stmts) {
|
|
29191
|
+
if (hasRiskyStoreDestructureRead(stmt)) {
|
|
29192
|
+
return true;
|
|
29193
|
+
}
|
|
29194
|
+
if (t4.isReturnStatement(stmt)) {
|
|
29195
|
+
const arg = stmt.argument;
|
|
29196
|
+
if (!arg || isJSXLikeNode(arg)) continue;
|
|
29197
|
+
if (containsReactiveAccessorRead([arg], { skipNestedFunctions: true })) {
|
|
29198
|
+
return true;
|
|
29199
|
+
}
|
|
29200
|
+
continue;
|
|
29201
|
+
}
|
|
29202
|
+
if (containsReactiveAccessorRead([stmt], { skipNestedFunctions: true })) {
|
|
29203
|
+
return true;
|
|
29204
|
+
}
|
|
29205
|
+
}
|
|
29206
|
+
return false;
|
|
29207
|
+
};
|
|
29208
|
+
const hasRiskyImmediateInvocationReads = (stmts) => hasNodeMatch(
|
|
29209
|
+
stmts,
|
|
29210
|
+
(node) => {
|
|
29211
|
+
if (!t4.isCallExpression(node) && !t4.isOptionalCallExpression(node)) return false;
|
|
29212
|
+
const callee = node.callee;
|
|
29213
|
+
if (!t4.isFunctionExpression(callee) && !t4.isArrowFunctionExpression(callee)) {
|
|
29214
|
+
return false;
|
|
29215
|
+
}
|
|
29216
|
+
const bodyNodes = t4.isBlockStatement(callee.body) ? callee.body.body : [callee.body];
|
|
29217
|
+
return containsReactiveAccessorRead(bodyNodes, { skipNestedFunctions: true });
|
|
29218
|
+
},
|
|
29219
|
+
{ skipNestedFunctions: true }
|
|
29220
|
+
);
|
|
29221
|
+
const needsTrackedBranchReads = (stmts) => {
|
|
29222
|
+
if (stmts.length === 0) return false;
|
|
29223
|
+
return hasRiskyBranchControlFlow(stmts) || hasRiskyBranchPreludeReads(stmts) || hasRiskyImmediateInvocationReads(stmts);
|
|
29224
|
+
};
|
|
28593
29225
|
const emitControlFlowFallbackWarning = (node, kind) => {
|
|
28594
29226
|
const onWarn = ctx.options?.onWarn;
|
|
28595
29227
|
if (!onWarn) return;
|
|
@@ -28658,7 +29290,7 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28658
29290
|
}
|
|
28659
29291
|
return found;
|
|
28660
29292
|
}
|
|
28661
|
-
function buildConditionalBindingExpr(testExpr, trueFn, falseFn) {
|
|
29293
|
+
function buildConditionalBindingExpr(testExpr, trueFn, falseFn, options) {
|
|
28662
29294
|
ctx.helpersUsed.add("conditional");
|
|
28663
29295
|
ctx.helpersUsed.add("createElement");
|
|
28664
29296
|
ctx.helpersUsed.add("onDestroy");
|
|
@@ -28669,6 +29301,16 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28669
29301
|
t4.identifier(RUNTIME_ALIASES.createElement),
|
|
28670
29302
|
falseFn
|
|
28671
29303
|
];
|
|
29304
|
+
if (options?.trackBranchReads) {
|
|
29305
|
+
const undefinedExpr = t4.unaryExpression("void", t4.numericLiteral(0));
|
|
29306
|
+
args.push(
|
|
29307
|
+
undefinedExpr,
|
|
29308
|
+
t4.cloneNode(undefinedExpr),
|
|
29309
|
+
t4.objectExpression([
|
|
29310
|
+
t4.objectProperty(t4.identifier("trackBranchReads"), t4.booleanLiteral(true))
|
|
29311
|
+
])
|
|
29312
|
+
);
|
|
29313
|
+
}
|
|
28672
29314
|
const bindingCall = t4.callExpression(t4.identifier(RUNTIME_ALIASES.conditional), args);
|
|
28673
29315
|
return t4.callExpression(
|
|
28674
29316
|
t4.arrowFunctionExpression(
|
|
@@ -28702,7 +29344,13 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28702
29344
|
const trueFn = buildBranchFunction(consequentStmts);
|
|
28703
29345
|
const falseFn = alternateStmts ? buildBranchFunction(alternateStmts) : null;
|
|
28704
29346
|
if (!trueFn || !falseFn) return null;
|
|
28705
|
-
|
|
29347
|
+
const shouldTrackBranchReads = needsTrackedBranchReads(consequentStmts) || (alternateStmts ? needsTrackedBranchReads(alternateStmts) : false);
|
|
29348
|
+
return buildConditionalBindingExpr(
|
|
29349
|
+
ifStmt.test,
|
|
29350
|
+
trueFn,
|
|
29351
|
+
falseFn,
|
|
29352
|
+
shouldTrackBranchReads ? { trackBranchReads: true } : void 0
|
|
29353
|
+
);
|
|
28706
29354
|
}
|
|
28707
29355
|
function isSupportedSwitchDiscriminant(_expr) {
|
|
28708
29356
|
return true;
|
|
@@ -28795,10 +29443,13 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28795
29443
|
),
|
|
28796
29444
|
[]
|
|
28797
29445
|
);
|
|
29446
|
+
let currentExprNeedsTrackedBranchReads = needsTrackedBranchReads(fallbackStatements);
|
|
28798
29447
|
for (let i = branches.length - 1; i >= 0; i--) {
|
|
28799
29448
|
const branch = branches[i];
|
|
28800
29449
|
const trueFn = buildBranchFunction(branch.statements, { disallowRenderHooks: true });
|
|
28801
29450
|
if (!trueFn) return null;
|
|
29451
|
+
const trueBranchNeedsTrackedBranchReads = needsTrackedBranchReads(branch.statements);
|
|
29452
|
+
const trackBranchReads = trueBranchNeedsTrackedBranchReads || currentExprNeedsTrackedBranchReads;
|
|
28802
29453
|
const falseFn = t4.arrowFunctionExpression(
|
|
28803
29454
|
[],
|
|
28804
29455
|
t4.blockStatement([t4.returnStatement(currentExpr)])
|
|
@@ -28815,7 +29466,13 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
28815
29466
|
(acc, expr) => t4.logicalExpression("||", acc, expr),
|
|
28816
29467
|
comparisons[0]
|
|
28817
29468
|
);
|
|
28818
|
-
currentExpr = buildConditionalBindingExpr(
|
|
29469
|
+
currentExpr = buildConditionalBindingExpr(
|
|
29470
|
+
testExpr,
|
|
29471
|
+
trueFn,
|
|
29472
|
+
falseFn,
|
|
29473
|
+
trackBranchReads ? { trackBranchReads: true } : void 0
|
|
29474
|
+
);
|
|
29475
|
+
currentExprNeedsTrackedBranchReads = trackBranchReads;
|
|
28819
29476
|
}
|
|
28820
29477
|
return t4.callExpression(
|
|
28821
29478
|
t4.arrowFunctionExpression(
|
|
@@ -30185,11 +30842,27 @@ function optimizeReactiveBlock(block, reactive, purity, options) {
|
|
|
30185
30842
|
const constArrays = /* @__PURE__ */ new Map();
|
|
30186
30843
|
const cseMap = /* @__PURE__ */ new Map();
|
|
30187
30844
|
const instructions = [];
|
|
30845
|
+
const deleteByBase = (map, name) => {
|
|
30846
|
+
const base = getSSABaseName(name);
|
|
30847
|
+
for (const key of Array.from(map.keys())) {
|
|
30848
|
+
if (getSSABaseName(key) === base) {
|
|
30849
|
+
map.delete(key);
|
|
30850
|
+
}
|
|
30851
|
+
}
|
|
30852
|
+
};
|
|
30188
30853
|
const invalidateCSE = (name) => {
|
|
30854
|
+
const base = getSSABaseName(name);
|
|
30189
30855
|
const toDelete = [];
|
|
30190
30856
|
for (const [hash, entry] of cseMap.entries()) {
|
|
30191
|
-
if (entry.name ===
|
|
30857
|
+
if (getSSABaseName(entry.name) === base) {
|
|
30192
30858
|
toDelete.push(hash);
|
|
30859
|
+
continue;
|
|
30860
|
+
}
|
|
30861
|
+
for (const dep of entry.deps) {
|
|
30862
|
+
if (getSSABaseName(dep) === base) {
|
|
30863
|
+
toDelete.push(hash);
|
|
30864
|
+
break;
|
|
30865
|
+
}
|
|
30193
30866
|
}
|
|
30194
30867
|
}
|
|
30195
30868
|
toDelete.forEach((hash) => cseMap.delete(hash));
|
|
@@ -30199,22 +30872,22 @@ function optimizeReactiveBlock(block, reactive, purity, options) {
|
|
|
30199
30872
|
const target = instr.target.name;
|
|
30200
30873
|
const declKind = instr.declarationKind;
|
|
30201
30874
|
invalidateCSE(target);
|
|
30202
|
-
constants
|
|
30203
|
-
constObjects
|
|
30204
|
-
constArrays
|
|
30875
|
+
deleteByBase(constants, target);
|
|
30876
|
+
deleteByBase(constObjects, target);
|
|
30877
|
+
deleteByBase(constArrays, target);
|
|
30205
30878
|
const sideWrites = collectWriteTargets(instr.value);
|
|
30206
30879
|
for (const name of sideWrites) {
|
|
30207
30880
|
if (name !== target) {
|
|
30208
|
-
constants
|
|
30881
|
+
deleteByBase(constants, name);
|
|
30209
30882
|
invalidateCSE(name);
|
|
30210
30883
|
}
|
|
30211
|
-
constObjects
|
|
30212
|
-
constArrays
|
|
30884
|
+
deleteByBase(constObjects, name);
|
|
30885
|
+
deleteByBase(constArrays, name);
|
|
30213
30886
|
}
|
|
30214
30887
|
const memberCalls = collectMemberCallTargets(instr.value);
|
|
30215
30888
|
for (const name of memberCalls) {
|
|
30216
|
-
constObjects
|
|
30217
|
-
constArrays
|
|
30889
|
+
deleteByBase(constObjects, name);
|
|
30890
|
+
deleteByBase(constArrays, name);
|
|
30218
30891
|
}
|
|
30219
30892
|
const dependsOnReactiveValue = expressionDependsOnReactive(instr.value, reactive);
|
|
30220
30893
|
let value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, options, constObjects, constArrays);
|
|
@@ -30254,15 +30927,15 @@ function optimizeReactiveBlock(block, reactive, purity, options) {
|
|
|
30254
30927
|
if (instr.kind === "Expression") {
|
|
30255
30928
|
const writes = collectWriteTargets(instr.value);
|
|
30256
30929
|
for (const name of writes) {
|
|
30257
|
-
constants
|
|
30930
|
+
deleteByBase(constants, name);
|
|
30258
30931
|
invalidateCSE(name);
|
|
30259
|
-
constObjects
|
|
30260
|
-
constArrays
|
|
30932
|
+
deleteByBase(constObjects, name);
|
|
30933
|
+
deleteByBase(constArrays, name);
|
|
30261
30934
|
}
|
|
30262
30935
|
const memberCalls = collectMemberCallTargets(instr.value);
|
|
30263
30936
|
for (const name of memberCalls) {
|
|
30264
|
-
constObjects
|
|
30265
|
-
constArrays
|
|
30937
|
+
deleteByBase(constObjects, name);
|
|
30938
|
+
deleteByBase(constArrays, name);
|
|
30266
30939
|
}
|
|
30267
30940
|
const dependsOnReactiveValue = expressionDependsOnReactive(instr.value, reactive);
|
|
30268
30941
|
const value = dependsOnReactiveValue ? instr.value : foldExpressionWithConstants(instr.value, constants, options, constObjects, constArrays);
|
|
@@ -30912,6 +31585,8 @@ function collectWriteTargets(expr) {
|
|
|
30912
31585
|
} else if (left.kind === "MemberExpression" || left.kind === "OptionalMemberExpression") {
|
|
30913
31586
|
const base = getMemberBaseIdentifier(left);
|
|
30914
31587
|
if (base) writes.add(base.name);
|
|
31588
|
+
visit(left.object);
|
|
31589
|
+
if (left.computed) visit(left.property);
|
|
30915
31590
|
} else {
|
|
30916
31591
|
visit(left);
|
|
30917
31592
|
}
|
|
@@ -30928,8 +31603,10 @@ function collectWriteTargets(expr) {
|
|
|
30928
31603
|
const base = getMemberBaseIdentifier(arg);
|
|
30929
31604
|
if (base) {
|
|
30930
31605
|
writes.add(base.name);
|
|
30931
|
-
return;
|
|
30932
31606
|
}
|
|
31607
|
+
visit(arg.object);
|
|
31608
|
+
if (arg.computed) visit(arg.property);
|
|
31609
|
+
return;
|
|
30933
31610
|
}
|
|
30934
31611
|
visit(arg);
|
|
30935
31612
|
return;
|
|
@@ -31235,6 +31912,16 @@ function propagateConstants(fn, options) {
|
|
|
31235
31912
|
}
|
|
31236
31913
|
function computeConstantMap(fn) {
|
|
31237
31914
|
const constants = /* @__PURE__ */ new Map();
|
|
31915
|
+
const invalidateWrittenName = (writtenName) => {
|
|
31916
|
+
const writtenBase = getSSABaseName(writtenName);
|
|
31917
|
+
let removed = false;
|
|
31918
|
+
for (const constantName of Array.from(constants.keys())) {
|
|
31919
|
+
if (constantName === writtenName || getSSABaseName(constantName) === writtenBase) {
|
|
31920
|
+
removed = constants.delete(constantName) || removed;
|
|
31921
|
+
}
|
|
31922
|
+
}
|
|
31923
|
+
return removed;
|
|
31924
|
+
};
|
|
31238
31925
|
let changed = true;
|
|
31239
31926
|
let iterations = 0;
|
|
31240
31927
|
const maxIterations = 10;
|
|
@@ -31243,6 +31930,14 @@ function computeConstantMap(fn) {
|
|
|
31243
31930
|
changed = false;
|
|
31244
31931
|
for (const block of fn.blocks) {
|
|
31245
31932
|
for (const instr of block.instructions) {
|
|
31933
|
+
if (instr.kind === "Assign" || instr.kind === "Expression") {
|
|
31934
|
+
const writes = collectWriteTargets(instr.value);
|
|
31935
|
+
for (const writtenName of writes) {
|
|
31936
|
+
if (invalidateWrittenName(writtenName)) {
|
|
31937
|
+
changed = true;
|
|
31938
|
+
}
|
|
31939
|
+
}
|
|
31940
|
+
}
|
|
31246
31941
|
if (instr.kind === "Assign") {
|
|
31247
31942
|
const value = evaluateConstant(instr.value, constants);
|
|
31248
31943
|
if (value !== UNKNOWN_CONST) {
|
|
@@ -33164,8 +33859,52 @@ function shouldSuppressWarning(suppressions, code, line) {
|
|
|
33164
33859
|
});
|
|
33165
33860
|
}
|
|
33166
33861
|
var DEFAULT_ERROR_WARNING_CODES = /* @__PURE__ */ new Set(["FICT-R004"]);
|
|
33862
|
+
var STRICT_REACTIVITY_WARNING_CODES = /* @__PURE__ */ new Set(["FICT-R003", "FICT-R006"]);
|
|
33863
|
+
var STRICT_GUARANTEE_WARNING_CODES = /* @__PURE__ */ new Set([
|
|
33864
|
+
"FICT-P001",
|
|
33865
|
+
"FICT-P002",
|
|
33866
|
+
"FICT-P003",
|
|
33867
|
+
"FICT-P004",
|
|
33868
|
+
"FICT-P005",
|
|
33869
|
+
"FICT-J003",
|
|
33870
|
+
"FICT-S002",
|
|
33871
|
+
"FICT-R001",
|
|
33872
|
+
"FICT-R002",
|
|
33873
|
+
"FICT-R003",
|
|
33874
|
+
"FICT-R006"
|
|
33875
|
+
]);
|
|
33876
|
+
function readBooleanEnv(name) {
|
|
33877
|
+
const raw = process.env[name];
|
|
33878
|
+
if (!raw) return void 0;
|
|
33879
|
+
const normalized = raw.trim().toLowerCase();
|
|
33880
|
+
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
33881
|
+
return true;
|
|
33882
|
+
}
|
|
33883
|
+
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
33884
|
+
return false;
|
|
33885
|
+
}
|
|
33886
|
+
return void 0;
|
|
33887
|
+
}
|
|
33888
|
+
function validateStrictGuaranteeConfig(options, suppressions) {
|
|
33889
|
+
if (!options.strictGuarantee) return;
|
|
33890
|
+
if (suppressions.length > 0) {
|
|
33891
|
+
throw new Error(
|
|
33892
|
+
"strictGuarantee does not allow fict-ignore suppression comments. Remove suppressions to keep fail-closed guarantees."
|
|
33893
|
+
);
|
|
33894
|
+
}
|
|
33895
|
+
if (!options.warningLevels) return;
|
|
33896
|
+
for (const [code, level] of Object.entries(options.warningLevels)) {
|
|
33897
|
+
if (!STRICT_GUARANTEE_WARNING_CODES.has(code)) continue;
|
|
33898
|
+
if (level === "error") continue;
|
|
33899
|
+
throw new Error(
|
|
33900
|
+
`strictGuarantee does not allow downgrading ${code} to "${level}". Remove this warningLevels override.`
|
|
33901
|
+
);
|
|
33902
|
+
}
|
|
33903
|
+
}
|
|
33167
33904
|
function hasErrorEscalation(options) {
|
|
33168
33905
|
if (DEFAULT_ERROR_WARNING_CODES.size > 0) return true;
|
|
33906
|
+
if (options.strictGuarantee) return true;
|
|
33907
|
+
if (options.strictReactivity) return true;
|
|
33169
33908
|
if (options.warningsAsErrors === true) return true;
|
|
33170
33909
|
if (Array.isArray(options.warningsAsErrors) && options.warningsAsErrors.length > 0) return true;
|
|
33171
33910
|
if (options.warningLevels) {
|
|
@@ -33174,8 +33913,10 @@ function hasErrorEscalation(options) {
|
|
|
33174
33913
|
return false;
|
|
33175
33914
|
}
|
|
33176
33915
|
function resolveWarningLevel(code, options) {
|
|
33916
|
+
if (options.strictGuarantee && STRICT_GUARANTEE_WARNING_CODES.has(code)) return "error";
|
|
33177
33917
|
const override = options.warningLevels?.[code];
|
|
33178
33918
|
if (override) return override;
|
|
33919
|
+
if (options.strictReactivity && STRICT_REACTIVITY_WARNING_CODES.has(code)) return "error";
|
|
33179
33920
|
if (options.warningsAsErrors === true) return "error";
|
|
33180
33921
|
if (Array.isArray(options.warningsAsErrors) && options.warningsAsErrors.includes(code)) {
|
|
33181
33922
|
return "error";
|
|
@@ -33189,6 +33930,7 @@ function formatWarningAsError(warning) {
|
|
|
33189
33930
|
at ${location}`;
|
|
33190
33931
|
}
|
|
33191
33932
|
function createWarningDispatcher(onWarn, suppressions, options, dev) {
|
|
33933
|
+
validateStrictGuaranteeConfig(options, suppressions);
|
|
33192
33934
|
const hasEscalation = hasErrorEscalation(options);
|
|
33193
33935
|
if (!dev && !hasEscalation) return () => {
|
|
33194
33936
|
};
|
|
@@ -33294,7 +34036,7 @@ function isDynamicPropertyAccess(node, t4) {
|
|
|
33294
34036
|
if (!node.computed) return false;
|
|
33295
34037
|
return !(t4.isStringLiteral(node.property) || t4.isNumericLiteral(node.property));
|
|
33296
34038
|
}
|
|
33297
|
-
function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, reactiveBindingIds, effectMacroNames, warn, fileName, t4) {
|
|
34039
|
+
function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, reactiveBindingIds, stateMacroNames, memoMacroNames, effectMacroNames, warn, fileName, t4) {
|
|
33298
34040
|
const hasTrackedBinding = (path2, name, tracked) => {
|
|
33299
34041
|
const binding = path2.scope.getBinding(name);
|
|
33300
34042
|
return !!(binding && tracked.has(binding.identifier));
|
|
@@ -33309,6 +34051,107 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33309
34051
|
if (!root) return false;
|
|
33310
34052
|
return hasTrackedBinding(path2, root.name, reactiveBindingIds);
|
|
33311
34053
|
};
|
|
34054
|
+
const NON_ESCAPING_CALLBACK_METHODS = /* @__PURE__ */ new Set([
|
|
34055
|
+
"map",
|
|
34056
|
+
"forEach",
|
|
34057
|
+
"filter",
|
|
34058
|
+
"some",
|
|
34059
|
+
"every",
|
|
34060
|
+
"find",
|
|
34061
|
+
"findIndex",
|
|
34062
|
+
"findLast",
|
|
34063
|
+
"findLastIndex",
|
|
34064
|
+
"flatMap",
|
|
34065
|
+
"reduce",
|
|
34066
|
+
"reduceRight",
|
|
34067
|
+
"sort",
|
|
34068
|
+
"toSorted",
|
|
34069
|
+
"then",
|
|
34070
|
+
"catch",
|
|
34071
|
+
"finally"
|
|
34072
|
+
]);
|
|
34073
|
+
const capturedClosureByBinding = /* @__PURE__ */ new Map();
|
|
34074
|
+
const shouldIgnoreIdentifierReference = (idPath) => {
|
|
34075
|
+
if (idPath.parentPath.isMemberExpression({ property: idPath.node }) && !idPath.parent.computed) {
|
|
34076
|
+
return true;
|
|
34077
|
+
}
|
|
34078
|
+
if (idPath.parentPath.isObjectProperty({ key: idPath.node }) && !idPath.parent.computed && !idPath.parent.shorthand) {
|
|
34079
|
+
return true;
|
|
34080
|
+
}
|
|
34081
|
+
return false;
|
|
34082
|
+
};
|
|
34083
|
+
const collectCapturedReactiveNames = (fnPath) => {
|
|
34084
|
+
const captured = /* @__PURE__ */ new Set();
|
|
34085
|
+
fnPath.traverse({
|
|
34086
|
+
Function(inner) {
|
|
34087
|
+
if (inner === fnPath) return;
|
|
34088
|
+
inner.skip();
|
|
34089
|
+
},
|
|
34090
|
+
Identifier(idPath) {
|
|
34091
|
+
if (shouldIgnoreIdentifierReference(idPath)) return;
|
|
34092
|
+
const name = idPath.node.name;
|
|
34093
|
+
const binding = idPath.scope.getBinding(name);
|
|
34094
|
+
if (!binding) return;
|
|
34095
|
+
if (!reactiveBindingIds.has(binding.identifier)) return;
|
|
34096
|
+
if (binding.scope === idPath.scope || binding.scope === fnPath.scope) return;
|
|
34097
|
+
captured.add(name);
|
|
34098
|
+
}
|
|
34099
|
+
});
|
|
34100
|
+
return captured;
|
|
34101
|
+
};
|
|
34102
|
+
const registerClosureCaptureBinding = (fnPath, captured) => {
|
|
34103
|
+
if (captured.size === 0) return;
|
|
34104
|
+
if (fnPath.isFunctionDeclaration() && fnPath.node.id) {
|
|
34105
|
+
const binding = fnPath.parentPath.scope.getBinding(fnPath.node.id.name);
|
|
34106
|
+
if (binding) {
|
|
34107
|
+
capturedClosureByBinding.set(binding.identifier, captured);
|
|
34108
|
+
}
|
|
34109
|
+
return;
|
|
34110
|
+
}
|
|
34111
|
+
if ((fnPath.isFunctionExpression() || fnPath.isArrowFunctionExpression()) && fnPath.parentPath.isVariableDeclarator()) {
|
|
34112
|
+
const id = fnPath.parentPath.node.id;
|
|
34113
|
+
if (!t4.isIdentifier(id)) return;
|
|
34114
|
+
const binding = fnPath.parentPath.scope.getBinding(id.name);
|
|
34115
|
+
if (binding) {
|
|
34116
|
+
capturedClosureByBinding.set(binding.identifier, captured);
|
|
34117
|
+
}
|
|
34118
|
+
return;
|
|
34119
|
+
}
|
|
34120
|
+
if (fnPath.parentPath.isAssignmentExpression({ right: fnPath.node })) {
|
|
34121
|
+
const left = fnPath.parentPath.node.left;
|
|
34122
|
+
if (!t4.isIdentifier(left)) return;
|
|
34123
|
+
const binding = fnPath.parentPath.scope.getBinding(left.name);
|
|
34124
|
+
if (binding) {
|
|
34125
|
+
capturedClosureByBinding.set(binding.identifier, captured);
|
|
34126
|
+
}
|
|
34127
|
+
}
|
|
34128
|
+
};
|
|
34129
|
+
const collectCapturedForArgument = (argPath) => {
|
|
34130
|
+
if (argPath.isArrowFunctionExpression() || argPath.isFunctionExpression()) {
|
|
34131
|
+
const captured2 = collectCapturedReactiveNames(argPath);
|
|
34132
|
+
return captured2.size > 0 ? captured2 : null;
|
|
34133
|
+
}
|
|
34134
|
+
if (!argPath.isIdentifier()) return null;
|
|
34135
|
+
const binding = argPath.scope.getBinding(argPath.node.name);
|
|
34136
|
+
if (!binding) return null;
|
|
34137
|
+
const captured = capturedClosureByBinding.get(binding.identifier);
|
|
34138
|
+
return captured && captured.size > 0 ? captured : null;
|
|
34139
|
+
};
|
|
34140
|
+
const isNonEscapingCallbackHost = (callee) => {
|
|
34141
|
+
const member = t4.isMemberExpression(callee) || t4.isOptionalMemberExpression(callee) ? callee : null;
|
|
34142
|
+
if (!member || member.computed || !t4.isIdentifier(member.property)) return false;
|
|
34143
|
+
return NON_ESCAPING_CALLBACK_METHODS.has(member.property.name);
|
|
34144
|
+
};
|
|
34145
|
+
const emitClosureCaptureWarning = (node, captured) => {
|
|
34146
|
+
const names = Array.from(captured).sort().join(", ");
|
|
34147
|
+
emitWarning(
|
|
34148
|
+
node,
|
|
34149
|
+
"FICT-R005",
|
|
34150
|
+
`Function captures reactive variable(s): ${names}. Pass them as parameters or memoize explicitly to avoid hidden dependencies.`,
|
|
34151
|
+
warn,
|
|
34152
|
+
fileName
|
|
34153
|
+
);
|
|
34154
|
+
};
|
|
33312
34155
|
const argumentHasReactive = (argPath) => {
|
|
33313
34156
|
if (argPath.isSpreadElement()) {
|
|
33314
34157
|
const inner = argPath.get("argument");
|
|
@@ -33331,12 +34174,7 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33331
34174
|
path2.skip();
|
|
33332
34175
|
},
|
|
33333
34176
|
Identifier(idPath) {
|
|
33334
|
-
if (
|
|
33335
|
-
return;
|
|
33336
|
-
}
|
|
33337
|
-
if (idPath.parentPath.isObjectProperty({ key: idPath.node }) && !idPath.parent.computed && !idPath.parent.shorthand) {
|
|
33338
|
-
return;
|
|
33339
|
-
}
|
|
34177
|
+
if (shouldIgnoreIdentifierReference(idPath)) return;
|
|
33340
34178
|
const binding = idPath.scope.getBinding(idPath.node.name);
|
|
33341
34179
|
if (binding && reactiveBindingIds.has(binding.identifier)) {
|
|
33342
34180
|
found = true;
|
|
@@ -33417,36 +34255,14 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33417
34255
|
}
|
|
33418
34256
|
},
|
|
33419
34257
|
Function(path2) {
|
|
33420
|
-
const captured =
|
|
33421
|
-
path2
|
|
33422
|
-
{
|
|
33423
|
-
Function(inner) {
|
|
33424
|
-
if (inner === path2) return;
|
|
33425
|
-
inner.skip();
|
|
33426
|
-
},
|
|
33427
|
-
Identifier(idPath) {
|
|
33428
|
-
const name = idPath.node.name;
|
|
33429
|
-
const binding = idPath.scope.getBinding(name);
|
|
33430
|
-
if (!binding) return;
|
|
33431
|
-
if (!reactiveBindingIds.has(binding.identifier)) return;
|
|
33432
|
-
if (binding.scope === idPath.scope || binding.scope === path2.scope) return;
|
|
33433
|
-
captured.add(name);
|
|
33434
|
-
}
|
|
33435
|
-
},
|
|
33436
|
-
{}
|
|
33437
|
-
);
|
|
33438
|
-
if (captured.size > 0) {
|
|
33439
|
-
emitWarning(
|
|
33440
|
-
path2.node,
|
|
33441
|
-
"FICT-R005",
|
|
33442
|
-
`Function captures reactive variable(s): ${Array.from(captured).join(", ")}. Pass them as parameters or memoize explicitly to avoid hidden dependencies.`,
|
|
33443
|
-
warn,
|
|
33444
|
-
fileName
|
|
33445
|
-
);
|
|
33446
|
-
}
|
|
34258
|
+
const captured = collectCapturedReactiveNames(path2);
|
|
34259
|
+
registerClosureCaptureBinding(path2, captured);
|
|
33447
34260
|
},
|
|
33448
34261
|
CallExpression(path2) {
|
|
33449
|
-
const
|
|
34262
|
+
const callNode = path2.node;
|
|
34263
|
+
if (isStateCall(callNode, t4, stateMacroNames)) return;
|
|
34264
|
+
if (isMemoCall(callNode, t4, memoMacroNames)) return;
|
|
34265
|
+
const isEffect = isEffectCall(callNode, t4, effectMacroNames);
|
|
33450
34266
|
if (isEffect) {
|
|
33451
34267
|
const argPath = path2.get("arguments.0");
|
|
33452
34268
|
if (argPath?.isFunctionExpression() || argPath?.isArrowFunctionExpression()) {
|
|
@@ -33469,7 +34285,7 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33469
34285
|
});
|
|
33470
34286
|
if (!hasReactiveDependency) {
|
|
33471
34287
|
emitWarning(
|
|
33472
|
-
|
|
34288
|
+
callNode,
|
|
33473
34289
|
"FICT-E001",
|
|
33474
34290
|
"Effect has no reactive reads; it will run once. Consider removing $effect or adding dependencies.",
|
|
33475
34291
|
warn,
|
|
@@ -33492,6 +34308,7 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33492
34308
|
const isSafe = calleeName && SAFE_FUNCTIONS.has(calleeName);
|
|
33493
34309
|
if (isSafe) return;
|
|
33494
34310
|
const argPaths = path2.get("arguments");
|
|
34311
|
+
const nonEscapingCallbackHost = isNonEscapingCallbackHost(callee);
|
|
33495
34312
|
for (const argPath of argPaths) {
|
|
33496
34313
|
if (argPath.isIdentifier() && hasTrackedBinding(argPath, argPath.node.name, stateBindingIds)) {
|
|
33497
34314
|
continue;
|
|
@@ -33507,6 +34324,13 @@ function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, react
|
|
|
33507
34324
|
break;
|
|
33508
34325
|
}
|
|
33509
34326
|
}
|
|
34327
|
+
if (nonEscapingCallbackHost) return;
|
|
34328
|
+
for (const argPath of argPaths) {
|
|
34329
|
+
const captured = collectCapturedForArgument(argPath);
|
|
34330
|
+
if (!captured) continue;
|
|
34331
|
+
emitClosureCaptureWarning(argPath.node, captured);
|
|
34332
|
+
break;
|
|
34333
|
+
}
|
|
33510
34334
|
},
|
|
33511
34335
|
OptionalMemberExpression(path2) {
|
|
33512
34336
|
if (!path2.node.computed) return;
|
|
@@ -34371,6 +35195,8 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
34371
35195
|
stateBindingIds,
|
|
34372
35196
|
stateRootBindingIds,
|
|
34373
35197
|
reactiveBindingIds,
|
|
35198
|
+
stateMacroNames,
|
|
35199
|
+
memoMacroNames,
|
|
34374
35200
|
effectMacroNames,
|
|
34375
35201
|
warn,
|
|
34376
35202
|
fileName,
|
|
@@ -34415,13 +35241,17 @@ var createFictPlugin = declare(
|
|
|
34415
35241
|
(api, options = {}) => {
|
|
34416
35242
|
api.assertVersion(7);
|
|
34417
35243
|
const t4 = api.types;
|
|
35244
|
+
const strictGuaranteeFromEnv = readBooleanEnv("FICT_STRICT_GUARANTEE") === true;
|
|
34418
35245
|
const normalizedOptions = {
|
|
34419
35246
|
...options,
|
|
34420
35247
|
fineGrainedDom: options.fineGrainedDom ?? true,
|
|
35248
|
+
lazyConditional: options.lazyConditional ?? true,
|
|
35249
|
+
getterCache: options.getterCache ?? true,
|
|
34421
35250
|
optimize: options.optimize ?? true,
|
|
34422
35251
|
optimizeLevel: options.optimizeLevel ?? "safe",
|
|
34423
35252
|
inlineDerivedMemos: options.inlineDerivedMemos ?? true,
|
|
34424
35253
|
emitModuleMetadata: options.emitModuleMetadata ?? "auto",
|
|
35254
|
+
strictGuarantee: strictGuaranteeFromEnv || options.strictGuarantee !== false,
|
|
34425
35255
|
dev: options.dev ?? (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test")
|
|
34426
35256
|
};
|
|
34427
35257
|
return {
|