@fictjs/compiler 0.1.0 → 0.2.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/dist/index.cjs +329 -249
- package/dist/index.js +329 -249
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -14267,6 +14267,35 @@ var SAFE_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
|
14267
14267
|
"Date.parse"
|
|
14268
14268
|
]);
|
|
14269
14269
|
|
|
14270
|
+
// src/debug.ts
|
|
14271
|
+
function parseFlag(raw) {
|
|
14272
|
+
if (!raw) return false;
|
|
14273
|
+
const val = raw.toLowerCase();
|
|
14274
|
+
return val === "1" || val === "true" || val === "yes" || val === "on";
|
|
14275
|
+
}
|
|
14276
|
+
function debugEnabled(flag) {
|
|
14277
|
+
const normalized = flag.toLowerCase();
|
|
14278
|
+
const legacy = process.env[`DEBUG_${flag.toUpperCase()}`];
|
|
14279
|
+
if (parseFlag(legacy)) return true;
|
|
14280
|
+
const fictLegacy = process.env[`FICT_DEBUG_${flag.toUpperCase()}`];
|
|
14281
|
+
if (parseFlag(fictLegacy)) return true;
|
|
14282
|
+
const raw = process.env.FICT_DEBUG ?? process.env.DEBUG_FICT;
|
|
14283
|
+
if (!raw) return false;
|
|
14284
|
+
if (parseFlag(raw)) return true;
|
|
14285
|
+
const parts = raw.split(",").map((p) => p.trim().toLowerCase()).filter(Boolean);
|
|
14286
|
+
return parts.includes(normalized) || parts.includes("all");
|
|
14287
|
+
}
|
|
14288
|
+
function debugLog(flag, message, data) {
|
|
14289
|
+
if (!debugEnabled(flag)) return;
|
|
14290
|
+
const msg = typeof message === "function" ? message() : message;
|
|
14291
|
+
const prefix = `[fict:${flag}]`;
|
|
14292
|
+
if (data !== void 0) {
|
|
14293
|
+
console.log(prefix, msg, data);
|
|
14294
|
+
} else {
|
|
14295
|
+
console.log(prefix, msg);
|
|
14296
|
+
}
|
|
14297
|
+
}
|
|
14298
|
+
|
|
14270
14299
|
// src/ir/build-hir.ts
|
|
14271
14300
|
var t = __toESM(require_lib3(), 1);
|
|
14272
14301
|
|
|
@@ -15668,7 +15697,7 @@ function convertExpression(node) {
|
|
|
15668
15697
|
}
|
|
15669
15698
|
if (t.isObjectMethod(prop)) {
|
|
15670
15699
|
if (prop.computed) return void 0;
|
|
15671
|
-
const keyExpr2 = t.isIdentifier(prop.key) ? { kind: "Identifier", name: prop.key.name } : t.isStringLiteral(prop.key) ? { kind: "Literal", value: prop.key.value } : void 0;
|
|
15700
|
+
const keyExpr2 = t.isIdentifier(prop.key) ? { kind: "Identifier", name: prop.key.name } : t.isStringLiteral(prop.key) ? { kind: "Literal", value: prop.key.value } : t.isNumericLiteral(prop.key) ? { kind: "Literal", value: prop.key.value } : void 0;
|
|
15672
15701
|
if (!keyExpr2) return void 0;
|
|
15673
15702
|
const fnExpr = t.functionExpression(
|
|
15674
15703
|
null,
|
|
@@ -15685,7 +15714,7 @@ function convertExpression(node) {
|
|
|
15685
15714
|
};
|
|
15686
15715
|
}
|
|
15687
15716
|
if (!t.isObjectProperty(prop) || prop.computed) return void 0;
|
|
15688
|
-
const keyExpr = t.isIdentifier(prop.key) ? { kind: "Identifier", name: prop.key.name } : t.isStringLiteral(prop.key) ? { kind: "Literal", value: prop.key.value } : void 0;
|
|
15717
|
+
const keyExpr = t.isIdentifier(prop.key) ? { kind: "Identifier", name: prop.key.name } : t.isStringLiteral(prop.key) ? { kind: "Literal", value: prop.key.value } : t.isNumericLiteral(prop.key) ? { kind: "Literal", value: prop.key.value } : void 0;
|
|
15689
15718
|
if (!keyExpr) return void 0;
|
|
15690
15719
|
if (!t.isExpression(prop.value)) return void 0;
|
|
15691
15720
|
return {
|
|
@@ -16027,23 +16056,6 @@ function convertJSXMemberExpr(node) {
|
|
|
16027
16056
|
};
|
|
16028
16057
|
}
|
|
16029
16058
|
|
|
16030
|
-
// src/debug.ts
|
|
16031
|
-
function parseFlag(raw) {
|
|
16032
|
-
if (!raw) return false;
|
|
16033
|
-
const val = raw.toLowerCase();
|
|
16034
|
-
return val === "1" || val === "true" || val === "yes" || val === "on";
|
|
16035
|
-
}
|
|
16036
|
-
function debugEnabled(flag) {
|
|
16037
|
-
const normalized = flag.toLowerCase();
|
|
16038
|
-
const legacy = process.env[`DEBUG_${flag.toUpperCase()}`];
|
|
16039
|
-
if (parseFlag(legacy)) return true;
|
|
16040
|
-
const raw = process.env.FICT_DEBUG ?? process.env.DEBUG_FICT;
|
|
16041
|
-
if (!raw) return false;
|
|
16042
|
-
if (parseFlag(raw)) return true;
|
|
16043
|
-
const parts = raw.split(",").map((p) => p.trim().toLowerCase()).filter(Boolean);
|
|
16044
|
-
return parts.includes(normalized) || parts.includes("all");
|
|
16045
|
-
}
|
|
16046
|
-
|
|
16047
16059
|
// src/fine-grained-dom.ts
|
|
16048
16060
|
function normalizeDependencyKey(name) {
|
|
16049
16061
|
return name.split(".").map((part) => part.replace(/_\d+$/, "")).join(".");
|
|
@@ -18093,6 +18105,35 @@ function structurizeTry(ctx, block, term) {
|
|
|
18093
18105
|
|
|
18094
18106
|
// src/ir/regions.ts
|
|
18095
18107
|
var REACTIVE_CREATORS = /* @__PURE__ */ new Set(["createEffect", "createMemo", "createSelector"]);
|
|
18108
|
+
function buildEffectCall(ctx, t2, effectFn, options) {
|
|
18109
|
+
if (ctx.inModule) {
|
|
18110
|
+
ctx.helpersUsed.add("effect");
|
|
18111
|
+
return t2.callExpression(t2.identifier(RUNTIME_ALIASES.effect), [effectFn]);
|
|
18112
|
+
}
|
|
18113
|
+
ctx.helpersUsed.add("useEffect");
|
|
18114
|
+
ctx.needsCtx = true;
|
|
18115
|
+
const args = [t2.identifier("__fictCtx"), effectFn];
|
|
18116
|
+
const slot = options?.slot;
|
|
18117
|
+
if (options?.forceSlot) {
|
|
18118
|
+
args.push(slot !== void 0 && slot >= 0 ? t2.numericLiteral(slot) : t2.identifier("undefined"));
|
|
18119
|
+
} else if (slot !== void 0 && slot >= 0) {
|
|
18120
|
+
args.push(t2.numericLiteral(slot));
|
|
18121
|
+
}
|
|
18122
|
+
return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), args);
|
|
18123
|
+
}
|
|
18124
|
+
function buildMemoCall(ctx, t2, memoFn, slot) {
|
|
18125
|
+
if (ctx.inModule) {
|
|
18126
|
+
ctx.helpersUsed.add("memo");
|
|
18127
|
+
return t2.callExpression(t2.identifier(RUNTIME_ALIASES.memo), [memoFn]);
|
|
18128
|
+
}
|
|
18129
|
+
ctx.helpersUsed.add("useMemo");
|
|
18130
|
+
ctx.needsCtx = true;
|
|
18131
|
+
const args = [t2.identifier("__fictCtx"), memoFn];
|
|
18132
|
+
if (slot !== void 0 && slot >= 0) {
|
|
18133
|
+
args.push(t2.numericLiteral(slot));
|
|
18134
|
+
}
|
|
18135
|
+
return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), args);
|
|
18136
|
+
}
|
|
18096
18137
|
function expressionCreatesReactive(expr) {
|
|
18097
18138
|
if (expr.kind === "CallExpression" && expr.callee.kind === "Identifier") {
|
|
18098
18139
|
const base = getSSABaseName(expr.callee.name);
|
|
@@ -18383,8 +18424,10 @@ function expressionUsesTracked(expr, ctx) {
|
|
|
18383
18424
|
case "Identifier":
|
|
18384
18425
|
return ctx.trackedVars.has(deSSAVarName(expr.name)) || (ctx.externalTracked?.has(deSSAVarName(expr.name)) ?? false) || (ctx.memoVars?.has(deSSAVarName(expr.name)) ?? false) || (ctx.aliasVars?.has(deSSAVarName(expr.name)) ?? false);
|
|
18385
18426
|
case "MemberExpression":
|
|
18427
|
+
case "OptionalMemberExpression":
|
|
18386
18428
|
return expressionUsesTracked(expr.object, ctx);
|
|
18387
18429
|
case "CallExpression":
|
|
18430
|
+
case "OptionalCallExpression":
|
|
18388
18431
|
if (expressionUsesTracked(expr.callee, ctx)) return true;
|
|
18389
18432
|
return expr.arguments.some((arg) => expressionUsesTracked(arg, ctx));
|
|
18390
18433
|
case "LogicalExpression":
|
|
@@ -18606,16 +18649,8 @@ function lowerNodeWithRegionContext(node, t2, ctx, declaredVars, regionCtx) {
|
|
|
18606
18649
|
const inNonReactiveScope = !!(ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0);
|
|
18607
18650
|
const shouldWrapEffect = ctx.wrapTrackedExpressions !== false && !ctx.inRegionMemo && !inNonReactiveScope && expressionUsesTracked(node.test, ctx) && !statementHasEarlyExit(ifStmt, t2);
|
|
18608
18651
|
if (shouldWrapEffect) {
|
|
18609
|
-
|
|
18610
|
-
ctx
|
|
18611
|
-
return [
|
|
18612
|
-
t2.expressionStatement(
|
|
18613
|
-
t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
|
|
18614
|
-
t2.identifier("__fictCtx"),
|
|
18615
|
-
t2.arrowFunctionExpression([], t2.blockStatement([ifStmt]))
|
|
18616
|
-
])
|
|
18617
|
-
)
|
|
18618
|
-
];
|
|
18652
|
+
const effectFn = t2.arrowFunctionExpression([], t2.blockStatement([ifStmt]));
|
|
18653
|
+
return [t2.expressionStatement(buildEffectCall(ctx, t2, effectFn))];
|
|
18619
18654
|
}
|
|
18620
18655
|
return [ifStmt];
|
|
18621
18656
|
}
|
|
@@ -18880,16 +18915,8 @@ function lowerStructuredNodeForRegion(node, region, t2, ctx, declaredVars, regio
|
|
|
18880
18915
|
ifStmt = buildIfStmt(consequent, alternate);
|
|
18881
18916
|
}
|
|
18882
18917
|
if (shouldWrapEffect) {
|
|
18883
|
-
|
|
18884
|
-
ctx
|
|
18885
|
-
return [
|
|
18886
|
-
t2.expressionStatement(
|
|
18887
|
-
t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
|
|
18888
|
-
t2.identifier("__fictCtx"),
|
|
18889
|
-
t2.arrowFunctionExpression([], t2.blockStatement([ifStmt]))
|
|
18890
|
-
])
|
|
18891
|
-
)
|
|
18892
|
-
];
|
|
18918
|
+
const effectFn = t2.arrowFunctionExpression([], t2.blockStatement([ifStmt]));
|
|
18919
|
+
return [t2.expressionStatement(buildEffectCall(ctx, t2, effectFn))];
|
|
18893
18920
|
}
|
|
18894
18921
|
return [ifStmt];
|
|
18895
18922
|
}
|
|
@@ -19261,30 +19288,16 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
19261
19288
|
const outputNames = outputNamesOverride ?? Array.from(region.declarations).map((name) => deSSAVarName(name));
|
|
19262
19289
|
const uniqueOutputNames = [...new Set(outputNames)];
|
|
19263
19290
|
const bindableOutputs = uniqueOutputNames.filter((name) => !declaredVars.has(name));
|
|
19264
|
-
|
|
19265
|
-
|
|
19266
|
-
|
|
19267
|
-
|
|
19268
|
-
});
|
|
19269
|
-
}
|
|
19291
|
+
debugLog("region", `Region memo ${region.id}`, {
|
|
19292
|
+
instructions: region.instructions.map((instr) => instr.kind),
|
|
19293
|
+
outputs: uniqueOutputNames
|
|
19294
|
+
});
|
|
19270
19295
|
if (uniqueOutputNames.length === 0) {
|
|
19271
|
-
|
|
19272
|
-
ctx.
|
|
19273
|
-
const
|
|
19274
|
-
t2.identifier("__fictCtx"),
|
|
19275
|
-
t2.arrowFunctionExpression([], t2.blockStatement(bodyStatements))
|
|
19276
|
-
];
|
|
19277
|
-
{
|
|
19278
|
-
const slot = reserveHookSlot(ctx);
|
|
19279
|
-
if (slot >= 0) {
|
|
19280
|
-
effectCallArgs.push(t2.numericLiteral(slot));
|
|
19281
|
-
}
|
|
19282
|
-
}
|
|
19283
|
-
const effectCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), effectCallArgs);
|
|
19296
|
+
const effectFn = t2.arrowFunctionExpression([], t2.blockStatement(bodyStatements));
|
|
19297
|
+
const slot = ctx.inModule ? void 0 : reserveHookSlot(ctx);
|
|
19298
|
+
const effectCall = buildEffectCall(ctx, t2, effectFn, { slot });
|
|
19284
19299
|
statements.push(t2.expressionStatement(effectCall));
|
|
19285
19300
|
} else {
|
|
19286
|
-
ctx.helpersUsed.add("useMemo");
|
|
19287
|
-
ctx.needsCtx = true;
|
|
19288
19301
|
if (!bodyStatementsOverride) {
|
|
19289
19302
|
const lazyInfo = analyzeHIRConditionalUsage(region, ctx);
|
|
19290
19303
|
if (lazyInfo) {
|
|
@@ -19313,15 +19326,8 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
19313
19326
|
};
|
|
19314
19327
|
const returnObj = t2.objectExpression(uniqueOutputNames.map((name) => buildOutputProperty(name)));
|
|
19315
19328
|
const memoBody = t2.blockStatement([...bodyStatements, t2.returnStatement(returnObj)]);
|
|
19316
|
-
const slot = reserveHookSlot(ctx);
|
|
19317
|
-
const
|
|
19318
|
-
t2.identifier("__fictCtx"),
|
|
19319
|
-
t2.arrowFunctionExpression([], memoBody)
|
|
19320
|
-
];
|
|
19321
|
-
if (slot >= 0) {
|
|
19322
|
-
memoArgs.push(t2.numericLiteral(slot));
|
|
19323
|
-
}
|
|
19324
|
-
const memoCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), memoArgs);
|
|
19329
|
+
const slot = ctx.inModule ? void 0 : reserveHookSlot(ctx);
|
|
19330
|
+
const memoCall = buildMemoCall(ctx, t2, t2.arrowFunctionExpression([], memoBody), slot);
|
|
19325
19331
|
const regionVarName = `__region_${region.id}`;
|
|
19326
19332
|
statements.push(
|
|
19327
19333
|
t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(regionVarName), memoCall)])
|
|
@@ -19331,16 +19337,13 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
19331
19337
|
(name) => ctx.trackedVars.has(name) && !isAccessorOutput(name)
|
|
19332
19338
|
);
|
|
19333
19339
|
const directOutputs = bindableOutputs.filter((name) => !getterOutputs.includes(name));
|
|
19334
|
-
|
|
19335
|
-
|
|
19336
|
-
|
|
19337
|
-
|
|
19338
|
-
|
|
19339
|
-
|
|
19340
|
-
|
|
19341
|
-
memoVars: Array.from(ctx.memoVars ?? [])
|
|
19342
|
-
});
|
|
19343
|
-
}
|
|
19340
|
+
debugLog("region", `Region debug ${region.id}`, {
|
|
19341
|
+
outputs: uniqueOutputNames,
|
|
19342
|
+
getterOutputs,
|
|
19343
|
+
directOutputs,
|
|
19344
|
+
tracked: Array.from(ctx.trackedVars),
|
|
19345
|
+
memoVars: Array.from(ctx.memoVars ?? [])
|
|
19346
|
+
});
|
|
19344
19347
|
if (directOutputs.length > 0) {
|
|
19345
19348
|
directOutputs.forEach((name) => declaredVars.add(name));
|
|
19346
19349
|
statements.push(
|
|
@@ -19368,21 +19371,15 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
19368
19371
|
ctx.memoVars?.add(name);
|
|
19369
19372
|
}
|
|
19370
19373
|
if (region.hasControlFlow && getterOutputs.length > 0) {
|
|
19371
|
-
ctx.helpersUsed.add("useEffect");
|
|
19372
|
-
ctx.needsCtx = true;
|
|
19373
19374
|
const effectBody = t2.blockStatement(
|
|
19374
19375
|
getterOutputs.map((name) => t2.expressionStatement(t2.callExpression(t2.identifier(name), [])))
|
|
19375
19376
|
);
|
|
19376
19377
|
statements.push(
|
|
19377
19378
|
t2.expressionStatement(
|
|
19378
|
-
|
|
19379
|
-
|
|
19380
|
-
|
|
19381
|
-
|
|
19382
|
-
const slot2 = reserveHookSlot(ctx);
|
|
19383
|
-
return slot2 >= 0 ? t2.numericLiteral(slot2) : t2.identifier("undefined");
|
|
19384
|
-
})()
|
|
19385
|
-
])
|
|
19379
|
+
buildEffectCall(ctx, t2, t2.arrowFunctionExpression([], effectBody), {
|
|
19380
|
+
slot: ctx.inModule ? void 0 : reserveHookSlot(ctx),
|
|
19381
|
+
forceSlot: true
|
|
19382
|
+
})
|
|
19386
19383
|
)
|
|
19387
19384
|
);
|
|
19388
19385
|
}
|
|
@@ -19596,18 +19593,13 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
|
|
|
19596
19593
|
t2.ifStatement(conditionId, t2.blockStatement(trueBlock), t2.blockStatement(falseBlock))
|
|
19597
19594
|
);
|
|
19598
19595
|
}
|
|
19599
|
-
ctx.helpersUsed.add("useMemo");
|
|
19600
|
-
ctx.needsCtx = true;
|
|
19601
19596
|
const regionVarName = `__region_${region.id}`;
|
|
19602
|
-
const
|
|
19603
|
-
|
|
19604
|
-
t2
|
|
19605
|
-
t2.arrowFunctionExpression([], t2.blockStatement(memoBody))
|
|
19606
|
-
|
|
19607
|
-
|
|
19608
|
-
memoArgs.push(t2.numericLiteral(slotForMemo));
|
|
19609
|
-
}
|
|
19610
|
-
const memoCall = t2.callExpression(t2.identifier("__fictUseMemo"), memoArgs);
|
|
19597
|
+
const memoCall = buildMemoCall(
|
|
19598
|
+
ctx,
|
|
19599
|
+
t2,
|
|
19600
|
+
t2.arrowFunctionExpression([], t2.blockStatement(memoBody)),
|
|
19601
|
+
ctx.inModule ? void 0 : reserveHookSlot(ctx)
|
|
19602
|
+
);
|
|
19611
19603
|
statements.push(
|
|
19612
19604
|
t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(regionVarName), memoCall)])
|
|
19613
19605
|
);
|
|
@@ -19696,20 +19688,9 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19696
19688
|
const isReactiveObjectCall = instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && ["mergeProps"].includes(instr.value.callee.name);
|
|
19697
19689
|
const isMemoReturningCall = isAccessorReturningCall || isReactiveObjectCall;
|
|
19698
19690
|
const lowerAssignedValue = (forceAssigned = false) => lowerExpressionWithDeSSA(instr.value, ctx, forceAssigned || isFunctionValue);
|
|
19699
|
-
const
|
|
19700
|
-
const
|
|
19701
|
-
|
|
19702
|
-
t2.arrowFunctionExpression([], expr)
|
|
19703
|
-
];
|
|
19704
|
-
if (inRegionMemo) {
|
|
19705
|
-
const slot = reserveHookSlot(ctx);
|
|
19706
|
-
if (slot >= 0) {
|
|
19707
|
-
args.push(t2.numericLiteral(slot));
|
|
19708
|
-
}
|
|
19709
|
-
}
|
|
19710
|
-
ctx.helpersUsed.add("useMemo");
|
|
19711
|
-
ctx.needsCtx = true;
|
|
19712
|
-
return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), args);
|
|
19691
|
+
const buildDerivedMemoCall = (expr) => {
|
|
19692
|
+
const slot = !ctx.inModule && inRegionMemo ? reserveHookSlot(ctx) : void 0;
|
|
19693
|
+
return buildMemoCall(ctx, t2, t2.arrowFunctionExpression([], expr), slot);
|
|
19713
19694
|
};
|
|
19714
19695
|
if (isShadowDeclaration && declKind) {
|
|
19715
19696
|
ctx.trackedVars.delete(baseName2);
|
|
@@ -19748,7 +19729,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19748
19729
|
return t2.variableDeclaration(normalizedDecl, [
|
|
19749
19730
|
t2.variableDeclarator(
|
|
19750
19731
|
t2.identifier(baseName2),
|
|
19751
|
-
isMemoReturningCall ? derivedExpr :
|
|
19732
|
+
isMemoReturningCall ? derivedExpr : buildDerivedMemoCall(derivedExpr)
|
|
19752
19733
|
)
|
|
19753
19734
|
]);
|
|
19754
19735
|
}
|
|
@@ -19775,7 +19756,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19775
19756
|
return t2.variableDeclaration(normalizedDecl, [
|
|
19776
19757
|
t2.variableDeclarator(
|
|
19777
19758
|
t2.identifier(baseName2),
|
|
19778
|
-
isMemoReturningCall ? derivedExpr :
|
|
19759
|
+
isMemoReturningCall ? derivedExpr : buildDerivedMemoCall(derivedExpr)
|
|
19779
19760
|
)
|
|
19780
19761
|
]);
|
|
19781
19762
|
}
|
|
@@ -19784,7 +19765,14 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19784
19765
|
]);
|
|
19785
19766
|
}
|
|
19786
19767
|
if (aliasVars.has(baseName2) && declaredVars.has(baseName2)) {
|
|
19787
|
-
throw new Error(
|
|
19768
|
+
throw new Error(
|
|
19769
|
+
`Alias reassignment is not supported for "${baseName2}".
|
|
19770
|
+
|
|
19771
|
+
"${baseName2}" was assigned from a reactive value and cannot be reassigned.
|
|
19772
|
+
Consider:
|
|
19773
|
+
- Using a new variable name for the new value
|
|
19774
|
+
- Updating the original reactive source instead`
|
|
19775
|
+
);
|
|
19788
19776
|
}
|
|
19789
19777
|
if (capturedTracked && isSignal) {
|
|
19790
19778
|
return t2.expressionStatement(
|
|
@@ -19792,7 +19780,14 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19792
19780
|
);
|
|
19793
19781
|
}
|
|
19794
19782
|
if (aliasVars.has(baseName2) && !declaredVars.has(baseName2)) {
|
|
19795
|
-
throw new Error(
|
|
19783
|
+
throw new Error(
|
|
19784
|
+
`Alias reassignment is not supported for "${baseName2}".
|
|
19785
|
+
|
|
19786
|
+
"${baseName2}" was assigned from a reactive value and cannot be reassigned.
|
|
19787
|
+
Consider:
|
|
19788
|
+
- Using a new variable name for the new value
|
|
19789
|
+
- Updating the original reactive source instead`
|
|
19790
|
+
);
|
|
19796
19791
|
}
|
|
19797
19792
|
if (dependsOnTracked && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
|
|
19798
19793
|
const derivedExpr = lowerAssignedValue(true);
|
|
@@ -19816,13 +19811,20 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19816
19811
|
t2.assignmentExpression(
|
|
19817
19812
|
"=",
|
|
19818
19813
|
t2.identifier(baseName2),
|
|
19819
|
-
isMemoReturningCall ? derivedExpr :
|
|
19814
|
+
isMemoReturningCall ? derivedExpr : buildDerivedMemoCall(derivedExpr)
|
|
19820
19815
|
)
|
|
19821
19816
|
);
|
|
19822
19817
|
}
|
|
19823
19818
|
if (declaredVars.has(baseName2)) {
|
|
19824
19819
|
if (aliasVars.has(baseName2)) {
|
|
19825
|
-
throw new Error(
|
|
19820
|
+
throw new Error(
|
|
19821
|
+
`Alias reassignment is not supported for "${baseName2}".
|
|
19822
|
+
|
|
19823
|
+
"${baseName2}" was assigned from a reactive value and cannot be reassigned.
|
|
19824
|
+
Consider:
|
|
19825
|
+
- Using a new variable name for the new value
|
|
19826
|
+
- Updating the original reactive source instead`
|
|
19827
|
+
);
|
|
19826
19828
|
}
|
|
19827
19829
|
if (isSignal) {
|
|
19828
19830
|
return t2.expressionStatement(
|
|
@@ -19864,7 +19866,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19864
19866
|
return t2.variableDeclaration("const", [
|
|
19865
19867
|
t2.variableDeclarator(
|
|
19866
19868
|
t2.identifier(baseName2),
|
|
19867
|
-
isMemoReturningCall ? derivedExpr :
|
|
19869
|
+
isMemoReturningCall ? derivedExpr : buildDerivedMemoCall(derivedExpr)
|
|
19868
19870
|
)
|
|
19869
19871
|
]);
|
|
19870
19872
|
}
|
|
@@ -19888,7 +19890,7 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19888
19890
|
return t2.variableDeclaration("const", [
|
|
19889
19891
|
t2.variableDeclarator(
|
|
19890
19892
|
t2.identifier(baseName2),
|
|
19891
|
-
isMemoReturningCall ? derivedExpr :
|
|
19893
|
+
isMemoReturningCall ? derivedExpr : buildDerivedMemoCall(derivedExpr)
|
|
19892
19894
|
)
|
|
19893
19895
|
]);
|
|
19894
19896
|
}
|
|
@@ -19908,8 +19910,6 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19908
19910
|
const inNonReactiveScope = !!(ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0);
|
|
19909
19911
|
const shouldWrapExpr = ctx.wrapTrackedExpressions !== false && !inNonReactiveScope && (usesTracked || hasTrackedControlDep);
|
|
19910
19912
|
if (shouldWrapExpr) {
|
|
19911
|
-
ctx.helpersUsed.add("useEffect");
|
|
19912
|
-
ctx.needsCtx = true;
|
|
19913
19913
|
const depReads = [];
|
|
19914
19914
|
if (hasTrackedControlDep) {
|
|
19915
19915
|
const uniqueDeps = new Set(Array.from(controlDeps).map((dep) => deSSAVarName(dep)));
|
|
@@ -19921,12 +19921,8 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19921
19921
|
}
|
|
19922
19922
|
const loweredExpr = lowerExpressionWithDeSSA(instr.value, ctx);
|
|
19923
19923
|
const effectBody = depReads.length > 0 ? ctx.t.blockStatement([...depReads, ctx.t.expressionStatement(loweredExpr)]) : loweredExpr;
|
|
19924
|
-
|
|
19925
|
-
|
|
19926
|
-
t2.identifier("__fictCtx"),
|
|
19927
|
-
ctx.t.isBlockStatement(effectBody) ? t2.arrowFunctionExpression([], effectBody) : t2.arrowFunctionExpression([], effectBody)
|
|
19928
|
-
])
|
|
19929
|
-
);
|
|
19924
|
+
const effectFn = ctx.t.isBlockStatement(effectBody) ? t2.arrowFunctionExpression([], effectBody) : t2.arrowFunctionExpression([], effectBody);
|
|
19925
|
+
return t2.expressionStatement(buildEffectCall(ctx, t2, effectFn));
|
|
19930
19926
|
}
|
|
19931
19927
|
return t2.expressionStatement(lowerExpressionWithDeSSA(instr.value, ctx));
|
|
19932
19928
|
}
|
|
@@ -20469,6 +20465,7 @@ function createCodegenContext(t2) {
|
|
|
20469
20465
|
mutatedVars: /* @__PURE__ */ new Set(),
|
|
20470
20466
|
inRegionMemo: false,
|
|
20471
20467
|
inListRender: false,
|
|
20468
|
+
inModule: false,
|
|
20472
20469
|
nextHookSlot: HOOK_SLOT_BASE,
|
|
20473
20470
|
nonReactiveScopeDepth: 0,
|
|
20474
20471
|
inConditional: 0,
|
|
@@ -20789,7 +20786,15 @@ function detectDerivedCycles(fn, _scopeResult) {
|
|
|
20789
20786
|
if (visiting.has(node)) {
|
|
20790
20787
|
const idx = stack.indexOf(node);
|
|
20791
20788
|
const cycle = idx >= 0 ? [...stack.slice(idx), node] : [...stack, node];
|
|
20792
|
-
throw new Error(
|
|
20789
|
+
throw new Error(
|
|
20790
|
+
`Detected cyclic derived dependency: ${cycle.join(" -> ")}
|
|
20791
|
+
|
|
20792
|
+
Tip: This usually happens when derived values depend on each other in a loop.
|
|
20793
|
+
Consider:
|
|
20794
|
+
- Using untrack() to break the dependency cycle
|
|
20795
|
+
- Restructuring your derived values to avoid circular dependencies
|
|
20796
|
+
- Moving one of the values to $state if it should be independently mutable`
|
|
20797
|
+
);
|
|
20793
20798
|
}
|
|
20794
20799
|
if (visited.has(node)) return;
|
|
20795
20800
|
visiting.add(node);
|
|
@@ -20804,12 +20809,11 @@ function detectDerivedCycles(fn, _scopeResult) {
|
|
|
20804
20809
|
for (const node of graph.keys()) {
|
|
20805
20810
|
visit(node);
|
|
20806
20811
|
}
|
|
20807
|
-
|
|
20808
|
-
|
|
20809
|
-
|
|
20810
|
-
|
|
20811
|
-
|
|
20812
|
-
}
|
|
20812
|
+
debugLog(
|
|
20813
|
+
"cycles",
|
|
20814
|
+
"cycle graph",
|
|
20815
|
+
Array.from(graph.entries()).map(([k, v]) => [k, Array.from(v)])
|
|
20816
|
+
);
|
|
20813
20817
|
}
|
|
20814
20818
|
function collectExpressionIdentifiers(expr, into) {
|
|
20815
20819
|
if (!expr || typeof expr !== "object") return;
|
|
@@ -21905,22 +21909,32 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
21905
21909
|
return t2.identifier("undefined");
|
|
21906
21910
|
case "CallExpression": {
|
|
21907
21911
|
if (expr.callee.kind === "Identifier" && expr.callee.name === "$state") {
|
|
21912
|
+
const args = lowerCallArguments(expr.arguments);
|
|
21913
|
+
if (ctx.inModule) {
|
|
21914
|
+
ctx.helpersUsed.add("signal");
|
|
21915
|
+
return t2.callExpression(t2.identifier(RUNTIME_ALIASES.signal), args);
|
|
21916
|
+
}
|
|
21908
21917
|
ctx.helpersUsed.add("useSignal");
|
|
21909
21918
|
ctx.needsCtx = true;
|
|
21910
21919
|
return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useSignal), [
|
|
21911
21920
|
t2.identifier("__fictCtx"),
|
|
21912
|
-
...
|
|
21921
|
+
...args
|
|
21913
21922
|
]);
|
|
21914
21923
|
}
|
|
21915
21924
|
if (expr.callee.kind === "Identifier" && expr.callee.name === "$effect") {
|
|
21925
|
+
const args = lowerCallArguments(
|
|
21926
|
+
expr.arguments,
|
|
21927
|
+
(arg) => arg.kind === "ArrowFunction" || arg.kind === "FunctionExpression" ? withNonReactiveScope(ctx, () => lowerExpression(arg, ctx)) : lowerExpression(arg, ctx)
|
|
21928
|
+
);
|
|
21929
|
+
if (ctx.inModule) {
|
|
21930
|
+
ctx.helpersUsed.add("effect");
|
|
21931
|
+
return t2.callExpression(t2.identifier(RUNTIME_ALIASES.effect), args);
|
|
21932
|
+
}
|
|
21916
21933
|
ctx.helpersUsed.add("useEffect");
|
|
21917
21934
|
ctx.needsCtx = true;
|
|
21918
21935
|
return t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
|
|
21919
21936
|
t2.identifier("__fictCtx"),
|
|
21920
|
-
...
|
|
21921
|
-
expr.arguments,
|
|
21922
|
-
(arg) => arg.kind === "ArrowFunction" || arg.kind === "FunctionExpression" ? withNonReactiveScope(ctx, () => lowerExpression(arg, ctx)) : lowerExpression(arg, ctx)
|
|
21923
|
-
)
|
|
21937
|
+
...args
|
|
21924
21938
|
]);
|
|
21925
21939
|
}
|
|
21926
21940
|
if (expr.callee.kind === "Identifier" && expr.callee.name === "__forOf") {
|
|
@@ -22812,6 +22826,16 @@ function isExpressionReactive(expr, ctx) {
|
|
|
22812
22826
|
for (const dep of deps) {
|
|
22813
22827
|
if (ctx.trackedVars.has(dep)) return true;
|
|
22814
22828
|
}
|
|
22829
|
+
if (ctx.memoVars) {
|
|
22830
|
+
for (const dep of deps) {
|
|
22831
|
+
if (ctx.memoVars.has(dep)) return true;
|
|
22832
|
+
}
|
|
22833
|
+
}
|
|
22834
|
+
if (ctx.signalVars) {
|
|
22835
|
+
for (const dep of deps) {
|
|
22836
|
+
if (ctx.signalVars.has(dep)) return true;
|
|
22837
|
+
}
|
|
22838
|
+
}
|
|
22815
22839
|
for (const region of regionsToCheck) {
|
|
22816
22840
|
for (const dep of deps) {
|
|
22817
22841
|
if (region.declarations.has(dep) || region.dependencies.has(dep)) {
|
|
@@ -23079,8 +23103,12 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
23079
23103
|
const regionMeta = containingRegion ? regionInfoToMetadata(containingRegion) : null;
|
|
23080
23104
|
const shouldMemo = !ctx.inListRender && !(ctx.inConditional && ctx.inConditional > 0) && regionMeta ? shouldMemoizeRegion(regionMeta) : false;
|
|
23081
23105
|
if (shouldMemo) {
|
|
23082
|
-
ctx.
|
|
23083
|
-
|
|
23106
|
+
if (ctx.inModule) {
|
|
23107
|
+
ctx.helpersUsed.add("memo");
|
|
23108
|
+
} else {
|
|
23109
|
+
ctx.helpersUsed.add("useMemo");
|
|
23110
|
+
ctx.needsCtx = true;
|
|
23111
|
+
}
|
|
23084
23112
|
}
|
|
23085
23113
|
const hoistedTmplId = getOrCreateHoistedTemplate(html, ctx);
|
|
23086
23114
|
const rootId = genTemp(ctx, "root");
|
|
@@ -23354,16 +23382,15 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
23354
23382
|
statements.push(t2.returnStatement(elId));
|
|
23355
23383
|
const body = t2.blockStatement(statements);
|
|
23356
23384
|
if (shouldMemo && containingRegion) {
|
|
23357
|
-
const
|
|
23358
|
-
|
|
23359
|
-
t2.
|
|
23360
|
-
|
|
23385
|
+
const memoBody = t2.arrowFunctionExpression([], body);
|
|
23386
|
+
if (ctx.inModule) {
|
|
23387
|
+
return t2.callExpression(t2.callExpression(t2.identifier(RUNTIME_ALIASES.memo), [memoBody]), []);
|
|
23388
|
+
}
|
|
23389
|
+
const memoArgs = [t2.identifier("__fictCtx"), memoBody];
|
|
23361
23390
|
if (ctx.isComponentFn) {
|
|
23362
|
-
|
|
23363
|
-
|
|
23364
|
-
|
|
23365
|
-
memoArgs.push(t2.numericLiteral(slot));
|
|
23366
|
-
}
|
|
23391
|
+
const slot = reserveHookSlot2(ctx);
|
|
23392
|
+
if (slot >= 0) {
|
|
23393
|
+
memoArgs.push(t2.numericLiteral(slot));
|
|
23367
23394
|
}
|
|
23368
23395
|
}
|
|
23369
23396
|
return t2.callExpression(t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), memoArgs), []);
|
|
@@ -23423,9 +23450,9 @@ function emitHIRChildBinding(markerId, expr, statements, ctx, containingRegion)
|
|
|
23423
23450
|
emitConditionalChild(parentId, markerId, expr, statements, ctx);
|
|
23424
23451
|
return;
|
|
23425
23452
|
}
|
|
23426
|
-
if (expr.kind === "CallExpression") {
|
|
23453
|
+
if (expr.kind === "CallExpression" || expr.kind === "OptionalCallExpression") {
|
|
23427
23454
|
const callee = expr.callee;
|
|
23428
|
-
if (callee.kind === "MemberExpression" && callee.property.kind === "Identifier" && callee.property.name === "map") {
|
|
23455
|
+
if ((callee.kind === "MemberExpression" || callee.kind === "OptionalMemberExpression") && callee.property.kind === "Identifier" && callee.property.name === "map") {
|
|
23429
23456
|
emitListChild(parentId, markerId, expr, statements, ctx);
|
|
23430
23457
|
return;
|
|
23431
23458
|
}
|
|
@@ -23465,10 +23492,14 @@ function emitConditionalChild(parentId, markerId, expr, statements, ctx) {
|
|
|
23465
23492
|
ctx.helpersUsed.add("conditional");
|
|
23466
23493
|
ctx.helpersUsed.add("createElement");
|
|
23467
23494
|
ctx.helpersUsed.add("onDestroy");
|
|
23468
|
-
ctx.helpersUsed.add("toNodeArray");
|
|
23469
23495
|
let condition;
|
|
23470
23496
|
let consequent;
|
|
23471
23497
|
let alternate = null;
|
|
23498
|
+
const lowerBranch = (branch) => {
|
|
23499
|
+
const listExpr = buildListCallExpression(branch, statements, ctx);
|
|
23500
|
+
if (listExpr) return listExpr;
|
|
23501
|
+
return lowerDomExpression(branch, ctx);
|
|
23502
|
+
};
|
|
23472
23503
|
const enterConditional = () => {
|
|
23473
23504
|
ctx.inConditional = (ctx.inConditional ?? 0) + 1;
|
|
23474
23505
|
};
|
|
@@ -23478,13 +23509,13 @@ function emitConditionalChild(parentId, markerId, expr, statements, ctx) {
|
|
|
23478
23509
|
if (expr.kind === "ConditionalExpression") {
|
|
23479
23510
|
condition = lowerDomExpression(expr.test, ctx);
|
|
23480
23511
|
enterConditional();
|
|
23481
|
-
consequent =
|
|
23482
|
-
alternate =
|
|
23512
|
+
consequent = lowerBranch(expr.consequent);
|
|
23513
|
+
alternate = lowerBranch(expr.alternate);
|
|
23483
23514
|
exitConditional();
|
|
23484
23515
|
} else if (expr.kind === "LogicalExpression" && expr.operator === "&&") {
|
|
23485
23516
|
condition = lowerDomExpression(expr.left, ctx);
|
|
23486
23517
|
enterConditional();
|
|
23487
|
-
consequent =
|
|
23518
|
+
consequent = lowerBranch(expr.right);
|
|
23488
23519
|
exitConditional();
|
|
23489
23520
|
} else {
|
|
23490
23521
|
return;
|
|
@@ -23506,29 +23537,11 @@ function emitConditionalChild(parentId, markerId, expr, statements, ctx) {
|
|
|
23506
23537
|
)
|
|
23507
23538
|
])
|
|
23508
23539
|
);
|
|
23509
|
-
const markersId = genTemp(ctx, "markers");
|
|
23510
|
-
statements.push(
|
|
23511
|
-
t2.variableDeclaration("const", [
|
|
23512
|
-
t2.variableDeclarator(
|
|
23513
|
-
markersId,
|
|
23514
|
-
t2.callExpression(t2.identifier(RUNTIME_ALIASES.toNodeArray), [
|
|
23515
|
-
t2.memberExpression(bindingId, t2.identifier("marker"))
|
|
23516
|
-
])
|
|
23517
|
-
)
|
|
23518
|
-
])
|
|
23519
|
-
);
|
|
23520
|
-
const mId = genTemp(ctx, "m");
|
|
23521
23540
|
statements.push(
|
|
23522
|
-
t2.
|
|
23523
|
-
t2.
|
|
23524
|
-
|
|
23525
|
-
|
|
23526
|
-
t2.expressionStatement(
|
|
23527
|
-
t2.callExpression(t2.memberExpression(parentId, t2.identifier("insertBefore")), [
|
|
23528
|
-
mId,
|
|
23529
|
-
markerId
|
|
23530
|
-
])
|
|
23531
|
-
)
|
|
23541
|
+
t2.expressionStatement(
|
|
23542
|
+
t2.callExpression(t2.memberExpression(parentId, t2.identifier("insertBefore")), [
|
|
23543
|
+
t2.memberExpression(bindingId, t2.identifier("marker")),
|
|
23544
|
+
markerId
|
|
23532
23545
|
])
|
|
23533
23546
|
)
|
|
23534
23547
|
);
|
|
@@ -23878,10 +23891,18 @@ function applySelectorHoist(callbackExpr, itemParamName, keyParamName, statement
|
|
|
23878
23891
|
};
|
|
23879
23892
|
const visitNode = (node) => {
|
|
23880
23893
|
if (t2.isFunctionExpression(node) || t2.isArrowFunctionExpression(node)) {
|
|
23881
|
-
if (node !== callbackExpr)
|
|
23894
|
+
if (node !== callbackExpr) {
|
|
23895
|
+
if (t2.isBlockStatement(node.body)) {
|
|
23896
|
+
node.body.body.forEach((stmt) => visitNode(stmt));
|
|
23897
|
+
} else if (t2.isExpression(node.body)) {
|
|
23898
|
+
visitNode(node.body);
|
|
23899
|
+
}
|
|
23900
|
+
return;
|
|
23901
|
+
}
|
|
23882
23902
|
}
|
|
23883
|
-
if (t2.isCallExpression(node)
|
|
23884
|
-
|
|
23903
|
+
if (t2.isCallExpression(node)) {
|
|
23904
|
+
const calleeName = t2.isIdentifier(node.callee) ? node.callee.name : t2.isMemberExpression(node.callee) && t2.isIdentifier(node.callee.property) ? node.callee.property.name : null;
|
|
23905
|
+
if (calleeName === RUNTIME_ALIASES.bindClass || calleeName === "bindClass") {
|
|
23885
23906
|
const handler = node.arguments[1];
|
|
23886
23907
|
if (handler && (t2.isArrowFunctionExpression(handler) || t2.isFunctionExpression(handler))) {
|
|
23887
23908
|
rewriteInFunction(handler);
|
|
@@ -23964,20 +23985,26 @@ function applySelectorHoist(callbackExpr, itemParamName, keyParamName, statement
|
|
|
23964
23985
|
}
|
|
23965
23986
|
}
|
|
23966
23987
|
}
|
|
23967
|
-
function
|
|
23988
|
+
function buildListCallExpression(expr, statements, ctx) {
|
|
23968
23989
|
const { t: t2 } = ctx;
|
|
23969
|
-
if (expr.kind !== "CallExpression"
|
|
23970
|
-
return;
|
|
23990
|
+
if (expr.kind !== "CallExpression" && expr.kind !== "OptionalCallExpression") {
|
|
23991
|
+
return null;
|
|
23992
|
+
}
|
|
23993
|
+
if (expr.callee.kind !== "MemberExpression" && expr.callee.kind !== "OptionalMemberExpression") {
|
|
23994
|
+
return null;
|
|
23971
23995
|
}
|
|
23972
|
-
|
|
23996
|
+
if (expr.callee.property.kind !== "Identifier" || expr.callee.property.name !== "map") {
|
|
23997
|
+
return null;
|
|
23998
|
+
}
|
|
23999
|
+
const isOptional = expr.kind === "OptionalCallExpression" || expr.callee.kind === "OptionalMemberExpression" && expr.callee.optional;
|
|
24000
|
+
const arrayExprBase = lowerDomExpression(expr.callee.object, ctx);
|
|
24001
|
+
const arrayExpr = isOptional ? t2.logicalExpression("??", arrayExprBase, t2.arrayExpression([])) : arrayExprBase;
|
|
23973
24002
|
const mapCallback = expr.arguments[0];
|
|
23974
24003
|
if (!mapCallback) {
|
|
23975
24004
|
throw new Error("map callback is required");
|
|
23976
24005
|
}
|
|
23977
24006
|
const keyExpr = extractKeyFromMapCallback(mapCallback);
|
|
23978
24007
|
const isKeyed = !!keyExpr;
|
|
23979
|
-
ctx.helpersUsed.add("onDestroy");
|
|
23980
|
-
ctx.helpersUsed.add("toNodeArray");
|
|
23981
24008
|
if (isKeyed) {
|
|
23982
24009
|
ctx.helpersUsed.add("keyedList");
|
|
23983
24010
|
} else {
|
|
@@ -24005,6 +24032,7 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
|
|
|
24005
24032
|
ctx.inListRender = true;
|
|
24006
24033
|
let callbackExpr = lowerExpression(mapCallback, ctx);
|
|
24007
24034
|
ctx.inListRender = prevInListRender;
|
|
24035
|
+
const capturedKeyParamName = ctx.listKeyParamName;
|
|
24008
24036
|
ctx.listKeyExpr = prevListKeyExpr;
|
|
24009
24037
|
ctx.listItemParamName = prevListItemParamName;
|
|
24010
24038
|
ctx.listKeyParamName = prevListKeyParamName;
|
|
@@ -24042,18 +24070,17 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
|
|
|
24042
24070
|
}
|
|
24043
24071
|
}
|
|
24044
24072
|
}
|
|
24045
|
-
const listId = genTemp(ctx, "list");
|
|
24046
24073
|
if (isKeyed) {
|
|
24047
24074
|
const itemParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : null : null;
|
|
24048
|
-
const keyParamName = ctx.listKeyParamName ?? null;
|
|
24049
24075
|
applySelectorHoist(
|
|
24050
24076
|
callbackExpr,
|
|
24051
24077
|
itemParamName,
|
|
24052
|
-
|
|
24078
|
+
capturedKeyParamName ?? null,
|
|
24053
24079
|
statements,
|
|
24054
24080
|
ctx
|
|
24055
24081
|
);
|
|
24056
24082
|
}
|
|
24083
|
+
let listCall;
|
|
24057
24084
|
if (isKeyed && keyExpr) {
|
|
24058
24085
|
let keyExprAst = lowerExpression(keyExpr, ctx);
|
|
24059
24086
|
if (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr)) {
|
|
@@ -24096,19 +24123,12 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
|
|
|
24096
24123
|
}
|
|
24097
24124
|
}
|
|
24098
24125
|
statements.push(...hoistedStatements);
|
|
24099
|
-
|
|
24100
|
-
t2.
|
|
24101
|
-
|
|
24102
|
-
|
|
24103
|
-
|
|
24104
|
-
|
|
24105
|
-
keyFn,
|
|
24106
|
-
callbackExpr,
|
|
24107
|
-
t2.booleanLiteral(hasIndexParam)
|
|
24108
|
-
])
|
|
24109
|
-
)
|
|
24110
|
-
])
|
|
24111
|
-
);
|
|
24126
|
+
listCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.keyedList), [
|
|
24127
|
+
t2.arrowFunctionExpression([], arrayExpr),
|
|
24128
|
+
keyFn,
|
|
24129
|
+
callbackExpr,
|
|
24130
|
+
t2.booleanLiteral(hasIndexParam)
|
|
24131
|
+
]);
|
|
24112
24132
|
} else {
|
|
24113
24133
|
statements.push(...hoistedStatements);
|
|
24114
24134
|
const itemParamName = t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr) ? t2.isIdentifier(callbackExpr.params[0]) ? callbackExpr.params[0].name : "__item" : "__item";
|
|
@@ -24118,20 +24138,23 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
|
|
|
24118
24138
|
[t2.identifier(itemParamName), t2.identifier(indexParamName)],
|
|
24119
24139
|
t2.identifier(indexParamName)
|
|
24120
24140
|
);
|
|
24121
|
-
|
|
24122
|
-
t2.
|
|
24123
|
-
|
|
24124
|
-
|
|
24125
|
-
|
|
24126
|
-
|
|
24127
|
-
keyFn,
|
|
24128
|
-
callbackExpr,
|
|
24129
|
-
t2.booleanLiteral(hasIndexParam)
|
|
24130
|
-
])
|
|
24131
|
-
)
|
|
24132
|
-
])
|
|
24133
|
-
);
|
|
24141
|
+
listCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.keyedList), [
|
|
24142
|
+
t2.arrowFunctionExpression([], arrayExpr),
|
|
24143
|
+
keyFn,
|
|
24144
|
+
callbackExpr,
|
|
24145
|
+
t2.booleanLiteral(hasIndexParam)
|
|
24146
|
+
]);
|
|
24134
24147
|
}
|
|
24148
|
+
return listCall;
|
|
24149
|
+
}
|
|
24150
|
+
function emitListChild(parentId, markerId, expr, statements, ctx) {
|
|
24151
|
+
const { t: t2 } = ctx;
|
|
24152
|
+
const listCall = buildListCallExpression(expr, statements, ctx);
|
|
24153
|
+
if (!listCall) return;
|
|
24154
|
+
ctx.helpersUsed.add("onDestroy");
|
|
24155
|
+
ctx.helpersUsed.add("toNodeArray");
|
|
24156
|
+
const listId = genTemp(ctx, "list");
|
|
24157
|
+
statements.push(t2.variableDeclaration("const", [t2.variableDeclarator(listId, listCall)]));
|
|
24135
24158
|
const markersId = genTemp(ctx, "markers");
|
|
24136
24159
|
statements.push(
|
|
24137
24160
|
t2.variableDeclaration("const", [
|
|
@@ -24486,8 +24509,14 @@ function lowerTopLevelStatementBlock(statements, ctx, t2, name = "__module_segme
|
|
|
24486
24509
|
ctx.hookReturnInfo.set(fn.name, info);
|
|
24487
24510
|
}
|
|
24488
24511
|
}
|
|
24489
|
-
const
|
|
24490
|
-
|
|
24512
|
+
const prevInModule = ctx.inModule;
|
|
24513
|
+
ctx.inModule = true;
|
|
24514
|
+
try {
|
|
24515
|
+
const lowered = generateRegionCode(fn, scopeResult, t2, ctx);
|
|
24516
|
+
return { statements: lowered, aliases: aliasVars };
|
|
24517
|
+
} finally {
|
|
24518
|
+
ctx.inModule = prevInModule;
|
|
24519
|
+
}
|
|
24491
24520
|
}
|
|
24492
24521
|
function transformControlFlowReturns(statements, ctx) {
|
|
24493
24522
|
const { t: t2 } = ctx;
|
|
@@ -24588,12 +24617,14 @@ function lowerFunctionWithRegions(fn, ctx) {
|
|
|
24588
24617
|
const prevWrapTracked = ctx.wrapTrackedExpressions;
|
|
24589
24618
|
const prevIsComponent = ctx.isComponentFn;
|
|
24590
24619
|
const prevHookResultVarMap = ctx.hookResultVarMap;
|
|
24620
|
+
const prevInModule = ctx.inModule;
|
|
24591
24621
|
const scopedTracked = new Set(ctx.trackedVars);
|
|
24592
24622
|
const shadowedParams = new Set(fn.params.map((p) => deSSAVarName(p.name)));
|
|
24593
24623
|
fn.params.forEach((p) => scopedTracked.delete(deSSAVarName(p.name)));
|
|
24594
24624
|
ctx.trackedVars = scopedTracked;
|
|
24595
24625
|
const prevNeedsCtx = ctx.needsCtx;
|
|
24596
24626
|
ctx.needsCtx = false;
|
|
24627
|
+
ctx.inModule = false;
|
|
24597
24628
|
const prevShadowed = ctx.shadowedNames;
|
|
24598
24629
|
const functionShadowed = new Set(prevShadowed ?? []);
|
|
24599
24630
|
shadowedParams.forEach((n) => functionShadowed.add(n));
|
|
@@ -24878,9 +24909,9 @@ function lowerFunctionWithRegions(fn, ctx) {
|
|
|
24878
24909
|
ctx.hookReturnInfo.set(fn.name, info);
|
|
24879
24910
|
}
|
|
24880
24911
|
}
|
|
24881
|
-
if (
|
|
24882
|
-
|
|
24883
|
-
|
|
24912
|
+
if (fn.name === "Counter") {
|
|
24913
|
+
debugLog("region", "Tracked vars for Counter", Array.from(ctx.trackedVars));
|
|
24914
|
+
debugLog("region", "Memo vars for Counter", Array.from(ctx.memoVars));
|
|
24884
24915
|
}
|
|
24885
24916
|
hookResultVars.forEach((varName) => {
|
|
24886
24917
|
const hookName = ctx.hookResultVarMap?.get(varName);
|
|
@@ -24910,6 +24941,7 @@ function lowerFunctionWithRegions(fn, ctx) {
|
|
|
24910
24941
|
ctx.noMemo = prevNoMemo;
|
|
24911
24942
|
ctx.wrapTrackedExpressions = prevWrapTracked;
|
|
24912
24943
|
ctx.hookResultVarMap = prevHookResultVarMap;
|
|
24944
|
+
ctx.inModule = prevInModule;
|
|
24913
24945
|
return null;
|
|
24914
24946
|
}
|
|
24915
24947
|
let statements;
|
|
@@ -24998,6 +25030,7 @@ function lowerFunctionWithRegions(fn, ctx) {
|
|
|
24998
25030
|
ctx.propsParamName = prevPropsParam;
|
|
24999
25031
|
ctx.propAccessorDecls = prevPropAccessors;
|
|
25000
25032
|
ctx.delegatedEventsUsed = prevDelegatedEventsUsed;
|
|
25033
|
+
ctx.inModule = prevInModule;
|
|
25001
25034
|
return funcDecl;
|
|
25002
25035
|
}
|
|
25003
25036
|
function flattenRegions(regions) {
|
|
@@ -25641,28 +25674,49 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
25641
25674
|
if (!init) return;
|
|
25642
25675
|
if (isStateCall(init, t2)) {
|
|
25643
25676
|
if (!fictImports.has("$state")) {
|
|
25644
|
-
throw varPath.buildCodeFrameError(
|
|
25677
|
+
throw varPath.buildCodeFrameError(
|
|
25678
|
+
`$state() must be imported from "fict".
|
|
25679
|
+
|
|
25680
|
+
Add this import at the top of your file:
|
|
25681
|
+
import { $state } from 'fict'`
|
|
25682
|
+
);
|
|
25645
25683
|
}
|
|
25646
25684
|
if (!t2.isIdentifier(varPath.node.id)) {
|
|
25647
25685
|
throw varPath.buildCodeFrameError(
|
|
25648
|
-
|
|
25686
|
+
`Destructuring $state is not supported.
|
|
25687
|
+
|
|
25688
|
+
Instead of: const { a, b } = $state({ a: 1, b: 2 })
|
|
25689
|
+
Use: let state = $state({ a: 1, b: 2 })
|
|
25690
|
+
const { a, b } = state // read-only aliases
|
|
25691
|
+
|
|
25692
|
+
For deep reactivity, consider using $store from 'fict'.`
|
|
25649
25693
|
);
|
|
25650
25694
|
}
|
|
25651
25695
|
const ownerComponent = varPath.getFunctionParent();
|
|
25652
25696
|
if (!ownerComponent || !isComponentOrHookDefinition(ownerComponent)) {
|
|
25653
25697
|
throw varPath.buildCodeFrameError(
|
|
25654
|
-
|
|
25698
|
+
`$state() must be declared inside a component or hook function body.
|
|
25699
|
+
|
|
25700
|
+
For module-level shared state, use one of these alternatives:
|
|
25701
|
+
\u2022 $store from 'fict' - for deep reactive objects
|
|
25702
|
+
\u2022 createSignal from 'fict/advanced' - for primitives`
|
|
25655
25703
|
);
|
|
25656
25704
|
}
|
|
25657
25705
|
stateVars.add(varPath.node.id.name);
|
|
25658
25706
|
if (isInsideLoop(varPath) || isInsideConditional(varPath)) {
|
|
25659
25707
|
throw varPath.buildCodeFrameError(
|
|
25660
|
-
|
|
25708
|
+
`$state() cannot be declared inside loops or conditionals.
|
|
25709
|
+
|
|
25710
|
+
Signals must be created at the top level of components for stable identity.
|
|
25711
|
+
Move the $state() declaration before the loop/condition.`
|
|
25661
25712
|
);
|
|
25662
25713
|
}
|
|
25663
25714
|
if (isInsideNestedFunction(varPath)) {
|
|
25664
25715
|
throw varPath.buildCodeFrameError(
|
|
25665
|
-
|
|
25716
|
+
`$state() cannot be declared inside nested functions.
|
|
25717
|
+
|
|
25718
|
+
Move the $state() declaration to the component's top level,
|
|
25719
|
+
or extract the nested logic into a custom hook (useXxx).`
|
|
25666
25720
|
);
|
|
25667
25721
|
}
|
|
25668
25722
|
} else if (t2.isIdentifier(varPath.node.id)) {
|
|
@@ -25704,43 +25758,77 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
25704
25758
|
const isVariableDeclarator = parentPath?.isVariableDeclarator() && parentPath.node.init === callPath.node;
|
|
25705
25759
|
if (!isVariableDeclarator) {
|
|
25706
25760
|
throw callPath.buildCodeFrameError(
|
|
25707
|
-
|
|
25761
|
+
`$state() must be assigned directly to a variable.
|
|
25762
|
+
|
|
25763
|
+
Correct usage:
|
|
25764
|
+
let count = $state(0)
|
|
25765
|
+
let user = $state({ name: 'Alice' })
|
|
25766
|
+
|
|
25767
|
+
For object state with deep reactivity, consider:
|
|
25768
|
+
import { $store } from 'fict'
|
|
25769
|
+
const user = $store({ name: 'Alice', address: { city: 'NYC' } })`
|
|
25708
25770
|
);
|
|
25709
25771
|
}
|
|
25710
25772
|
if (!t2.isIdentifier(parentPath.node.id)) {
|
|
25711
25773
|
throw callPath.buildCodeFrameError(
|
|
25712
|
-
|
|
25774
|
+
`Destructuring $state is not supported.
|
|
25775
|
+
|
|
25776
|
+
Instead of: const { a, b } = $state({ a: 1, b: 2 })
|
|
25777
|
+
Use: let state = $state({ a: 1, b: 2 })
|
|
25778
|
+
const { a, b } = state // read-only aliases`
|
|
25713
25779
|
);
|
|
25714
25780
|
}
|
|
25715
25781
|
const ownerComponent = callPath.getFunctionParent();
|
|
25716
25782
|
if (!ownerComponent || !isComponentOrHookDefinition(ownerComponent)) {
|
|
25717
25783
|
throw callPath.buildCodeFrameError(
|
|
25718
|
-
|
|
25784
|
+
`$state() must be declared inside a component or hook function body.
|
|
25785
|
+
|
|
25786
|
+
For module-level shared state, use one of these alternatives:
|
|
25787
|
+
\u2022 $store from 'fict' - for deep reactive objects
|
|
25788
|
+
\u2022 createSignal from 'fict/advanced' - for primitives`
|
|
25719
25789
|
);
|
|
25720
25790
|
}
|
|
25721
25791
|
if (isInsideLoop(callPath) || isInsideConditional(callPath)) {
|
|
25722
25792
|
throw callPath.buildCodeFrameError(
|
|
25723
|
-
|
|
25793
|
+
`$state() cannot be declared inside loops or conditionals.
|
|
25794
|
+
|
|
25795
|
+
Move the declaration to the top of your component.
|
|
25796
|
+
For dynamic collections, consider using $store with an array/object.`
|
|
25724
25797
|
);
|
|
25725
25798
|
}
|
|
25726
25799
|
if (isInsideNestedFunction(callPath)) {
|
|
25727
25800
|
throw callPath.buildCodeFrameError(
|
|
25728
|
-
|
|
25801
|
+
`$state() cannot be declared inside nested functions.
|
|
25802
|
+
|
|
25803
|
+
Move the declaration to the component's top level,
|
|
25804
|
+
or extract the nested logic into a custom hook (useXxx).`
|
|
25729
25805
|
);
|
|
25730
25806
|
}
|
|
25731
25807
|
}
|
|
25732
25808
|
if (isEffectCall(callPath.node, t2)) {
|
|
25733
25809
|
if (!fictImports.has("$effect")) {
|
|
25734
|
-
throw callPath.buildCodeFrameError(
|
|
25810
|
+
throw callPath.buildCodeFrameError(
|
|
25811
|
+
`$effect() must be imported from "fict".
|
|
25812
|
+
|
|
25813
|
+
Add this import at the top of your file:
|
|
25814
|
+
import { $effect } from 'fict'`
|
|
25815
|
+
);
|
|
25735
25816
|
}
|
|
25736
25817
|
if (isInsideLoop(callPath) || isInsideConditional(callPath)) {
|
|
25737
25818
|
throw callPath.buildCodeFrameError(
|
|
25738
|
-
|
|
25819
|
+
`$effect() cannot be called inside loops or conditionals.
|
|
25820
|
+
|
|
25821
|
+
Effects must be registered at the top level of components.
|
|
25822
|
+
For conditional effects, use a condition inside the effect body instead:
|
|
25823
|
+
$effect(() => { if (condition) { /* ... */ } })`
|
|
25739
25824
|
);
|
|
25740
25825
|
}
|
|
25741
25826
|
if (isInsideNestedFunction(callPath)) {
|
|
25742
25827
|
throw callPath.buildCodeFrameError(
|
|
25743
|
-
|
|
25828
|
+
`$effect() cannot be called inside nested functions.
|
|
25829
|
+
|
|
25830
|
+
Move the effect to the component's top level,
|
|
25831
|
+
or extract the nested logic into a custom hook (useXxx).`
|
|
25744
25832
|
);
|
|
25745
25833
|
}
|
|
25746
25834
|
}
|
|
@@ -25828,9 +25916,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
25828
25916
|
});
|
|
25829
25917
|
return usesState;
|
|
25830
25918
|
};
|
|
25831
|
-
|
|
25832
|
-
console.log("[fict] alias check state vars", Array.from(stateVars));
|
|
25833
|
-
}
|
|
25919
|
+
debugLog("alias", "state vars", Array.from(stateVars));
|
|
25834
25920
|
path.traverse({
|
|
25835
25921
|
Function: {
|
|
25836
25922
|
enter() {
|
|
@@ -25843,9 +25929,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
25843
25929
|
VariableDeclarator(varPath) {
|
|
25844
25930
|
const aliasSet = currentAliasSet();
|
|
25845
25931
|
if (aliasSet && t2.isIdentifier(varPath.node.id) && rhsUsesState(varPath.get("init"))) {
|
|
25846
|
-
|
|
25847
|
-
console.log("[fict] alias add from decl", varPath.node.id.name);
|
|
25848
|
-
}
|
|
25932
|
+
debugLog("alias", "add from decl", varPath.node.id.name);
|
|
25849
25933
|
aliasSet.add(varPath.node.id.name);
|
|
25850
25934
|
}
|
|
25851
25935
|
},
|
|
@@ -25856,16 +25940,12 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
25856
25940
|
const targetName = assignPath.node.left.name;
|
|
25857
25941
|
const rightPath = assignPath.get("right");
|
|
25858
25942
|
if (rhsUsesState(rightPath)) {
|
|
25859
|
-
|
|
25860
|
-
console.log("[fict] alias add from assign", targetName);
|
|
25861
|
-
}
|
|
25943
|
+
debugLog("alias", "add from assign", targetName);
|
|
25862
25944
|
aliasSet.add(targetName);
|
|
25863
25945
|
return;
|
|
25864
25946
|
}
|
|
25865
25947
|
if (aliasSet.has(targetName)) {
|
|
25866
|
-
|
|
25867
|
-
console.log("[fict] alias reassignment detected", targetName);
|
|
25868
|
-
}
|
|
25948
|
+
debugLog("alias", "reassignment detected", targetName);
|
|
25869
25949
|
throw assignPath.buildCodeFrameError(
|
|
25870
25950
|
`Alias reassignment is not supported for "${targetName}"`
|
|
25871
25951
|
);
|