@fictjs/compiler 0.0.7 → 0.0.9
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 +640 -267
- package/dist/index.js +640 -267
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -14384,6 +14384,9 @@ function pathToString(path) {
|
|
|
14384
14384
|
|
|
14385
14385
|
// src/ir/build-hir.ts
|
|
14386
14386
|
var destructuringTempCounter = 0;
|
|
14387
|
+
var getLoc = (node) => {
|
|
14388
|
+
return node?.loc ?? null;
|
|
14389
|
+
};
|
|
14387
14390
|
function normalizeVarKind(kind) {
|
|
14388
14391
|
return kind === "const" || kind === "let" || kind === "var" ? kind : "let";
|
|
14389
14392
|
}
|
|
@@ -14453,7 +14456,8 @@ function buildHIR(ast) {
|
|
|
14453
14456
|
functions.push(
|
|
14454
14457
|
convertFunction(name, stmt.params, stmt.body.body, {
|
|
14455
14458
|
noMemo: programNoMemo,
|
|
14456
|
-
directives: stmt.body.directives
|
|
14459
|
+
directives: stmt.body.directives,
|
|
14460
|
+
loc: getLoc(stmt)
|
|
14457
14461
|
})
|
|
14458
14462
|
);
|
|
14459
14463
|
continue;
|
|
@@ -14466,7 +14470,8 @@ function buildHIR(ast) {
|
|
|
14466
14470
|
functions.push(
|
|
14467
14471
|
convertFunction(name, decl.params, decl.body.body, {
|
|
14468
14472
|
noMemo: programNoMemo,
|
|
14469
|
-
directives: decl.body.directives
|
|
14473
|
+
directives: decl.body.directives,
|
|
14474
|
+
loc: getLoc(decl)
|
|
14470
14475
|
})
|
|
14471
14476
|
);
|
|
14472
14477
|
postamble.push({ kind: "ExportFunction", name });
|
|
@@ -14484,9 +14489,11 @@ function buildHIR(ast) {
|
|
|
14484
14489
|
const hasExpressionBody = isArrow && !t.isBlockStatement(body);
|
|
14485
14490
|
const fnHIR = t.isBlockStatement(body) ? convertFunction(name, params, body.body, {
|
|
14486
14491
|
noMemo: programNoMemo,
|
|
14487
|
-
directives: body.directives
|
|
14492
|
+
directives: body.directives,
|
|
14493
|
+
loc: getLoc(v.init ?? v)
|
|
14488
14494
|
}) : convertFunction(name, params, [t.returnStatement(body)], {
|
|
14489
|
-
noMemo: programNoMemo
|
|
14495
|
+
noMemo: programNoMemo,
|
|
14496
|
+
loc: getLoc(v.init ?? v)
|
|
14490
14497
|
});
|
|
14491
14498
|
fnHIR.meta = { ...fnHIR.meta ?? {}, fromExpression: true, isArrow, hasExpressionBody };
|
|
14492
14499
|
functions.push(fnHIR);
|
|
@@ -14511,7 +14518,8 @@ function buildHIR(ast) {
|
|
|
14511
14518
|
functions.push(
|
|
14512
14519
|
convertFunction(name, decl.params, decl.body.body, {
|
|
14513
14520
|
noMemo: programNoMemo,
|
|
14514
|
-
directives: decl.body.directives
|
|
14521
|
+
directives: decl.body.directives,
|
|
14522
|
+
loc: getLoc(decl)
|
|
14515
14523
|
})
|
|
14516
14524
|
);
|
|
14517
14525
|
postamble.push({ kind: "ExportDefault", name });
|
|
@@ -14536,13 +14544,15 @@ function buildHIR(ast) {
|
|
|
14536
14544
|
const hasExpressionBody = isArrow && !t.isBlockStatement(body);
|
|
14537
14545
|
const fnHIR = t.isBlockStatement(body) ? convertFunction(name, params, body.body, {
|
|
14538
14546
|
noMemo: programNoMemo,
|
|
14539
|
-
directives: body.directives
|
|
14547
|
+
directives: body.directives,
|
|
14548
|
+
loc: getLoc(decl.init ?? decl)
|
|
14540
14549
|
}) : convertFunction(
|
|
14541
14550
|
name,
|
|
14542
14551
|
params,
|
|
14543
14552
|
[t.returnStatement(body)],
|
|
14544
14553
|
{
|
|
14545
|
-
noMemo: programNoMemo
|
|
14554
|
+
noMemo: programNoMemo,
|
|
14555
|
+
loc: getLoc(decl.init ?? decl)
|
|
14546
14556
|
}
|
|
14547
14557
|
);
|
|
14548
14558
|
fnHIR.meta = { ...fnHIR.meta ?? {}, fromExpression: true, isArrow, hasExpressionBody };
|
|
@@ -15050,11 +15060,12 @@ function convertFunction(name, params, body, options) {
|
|
|
15050
15060
|
name,
|
|
15051
15061
|
params: paramIds,
|
|
15052
15062
|
blocks,
|
|
15053
|
-
meta: hasNoMemo ? { noMemo: true } : void 0
|
|
15063
|
+
meta: hasNoMemo ? { noMemo: true } : void 0,
|
|
15064
|
+
loc: options?.loc ?? null
|
|
15054
15065
|
};
|
|
15055
15066
|
}
|
|
15056
15067
|
function convertStatementsToHIRFunction(name, statements) {
|
|
15057
|
-
return convertFunction(name, [], statements);
|
|
15068
|
+
return convertFunction(name, [], statements, { loc: getLoc(statements[0]) });
|
|
15058
15069
|
}
|
|
15059
15070
|
function convertAssignmentValue(expr) {
|
|
15060
15071
|
const right = convertExpression(expr.right);
|
|
@@ -15552,14 +15563,16 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15552
15563
|
return bb;
|
|
15553
15564
|
}
|
|
15554
15565
|
function convertExpression(node) {
|
|
15555
|
-
|
|
15566
|
+
const loc = getLoc(node);
|
|
15567
|
+
if (t.isIdentifier(node)) return { kind: "Identifier", name: node.name, loc };
|
|
15556
15568
|
if (t.isStringLiteral(node) || t.isNumericLiteral(node) || t.isBooleanLiteral(node) || t.isNullLiteral(node))
|
|
15557
|
-
return { kind: "Literal", value: node.value ?? null };
|
|
15569
|
+
return { kind: "Literal", value: node.value ?? null, loc };
|
|
15558
15570
|
if (t.isCallExpression(node)) {
|
|
15559
15571
|
const call = {
|
|
15560
15572
|
kind: "CallExpression",
|
|
15561
15573
|
callee: convertExpression(node.callee),
|
|
15562
|
-
arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean)
|
|
15574
|
+
arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
|
|
15575
|
+
loc
|
|
15563
15576
|
};
|
|
15564
15577
|
return call;
|
|
15565
15578
|
}
|
|
@@ -15574,7 +15587,8 @@ function convertExpression(node) {
|
|
|
15574
15587
|
object,
|
|
15575
15588
|
property,
|
|
15576
15589
|
computed: node.computed,
|
|
15577
|
-
optional: node.optional ?? true
|
|
15590
|
+
optional: node.optional ?? true,
|
|
15591
|
+
loc
|
|
15578
15592
|
};
|
|
15579
15593
|
return optionalMember;
|
|
15580
15594
|
}
|
|
@@ -15583,7 +15597,8 @@ function convertExpression(node) {
|
|
|
15583
15597
|
object,
|
|
15584
15598
|
property,
|
|
15585
15599
|
computed: node.computed,
|
|
15586
|
-
optional: false
|
|
15600
|
+
optional: false,
|
|
15601
|
+
loc
|
|
15587
15602
|
};
|
|
15588
15603
|
return member;
|
|
15589
15604
|
}
|
|
@@ -15592,7 +15607,8 @@ function convertExpression(node) {
|
|
|
15592
15607
|
kind: "BinaryExpression",
|
|
15593
15608
|
operator: node.operator,
|
|
15594
15609
|
left: convertExpression(node.left),
|
|
15595
|
-
right: convertExpression(node.right)
|
|
15610
|
+
right: convertExpression(node.right),
|
|
15611
|
+
loc
|
|
15596
15612
|
};
|
|
15597
15613
|
return bin;
|
|
15598
15614
|
}
|
|
@@ -15601,7 +15617,8 @@ function convertExpression(node) {
|
|
|
15601
15617
|
kind: "UnaryExpression",
|
|
15602
15618
|
operator: node.operator,
|
|
15603
15619
|
argument: convertExpression(node.argument),
|
|
15604
|
-
prefix: node.prefix
|
|
15620
|
+
prefix: node.prefix,
|
|
15621
|
+
loc
|
|
15605
15622
|
};
|
|
15606
15623
|
return un;
|
|
15607
15624
|
}
|
|
@@ -15610,7 +15627,8 @@ function convertExpression(node) {
|
|
|
15610
15627
|
kind: "LogicalExpression",
|
|
15611
15628
|
operator: node.operator,
|
|
15612
15629
|
left: convertExpression(node.left),
|
|
15613
|
-
right: convertExpression(node.right)
|
|
15630
|
+
right: convertExpression(node.right),
|
|
15631
|
+
loc
|
|
15614
15632
|
};
|
|
15615
15633
|
return log;
|
|
15616
15634
|
}
|
|
@@ -15619,7 +15637,8 @@ function convertExpression(node) {
|
|
|
15619
15637
|
kind: "ConditionalExpression",
|
|
15620
15638
|
test: convertExpression(node.test),
|
|
15621
15639
|
consequent: convertExpression(node.consequent),
|
|
15622
|
-
alternate: convertExpression(node.alternate)
|
|
15640
|
+
alternate: convertExpression(node.alternate),
|
|
15641
|
+
loc
|
|
15623
15642
|
};
|
|
15624
15643
|
return cond;
|
|
15625
15644
|
}
|
|
@@ -15631,12 +15650,14 @@ function convertExpression(node) {
|
|
|
15631
15650
|
if (t.isSpreadElement(el)) {
|
|
15632
15651
|
return {
|
|
15633
15652
|
kind: "SpreadElement",
|
|
15634
|
-
argument: convertExpression(el.argument)
|
|
15653
|
+
argument: convertExpression(el.argument),
|
|
15654
|
+
loc: getLoc(el)
|
|
15635
15655
|
};
|
|
15636
15656
|
}
|
|
15637
15657
|
if (t.isExpression(el)) return convertExpression(el);
|
|
15638
15658
|
return void 0;
|
|
15639
|
-
}).filter(Boolean)
|
|
15659
|
+
}).filter(Boolean),
|
|
15660
|
+
loc
|
|
15640
15661
|
};
|
|
15641
15662
|
return arr;
|
|
15642
15663
|
}
|
|
@@ -15647,7 +15668,8 @@ function convertExpression(node) {
|
|
|
15647
15668
|
if (t.isSpreadElement(prop)) {
|
|
15648
15669
|
return {
|
|
15649
15670
|
kind: "SpreadElement",
|
|
15650
|
-
argument: convertExpression(prop.argument)
|
|
15671
|
+
argument: convertExpression(prop.argument),
|
|
15672
|
+
loc: getLoc(prop)
|
|
15651
15673
|
};
|
|
15652
15674
|
}
|
|
15653
15675
|
if (t.isObjectMethod(prop)) {
|
|
@@ -15664,7 +15686,8 @@ function convertExpression(node) {
|
|
|
15664
15686
|
return {
|
|
15665
15687
|
kind: "Property",
|
|
15666
15688
|
key: keyExpr2,
|
|
15667
|
-
value: convertExpression(fnExpr)
|
|
15689
|
+
value: convertExpression(fnExpr),
|
|
15690
|
+
loc: getLoc(prop)
|
|
15668
15691
|
};
|
|
15669
15692
|
}
|
|
15670
15693
|
if (!t.isObjectProperty(prop) || prop.computed) return void 0;
|
|
@@ -15674,9 +15697,12 @@ function convertExpression(node) {
|
|
|
15674
15697
|
return {
|
|
15675
15698
|
kind: "Property",
|
|
15676
15699
|
key: keyExpr,
|
|
15677
|
-
value: convertExpression(prop.value)
|
|
15700
|
+
value: convertExpression(prop.value),
|
|
15701
|
+
shorthand: prop.shorthand && t.isIdentifier(prop.value),
|
|
15702
|
+
loc: getLoc(prop)
|
|
15678
15703
|
};
|
|
15679
|
-
}).filter(Boolean)
|
|
15704
|
+
}).filter(Boolean),
|
|
15705
|
+
loc
|
|
15680
15706
|
};
|
|
15681
15707
|
return obj;
|
|
15682
15708
|
}
|
|
@@ -15689,38 +15715,42 @@ function convertExpression(node) {
|
|
|
15689
15715
|
if (t.isJSXText(child)) {
|
|
15690
15716
|
const text = child.value;
|
|
15691
15717
|
if (text.trim()) {
|
|
15692
|
-
children.push({ kind: "text", value: text });
|
|
15718
|
+
children.push({ kind: "text", value: text, loc: getLoc(child) });
|
|
15693
15719
|
}
|
|
15694
15720
|
} else if (t.isJSXExpressionContainer(child)) {
|
|
15695
15721
|
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
15696
15722
|
children.push({
|
|
15697
15723
|
kind: "expression",
|
|
15698
|
-
value: convertExpression(child.expression)
|
|
15724
|
+
value: convertExpression(child.expression),
|
|
15725
|
+
loc: getLoc(child)
|
|
15699
15726
|
});
|
|
15700
15727
|
}
|
|
15701
15728
|
} else if (t.isJSXElement(child)) {
|
|
15702
15729
|
children.push({
|
|
15703
15730
|
kind: "element",
|
|
15704
|
-
value: convertJSXElement(child)
|
|
15731
|
+
value: convertJSXElement(child),
|
|
15732
|
+
loc: getLoc(child)
|
|
15705
15733
|
});
|
|
15706
15734
|
} else if (t.isJSXFragment(child)) {
|
|
15707
15735
|
for (const fragChild of child.children) {
|
|
15708
15736
|
if (t.isJSXText(fragChild)) {
|
|
15709
15737
|
const text = fragChild.value;
|
|
15710
15738
|
if (text.trim()) {
|
|
15711
|
-
children.push({ kind: "text", value: text });
|
|
15739
|
+
children.push({ kind: "text", value: text, loc: getLoc(fragChild) });
|
|
15712
15740
|
}
|
|
15713
15741
|
} else if (t.isJSXExpressionContainer(fragChild)) {
|
|
15714
15742
|
if (!t.isJSXEmptyExpression(fragChild.expression)) {
|
|
15715
15743
|
children.push({
|
|
15716
15744
|
kind: "expression",
|
|
15717
|
-
value: convertExpression(fragChild.expression)
|
|
15745
|
+
value: convertExpression(fragChild.expression),
|
|
15746
|
+
loc: getLoc(fragChild)
|
|
15718
15747
|
});
|
|
15719
15748
|
}
|
|
15720
15749
|
} else if (t.isJSXElement(fragChild)) {
|
|
15721
15750
|
children.push({
|
|
15722
15751
|
kind: "element",
|
|
15723
|
-
value: convertJSXElement(fragChild)
|
|
15752
|
+
value: convertJSXElement(fragChild),
|
|
15753
|
+
loc: getLoc(fragChild)
|
|
15724
15754
|
});
|
|
15725
15755
|
}
|
|
15726
15756
|
}
|
|
@@ -15728,24 +15758,27 @@ function convertExpression(node) {
|
|
|
15728
15758
|
}
|
|
15729
15759
|
return {
|
|
15730
15760
|
kind: "JSXElement",
|
|
15731
|
-
tagName: { kind: "Identifier", name: "Fragment" },
|
|
15761
|
+
tagName: { kind: "Identifier", name: "Fragment", loc: getLoc(node) },
|
|
15732
15762
|
isComponent: true,
|
|
15733
15763
|
attributes: [],
|
|
15734
|
-
children
|
|
15764
|
+
children,
|
|
15765
|
+
loc: getLoc(node)
|
|
15735
15766
|
};
|
|
15736
15767
|
}
|
|
15737
15768
|
if (t.isArrowFunctionExpression(node)) {
|
|
15738
15769
|
if (t.isBlockStatement(node.body)) {
|
|
15739
15770
|
const nested = convertFunction(void 0, node.params, node.body.body, {
|
|
15740
15771
|
noMemo: hasNoMemoDirectiveInStatements(node.body.body),
|
|
15741
|
-
directives: node.body.directives
|
|
15772
|
+
directives: node.body.directives,
|
|
15773
|
+
loc: getLoc(node)
|
|
15742
15774
|
});
|
|
15743
15775
|
const arrow = {
|
|
15744
15776
|
kind: "ArrowFunction",
|
|
15745
15777
|
params: nested.params,
|
|
15746
15778
|
body: nested.blocks,
|
|
15747
15779
|
isExpression: false,
|
|
15748
|
-
isAsync: node.async
|
|
15780
|
+
isAsync: node.async,
|
|
15781
|
+
loc
|
|
15749
15782
|
};
|
|
15750
15783
|
return arrow;
|
|
15751
15784
|
} else {
|
|
@@ -15756,7 +15789,8 @@ function convertExpression(node) {
|
|
|
15756
15789
|
).flat(),
|
|
15757
15790
|
body: convertExpression(node.body),
|
|
15758
15791
|
isExpression: true,
|
|
15759
|
-
isAsync: node.async
|
|
15792
|
+
isAsync: node.async,
|
|
15793
|
+
loc
|
|
15760
15794
|
};
|
|
15761
15795
|
return arrow;
|
|
15762
15796
|
}
|
|
@@ -15764,14 +15798,16 @@ function convertExpression(node) {
|
|
|
15764
15798
|
if (t.isFunctionExpression(node)) {
|
|
15765
15799
|
const nested = convertFunction(void 0, node.params, node.body.body, {
|
|
15766
15800
|
noMemo: hasNoMemoDirectiveInStatements(node.body.body),
|
|
15767
|
-
directives: node.body.directives
|
|
15801
|
+
directives: node.body.directives,
|
|
15802
|
+
loc: getLoc(node)
|
|
15768
15803
|
});
|
|
15769
15804
|
const fn = {
|
|
15770
15805
|
kind: "FunctionExpression",
|
|
15771
15806
|
name: node.id?.name ?? "",
|
|
15772
15807
|
params: nested.params,
|
|
15773
15808
|
body: nested.blocks,
|
|
15774
|
-
isAsync: node.async
|
|
15809
|
+
isAsync: node.async,
|
|
15810
|
+
loc
|
|
15775
15811
|
};
|
|
15776
15812
|
return fn;
|
|
15777
15813
|
}
|
|
@@ -15780,7 +15816,8 @@ function convertExpression(node) {
|
|
|
15780
15816
|
kind: "AssignmentExpression",
|
|
15781
15817
|
operator: node.operator,
|
|
15782
15818
|
left: convertExpression(node.left),
|
|
15783
|
-
right: convertExpression(node.right)
|
|
15819
|
+
right: convertExpression(node.right),
|
|
15820
|
+
loc
|
|
15784
15821
|
};
|
|
15785
15822
|
return assign;
|
|
15786
15823
|
}
|
|
@@ -15789,7 +15826,8 @@ function convertExpression(node) {
|
|
|
15789
15826
|
kind: "UpdateExpression",
|
|
15790
15827
|
operator: node.operator,
|
|
15791
15828
|
argument: convertExpression(node.argument),
|
|
15792
|
-
prefix: node.prefix
|
|
15829
|
+
prefix: node.prefix,
|
|
15830
|
+
loc
|
|
15793
15831
|
};
|
|
15794
15832
|
return update;
|
|
15795
15833
|
}
|
|
@@ -15797,34 +15835,39 @@ function convertExpression(node) {
|
|
|
15797
15835
|
const template = {
|
|
15798
15836
|
kind: "TemplateLiteral",
|
|
15799
15837
|
quasis: node.quasis.map((q) => q.value.cooked ?? q.value.raw),
|
|
15800
|
-
expressions: node.expressions.map((e) => convertExpression(e))
|
|
15838
|
+
expressions: node.expressions.map((e) => convertExpression(e)),
|
|
15839
|
+
loc
|
|
15801
15840
|
};
|
|
15802
15841
|
return template;
|
|
15803
15842
|
}
|
|
15804
15843
|
if (t.isAwaitExpression(node)) {
|
|
15805
15844
|
return {
|
|
15806
15845
|
kind: "AwaitExpression",
|
|
15807
|
-
argument: convertExpression(node.argument)
|
|
15846
|
+
argument: convertExpression(node.argument),
|
|
15847
|
+
loc
|
|
15808
15848
|
};
|
|
15809
15849
|
}
|
|
15810
15850
|
if (t.isNewExpression(node)) {
|
|
15811
15851
|
return {
|
|
15812
15852
|
kind: "NewExpression",
|
|
15813
15853
|
callee: convertExpression(node.callee),
|
|
15814
|
-
arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean)
|
|
15854
|
+
arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
|
|
15855
|
+
loc
|
|
15815
15856
|
};
|
|
15816
15857
|
}
|
|
15817
15858
|
if (t.isSequenceExpression(node)) {
|
|
15818
15859
|
return {
|
|
15819
15860
|
kind: "SequenceExpression",
|
|
15820
|
-
expressions: node.expressions.map((e) => convertExpression(e))
|
|
15861
|
+
expressions: node.expressions.map((e) => convertExpression(e)),
|
|
15862
|
+
loc
|
|
15821
15863
|
};
|
|
15822
15864
|
}
|
|
15823
15865
|
if (t.isYieldExpression(node)) {
|
|
15824
15866
|
return {
|
|
15825
15867
|
kind: "YieldExpression",
|
|
15826
15868
|
argument: node.argument ? convertExpression(node.argument) : null,
|
|
15827
|
-
delegate: node.delegate
|
|
15869
|
+
delegate: node.delegate,
|
|
15870
|
+
loc
|
|
15828
15871
|
};
|
|
15829
15872
|
}
|
|
15830
15873
|
if (t.isOptionalCallExpression(node)) {
|
|
@@ -15832,7 +15875,8 @@ function convertExpression(node) {
|
|
|
15832
15875
|
kind: "OptionalCallExpression",
|
|
15833
15876
|
callee: convertExpression(node.callee),
|
|
15834
15877
|
arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
|
|
15835
|
-
optional: node.optional
|
|
15878
|
+
optional: node.optional,
|
|
15879
|
+
loc
|
|
15836
15880
|
};
|
|
15837
15881
|
}
|
|
15838
15882
|
if (t.isTaggedTemplateExpression(node)) {
|
|
@@ -15844,8 +15888,10 @@ function convertExpression(node) {
|
|
|
15844
15888
|
quasis: node.quasi.quasis.map((q) => q.value.cooked ?? q.value.raw),
|
|
15845
15889
|
expressions: node.quasi.expressions.map(
|
|
15846
15890
|
(e) => convertExpression(e)
|
|
15847
|
-
)
|
|
15848
|
-
|
|
15891
|
+
),
|
|
15892
|
+
loc: getLoc(node.quasi)
|
|
15893
|
+
},
|
|
15894
|
+
loc
|
|
15849
15895
|
};
|
|
15850
15896
|
}
|
|
15851
15897
|
if (t.isClassExpression(node)) {
|
|
@@ -15853,17 +15899,18 @@ function convertExpression(node) {
|
|
|
15853
15899
|
kind: "ClassExpression",
|
|
15854
15900
|
name: node.id?.name,
|
|
15855
15901
|
superClass: node.superClass ? convertExpression(node.superClass) : void 0,
|
|
15856
|
-
body: node.body.body
|
|
15902
|
+
body: node.body.body,
|
|
15857
15903
|
// Store as Babel AST for now
|
|
15904
|
+
loc
|
|
15858
15905
|
};
|
|
15859
15906
|
}
|
|
15860
15907
|
if (t.isThisExpression(node)) {
|
|
15861
|
-
return { kind: "ThisExpression" };
|
|
15908
|
+
return { kind: "ThisExpression", loc };
|
|
15862
15909
|
}
|
|
15863
15910
|
if (t.isSuper(node)) {
|
|
15864
|
-
return { kind: "SuperExpression" };
|
|
15911
|
+
return { kind: "SuperExpression", loc };
|
|
15865
15912
|
}
|
|
15866
|
-
const fallback = { kind: "Literal", value: void 0 };
|
|
15913
|
+
const fallback = { kind: "Literal", value: void 0, loc };
|
|
15867
15914
|
return fallback;
|
|
15868
15915
|
}
|
|
15869
15916
|
function convertJSXElement(node) {
|
|
@@ -15874,7 +15921,7 @@ function convertJSXElement(node) {
|
|
|
15874
15921
|
const name = opening.name.name;
|
|
15875
15922
|
const firstChar = name[0];
|
|
15876
15923
|
if (firstChar && firstChar === firstChar.toUpperCase()) {
|
|
15877
|
-
tagName = { kind: "Identifier", name };
|
|
15924
|
+
tagName = { kind: "Identifier", name, loc: getLoc(opening.name) };
|
|
15878
15925
|
isComponent = true;
|
|
15879
15926
|
} else {
|
|
15880
15927
|
tagName = name;
|
|
@@ -15892,20 +15939,22 @@ function convertJSXElement(node) {
|
|
|
15892
15939
|
name: "",
|
|
15893
15940
|
value: null,
|
|
15894
15941
|
isSpread: true,
|
|
15895
|
-
spreadExpr: convertExpression(attr.argument)
|
|
15942
|
+
spreadExpr: convertExpression(attr.argument),
|
|
15943
|
+
loc: getLoc(attr)
|
|
15896
15944
|
});
|
|
15897
15945
|
} else if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
|
|
15898
15946
|
let value = null;
|
|
15899
15947
|
if (attr.value) {
|
|
15900
15948
|
if (t.isStringLiteral(attr.value)) {
|
|
15901
|
-
value = { kind: "Literal", value: attr.value.value };
|
|
15949
|
+
value = { kind: "Literal", value: attr.value.value, loc: getLoc(attr.value) };
|
|
15902
15950
|
} else if (t.isJSXExpressionContainer(attr.value) && !t.isJSXEmptyExpression(attr.value.expression)) {
|
|
15903
15951
|
value = convertExpression(attr.value.expression);
|
|
15904
15952
|
}
|
|
15905
15953
|
}
|
|
15906
15954
|
attributes.push({
|
|
15907
15955
|
name: attr.name.name,
|
|
15908
|
-
value
|
|
15956
|
+
value,
|
|
15957
|
+
loc: getLoc(attr)
|
|
15909
15958
|
});
|
|
15910
15959
|
}
|
|
15911
15960
|
}
|
|
@@ -15914,38 +15963,42 @@ function convertJSXElement(node) {
|
|
|
15914
15963
|
if (t.isJSXText(child)) {
|
|
15915
15964
|
const text = child.value;
|
|
15916
15965
|
if (text.trim()) {
|
|
15917
|
-
children.push({ kind: "text", value: text });
|
|
15966
|
+
children.push({ kind: "text", value: text, loc: getLoc(child) });
|
|
15918
15967
|
}
|
|
15919
15968
|
} else if (t.isJSXExpressionContainer(child)) {
|
|
15920
15969
|
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
15921
15970
|
children.push({
|
|
15922
15971
|
kind: "expression",
|
|
15923
|
-
value: convertExpression(child.expression)
|
|
15972
|
+
value: convertExpression(child.expression),
|
|
15973
|
+
loc: getLoc(child)
|
|
15924
15974
|
});
|
|
15925
15975
|
}
|
|
15926
15976
|
} else if (t.isJSXElement(child)) {
|
|
15927
15977
|
children.push({
|
|
15928
15978
|
kind: "element",
|
|
15929
|
-
value: convertJSXElement(child)
|
|
15979
|
+
value: convertJSXElement(child),
|
|
15980
|
+
loc: getLoc(child)
|
|
15930
15981
|
});
|
|
15931
15982
|
} else if (t.isJSXFragment(child)) {
|
|
15932
15983
|
for (const fragChild of child.children) {
|
|
15933
15984
|
if (t.isJSXText(fragChild)) {
|
|
15934
15985
|
const text = fragChild.value;
|
|
15935
15986
|
if (text.trim()) {
|
|
15936
|
-
children.push({ kind: "text", value: text });
|
|
15987
|
+
children.push({ kind: "text", value: text, loc: getLoc(fragChild) });
|
|
15937
15988
|
}
|
|
15938
15989
|
} else if (t.isJSXExpressionContainer(fragChild)) {
|
|
15939
15990
|
if (!t.isJSXEmptyExpression(fragChild.expression)) {
|
|
15940
15991
|
children.push({
|
|
15941
15992
|
kind: "expression",
|
|
15942
|
-
value: convertExpression(fragChild.expression)
|
|
15993
|
+
value: convertExpression(fragChild.expression),
|
|
15994
|
+
loc: getLoc(fragChild)
|
|
15943
15995
|
});
|
|
15944
15996
|
}
|
|
15945
15997
|
} else if (t.isJSXElement(fragChild)) {
|
|
15946
15998
|
children.push({
|
|
15947
15999
|
kind: "element",
|
|
15948
|
-
value: convertJSXElement(fragChild)
|
|
16000
|
+
value: convertJSXElement(fragChild),
|
|
16001
|
+
loc: getLoc(fragChild)
|
|
15949
16002
|
});
|
|
15950
16003
|
}
|
|
15951
16004
|
}
|
|
@@ -15956,21 +16009,27 @@ function convertJSXElement(node) {
|
|
|
15956
16009
|
tagName,
|
|
15957
16010
|
isComponent,
|
|
15958
16011
|
attributes,
|
|
15959
|
-
children
|
|
16012
|
+
children,
|
|
16013
|
+
loc: getLoc(node)
|
|
15960
16014
|
};
|
|
15961
16015
|
}
|
|
15962
16016
|
function convertJSXMemberExpr(node) {
|
|
15963
16017
|
let object;
|
|
15964
16018
|
if (t.isJSXIdentifier(node.object)) {
|
|
15965
|
-
object = { kind: "Identifier", name: node.object.name };
|
|
16019
|
+
object = { kind: "Identifier", name: node.object.name, loc: getLoc(node.object) };
|
|
15966
16020
|
} else {
|
|
15967
16021
|
object = convertJSXMemberExpr(node.object);
|
|
15968
16022
|
}
|
|
15969
16023
|
return {
|
|
15970
16024
|
kind: "MemberExpression",
|
|
15971
16025
|
object,
|
|
15972
|
-
property: {
|
|
15973
|
-
|
|
16026
|
+
property: {
|
|
16027
|
+
kind: "Identifier",
|
|
16028
|
+
name: node.property.name,
|
|
16029
|
+
loc: getLoc(node.property)
|
|
16030
|
+
},
|
|
16031
|
+
computed: false,
|
|
16032
|
+
loc: getLoc(node)
|
|
15974
16033
|
};
|
|
15975
16034
|
}
|
|
15976
16035
|
|
|
@@ -15991,6 +16050,75 @@ function debugEnabled(flag) {
|
|
|
15991
16050
|
return parts.includes(normalized) || parts.includes("all");
|
|
15992
16051
|
}
|
|
15993
16052
|
|
|
16053
|
+
// src/utils.ts
|
|
16054
|
+
function isStateCall(node, t2) {
|
|
16055
|
+
return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$state";
|
|
16056
|
+
}
|
|
16057
|
+
function isEffectCall(node, t2) {
|
|
16058
|
+
return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$effect";
|
|
16059
|
+
}
|
|
16060
|
+
function getRootIdentifier(expr, t2) {
|
|
16061
|
+
if (t2.isIdentifier(expr)) {
|
|
16062
|
+
return expr;
|
|
16063
|
+
}
|
|
16064
|
+
if (t2.isMemberExpression(expr) && t2.isExpression(expr.object) && !t2.isOptionalMemberExpression(expr)) {
|
|
16065
|
+
return getRootIdentifier(expr.object, t2);
|
|
16066
|
+
}
|
|
16067
|
+
if (t2.isOptionalMemberExpression(expr) && t2.isExpression(expr.object)) {
|
|
16068
|
+
return getRootIdentifier(expr.object, t2);
|
|
16069
|
+
}
|
|
16070
|
+
if (t2.isCallExpression(expr) && t2.isExpression(expr.callee)) {
|
|
16071
|
+
return getRootIdentifier(expr.callee, t2);
|
|
16072
|
+
}
|
|
16073
|
+
if (t2.isOptionalCallExpression(expr) && t2.isExpression(expr.callee)) {
|
|
16074
|
+
return getRootIdentifier(expr.callee, t2);
|
|
16075
|
+
}
|
|
16076
|
+
if (t2.isTSAsExpression(expr) && t2.isExpression(expr.expression)) {
|
|
16077
|
+
return getRootIdentifier(expr.expression, t2);
|
|
16078
|
+
}
|
|
16079
|
+
if (t2.isTSNonNullExpression(expr) && t2.isExpression(expr.expression)) {
|
|
16080
|
+
return getRootIdentifier(expr.expression, t2);
|
|
16081
|
+
}
|
|
16082
|
+
return null;
|
|
16083
|
+
}
|
|
16084
|
+
|
|
16085
|
+
// src/fine-grained-dom.ts
|
|
16086
|
+
function normalizeDependencyKey(name) {
|
|
16087
|
+
return name.split(".").map((part) => part.replace(/_\d+$/, "")).join(".");
|
|
16088
|
+
}
|
|
16089
|
+
function applyRegionMetadata(state, options) {
|
|
16090
|
+
if (!options.region) return;
|
|
16091
|
+
const region = options.region;
|
|
16092
|
+
state.regionMetadata = region;
|
|
16093
|
+
if (region.dependencies.size > 0) {
|
|
16094
|
+
state.identifierOverrides = state.identifierOverrides ?? {};
|
|
16095
|
+
const dependencyGetter = options.dependencyGetter ?? null;
|
|
16096
|
+
if (!dependencyGetter) {
|
|
16097
|
+
return;
|
|
16098
|
+
}
|
|
16099
|
+
for (const dep of region.dependencies) {
|
|
16100
|
+
const key = normalizeDependencyKey(dep);
|
|
16101
|
+
state.identifierOverrides[key] = () => dependencyGetter(dep);
|
|
16102
|
+
const base = key.split(".")[0];
|
|
16103
|
+
if (base && !state.identifierOverrides[base]) {
|
|
16104
|
+
state.identifierOverrides[base] = () => dependencyGetter(base);
|
|
16105
|
+
}
|
|
16106
|
+
}
|
|
16107
|
+
}
|
|
16108
|
+
}
|
|
16109
|
+
function shouldMemoizeRegion(region) {
|
|
16110
|
+
if (region.dependencies.size > 0) {
|
|
16111
|
+
return true;
|
|
16112
|
+
}
|
|
16113
|
+
if (region.hasControlFlow) {
|
|
16114
|
+
return true;
|
|
16115
|
+
}
|
|
16116
|
+
if (region.hasReactiveWrites) {
|
|
16117
|
+
return true;
|
|
16118
|
+
}
|
|
16119
|
+
return false;
|
|
16120
|
+
}
|
|
16121
|
+
|
|
15994
16122
|
// src/ir/ssa.ts
|
|
15995
16123
|
function analyzeCFG(blocks) {
|
|
15996
16124
|
const predecessors = computePredecessors(blocks);
|
|
@@ -16481,7 +16609,7 @@ function collectExprReads(expr, into, paths, bound = /* @__PURE__ */ new Set(),
|
|
|
16481
16609
|
}
|
|
16482
16610
|
return;
|
|
16483
16611
|
case "CallExpression": {
|
|
16484
|
-
const isMacroCallee = expr.callee.kind === "Identifier" && (expr.callee.name === "$state" || expr.callee.name === "$effect");
|
|
16612
|
+
const isMacroCallee = expr.callee.kind === "Identifier" && (expr.callee.name === "$state" || expr.callee.name === "$effect" || expr.callee.name === "$store");
|
|
16485
16613
|
if (!isMacroCallee) {
|
|
16486
16614
|
collectExprReads(expr.callee, into, paths, bound);
|
|
16487
16615
|
}
|
|
@@ -18849,6 +18977,7 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
18849
18977
|
}
|
|
18850
18978
|
const outputNames = outputNamesOverride ?? Array.from(region.declarations).map((name) => deSSAVarName(name));
|
|
18851
18979
|
const uniqueOutputNames = [...new Set(outputNames)];
|
|
18980
|
+
const bindableOutputs = uniqueOutputNames.filter((name) => !declaredVars.has(name));
|
|
18852
18981
|
if (debugEnabled("region")) {
|
|
18853
18982
|
console.log("Region memo", region.id, {
|
|
18854
18983
|
instructions: region.instructions.map((instr) => instr.kind),
|
|
@@ -18858,11 +18987,17 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
18858
18987
|
if (uniqueOutputNames.length === 0) {
|
|
18859
18988
|
ctx.helpersUsed.add("useEffect");
|
|
18860
18989
|
ctx.needsCtx = true;
|
|
18861
|
-
const
|
|
18990
|
+
const effectCallArgs = [
|
|
18862
18991
|
t2.identifier("__fictCtx"),
|
|
18863
|
-
t2.arrowFunctionExpression([], t2.blockStatement(bodyStatements))
|
|
18864
|
-
|
|
18865
|
-
|
|
18992
|
+
t2.arrowFunctionExpression([], t2.blockStatement(bodyStatements))
|
|
18993
|
+
];
|
|
18994
|
+
{
|
|
18995
|
+
const slot = reserveHookSlot(ctx);
|
|
18996
|
+
if (slot >= 0) {
|
|
18997
|
+
effectCallArgs.push(t2.numericLiteral(slot));
|
|
18998
|
+
}
|
|
18999
|
+
}
|
|
19000
|
+
const effectCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), effectCallArgs);
|
|
18866
19001
|
statements.push(t2.expressionStatement(effectCall));
|
|
18867
19002
|
} else {
|
|
18868
19003
|
ctx.helpersUsed.add("useMemo");
|
|
@@ -18895,20 +19030,24 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
18895
19030
|
};
|
|
18896
19031
|
const returnObj = t2.objectExpression(uniqueOutputNames.map((name) => buildOutputProperty(name)));
|
|
18897
19032
|
const memoBody = t2.blockStatement([...bodyStatements, t2.returnStatement(returnObj)]);
|
|
18898
|
-
const
|
|
19033
|
+
const slot = reserveHookSlot(ctx);
|
|
19034
|
+
const memoArgs = [
|
|
18899
19035
|
t2.identifier("__fictCtx"),
|
|
18900
|
-
t2.arrowFunctionExpression([], memoBody)
|
|
18901
|
-
|
|
18902
|
-
|
|
19036
|
+
t2.arrowFunctionExpression([], memoBody)
|
|
19037
|
+
];
|
|
19038
|
+
if (slot >= 0) {
|
|
19039
|
+
memoArgs.push(t2.numericLiteral(slot));
|
|
19040
|
+
}
|
|
19041
|
+
const memoCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), memoArgs);
|
|
18903
19042
|
const regionVarName = `__region_${region.id}`;
|
|
18904
19043
|
statements.push(
|
|
18905
19044
|
t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(regionVarName), memoCall)])
|
|
18906
19045
|
);
|
|
18907
19046
|
const isAccessorOutput = (name) => ctx.signalVars?.has(name) || ctx.memoVars?.has(name) || ctx.aliasVars?.has(name) || ctx.storeVars?.has(name);
|
|
18908
|
-
const getterOutputs =
|
|
19047
|
+
const getterOutputs = bindableOutputs.filter(
|
|
18909
19048
|
(name) => ctx.trackedVars.has(name) && !isAccessorOutput(name)
|
|
18910
19049
|
);
|
|
18911
|
-
const directOutputs =
|
|
19050
|
+
const directOutputs = bindableOutputs.filter((name) => !getterOutputs.includes(name));
|
|
18912
19051
|
if (debugEnabled("region")) {
|
|
18913
19052
|
console.log("Region debug", {
|
|
18914
19053
|
id: region.id,
|
|
@@ -18956,7 +19095,10 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
18956
19095
|
t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
|
|
18957
19096
|
t2.identifier("__fictCtx"),
|
|
18958
19097
|
t2.arrowFunctionExpression([], effectBody),
|
|
18959
|
-
|
|
19098
|
+
(() => {
|
|
19099
|
+
const slot2 = reserveHookSlot(ctx);
|
|
19100
|
+
return slot2 >= 0 ? t2.numericLiteral(slot2) : t2.identifier("undefined");
|
|
19101
|
+
})()
|
|
18960
19102
|
])
|
|
18961
19103
|
)
|
|
18962
19104
|
);
|
|
@@ -19174,11 +19316,15 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
|
|
|
19174
19316
|
ctx.helpersUsed.add("useMemo");
|
|
19175
19317
|
ctx.needsCtx = true;
|
|
19176
19318
|
const regionVarName = `__region_${region.id}`;
|
|
19177
|
-
const
|
|
19319
|
+
const slotForMemo = reserveHookSlot(ctx);
|
|
19320
|
+
const memoArgs = [
|
|
19178
19321
|
t2.identifier("__fictCtx"),
|
|
19179
|
-
t2.arrowFunctionExpression([], t2.blockStatement(memoBody))
|
|
19180
|
-
|
|
19181
|
-
|
|
19322
|
+
t2.arrowFunctionExpression([], t2.blockStatement(memoBody))
|
|
19323
|
+
];
|
|
19324
|
+
if (slotForMemo >= 0) {
|
|
19325
|
+
memoArgs.push(t2.numericLiteral(slotForMemo));
|
|
19326
|
+
}
|
|
19327
|
+
const memoCall = t2.callExpression(t2.identifier("__fictUseMemo"), memoArgs);
|
|
19182
19328
|
statements.push(
|
|
19183
19329
|
t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(regionVarName), memoCall)])
|
|
19184
19330
|
);
|
|
@@ -19200,6 +19346,9 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
|
|
|
19200
19346
|
return statements;
|
|
19201
19347
|
}
|
|
19202
19348
|
function reserveHookSlot(ctx) {
|
|
19349
|
+
if (ctx.dynamicHookSlotDepth && ctx.dynamicHookSlotDepth > 0) {
|
|
19350
|
+
return -1;
|
|
19351
|
+
}
|
|
19203
19352
|
const slot = ctx.nextHookSlot ?? 0;
|
|
19204
19353
|
ctx.nextHookSlot = slot + 1;
|
|
19205
19354
|
return slot;
|
|
@@ -19270,7 +19419,10 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19270
19419
|
t2.arrowFunctionExpression([], expr)
|
|
19271
19420
|
];
|
|
19272
19421
|
if (inRegionMemo) {
|
|
19273
|
-
|
|
19422
|
+
const slot = reserveHookSlot(ctx);
|
|
19423
|
+
if (slot >= 0) {
|
|
19424
|
+
args.push(t2.numericLiteral(slot));
|
|
19425
|
+
}
|
|
19274
19426
|
}
|
|
19275
19427
|
ctx.helpersUsed.add("useMemo");
|
|
19276
19428
|
ctx.needsCtx = true;
|
|
@@ -19284,17 +19436,6 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19284
19436
|
const needsMutable = ctx.mutatedVars?.has(baseName2) ?? false;
|
|
19285
19437
|
const isExternalAlias = declKind === "const" && instr.value.kind === "Identifier" && !(ctx.scopes?.byName?.has(deSSAVarName(instr.value.name)) ?? false);
|
|
19286
19438
|
const fallbackDecl = !treatAsTracked && (!dependsOnTracked2 || isDestructuringTemp) ? declKind === "const" && (needsMutable || isExternalAlias) ? "let" : declKind : normalizedDecl;
|
|
19287
|
-
const isAliasOfTracked = !isShadowDeclaration && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp;
|
|
19288
|
-
if (isAliasOfTracked) {
|
|
19289
|
-
declaredVars.add(baseName2);
|
|
19290
|
-
const sourceIdent = instr.value;
|
|
19291
|
-
return t2.variableDeclaration(fallbackDecl, [
|
|
19292
|
-
t2.variableDeclarator(
|
|
19293
|
-
t2.identifier(baseName2),
|
|
19294
|
-
t2.callExpression(t2.identifier(deSSAVarName(sourceIdent.name)), [])
|
|
19295
|
-
)
|
|
19296
|
-
]);
|
|
19297
|
-
}
|
|
19298
19439
|
declaredVars.add(baseName2);
|
|
19299
19440
|
if (treatAsTracked && !isDestructuringTemp) {
|
|
19300
19441
|
if (isStateCall2) {
|
|
@@ -19303,6 +19444,9 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19303
19444
|
]);
|
|
19304
19445
|
}
|
|
19305
19446
|
if (dependsOnTracked2) {
|
|
19447
|
+
if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
|
|
19448
|
+
aliasVars.add(baseName2);
|
|
19449
|
+
}
|
|
19306
19450
|
const derivedExpr = lowerAssignedValue(true);
|
|
19307
19451
|
if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
|
|
19308
19452
|
return t2.variableDeclaration(normalizedDecl, [
|
|
@@ -19327,6 +19471,9 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19327
19471
|
}
|
|
19328
19472
|
}
|
|
19329
19473
|
if (dependsOnTracked2 && !isDestructuringTemp) {
|
|
19474
|
+
if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
|
|
19475
|
+
aliasVars.add(baseName2);
|
|
19476
|
+
}
|
|
19330
19477
|
const derivedExpr = lowerAssignedValue(true);
|
|
19331
19478
|
if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
|
|
19332
19479
|
return t2.variableDeclaration(normalizedDecl, [
|
|
@@ -19361,17 +19508,35 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19361
19508
|
t2.callExpression(t2.identifier(baseName2), [lowerAssignedValue(true)])
|
|
19362
19509
|
);
|
|
19363
19510
|
}
|
|
19364
|
-
if (instr.value.kind === "Identifier" && !isDestructuringTemp) {
|
|
19365
|
-
const source = deSSAVarName(instr.value.name);
|
|
19366
|
-
if (ctx.trackedVars.has(source) && !declaredVars.has(baseName2)) {
|
|
19367
|
-
return t2.variableDeclaration(declKind ?? "const", [
|
|
19368
|
-
t2.variableDeclarator(t2.identifier(baseName2), t2.callExpression(t2.identifier(source), []))
|
|
19369
|
-
]);
|
|
19370
|
-
}
|
|
19371
|
-
}
|
|
19372
19511
|
if (aliasVars.has(baseName2) && !declaredVars.has(baseName2)) {
|
|
19373
19512
|
throw new Error(`Alias reassignment is not supported for "${baseName2}"`);
|
|
19374
19513
|
}
|
|
19514
|
+
if (dependsOnTracked2 && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
|
|
19515
|
+
const derivedExpr = lowerAssignedValue(true);
|
|
19516
|
+
aliasVars.add(baseName2);
|
|
19517
|
+
if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
|
|
19518
|
+
return t2.expressionStatement(
|
|
19519
|
+
t2.assignmentExpression("=", t2.identifier(baseName2), derivedExpr)
|
|
19520
|
+
);
|
|
19521
|
+
}
|
|
19522
|
+
if (!isReactiveObjectCall) ctx.memoVars?.add(baseName2);
|
|
19523
|
+
if (ctx.noMemo) {
|
|
19524
|
+
return t2.expressionStatement(
|
|
19525
|
+
t2.assignmentExpression(
|
|
19526
|
+
"=",
|
|
19527
|
+
t2.identifier(baseName2),
|
|
19528
|
+
t2.arrowFunctionExpression([], derivedExpr)
|
|
19529
|
+
)
|
|
19530
|
+
);
|
|
19531
|
+
}
|
|
19532
|
+
return t2.expressionStatement(
|
|
19533
|
+
t2.assignmentExpression(
|
|
19534
|
+
"=",
|
|
19535
|
+
t2.identifier(baseName2),
|
|
19536
|
+
isMemoReturningCall ? derivedExpr : buildMemoCall(derivedExpr)
|
|
19537
|
+
)
|
|
19538
|
+
);
|
|
19539
|
+
}
|
|
19375
19540
|
if (declaredVars.has(baseName2)) {
|
|
19376
19541
|
if (aliasVars.has(baseName2)) {
|
|
19377
19542
|
throw new Error(`Alias reassignment is not supported for "${baseName2}"`);
|
|
@@ -19769,78 +19934,20 @@ function deSSAJSXChild(child, t2) {
|
|
|
19769
19934
|
return child;
|
|
19770
19935
|
}
|
|
19771
19936
|
|
|
19772
|
-
// src/utils.ts
|
|
19773
|
-
function isStateCall(node, t2) {
|
|
19774
|
-
return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$state";
|
|
19775
|
-
}
|
|
19776
|
-
function isEffectCall(node, t2) {
|
|
19777
|
-
return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$effect";
|
|
19778
|
-
}
|
|
19779
|
-
function getRootIdentifier(expr, t2) {
|
|
19780
|
-
if (t2.isIdentifier(expr)) {
|
|
19781
|
-
return expr;
|
|
19782
|
-
}
|
|
19783
|
-
if (t2.isMemberExpression(expr) && t2.isExpression(expr.object) && !t2.isOptionalMemberExpression(expr)) {
|
|
19784
|
-
return getRootIdentifier(expr.object, t2);
|
|
19785
|
-
}
|
|
19786
|
-
if (t2.isOptionalMemberExpression(expr) && t2.isExpression(expr.object)) {
|
|
19787
|
-
return getRootIdentifier(expr.object, t2);
|
|
19788
|
-
}
|
|
19789
|
-
if (t2.isCallExpression(expr) && t2.isExpression(expr.callee)) {
|
|
19790
|
-
return getRootIdentifier(expr.callee, t2);
|
|
19791
|
-
}
|
|
19792
|
-
if (t2.isOptionalCallExpression(expr) && t2.isExpression(expr.callee)) {
|
|
19793
|
-
return getRootIdentifier(expr.callee, t2);
|
|
19794
|
-
}
|
|
19795
|
-
if (t2.isTSAsExpression(expr) && t2.isExpression(expr.expression)) {
|
|
19796
|
-
return getRootIdentifier(expr.expression, t2);
|
|
19797
|
-
}
|
|
19798
|
-
if (t2.isTSNonNullExpression(expr) && t2.isExpression(expr.expression)) {
|
|
19799
|
-
return getRootIdentifier(expr.expression, t2);
|
|
19800
|
-
}
|
|
19801
|
-
return null;
|
|
19802
|
-
}
|
|
19803
|
-
|
|
19804
|
-
// src/fine-grained-dom.ts
|
|
19805
|
-
function normalizeDependencyKey(name) {
|
|
19806
|
-
return name.split(".").map((part) => part.replace(/_\d+$/, "")).join(".");
|
|
19807
|
-
}
|
|
19808
|
-
function applyRegionMetadata(state, options) {
|
|
19809
|
-
if (!options.region) return;
|
|
19810
|
-
const region = options.region;
|
|
19811
|
-
state.regionMetadata = region;
|
|
19812
|
-
if (region.dependencies.size > 0) {
|
|
19813
|
-
state.identifierOverrides = state.identifierOverrides ?? {};
|
|
19814
|
-
const dependencyGetter = options.dependencyGetter ?? null;
|
|
19815
|
-
if (!dependencyGetter) {
|
|
19816
|
-
return;
|
|
19817
|
-
}
|
|
19818
|
-
for (const dep of region.dependencies) {
|
|
19819
|
-
const key = normalizeDependencyKey(dep);
|
|
19820
|
-
state.identifierOverrides[key] = () => dependencyGetter(dep);
|
|
19821
|
-
const base = key.split(".")[0];
|
|
19822
|
-
if (base && !state.identifierOverrides[base]) {
|
|
19823
|
-
state.identifierOverrides[base] = () => dependencyGetter(base);
|
|
19824
|
-
}
|
|
19825
|
-
}
|
|
19826
|
-
}
|
|
19827
|
-
}
|
|
19828
|
-
function shouldMemoizeRegion(region) {
|
|
19829
|
-
if (region.dependencies.size > 0) {
|
|
19830
|
-
return true;
|
|
19831
|
-
}
|
|
19832
|
-
if (region.hasControlFlow) {
|
|
19833
|
-
return true;
|
|
19834
|
-
}
|
|
19835
|
-
if (region.hasReactiveWrites) {
|
|
19836
|
-
return true;
|
|
19837
|
-
}
|
|
19838
|
-
return false;
|
|
19839
|
-
}
|
|
19840
|
-
|
|
19841
19937
|
// src/ir/codegen.ts
|
|
19842
19938
|
var HOOK_SLOT_BASE = 1e3;
|
|
19843
19939
|
var HOOK_NAME_PREFIX = "use";
|
|
19940
|
+
var cloneLoc = (loc) => loc === void 0 ? void 0 : loc === null ? null : {
|
|
19941
|
+
start: { ...loc.start },
|
|
19942
|
+
end: { ...loc.end },
|
|
19943
|
+
filename: loc.filename,
|
|
19944
|
+
identifierName: loc.identifierName
|
|
19945
|
+
};
|
|
19946
|
+
function setNodeLoc(node, loc) {
|
|
19947
|
+
if (loc === void 0) return node;
|
|
19948
|
+
node.loc = cloneLoc(loc) ?? null;
|
|
19949
|
+
return node;
|
|
19950
|
+
}
|
|
19844
19951
|
function isHookName(name) {
|
|
19845
19952
|
return !!name && name.startsWith(HOOK_NAME_PREFIX);
|
|
19846
19953
|
}
|
|
@@ -19874,13 +19981,22 @@ function applyRegionToContext(ctx, region) {
|
|
|
19874
19981
|
return prevRegion;
|
|
19875
19982
|
}
|
|
19876
19983
|
function reserveHookSlot2(ctx) {
|
|
19984
|
+
if (ctx.dynamicHookSlotDepth && ctx.dynamicHookSlotDepth > 0) {
|
|
19985
|
+
return -1;
|
|
19986
|
+
}
|
|
19877
19987
|
const slot = ctx.nextHookSlot ?? HOOK_SLOT_BASE;
|
|
19878
19988
|
ctx.nextHookSlot = slot + 1;
|
|
19879
19989
|
return slot;
|
|
19880
19990
|
}
|
|
19881
19991
|
function expressionContainsJSX(expr) {
|
|
19992
|
+
if (Array.isArray(expr)) {
|
|
19993
|
+
return expr.some((item) => expressionContainsJSX(item));
|
|
19994
|
+
}
|
|
19882
19995
|
if (!expr || typeof expr !== "object") return false;
|
|
19883
19996
|
if (expr.kind === "JSXElement") return true;
|
|
19997
|
+
if (Array.isArray(expr.instructions)) {
|
|
19998
|
+
return expr.instructions.some((i) => expressionContainsJSX(i?.value ?? i));
|
|
19999
|
+
}
|
|
19884
20000
|
switch (expr.kind) {
|
|
19885
20001
|
case "CallExpression":
|
|
19886
20002
|
if (expressionContainsJSX(expr.callee)) return true;
|
|
@@ -19893,10 +20009,29 @@ function expressionContainsJSX(expr) {
|
|
|
19893
20009
|
return expressionContainsJSX(expr.test) || expressionContainsJSX(expr.consequent) || expressionContainsJSX(expr.alternate);
|
|
19894
20010
|
case "ArrowFunction":
|
|
19895
20011
|
return expressionContainsJSX(expr.body);
|
|
20012
|
+
case "FunctionExpression":
|
|
20013
|
+
if (Array.isArray(expr.body)) {
|
|
20014
|
+
return expr.body.some(
|
|
20015
|
+
(block) => block.instructions?.some((i) => expressionContainsJSX(i.value))
|
|
20016
|
+
);
|
|
20017
|
+
}
|
|
20018
|
+
return false;
|
|
19896
20019
|
default:
|
|
19897
20020
|
return false;
|
|
19898
20021
|
}
|
|
19899
20022
|
}
|
|
20023
|
+
function withNoMemoAndDynamicHooks(ctx, fn) {
|
|
20024
|
+
const prevNoMemo = ctx.noMemo;
|
|
20025
|
+
const prevDynamic = ctx.dynamicHookSlotDepth ?? 0;
|
|
20026
|
+
ctx.noMemo = true;
|
|
20027
|
+
ctx.dynamicHookSlotDepth = prevDynamic + 1;
|
|
20028
|
+
try {
|
|
20029
|
+
return fn();
|
|
20030
|
+
} finally {
|
|
20031
|
+
ctx.noMemo = prevNoMemo;
|
|
20032
|
+
ctx.dynamicHookSlotDepth = prevDynamic;
|
|
20033
|
+
}
|
|
20034
|
+
}
|
|
19900
20035
|
function functionContainsJSX(fn) {
|
|
19901
20036
|
for (const block of fn.blocks) {
|
|
19902
20037
|
for (const instr of block.instructions) {
|
|
@@ -20995,18 +21130,25 @@ function lowerTrackedExpression(expr, ctx) {
|
|
|
20995
21130
|
}
|
|
20996
21131
|
function lowerInstruction(instr, ctx) {
|
|
20997
21132
|
const { t: t2 } = ctx;
|
|
21133
|
+
const applyLoc = (stmt) => {
|
|
21134
|
+
if (!stmt) return stmt;
|
|
21135
|
+
const baseLoc = instr.loc ?? (instr.kind === "Assign" || instr.kind === "Expression" ? instr.value.loc : void 0);
|
|
21136
|
+
return setNodeLoc(stmt, baseLoc);
|
|
21137
|
+
};
|
|
20998
21138
|
if (instr.kind === "Assign") {
|
|
20999
21139
|
const baseName2 = deSSAVarName(instr.target.name);
|
|
21000
21140
|
const isFunctionDecl = instr.value.kind === "FunctionExpression" && (instr.declarationKind === "function" || !instr.declarationKind && instr.value.name === baseName2);
|
|
21001
21141
|
if (isFunctionDecl) {
|
|
21002
21142
|
const loweredFn = lowerExpression(instr.value, ctx);
|
|
21003
21143
|
if (t2.isFunctionExpression(loweredFn)) {
|
|
21004
|
-
return
|
|
21005
|
-
t2.
|
|
21006
|
-
|
|
21007
|
-
|
|
21008
|
-
|
|
21009
|
-
|
|
21144
|
+
return applyLoc(
|
|
21145
|
+
t2.functionDeclaration(
|
|
21146
|
+
t2.identifier(baseName2),
|
|
21147
|
+
loweredFn.params,
|
|
21148
|
+
loweredFn.body,
|
|
21149
|
+
loweredFn.generator ?? false,
|
|
21150
|
+
loweredFn.async ?? false
|
|
21151
|
+
)
|
|
21010
21152
|
);
|
|
21011
21153
|
}
|
|
21012
21154
|
}
|
|
@@ -21021,12 +21163,16 @@ function lowerInstruction(instr, ctx) {
|
|
|
21021
21163
|
ctx.memoVars?.add(baseName2);
|
|
21022
21164
|
}
|
|
21023
21165
|
if (declKind) {
|
|
21024
|
-
return
|
|
21025
|
-
t2.
|
|
21026
|
-
|
|
21166
|
+
return applyLoc(
|
|
21167
|
+
t2.variableDeclaration(declKind, [
|
|
21168
|
+
t2.variableDeclarator(t2.identifier(baseName2), hookMember.member)
|
|
21169
|
+
])
|
|
21170
|
+
);
|
|
21027
21171
|
}
|
|
21028
|
-
return
|
|
21029
|
-
t2.
|
|
21172
|
+
return applyLoc(
|
|
21173
|
+
t2.expressionStatement(
|
|
21174
|
+
t2.assignmentExpression("=", t2.identifier(baseName2), hookMember.member)
|
|
21175
|
+
)
|
|
21030
21176
|
);
|
|
21031
21177
|
}
|
|
21032
21178
|
if (instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && isHookName(instr.value.callee.name)) {
|
|
@@ -21040,16 +21186,24 @@ function lowerInstruction(instr, ctx) {
|
|
|
21040
21186
|
}
|
|
21041
21187
|
}
|
|
21042
21188
|
if (ctx.signalVars?.has(baseName2)) {
|
|
21043
|
-
return
|
|
21044
|
-
t2.
|
|
21189
|
+
return applyLoc(
|
|
21190
|
+
t2.expressionStatement(
|
|
21191
|
+
t2.callExpression(t2.identifier(baseName2), [lowerTrackedExpression(instr.value, ctx)])
|
|
21192
|
+
)
|
|
21045
21193
|
);
|
|
21046
21194
|
}
|
|
21047
|
-
return
|
|
21048
|
-
t2.
|
|
21195
|
+
return applyLoc(
|
|
21196
|
+
t2.expressionStatement(
|
|
21197
|
+
t2.assignmentExpression(
|
|
21198
|
+
"=",
|
|
21199
|
+
t2.identifier(baseName2),
|
|
21200
|
+
lowerTrackedExpression(instr.value, ctx)
|
|
21201
|
+
)
|
|
21202
|
+
)
|
|
21049
21203
|
);
|
|
21050
21204
|
}
|
|
21051
21205
|
if (instr.kind === "Expression") {
|
|
21052
|
-
return t2.expressionStatement(lowerTrackedExpression(instr.value, ctx));
|
|
21206
|
+
return applyLoc(t2.expressionStatement(lowerTrackedExpression(instr.value, ctx)));
|
|
21053
21207
|
}
|
|
21054
21208
|
if (instr.kind === "Phi") {
|
|
21055
21209
|
return null;
|
|
@@ -21058,6 +21212,9 @@ function lowerInstruction(instr, ctx) {
|
|
|
21058
21212
|
}
|
|
21059
21213
|
function lowerTerminator(block, ctx) {
|
|
21060
21214
|
const { t: t2 } = ctx;
|
|
21215
|
+
const baseLoc = block.terminator.loc ?? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21216
|
+
block.terminator.argument?.loc;
|
|
21217
|
+
const applyLoc = (stmts) => stmts.map((stmt) => setNodeLoc(stmt, baseLoc));
|
|
21061
21218
|
switch (block.terminator.kind) {
|
|
21062
21219
|
case "Return": {
|
|
21063
21220
|
const prevRegion = ctx.currentRegion;
|
|
@@ -21070,14 +21227,14 @@ function lowerTerminator(block, ctx) {
|
|
|
21070
21227
|
}
|
|
21071
21228
|
ctx.inReturn = false;
|
|
21072
21229
|
ctx.currentRegion = prevRegion;
|
|
21073
|
-
return [t2.returnStatement(retExpr)];
|
|
21230
|
+
return applyLoc([t2.returnStatement(retExpr)]);
|
|
21074
21231
|
}
|
|
21075
21232
|
case "Throw":
|
|
21076
|
-
return [t2.throwStatement(lowerTrackedExpression(block.terminator.argument, ctx))];
|
|
21233
|
+
return applyLoc([t2.throwStatement(lowerTrackedExpression(block.terminator.argument, ctx))]);
|
|
21077
21234
|
case "Jump":
|
|
21078
|
-
return [t2.expressionStatement(t2.stringLiteral(`jump ${block.terminator.target}`))];
|
|
21235
|
+
return applyLoc([t2.expressionStatement(t2.stringLiteral(`jump ${block.terminator.target}`))]);
|
|
21079
21236
|
case "Branch":
|
|
21080
|
-
return [
|
|
21237
|
+
return applyLoc([
|
|
21081
21238
|
t2.ifStatement(
|
|
21082
21239
|
lowerTrackedExpression(block.terminator.test, ctx),
|
|
21083
21240
|
t2.blockStatement([
|
|
@@ -21087,9 +21244,9 @@ function lowerTerminator(block, ctx) {
|
|
|
21087
21244
|
t2.expressionStatement(t2.stringLiteral(`goto ${block.terminator.alternate}`))
|
|
21088
21245
|
])
|
|
21089
21246
|
)
|
|
21090
|
-
];
|
|
21247
|
+
]);
|
|
21091
21248
|
case "Switch":
|
|
21092
|
-
return [
|
|
21249
|
+
return applyLoc([
|
|
21093
21250
|
t2.switchStatement(
|
|
21094
21251
|
lowerTrackedExpression(block.terminator.discriminant, ctx),
|
|
21095
21252
|
block.terminator.cases.map(
|
|
@@ -21098,30 +21255,30 @@ function lowerTerminator(block, ctx) {
|
|
|
21098
21255
|
])
|
|
21099
21256
|
)
|
|
21100
21257
|
)
|
|
21101
|
-
];
|
|
21258
|
+
]);
|
|
21102
21259
|
case "ForOf": {
|
|
21103
21260
|
const term = block.terminator;
|
|
21104
21261
|
const varKind = term.variableKind ?? "const";
|
|
21105
21262
|
const leftPattern = term.pattern ? term.pattern : t2.identifier(term.variable);
|
|
21106
|
-
return [
|
|
21263
|
+
return applyLoc([
|
|
21107
21264
|
t2.forOfStatement(
|
|
21108
21265
|
t2.variableDeclaration(varKind, [t2.variableDeclarator(leftPattern)]),
|
|
21109
21266
|
lowerExpression(term.iterable, ctx),
|
|
21110
21267
|
t2.blockStatement([t2.expressionStatement(t2.stringLiteral(`body ${term.body}`))])
|
|
21111
21268
|
)
|
|
21112
|
-
];
|
|
21269
|
+
]);
|
|
21113
21270
|
}
|
|
21114
21271
|
case "ForIn": {
|
|
21115
21272
|
const term = block.terminator;
|
|
21116
21273
|
const varKind = term.variableKind ?? "const";
|
|
21117
21274
|
const leftPattern = term.pattern ? term.pattern : t2.identifier(term.variable);
|
|
21118
|
-
return [
|
|
21275
|
+
return applyLoc([
|
|
21119
21276
|
t2.forInStatement(
|
|
21120
21277
|
t2.variableDeclaration(varKind, [t2.variableDeclarator(leftPattern)]),
|
|
21121
21278
|
lowerExpression(term.object, ctx),
|
|
21122
21279
|
t2.blockStatement([t2.expressionStatement(t2.stringLiteral(`body ${term.body}`))])
|
|
21123
21280
|
)
|
|
21124
|
-
];
|
|
21281
|
+
]);
|
|
21125
21282
|
}
|
|
21126
21283
|
case "Try": {
|
|
21127
21284
|
const term = block.terminator;
|
|
@@ -21137,20 +21294,20 @@ function lowerTerminator(block, ctx) {
|
|
|
21137
21294
|
const finallyBlock = term.finallyBlock !== void 0 ? t2.blockStatement([
|
|
21138
21295
|
t2.expressionStatement(t2.stringLiteral(`finally ${term.finallyBlock}`))
|
|
21139
21296
|
]) : null;
|
|
21140
|
-
return [t2.tryStatement(tryBlock, catchClause, finallyBlock)];
|
|
21297
|
+
return applyLoc([t2.tryStatement(tryBlock, catchClause, finallyBlock)]);
|
|
21141
21298
|
}
|
|
21142
21299
|
case "Unreachable":
|
|
21143
|
-
return [];
|
|
21300
|
+
return applyLoc([]);
|
|
21144
21301
|
case "Break":
|
|
21145
|
-
return [
|
|
21302
|
+
return applyLoc([
|
|
21146
21303
|
t2.breakStatement(block.terminator.label ? t2.identifier(block.terminator.label) : null)
|
|
21147
|
-
];
|
|
21304
|
+
]);
|
|
21148
21305
|
case "Continue":
|
|
21149
|
-
return [
|
|
21306
|
+
return applyLoc([
|
|
21150
21307
|
t2.continueStatement(block.terminator.label ? t2.identifier(block.terminator.label) : null)
|
|
21151
|
-
];
|
|
21308
|
+
]);
|
|
21152
21309
|
default:
|
|
21153
|
-
return [];
|
|
21310
|
+
return applyLoc([]);
|
|
21154
21311
|
}
|
|
21155
21312
|
}
|
|
21156
21313
|
function attachHelperImports(ctx, body, t2) {
|
|
@@ -21289,7 +21446,7 @@ function lowerExpression(expr, ctx, isAssigned = false) {
|
|
|
21289
21446
|
}
|
|
21290
21447
|
ctx.expressionDepth = depth;
|
|
21291
21448
|
try {
|
|
21292
|
-
return lowerExpressionImpl(expr, ctx, isAssigned);
|
|
21449
|
+
return setNodeLoc(lowerExpressionImpl(expr, ctx, isAssigned), expr.loc);
|
|
21293
21450
|
} finally {
|
|
21294
21451
|
ctx.expressionDepth = depth - 1;
|
|
21295
21452
|
}
|
|
@@ -21424,14 +21581,22 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
|
|
|
21424
21581
|
const calleeIsMemoAccessor = !!calleeName && ctx.memoVars?.has(calleeName);
|
|
21425
21582
|
const calleeIsSignalLike = !!calleeName && (ctx.signalVars?.has(calleeName) || ctx.storeVars?.has(calleeName));
|
|
21426
21583
|
if (calleeIsMemoAccessor && !calleeIsSignalLike && expr.arguments.length > 0) {
|
|
21427
|
-
const
|
|
21428
|
-
return t2.callExpression(t2.callExpression(t2.identifier(calleeName), []),
|
|
21584
|
+
const loweredArgs2 = expr.arguments.map((a) => lowerExpression(a, ctx));
|
|
21585
|
+
return t2.callExpression(t2.callExpression(t2.identifier(calleeName), []), loweredArgs2);
|
|
21429
21586
|
}
|
|
21430
21587
|
const lowerCallee = () => isIIFE ? withNonReactiveScope(ctx, () => lowerExpression(expr.callee, ctx)) : lowerExpression(expr.callee, ctx);
|
|
21431
|
-
|
|
21432
|
-
|
|
21433
|
-
|
|
21434
|
-
|
|
21588
|
+
const isIteratingMethod = expr.callee.kind === "MemberExpression" && (expr.callee.property.kind === "Identifier" && ["map", "reduce", "forEach", "filter", "flatMap", "some", "every", "find"].includes(
|
|
21589
|
+
expr.callee.property.name
|
|
21590
|
+
) || expr.callee.property.kind === "Literal" && ["map", "reduce", "forEach", "filter", "flatMap", "some", "every", "find"].includes(
|
|
21591
|
+
String(expr.callee.property.value)
|
|
21592
|
+
));
|
|
21593
|
+
const loweredArgs = expr.arguments.map((a, idx) => {
|
|
21594
|
+
if (idx === 0 && isIteratingMethod && (a.kind === "ArrowFunction" || a.kind === "FunctionExpression")) {
|
|
21595
|
+
return withNoMemoAndDynamicHooks(ctx, () => lowerExpression(a, ctx));
|
|
21596
|
+
}
|
|
21597
|
+
return lowerExpression(a, ctx);
|
|
21598
|
+
});
|
|
21599
|
+
return t2.callExpression(lowerCallee(), loweredArgs);
|
|
21435
21600
|
}
|
|
21436
21601
|
case "MemberExpression":
|
|
21437
21602
|
if (matchesListKeyPattern(expr, ctx)) {
|
|
@@ -21995,6 +22160,8 @@ function getDependencyPathFromNode(node, t2) {
|
|
|
21995
22160
|
if (node.computed) {
|
|
21996
22161
|
if (t2.isStringLiteral(property) || t2.isNumericLiteral(property)) {
|
|
21997
22162
|
propName = String(property.value);
|
|
22163
|
+
} else {
|
|
22164
|
+
return objectPath;
|
|
21998
22165
|
}
|
|
21999
22166
|
} else if (t2.isIdentifier(property)) {
|
|
22000
22167
|
propName = property.name;
|
|
@@ -22111,10 +22278,12 @@ function replaceIdentifiersWithOverrides(node, overrides, t2, parentKind, parent
|
|
|
22111
22278
|
return names;
|
|
22112
22279
|
};
|
|
22113
22280
|
if (!skipCurrentNode && (t2.isMemberExpression(node) || t2.isOptionalMemberExpression(node))) {
|
|
22281
|
+
const propertyNode = node.property;
|
|
22282
|
+
const isDynamicComputed = (node.computed ?? false) && !t2.isStringLiteral(propertyNode) && !t2.isNumericLiteral(propertyNode);
|
|
22114
22283
|
const path = getDependencyPathFromNode(node, t2);
|
|
22115
22284
|
const normalized = path ? normalizeDependencyKey2(path) : null;
|
|
22116
22285
|
const override = normalized && overrides[normalized] || (path ? overrides[path] : void 0);
|
|
22117
|
-
if (override && !isCallTarget) {
|
|
22286
|
+
if (override && !isCallTarget && !isDynamicComputed) {
|
|
22118
22287
|
const replacement = override();
|
|
22119
22288
|
Object.assign(node, replacement);
|
|
22120
22289
|
return;
|
|
@@ -22284,15 +22453,6 @@ function isStaticValue(expr) {
|
|
|
22284
22453
|
if (!expr) return false;
|
|
22285
22454
|
return expr.kind === "Literal";
|
|
22286
22455
|
}
|
|
22287
|
-
function isComponentLikeCallee(expr) {
|
|
22288
|
-
if (expr.kind === "Identifier") {
|
|
22289
|
-
return expr.name[0] === expr.name[0]?.toUpperCase();
|
|
22290
|
-
}
|
|
22291
|
-
if (expr.kind === "MemberExpression" || expr.kind === "OptionalMemberExpression") {
|
|
22292
|
-
return isComponentLikeCallee(expr.object);
|
|
22293
|
-
}
|
|
22294
|
-
return false;
|
|
22295
|
-
}
|
|
22296
22456
|
function isLikelyTextExpression(expr, ctx) {
|
|
22297
22457
|
let ok = true;
|
|
22298
22458
|
const isReactiveIdentifier = (name) => {
|
|
@@ -22321,15 +22481,9 @@ function isLikelyTextExpression(expr, ctx) {
|
|
|
22321
22481
|
ok = false;
|
|
22322
22482
|
return;
|
|
22323
22483
|
case "CallExpression":
|
|
22324
|
-
case "OptionalCallExpression":
|
|
22325
|
-
|
|
22326
|
-
ok = false;
|
|
22327
|
-
return;
|
|
22328
|
-
}
|
|
22329
|
-
visit(node.callee, true);
|
|
22330
|
-
node.arguments.forEach((arg) => visit(arg));
|
|
22484
|
+
case "OptionalCallExpression":
|
|
22485
|
+
ok = false;
|
|
22331
22486
|
return;
|
|
22332
|
-
}
|
|
22333
22487
|
case "MemberExpression":
|
|
22334
22488
|
case "OptionalMemberExpression":
|
|
22335
22489
|
visit(node.object, true);
|
|
@@ -22784,7 +22938,12 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
22784
22938
|
t2.arrowFunctionExpression([], body)
|
|
22785
22939
|
];
|
|
22786
22940
|
if (ctx.isComponentFn) {
|
|
22787
|
-
|
|
22941
|
+
{
|
|
22942
|
+
const slot = reserveHookSlot2(ctx);
|
|
22943
|
+
if (slot >= 0) {
|
|
22944
|
+
memoArgs.push(t2.numericLiteral(slot));
|
|
22945
|
+
}
|
|
22946
|
+
}
|
|
22788
22947
|
}
|
|
22789
22948
|
return t2.callExpression(t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), memoArgs), []);
|
|
22790
22949
|
}
|
|
@@ -23339,12 +23498,16 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
|
|
|
23339
23498
|
const hoistedStatements = ctx.hoistedTemplateStatements;
|
|
23340
23499
|
ctx.hoistedTemplates = prevHoistedTemplates;
|
|
23341
23500
|
ctx.hoistedTemplateStatements = prevHoistedTemplateStatements;
|
|
23342
|
-
if (
|
|
23343
|
-
const firstParam = callbackExpr.params
|
|
23501
|
+
if (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr)) {
|
|
23502
|
+
const [firstParam, secondParam] = callbackExpr.params;
|
|
23503
|
+
const overrides = {};
|
|
23344
23504
|
if (t2.isIdentifier(firstParam)) {
|
|
23345
|
-
|
|
23346
|
-
|
|
23347
|
-
|
|
23505
|
+
overrides[firstParam.name] = () => t2.callExpression(t2.identifier(firstParam.name), []);
|
|
23506
|
+
}
|
|
23507
|
+
if (t2.isIdentifier(secondParam)) {
|
|
23508
|
+
overrides[secondParam.name] = () => t2.callExpression(t2.identifier(secondParam.name), []);
|
|
23509
|
+
}
|
|
23510
|
+
if (Object.keys(overrides).length > 0) {
|
|
23348
23511
|
if (t2.isBlockStatement(callbackExpr.body)) {
|
|
23349
23512
|
replaceIdentifiersWithOverrides(callbackExpr.body, overrides, t2, callbackExpr.type, "body");
|
|
23350
23513
|
} else {
|
|
@@ -23591,8 +23754,11 @@ function lowerHIRWithRegions(program, t2, options) {
|
|
|
23591
23754
|
for (const stmt of originalBody) {
|
|
23592
23755
|
if (t2.isVariableDeclaration(stmt)) {
|
|
23593
23756
|
for (const decl of stmt.declarations) {
|
|
23594
|
-
if (t2.isIdentifier(decl.id) && decl.init && t2.isCallExpression(decl.init) && t2.isIdentifier(decl.init.callee) && decl.init.callee.name === "$state") {
|
|
23757
|
+
if (t2.isIdentifier(decl.id) && decl.init && t2.isCallExpression(decl.init) && t2.isIdentifier(decl.init.callee) && (decl.init.callee.name === "$state" || decl.init.callee.name === "$store")) {
|
|
23595
23758
|
ctx.trackedVars.add(decl.id.name);
|
|
23759
|
+
if (decl.init.callee.name === "$store") {
|
|
23760
|
+
ctx.storeVars?.add(decl.id.name);
|
|
23761
|
+
}
|
|
23596
23762
|
}
|
|
23597
23763
|
}
|
|
23598
23764
|
}
|
|
@@ -24235,10 +24401,9 @@ function lowerFunctionWithRegions(fn, ctx) {
|
|
|
24235
24401
|
}
|
|
24236
24402
|
}
|
|
24237
24403
|
const params = finalParams;
|
|
24238
|
-
const funcDecl =
|
|
24239
|
-
t2.identifier(fn.name ?? "fn"),
|
|
24240
|
-
|
|
24241
|
-
t2.blockStatement(statements)
|
|
24404
|
+
const funcDecl = setNodeLoc(
|
|
24405
|
+
t2.functionDeclaration(t2.identifier(fn.name ?? "fn"), params, t2.blockStatement(statements)),
|
|
24406
|
+
fn.loc
|
|
24242
24407
|
);
|
|
24243
24408
|
ctx.needsCtx = prevNeedsCtx;
|
|
24244
24409
|
ctx.shadowedNames = prevShadowed;
|
|
@@ -24327,10 +24492,44 @@ function isInsideNestedFunction(path) {
|
|
|
24327
24492
|
function isInsideJSX(path) {
|
|
24328
24493
|
return !!path.findParent((p) => p.isJSXElement?.() || p.isJSXFragment?.());
|
|
24329
24494
|
}
|
|
24330
|
-
function
|
|
24331
|
-
if (!
|
|
24495
|
+
function parseSuppressionCodes(raw) {
|
|
24496
|
+
if (!raw) return void 0;
|
|
24497
|
+
const codes = raw.split(/[,\s]+/).map((c) => c.trim()).filter(Boolean);
|
|
24498
|
+
return codes.length > 0 ? new Set(codes) : void 0;
|
|
24499
|
+
}
|
|
24500
|
+
function parseSuppressions(comments) {
|
|
24501
|
+
if (!comments) return [];
|
|
24502
|
+
const suppressions = [];
|
|
24503
|
+
for (const comment of comments) {
|
|
24504
|
+
const match = comment.value.match(/fict-ignore(-next-line)?(?:\s+(.+))?/i);
|
|
24505
|
+
if (!match || !comment.loc) continue;
|
|
24506
|
+
suppressions.push({
|
|
24507
|
+
line: comment.loc.start.line,
|
|
24508
|
+
nextLine: !!match[1],
|
|
24509
|
+
codes: parseSuppressionCodes(match[2])
|
|
24510
|
+
});
|
|
24511
|
+
}
|
|
24512
|
+
return suppressions;
|
|
24513
|
+
}
|
|
24514
|
+
function shouldSuppressWarning(suppressions, code, line) {
|
|
24515
|
+
return suppressions.some((entry) => {
|
|
24516
|
+
const targetLine = entry.nextLine ? entry.line + 1 : entry.line;
|
|
24517
|
+
if (targetLine !== line) return false;
|
|
24518
|
+
if (!entry.codes || entry.codes.size === 0) return true;
|
|
24519
|
+
return entry.codes.has(code);
|
|
24520
|
+
});
|
|
24521
|
+
}
|
|
24522
|
+
function createWarningDispatcher(onWarn, suppressions) {
|
|
24523
|
+
if (!onWarn) return () => {
|
|
24524
|
+
};
|
|
24525
|
+
return (warning) => {
|
|
24526
|
+
if (shouldSuppressWarning(suppressions, warning.code, warning.line)) return;
|
|
24527
|
+
onWarn(warning);
|
|
24528
|
+
};
|
|
24529
|
+
}
|
|
24530
|
+
function emitWarning(node, code, message, warn, fileName) {
|
|
24332
24531
|
const loc = node.loc?.start;
|
|
24333
|
-
|
|
24532
|
+
warn({
|
|
24334
24533
|
code,
|
|
24335
24534
|
message,
|
|
24336
24535
|
fileName,
|
|
@@ -24418,8 +24617,7 @@ function isDynamicPropertyAccess(node, t2) {
|
|
|
24418
24617
|
if (!node.computed) return false;
|
|
24419
24618
|
return !(t2.isStringLiteral(node.property) || t2.isNumericLiteral(node.property));
|
|
24420
24619
|
}
|
|
24421
|
-
function runWarningPass(programPath, stateVars, derivedVars,
|
|
24422
|
-
const fileName = programPath.hub?.file?.opts?.filename || "<unknown>";
|
|
24620
|
+
function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t2) {
|
|
24423
24621
|
const isStateRoot = (expr) => {
|
|
24424
24622
|
const root = getRootIdentifier(expr, t2);
|
|
24425
24623
|
return !!(root && stateVars.has(root.name));
|
|
@@ -24435,7 +24633,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24435
24633
|
path.node,
|
|
24436
24634
|
"FICT-M",
|
|
24437
24635
|
"Direct mutation of nested property detected; use immutable update or $store helpers",
|
|
24438
|
-
|
|
24636
|
+
warn,
|
|
24439
24637
|
fileName
|
|
24440
24638
|
);
|
|
24441
24639
|
if (isDynamicPropertyAccess(left, t2)) {
|
|
@@ -24443,7 +24641,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24443
24641
|
path.node,
|
|
24444
24642
|
"FICT-H",
|
|
24445
24643
|
"Dynamic property access widens dependency tracking",
|
|
24446
|
-
|
|
24644
|
+
warn,
|
|
24447
24645
|
fileName
|
|
24448
24646
|
);
|
|
24449
24647
|
}
|
|
@@ -24458,7 +24656,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24458
24656
|
path.node,
|
|
24459
24657
|
"FICT-M",
|
|
24460
24658
|
"Direct mutation of nested property detected; use immutable update or $store helpers",
|
|
24461
|
-
|
|
24659
|
+
warn,
|
|
24462
24660
|
fileName
|
|
24463
24661
|
);
|
|
24464
24662
|
if (isDynamicPropertyAccess(arg, t2)) {
|
|
@@ -24466,7 +24664,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24466
24664
|
path.node,
|
|
24467
24665
|
"FICT-H",
|
|
24468
24666
|
"Dynamic property access widens dependency tracking",
|
|
24469
|
-
|
|
24667
|
+
warn,
|
|
24470
24668
|
fileName
|
|
24471
24669
|
);
|
|
24472
24670
|
}
|
|
@@ -24482,7 +24680,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24482
24680
|
path.node,
|
|
24483
24681
|
"FICT-H",
|
|
24484
24682
|
"Dynamic property access widens dependency tracking",
|
|
24485
|
-
|
|
24683
|
+
warn,
|
|
24486
24684
|
fileName
|
|
24487
24685
|
);
|
|
24488
24686
|
}
|
|
@@ -24511,7 +24709,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24511
24709
|
path.node,
|
|
24512
24710
|
"FICT-R005",
|
|
24513
24711
|
`Function captures reactive variable(s): ${Array.from(captured).join(", ")}. Pass them as parameters or memoize explicitly to avoid hidden dependencies.`,
|
|
24514
|
-
|
|
24712
|
+
warn,
|
|
24515
24713
|
fileName
|
|
24516
24714
|
);
|
|
24517
24715
|
}
|
|
@@ -24542,7 +24740,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24542
24740
|
path.node,
|
|
24543
24741
|
"FICT-E001",
|
|
24544
24742
|
"Effect has no reactive reads; it will run once. Consider removing $effect or adding dependencies.",
|
|
24545
|
-
|
|
24743
|
+
warn,
|
|
24546
24744
|
fileName
|
|
24547
24745
|
);
|
|
24548
24746
|
}
|
|
@@ -24568,7 +24766,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24568
24766
|
arg,
|
|
24569
24767
|
"FICT-H",
|
|
24570
24768
|
"State value passed to unknown function (black box); dependency tracking may be imprecise",
|
|
24571
|
-
|
|
24769
|
+
warn,
|
|
24572
24770
|
fileName
|
|
24573
24771
|
);
|
|
24574
24772
|
break;
|
|
@@ -24584,7 +24782,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24584
24782
|
path.node,
|
|
24585
24783
|
"FICT-H",
|
|
24586
24784
|
"Dynamic property access widens dependency tracking",
|
|
24587
|
-
|
|
24785
|
+
warn,
|
|
24588
24786
|
fileName
|
|
24589
24787
|
);
|
|
24590
24788
|
}
|
|
@@ -24634,19 +24832,97 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24634
24832
|
Program: {
|
|
24635
24833
|
exit(path) {
|
|
24636
24834
|
const fileName = path.hub?.file?.opts?.filename || "<unknown>";
|
|
24835
|
+
const comments = path.hub?.file?.ast?.comments || [];
|
|
24836
|
+
const suppressions = parseSuppressions(comments);
|
|
24837
|
+
const warn = createWarningDispatcher(options.onWarn, suppressions);
|
|
24838
|
+
const optionsWithWarnings = { ...options, onWarn: warn };
|
|
24839
|
+
const isHookName2 = (name) => !!name && /^use[A-Z]/.test(name);
|
|
24840
|
+
const getFunctionName = (fnPath) => {
|
|
24841
|
+
return fnPath.isFunctionDeclaration() && fnPath.node.id ? fnPath.node.id.name : fnPath.isFunctionExpression() && fnPath.node.id ? fnPath.node.id.name : fnPath.parentPath.isVariableDeclarator() && t2.isIdentifier(fnPath.parentPath.node.id) && fnPath.parentPath.node.init === fnPath.node ? fnPath.parentPath.node.id.name : void 0;
|
|
24842
|
+
};
|
|
24843
|
+
const isComponentDefinition = (fnPath) => {
|
|
24844
|
+
const name = getFunctionName(fnPath);
|
|
24845
|
+
return name && isComponentName(name) || functionHasJSX(fnPath);
|
|
24846
|
+
};
|
|
24847
|
+
const isHookDefinition = (fnPath) => {
|
|
24848
|
+
const name = getFunctionName(fnPath);
|
|
24849
|
+
return isHookName2(name);
|
|
24850
|
+
};
|
|
24851
|
+
const isComponentOrHookDefinition = (fnPath) => isComponentDefinition(fnPath) || isHookDefinition(fnPath);
|
|
24637
24852
|
const isComponentLike = (fnPath) => {
|
|
24638
|
-
const name =
|
|
24639
|
-
return name && isComponentName(name) || functionHasJSX(fnPath) || functionUsesStateLike(fnPath, t2);
|
|
24853
|
+
const name = getFunctionName(fnPath);
|
|
24854
|
+
return name && isComponentName(name) || isHookName2(name) || functionHasJSX(fnPath) || functionUsesStateLike(fnPath, t2);
|
|
24640
24855
|
};
|
|
24641
24856
|
const memoHasSideEffects = (fn) => {
|
|
24857
|
+
const pureCalls = new Set(
|
|
24858
|
+
Array.from(SAFE_FUNCTIONS).filter(
|
|
24859
|
+
(name) => !name.startsWith("console.") && name !== "Math.random"
|
|
24860
|
+
)
|
|
24861
|
+
);
|
|
24862
|
+
const effectfulCalls = /* @__PURE__ */ new Set([
|
|
24863
|
+
"$effect",
|
|
24864
|
+
"render",
|
|
24865
|
+
"fetch",
|
|
24866
|
+
"setTimeout",
|
|
24867
|
+
"setInterval",
|
|
24868
|
+
"clearTimeout",
|
|
24869
|
+
"clearInterval",
|
|
24870
|
+
"requestAnimationFrame",
|
|
24871
|
+
"cancelAnimationFrame"
|
|
24872
|
+
]);
|
|
24873
|
+
const getCalleeName = (callee) => {
|
|
24874
|
+
if (t2.isIdentifier(callee)) return callee.name;
|
|
24875
|
+
if (t2.isMemberExpression(callee) && !callee.computed && t2.isIdentifier(callee.property) && t2.isIdentifier(callee.object)) {
|
|
24876
|
+
return `${callee.object.name}.${callee.property.name}`;
|
|
24877
|
+
}
|
|
24878
|
+
return null;
|
|
24879
|
+
};
|
|
24880
|
+
const mutatingMemberProps = /* @__PURE__ */ new Set([
|
|
24881
|
+
"push",
|
|
24882
|
+
"pop",
|
|
24883
|
+
"splice",
|
|
24884
|
+
"shift",
|
|
24885
|
+
"unshift",
|
|
24886
|
+
"sort",
|
|
24887
|
+
"reverse",
|
|
24888
|
+
"set",
|
|
24889
|
+
"add",
|
|
24890
|
+
"delete",
|
|
24891
|
+
"append",
|
|
24892
|
+
"appendChild",
|
|
24893
|
+
"remove",
|
|
24894
|
+
"removeChild",
|
|
24895
|
+
"setAttribute",
|
|
24896
|
+
"dispatchEvent",
|
|
24897
|
+
"replaceChildren",
|
|
24898
|
+
"replaceWith"
|
|
24899
|
+
]);
|
|
24900
|
+
const isEffectfulCall = (node) => {
|
|
24901
|
+
const name = getCalleeName(node.callee);
|
|
24902
|
+
if (!name) return true;
|
|
24903
|
+
if (pureCalls.has(name)) return false;
|
|
24904
|
+
if (effectfulCalls.has(name)) return true;
|
|
24905
|
+
if (name.startsWith("console.") || name.startsWith("document.") || name.startsWith("window.")) {
|
|
24906
|
+
return true;
|
|
24907
|
+
}
|
|
24908
|
+
if (t2.isMemberExpression(node.callee) && !node.callee.computed && t2.isIdentifier(node.callee.property)) {
|
|
24909
|
+
const prop = node.callee.property.name;
|
|
24910
|
+
if (mutatingMemberProps.has(prop)) return true;
|
|
24911
|
+
if (t2.isIdentifier(node.callee.object) && (node.callee.object.name === "document" || node.callee.object.name === "window")) {
|
|
24912
|
+
return true;
|
|
24913
|
+
}
|
|
24914
|
+
}
|
|
24915
|
+
return false;
|
|
24916
|
+
};
|
|
24642
24917
|
const checkNode = (node) => {
|
|
24643
24918
|
if (!node) return false;
|
|
24644
24919
|
if (t2.isAssignmentExpression(node) || t2.isUpdateExpression(node) || t2.isThrowStatement(node) || t2.isNewExpression(node)) {
|
|
24645
24920
|
return true;
|
|
24646
24921
|
}
|
|
24647
|
-
if (t2.isCallExpression(node) && (
|
|
24922
|
+
if (t2.isCallExpression(node) && isEffectfulCall(node)) {
|
|
24648
24923
|
return true;
|
|
24649
24924
|
}
|
|
24925
|
+
if (t2.isAwaitExpression(node)) return true;
|
|
24650
24926
|
if (t2.isExpressionStatement(node)) return checkNode(node.expression);
|
|
24651
24927
|
if (t2.isBlockStatement(node)) return node.body.some((stmt) => checkNode(stmt));
|
|
24652
24928
|
if (t2.isReturnStatement(node)) return checkNode(node.argument);
|
|
@@ -24670,7 +24946,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24670
24946
|
fnPath.node,
|
|
24671
24947
|
"FICT-C004",
|
|
24672
24948
|
"Component has no return statement and will render nothing.",
|
|
24673
|
-
|
|
24949
|
+
warn,
|
|
24674
24950
|
fileName
|
|
24675
24951
|
);
|
|
24676
24952
|
},
|
|
@@ -24688,7 +24964,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24688
24964
|
init,
|
|
24689
24965
|
"FICT-C004",
|
|
24690
24966
|
"Component has no return statement and will render nothing.",
|
|
24691
|
-
|
|
24967
|
+
warn,
|
|
24692
24968
|
fileName
|
|
24693
24969
|
);
|
|
24694
24970
|
}
|
|
@@ -24738,7 +25014,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24738
25014
|
}
|
|
24739
25015
|
}
|
|
24740
25016
|
if (hasKey || hasUnknownSpread) return;
|
|
24741
|
-
|
|
25017
|
+
warn({
|
|
24742
25018
|
code: "FICT-J002",
|
|
24743
25019
|
message: "Missing key prop in list rendering.",
|
|
24744
25020
|
fileName,
|
|
@@ -24763,6 +25039,12 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24763
25039
|
"Destructuring $state is not supported. Use a simple identifier."
|
|
24764
25040
|
);
|
|
24765
25041
|
}
|
|
25042
|
+
const ownerComponent = varPath.getFunctionParent();
|
|
25043
|
+
if (!ownerComponent || !isComponentOrHookDefinition(ownerComponent)) {
|
|
25044
|
+
throw varPath.buildCodeFrameError(
|
|
25045
|
+
"$state() must be declared inside a component or hook function body"
|
|
25046
|
+
);
|
|
25047
|
+
}
|
|
24766
25048
|
stateVars.add(varPath.node.id.name);
|
|
24767
25049
|
if (isInsideLoop(varPath) || isInsideConditional(varPath)) {
|
|
24768
25050
|
throw varPath.buildCodeFrameError(
|
|
@@ -24803,12 +25085,18 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24803
25085
|
fnPath.node,
|
|
24804
25086
|
"FICT-C003",
|
|
24805
25087
|
"Components should not be defined inside other components. Move this definition to module scope to preserve identity and performance.",
|
|
24806
|
-
|
|
25088
|
+
warn,
|
|
24807
25089
|
fileName
|
|
24808
25090
|
);
|
|
24809
25091
|
},
|
|
24810
25092
|
CallExpression(callPath) {
|
|
24811
25093
|
if (isStateCall(callPath.node, t2)) {
|
|
25094
|
+
const ownerComponent = callPath.getFunctionParent();
|
|
25095
|
+
if (!ownerComponent || !isComponentOrHookDefinition(ownerComponent)) {
|
|
25096
|
+
throw callPath.buildCodeFrameError(
|
|
25097
|
+
"$state() must be declared inside a component or hook function body"
|
|
25098
|
+
);
|
|
25099
|
+
}
|
|
24812
25100
|
if (isInsideLoop(callPath) || isInsideConditional(callPath)) {
|
|
24813
25101
|
throw callPath.buildCodeFrameError(
|
|
24814
25102
|
"$state() cannot be declared inside loops or conditionals"
|
|
@@ -24842,10 +25130,31 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24842
25130
|
callPath.node,
|
|
24843
25131
|
"FICT-R004",
|
|
24844
25132
|
"Reactive creation inside non-JSX control flow will not auto-dispose; wrap it in createScope/runInScope or move it into JSX-managed regions.",
|
|
24845
|
-
|
|
25133
|
+
warn,
|
|
24846
25134
|
fileName
|
|
24847
25135
|
);
|
|
24848
25136
|
}
|
|
25137
|
+
if (calleeId && isHookName2(calleeId)) {
|
|
25138
|
+
const binding = callPath.scope.getBinding(calleeId);
|
|
25139
|
+
const bindingPath = binding?.path;
|
|
25140
|
+
const bindingIsHook = !bindingPath && isHookName2(calleeId) || bindingPath?.isImportSpecifier() || bindingPath?.isImportDefaultSpecifier() || bindingPath?.isFunctionDeclaration() && isHookDefinition(bindingPath) || bindingPath?.isVariableDeclarator() && (() => {
|
|
25141
|
+
const init = bindingPath.get?.("init");
|
|
25142
|
+
return init ? isHookDefinition(init) : false;
|
|
25143
|
+
})();
|
|
25144
|
+
if (bindingIsHook) {
|
|
25145
|
+
const ownerFunction = callPath.getFunctionParent();
|
|
25146
|
+
if (!ownerFunction || !isComponentOrHookDefinition(ownerFunction)) {
|
|
25147
|
+
throw callPath.buildCodeFrameError(
|
|
25148
|
+
`${calleeId}() must be called inside a component or hook (useX)`
|
|
25149
|
+
);
|
|
25150
|
+
}
|
|
25151
|
+
if (isInsideLoop(callPath) || isInsideConditional(callPath) || isInsideNestedFunction(callPath)) {
|
|
25152
|
+
throw callPath.buildCodeFrameError(
|
|
25153
|
+
`${calleeId}() must be called at the top level of a component or hook (no loops/conditions/nested functions)`
|
|
25154
|
+
);
|
|
25155
|
+
}
|
|
25156
|
+
}
|
|
25157
|
+
}
|
|
24849
25158
|
const allowedStateCallees = /* @__PURE__ */ new Set([
|
|
24850
25159
|
"$effect",
|
|
24851
25160
|
"$memo",
|
|
@@ -24856,7 +25165,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24856
25165
|
callPath.node.arguments.forEach((arg) => {
|
|
24857
25166
|
if (t2.isIdentifier(arg) && stateVars.has(arg.name) && (!calleeId || !allowedStateCallees.has(calleeId))) {
|
|
24858
25167
|
const loc = arg.loc?.start ?? callPath.node.loc?.start;
|
|
24859
|
-
|
|
25168
|
+
warn({
|
|
24860
25169
|
code: "FICT-S002",
|
|
24861
25170
|
message: "State variable is passed as an argument; this passes a value snapshot and may escape component scope.",
|
|
24862
25171
|
fileName,
|
|
@@ -24869,7 +25178,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24869
25178
|
const firstArg = callPath.node.arguments[0];
|
|
24870
25179
|
if (firstArg && (t2.isArrowFunctionExpression(firstArg) || t2.isFunctionExpression(firstArg)) && memoHasSideEffects(firstArg)) {
|
|
24871
25180
|
const loc = firstArg.loc?.start ?? callPath.node.loc?.start;
|
|
24872
|
-
|
|
25181
|
+
warn({
|
|
24873
25182
|
code: "FICT-M003",
|
|
24874
25183
|
message: "Memo should not contain side effects.",
|
|
24875
25184
|
fileName,
|
|
@@ -24880,6 +25189,68 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24880
25189
|
}
|
|
24881
25190
|
}
|
|
24882
25191
|
});
|
|
25192
|
+
const aliasStack = [/* @__PURE__ */ new Set()];
|
|
25193
|
+
const currentAliasSet = () => aliasStack[aliasStack.length - 1];
|
|
25194
|
+
const rhsUsesState = (exprPath) => {
|
|
25195
|
+
if (!exprPath) return false;
|
|
25196
|
+
if (exprPath.isIdentifier() && t2.isIdentifier(exprPath.node) && stateVars.has(exprPath.node.name)) {
|
|
25197
|
+
return true;
|
|
25198
|
+
}
|
|
25199
|
+
let usesState = false;
|
|
25200
|
+
exprPath.traverse({
|
|
25201
|
+
Identifier(idPath) {
|
|
25202
|
+
if (stateVars.has(idPath.node.name)) {
|
|
25203
|
+
usesState = true;
|
|
25204
|
+
idPath.stop();
|
|
25205
|
+
}
|
|
25206
|
+
}
|
|
25207
|
+
});
|
|
25208
|
+
return usesState;
|
|
25209
|
+
};
|
|
25210
|
+
if (process.env.FICT_DEBUG_ALIAS) {
|
|
25211
|
+
console.log("[fict] alias check state vars", Array.from(stateVars));
|
|
25212
|
+
}
|
|
25213
|
+
path.traverse({
|
|
25214
|
+
Function: {
|
|
25215
|
+
enter() {
|
|
25216
|
+
aliasStack.push(/* @__PURE__ */ new Set());
|
|
25217
|
+
},
|
|
25218
|
+
exit() {
|
|
25219
|
+
aliasStack.pop();
|
|
25220
|
+
}
|
|
25221
|
+
},
|
|
25222
|
+
VariableDeclarator(varPath) {
|
|
25223
|
+
const aliasSet = currentAliasSet();
|
|
25224
|
+
if (aliasSet && t2.isIdentifier(varPath.node.id) && rhsUsesState(varPath.get("init"))) {
|
|
25225
|
+
if (process.env.FICT_DEBUG_ALIAS) {
|
|
25226
|
+
console.log("[fict] alias add from decl", varPath.node.id.name);
|
|
25227
|
+
}
|
|
25228
|
+
aliasSet.add(varPath.node.id.name);
|
|
25229
|
+
}
|
|
25230
|
+
},
|
|
25231
|
+
AssignmentExpression(assignPath) {
|
|
25232
|
+
const aliasSet = currentAliasSet();
|
|
25233
|
+
if (!aliasSet) return;
|
|
25234
|
+
if (!t2.isIdentifier(assignPath.node.left)) return;
|
|
25235
|
+
const targetName = assignPath.node.left.name;
|
|
25236
|
+
const rightPath = assignPath.get("right");
|
|
25237
|
+
if (rhsUsesState(rightPath)) {
|
|
25238
|
+
if (process.env.FICT_DEBUG_ALIAS) {
|
|
25239
|
+
console.log("[fict] alias add from assign", targetName);
|
|
25240
|
+
}
|
|
25241
|
+
aliasSet.add(targetName);
|
|
25242
|
+
return;
|
|
25243
|
+
}
|
|
25244
|
+
if (aliasSet.has(targetName)) {
|
|
25245
|
+
if (process.env.FICT_DEBUG_ALIAS) {
|
|
25246
|
+
console.log("[fict] alias reassignment detected", targetName);
|
|
25247
|
+
}
|
|
25248
|
+
throw assignPath.buildCodeFrameError(
|
|
25249
|
+
`Alias reassignment is not supported for "${targetName}"`
|
|
25250
|
+
);
|
|
25251
|
+
}
|
|
25252
|
+
}
|
|
25253
|
+
});
|
|
24883
25254
|
if (derivedVars.size > 0) {
|
|
24884
25255
|
path.traverse({
|
|
24885
25256
|
AssignmentExpression(assignPath) {
|
|
@@ -24912,13 +25283,15 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24912
25283
|
}
|
|
24913
25284
|
});
|
|
24914
25285
|
}
|
|
24915
|
-
runWarningPass(path, stateVars, derivedVars,
|
|
25286
|
+
runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
|
|
24916
25287
|
const fileAst = t2.file(path.node);
|
|
24917
25288
|
const hir = buildHIR(fileAst);
|
|
24918
|
-
const lowered = lowerHIRWithRegions(hir, t2,
|
|
25289
|
+
const lowered = lowerHIRWithRegions(hir, t2, optionsWithWarnings);
|
|
24919
25290
|
path.node.body = lowered.program.body;
|
|
24920
25291
|
path.node.directives = lowered.program.directives;
|
|
24921
|
-
|
|
25292
|
+
if (!process.env.FICT_SKIP_SCOPE_CRAWL) {
|
|
25293
|
+
path.scope.crawl();
|
|
25294
|
+
}
|
|
24922
25295
|
stripMacroImports(path, t2);
|
|
24923
25296
|
}
|
|
24924
25297
|
}
|