@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.js
CHANGED
|
@@ -14372,6 +14372,9 @@ function pathToString(path) {
|
|
|
14372
14372
|
|
|
14373
14373
|
// src/ir/build-hir.ts
|
|
14374
14374
|
var destructuringTempCounter = 0;
|
|
14375
|
+
var getLoc = (node) => {
|
|
14376
|
+
return node?.loc ?? null;
|
|
14377
|
+
};
|
|
14375
14378
|
function normalizeVarKind(kind) {
|
|
14376
14379
|
return kind === "const" || kind === "let" || kind === "var" ? kind : "let";
|
|
14377
14380
|
}
|
|
@@ -14441,7 +14444,8 @@ function buildHIR(ast) {
|
|
|
14441
14444
|
functions.push(
|
|
14442
14445
|
convertFunction(name, stmt.params, stmt.body.body, {
|
|
14443
14446
|
noMemo: programNoMemo,
|
|
14444
|
-
directives: stmt.body.directives
|
|
14447
|
+
directives: stmt.body.directives,
|
|
14448
|
+
loc: getLoc(stmt)
|
|
14445
14449
|
})
|
|
14446
14450
|
);
|
|
14447
14451
|
continue;
|
|
@@ -14454,7 +14458,8 @@ function buildHIR(ast) {
|
|
|
14454
14458
|
functions.push(
|
|
14455
14459
|
convertFunction(name, decl.params, decl.body.body, {
|
|
14456
14460
|
noMemo: programNoMemo,
|
|
14457
|
-
directives: decl.body.directives
|
|
14461
|
+
directives: decl.body.directives,
|
|
14462
|
+
loc: getLoc(decl)
|
|
14458
14463
|
})
|
|
14459
14464
|
);
|
|
14460
14465
|
postamble.push({ kind: "ExportFunction", name });
|
|
@@ -14472,9 +14477,11 @@ function buildHIR(ast) {
|
|
|
14472
14477
|
const hasExpressionBody = isArrow && !t.isBlockStatement(body);
|
|
14473
14478
|
const fnHIR = t.isBlockStatement(body) ? convertFunction(name, params, body.body, {
|
|
14474
14479
|
noMemo: programNoMemo,
|
|
14475
|
-
directives: body.directives
|
|
14480
|
+
directives: body.directives,
|
|
14481
|
+
loc: getLoc(v.init ?? v)
|
|
14476
14482
|
}) : convertFunction(name, params, [t.returnStatement(body)], {
|
|
14477
|
-
noMemo: programNoMemo
|
|
14483
|
+
noMemo: programNoMemo,
|
|
14484
|
+
loc: getLoc(v.init ?? v)
|
|
14478
14485
|
});
|
|
14479
14486
|
fnHIR.meta = { ...fnHIR.meta ?? {}, fromExpression: true, isArrow, hasExpressionBody };
|
|
14480
14487
|
functions.push(fnHIR);
|
|
@@ -14499,7 +14506,8 @@ function buildHIR(ast) {
|
|
|
14499
14506
|
functions.push(
|
|
14500
14507
|
convertFunction(name, decl.params, decl.body.body, {
|
|
14501
14508
|
noMemo: programNoMemo,
|
|
14502
|
-
directives: decl.body.directives
|
|
14509
|
+
directives: decl.body.directives,
|
|
14510
|
+
loc: getLoc(decl)
|
|
14503
14511
|
})
|
|
14504
14512
|
);
|
|
14505
14513
|
postamble.push({ kind: "ExportDefault", name });
|
|
@@ -14524,13 +14532,15 @@ function buildHIR(ast) {
|
|
|
14524
14532
|
const hasExpressionBody = isArrow && !t.isBlockStatement(body);
|
|
14525
14533
|
const fnHIR = t.isBlockStatement(body) ? convertFunction(name, params, body.body, {
|
|
14526
14534
|
noMemo: programNoMemo,
|
|
14527
|
-
directives: body.directives
|
|
14535
|
+
directives: body.directives,
|
|
14536
|
+
loc: getLoc(decl.init ?? decl)
|
|
14528
14537
|
}) : convertFunction(
|
|
14529
14538
|
name,
|
|
14530
14539
|
params,
|
|
14531
14540
|
[t.returnStatement(body)],
|
|
14532
14541
|
{
|
|
14533
|
-
noMemo: programNoMemo
|
|
14542
|
+
noMemo: programNoMemo,
|
|
14543
|
+
loc: getLoc(decl.init ?? decl)
|
|
14534
14544
|
}
|
|
14535
14545
|
);
|
|
14536
14546
|
fnHIR.meta = { ...fnHIR.meta ?? {}, fromExpression: true, isArrow, hasExpressionBody };
|
|
@@ -15038,11 +15048,12 @@ function convertFunction(name, params, body, options) {
|
|
|
15038
15048
|
name,
|
|
15039
15049
|
params: paramIds,
|
|
15040
15050
|
blocks,
|
|
15041
|
-
meta: hasNoMemo ? { noMemo: true } : void 0
|
|
15051
|
+
meta: hasNoMemo ? { noMemo: true } : void 0,
|
|
15052
|
+
loc: options?.loc ?? null
|
|
15042
15053
|
};
|
|
15043
15054
|
}
|
|
15044
15055
|
function convertStatementsToHIRFunction(name, statements) {
|
|
15045
|
-
return convertFunction(name, [], statements);
|
|
15056
|
+
return convertFunction(name, [], statements, { loc: getLoc(statements[0]) });
|
|
15046
15057
|
}
|
|
15047
15058
|
function convertAssignmentValue(expr) {
|
|
15048
15059
|
const right = convertExpression(expr.right);
|
|
@@ -15540,14 +15551,16 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15540
15551
|
return bb;
|
|
15541
15552
|
}
|
|
15542
15553
|
function convertExpression(node) {
|
|
15543
|
-
|
|
15554
|
+
const loc = getLoc(node);
|
|
15555
|
+
if (t.isIdentifier(node)) return { kind: "Identifier", name: node.name, loc };
|
|
15544
15556
|
if (t.isStringLiteral(node) || t.isNumericLiteral(node) || t.isBooleanLiteral(node) || t.isNullLiteral(node))
|
|
15545
|
-
return { kind: "Literal", value: node.value ?? null };
|
|
15557
|
+
return { kind: "Literal", value: node.value ?? null, loc };
|
|
15546
15558
|
if (t.isCallExpression(node)) {
|
|
15547
15559
|
const call = {
|
|
15548
15560
|
kind: "CallExpression",
|
|
15549
15561
|
callee: convertExpression(node.callee),
|
|
15550
|
-
arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean)
|
|
15562
|
+
arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
|
|
15563
|
+
loc
|
|
15551
15564
|
};
|
|
15552
15565
|
return call;
|
|
15553
15566
|
}
|
|
@@ -15562,7 +15575,8 @@ function convertExpression(node) {
|
|
|
15562
15575
|
object,
|
|
15563
15576
|
property,
|
|
15564
15577
|
computed: node.computed,
|
|
15565
|
-
optional: node.optional ?? true
|
|
15578
|
+
optional: node.optional ?? true,
|
|
15579
|
+
loc
|
|
15566
15580
|
};
|
|
15567
15581
|
return optionalMember;
|
|
15568
15582
|
}
|
|
@@ -15571,7 +15585,8 @@ function convertExpression(node) {
|
|
|
15571
15585
|
object,
|
|
15572
15586
|
property,
|
|
15573
15587
|
computed: node.computed,
|
|
15574
|
-
optional: false
|
|
15588
|
+
optional: false,
|
|
15589
|
+
loc
|
|
15575
15590
|
};
|
|
15576
15591
|
return member;
|
|
15577
15592
|
}
|
|
@@ -15580,7 +15595,8 @@ function convertExpression(node) {
|
|
|
15580
15595
|
kind: "BinaryExpression",
|
|
15581
15596
|
operator: node.operator,
|
|
15582
15597
|
left: convertExpression(node.left),
|
|
15583
|
-
right: convertExpression(node.right)
|
|
15598
|
+
right: convertExpression(node.right),
|
|
15599
|
+
loc
|
|
15584
15600
|
};
|
|
15585
15601
|
return bin;
|
|
15586
15602
|
}
|
|
@@ -15589,7 +15605,8 @@ function convertExpression(node) {
|
|
|
15589
15605
|
kind: "UnaryExpression",
|
|
15590
15606
|
operator: node.operator,
|
|
15591
15607
|
argument: convertExpression(node.argument),
|
|
15592
|
-
prefix: node.prefix
|
|
15608
|
+
prefix: node.prefix,
|
|
15609
|
+
loc
|
|
15593
15610
|
};
|
|
15594
15611
|
return un;
|
|
15595
15612
|
}
|
|
@@ -15598,7 +15615,8 @@ function convertExpression(node) {
|
|
|
15598
15615
|
kind: "LogicalExpression",
|
|
15599
15616
|
operator: node.operator,
|
|
15600
15617
|
left: convertExpression(node.left),
|
|
15601
|
-
right: convertExpression(node.right)
|
|
15618
|
+
right: convertExpression(node.right),
|
|
15619
|
+
loc
|
|
15602
15620
|
};
|
|
15603
15621
|
return log;
|
|
15604
15622
|
}
|
|
@@ -15607,7 +15625,8 @@ function convertExpression(node) {
|
|
|
15607
15625
|
kind: "ConditionalExpression",
|
|
15608
15626
|
test: convertExpression(node.test),
|
|
15609
15627
|
consequent: convertExpression(node.consequent),
|
|
15610
|
-
alternate: convertExpression(node.alternate)
|
|
15628
|
+
alternate: convertExpression(node.alternate),
|
|
15629
|
+
loc
|
|
15611
15630
|
};
|
|
15612
15631
|
return cond;
|
|
15613
15632
|
}
|
|
@@ -15619,12 +15638,14 @@ function convertExpression(node) {
|
|
|
15619
15638
|
if (t.isSpreadElement(el)) {
|
|
15620
15639
|
return {
|
|
15621
15640
|
kind: "SpreadElement",
|
|
15622
|
-
argument: convertExpression(el.argument)
|
|
15641
|
+
argument: convertExpression(el.argument),
|
|
15642
|
+
loc: getLoc(el)
|
|
15623
15643
|
};
|
|
15624
15644
|
}
|
|
15625
15645
|
if (t.isExpression(el)) return convertExpression(el);
|
|
15626
15646
|
return void 0;
|
|
15627
|
-
}).filter(Boolean)
|
|
15647
|
+
}).filter(Boolean),
|
|
15648
|
+
loc
|
|
15628
15649
|
};
|
|
15629
15650
|
return arr;
|
|
15630
15651
|
}
|
|
@@ -15635,7 +15656,8 @@ function convertExpression(node) {
|
|
|
15635
15656
|
if (t.isSpreadElement(prop)) {
|
|
15636
15657
|
return {
|
|
15637
15658
|
kind: "SpreadElement",
|
|
15638
|
-
argument: convertExpression(prop.argument)
|
|
15659
|
+
argument: convertExpression(prop.argument),
|
|
15660
|
+
loc: getLoc(prop)
|
|
15639
15661
|
};
|
|
15640
15662
|
}
|
|
15641
15663
|
if (t.isObjectMethod(prop)) {
|
|
@@ -15652,7 +15674,8 @@ function convertExpression(node) {
|
|
|
15652
15674
|
return {
|
|
15653
15675
|
kind: "Property",
|
|
15654
15676
|
key: keyExpr2,
|
|
15655
|
-
value: convertExpression(fnExpr)
|
|
15677
|
+
value: convertExpression(fnExpr),
|
|
15678
|
+
loc: getLoc(prop)
|
|
15656
15679
|
};
|
|
15657
15680
|
}
|
|
15658
15681
|
if (!t.isObjectProperty(prop) || prop.computed) return void 0;
|
|
@@ -15662,9 +15685,12 @@ function convertExpression(node) {
|
|
|
15662
15685
|
return {
|
|
15663
15686
|
kind: "Property",
|
|
15664
15687
|
key: keyExpr,
|
|
15665
|
-
value: convertExpression(prop.value)
|
|
15688
|
+
value: convertExpression(prop.value),
|
|
15689
|
+
shorthand: prop.shorthand && t.isIdentifier(prop.value),
|
|
15690
|
+
loc: getLoc(prop)
|
|
15666
15691
|
};
|
|
15667
|
-
}).filter(Boolean)
|
|
15692
|
+
}).filter(Boolean),
|
|
15693
|
+
loc
|
|
15668
15694
|
};
|
|
15669
15695
|
return obj;
|
|
15670
15696
|
}
|
|
@@ -15677,38 +15703,42 @@ function convertExpression(node) {
|
|
|
15677
15703
|
if (t.isJSXText(child)) {
|
|
15678
15704
|
const text = child.value;
|
|
15679
15705
|
if (text.trim()) {
|
|
15680
|
-
children.push({ kind: "text", value: text });
|
|
15706
|
+
children.push({ kind: "text", value: text, loc: getLoc(child) });
|
|
15681
15707
|
}
|
|
15682
15708
|
} else if (t.isJSXExpressionContainer(child)) {
|
|
15683
15709
|
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
15684
15710
|
children.push({
|
|
15685
15711
|
kind: "expression",
|
|
15686
|
-
value: convertExpression(child.expression)
|
|
15712
|
+
value: convertExpression(child.expression),
|
|
15713
|
+
loc: getLoc(child)
|
|
15687
15714
|
});
|
|
15688
15715
|
}
|
|
15689
15716
|
} else if (t.isJSXElement(child)) {
|
|
15690
15717
|
children.push({
|
|
15691
15718
|
kind: "element",
|
|
15692
|
-
value: convertJSXElement(child)
|
|
15719
|
+
value: convertJSXElement(child),
|
|
15720
|
+
loc: getLoc(child)
|
|
15693
15721
|
});
|
|
15694
15722
|
} else if (t.isJSXFragment(child)) {
|
|
15695
15723
|
for (const fragChild of child.children) {
|
|
15696
15724
|
if (t.isJSXText(fragChild)) {
|
|
15697
15725
|
const text = fragChild.value;
|
|
15698
15726
|
if (text.trim()) {
|
|
15699
|
-
children.push({ kind: "text", value: text });
|
|
15727
|
+
children.push({ kind: "text", value: text, loc: getLoc(fragChild) });
|
|
15700
15728
|
}
|
|
15701
15729
|
} else if (t.isJSXExpressionContainer(fragChild)) {
|
|
15702
15730
|
if (!t.isJSXEmptyExpression(fragChild.expression)) {
|
|
15703
15731
|
children.push({
|
|
15704
15732
|
kind: "expression",
|
|
15705
|
-
value: convertExpression(fragChild.expression)
|
|
15733
|
+
value: convertExpression(fragChild.expression),
|
|
15734
|
+
loc: getLoc(fragChild)
|
|
15706
15735
|
});
|
|
15707
15736
|
}
|
|
15708
15737
|
} else if (t.isJSXElement(fragChild)) {
|
|
15709
15738
|
children.push({
|
|
15710
15739
|
kind: "element",
|
|
15711
|
-
value: convertJSXElement(fragChild)
|
|
15740
|
+
value: convertJSXElement(fragChild),
|
|
15741
|
+
loc: getLoc(fragChild)
|
|
15712
15742
|
});
|
|
15713
15743
|
}
|
|
15714
15744
|
}
|
|
@@ -15716,24 +15746,27 @@ function convertExpression(node) {
|
|
|
15716
15746
|
}
|
|
15717
15747
|
return {
|
|
15718
15748
|
kind: "JSXElement",
|
|
15719
|
-
tagName: { kind: "Identifier", name: "Fragment" },
|
|
15749
|
+
tagName: { kind: "Identifier", name: "Fragment", loc: getLoc(node) },
|
|
15720
15750
|
isComponent: true,
|
|
15721
15751
|
attributes: [],
|
|
15722
|
-
children
|
|
15752
|
+
children,
|
|
15753
|
+
loc: getLoc(node)
|
|
15723
15754
|
};
|
|
15724
15755
|
}
|
|
15725
15756
|
if (t.isArrowFunctionExpression(node)) {
|
|
15726
15757
|
if (t.isBlockStatement(node.body)) {
|
|
15727
15758
|
const nested = convertFunction(void 0, node.params, node.body.body, {
|
|
15728
15759
|
noMemo: hasNoMemoDirectiveInStatements(node.body.body),
|
|
15729
|
-
directives: node.body.directives
|
|
15760
|
+
directives: node.body.directives,
|
|
15761
|
+
loc: getLoc(node)
|
|
15730
15762
|
});
|
|
15731
15763
|
const arrow = {
|
|
15732
15764
|
kind: "ArrowFunction",
|
|
15733
15765
|
params: nested.params,
|
|
15734
15766
|
body: nested.blocks,
|
|
15735
15767
|
isExpression: false,
|
|
15736
|
-
isAsync: node.async
|
|
15768
|
+
isAsync: node.async,
|
|
15769
|
+
loc
|
|
15737
15770
|
};
|
|
15738
15771
|
return arrow;
|
|
15739
15772
|
} else {
|
|
@@ -15744,7 +15777,8 @@ function convertExpression(node) {
|
|
|
15744
15777
|
).flat(),
|
|
15745
15778
|
body: convertExpression(node.body),
|
|
15746
15779
|
isExpression: true,
|
|
15747
|
-
isAsync: node.async
|
|
15780
|
+
isAsync: node.async,
|
|
15781
|
+
loc
|
|
15748
15782
|
};
|
|
15749
15783
|
return arrow;
|
|
15750
15784
|
}
|
|
@@ -15752,14 +15786,16 @@ function convertExpression(node) {
|
|
|
15752
15786
|
if (t.isFunctionExpression(node)) {
|
|
15753
15787
|
const nested = convertFunction(void 0, node.params, node.body.body, {
|
|
15754
15788
|
noMemo: hasNoMemoDirectiveInStatements(node.body.body),
|
|
15755
|
-
directives: node.body.directives
|
|
15789
|
+
directives: node.body.directives,
|
|
15790
|
+
loc: getLoc(node)
|
|
15756
15791
|
});
|
|
15757
15792
|
const fn = {
|
|
15758
15793
|
kind: "FunctionExpression",
|
|
15759
15794
|
name: node.id?.name ?? "",
|
|
15760
15795
|
params: nested.params,
|
|
15761
15796
|
body: nested.blocks,
|
|
15762
|
-
isAsync: node.async
|
|
15797
|
+
isAsync: node.async,
|
|
15798
|
+
loc
|
|
15763
15799
|
};
|
|
15764
15800
|
return fn;
|
|
15765
15801
|
}
|
|
@@ -15768,7 +15804,8 @@ function convertExpression(node) {
|
|
|
15768
15804
|
kind: "AssignmentExpression",
|
|
15769
15805
|
operator: node.operator,
|
|
15770
15806
|
left: convertExpression(node.left),
|
|
15771
|
-
right: convertExpression(node.right)
|
|
15807
|
+
right: convertExpression(node.right),
|
|
15808
|
+
loc
|
|
15772
15809
|
};
|
|
15773
15810
|
return assign;
|
|
15774
15811
|
}
|
|
@@ -15777,7 +15814,8 @@ function convertExpression(node) {
|
|
|
15777
15814
|
kind: "UpdateExpression",
|
|
15778
15815
|
operator: node.operator,
|
|
15779
15816
|
argument: convertExpression(node.argument),
|
|
15780
|
-
prefix: node.prefix
|
|
15817
|
+
prefix: node.prefix,
|
|
15818
|
+
loc
|
|
15781
15819
|
};
|
|
15782
15820
|
return update;
|
|
15783
15821
|
}
|
|
@@ -15785,34 +15823,39 @@ function convertExpression(node) {
|
|
|
15785
15823
|
const template = {
|
|
15786
15824
|
kind: "TemplateLiteral",
|
|
15787
15825
|
quasis: node.quasis.map((q) => q.value.cooked ?? q.value.raw),
|
|
15788
|
-
expressions: node.expressions.map((e) => convertExpression(e))
|
|
15826
|
+
expressions: node.expressions.map((e) => convertExpression(e)),
|
|
15827
|
+
loc
|
|
15789
15828
|
};
|
|
15790
15829
|
return template;
|
|
15791
15830
|
}
|
|
15792
15831
|
if (t.isAwaitExpression(node)) {
|
|
15793
15832
|
return {
|
|
15794
15833
|
kind: "AwaitExpression",
|
|
15795
|
-
argument: convertExpression(node.argument)
|
|
15834
|
+
argument: convertExpression(node.argument),
|
|
15835
|
+
loc
|
|
15796
15836
|
};
|
|
15797
15837
|
}
|
|
15798
15838
|
if (t.isNewExpression(node)) {
|
|
15799
15839
|
return {
|
|
15800
15840
|
kind: "NewExpression",
|
|
15801
15841
|
callee: convertExpression(node.callee),
|
|
15802
|
-
arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean)
|
|
15842
|
+
arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
|
|
15843
|
+
loc
|
|
15803
15844
|
};
|
|
15804
15845
|
}
|
|
15805
15846
|
if (t.isSequenceExpression(node)) {
|
|
15806
15847
|
return {
|
|
15807
15848
|
kind: "SequenceExpression",
|
|
15808
|
-
expressions: node.expressions.map((e) => convertExpression(e))
|
|
15849
|
+
expressions: node.expressions.map((e) => convertExpression(e)),
|
|
15850
|
+
loc
|
|
15809
15851
|
};
|
|
15810
15852
|
}
|
|
15811
15853
|
if (t.isYieldExpression(node)) {
|
|
15812
15854
|
return {
|
|
15813
15855
|
kind: "YieldExpression",
|
|
15814
15856
|
argument: node.argument ? convertExpression(node.argument) : null,
|
|
15815
|
-
delegate: node.delegate
|
|
15857
|
+
delegate: node.delegate,
|
|
15858
|
+
loc
|
|
15816
15859
|
};
|
|
15817
15860
|
}
|
|
15818
15861
|
if (t.isOptionalCallExpression(node)) {
|
|
@@ -15820,7 +15863,8 @@ function convertExpression(node) {
|
|
|
15820
15863
|
kind: "OptionalCallExpression",
|
|
15821
15864
|
callee: convertExpression(node.callee),
|
|
15822
15865
|
arguments: node.arguments.map((arg) => t.isExpression(arg) ? convertExpression(arg) : void 0).filter(Boolean),
|
|
15823
|
-
optional: node.optional
|
|
15866
|
+
optional: node.optional,
|
|
15867
|
+
loc
|
|
15824
15868
|
};
|
|
15825
15869
|
}
|
|
15826
15870
|
if (t.isTaggedTemplateExpression(node)) {
|
|
@@ -15832,8 +15876,10 @@ function convertExpression(node) {
|
|
|
15832
15876
|
quasis: node.quasi.quasis.map((q) => q.value.cooked ?? q.value.raw),
|
|
15833
15877
|
expressions: node.quasi.expressions.map(
|
|
15834
15878
|
(e) => convertExpression(e)
|
|
15835
|
-
)
|
|
15836
|
-
|
|
15879
|
+
),
|
|
15880
|
+
loc: getLoc(node.quasi)
|
|
15881
|
+
},
|
|
15882
|
+
loc
|
|
15837
15883
|
};
|
|
15838
15884
|
}
|
|
15839
15885
|
if (t.isClassExpression(node)) {
|
|
@@ -15841,17 +15887,18 @@ function convertExpression(node) {
|
|
|
15841
15887
|
kind: "ClassExpression",
|
|
15842
15888
|
name: node.id?.name,
|
|
15843
15889
|
superClass: node.superClass ? convertExpression(node.superClass) : void 0,
|
|
15844
|
-
body: node.body.body
|
|
15890
|
+
body: node.body.body,
|
|
15845
15891
|
// Store as Babel AST for now
|
|
15892
|
+
loc
|
|
15846
15893
|
};
|
|
15847
15894
|
}
|
|
15848
15895
|
if (t.isThisExpression(node)) {
|
|
15849
|
-
return { kind: "ThisExpression" };
|
|
15896
|
+
return { kind: "ThisExpression", loc };
|
|
15850
15897
|
}
|
|
15851
15898
|
if (t.isSuper(node)) {
|
|
15852
|
-
return { kind: "SuperExpression" };
|
|
15899
|
+
return { kind: "SuperExpression", loc };
|
|
15853
15900
|
}
|
|
15854
|
-
const fallback = { kind: "Literal", value: void 0 };
|
|
15901
|
+
const fallback = { kind: "Literal", value: void 0, loc };
|
|
15855
15902
|
return fallback;
|
|
15856
15903
|
}
|
|
15857
15904
|
function convertJSXElement(node) {
|
|
@@ -15862,7 +15909,7 @@ function convertJSXElement(node) {
|
|
|
15862
15909
|
const name = opening.name.name;
|
|
15863
15910
|
const firstChar = name[0];
|
|
15864
15911
|
if (firstChar && firstChar === firstChar.toUpperCase()) {
|
|
15865
|
-
tagName = { kind: "Identifier", name };
|
|
15912
|
+
tagName = { kind: "Identifier", name, loc: getLoc(opening.name) };
|
|
15866
15913
|
isComponent = true;
|
|
15867
15914
|
} else {
|
|
15868
15915
|
tagName = name;
|
|
@@ -15880,20 +15927,22 @@ function convertJSXElement(node) {
|
|
|
15880
15927
|
name: "",
|
|
15881
15928
|
value: null,
|
|
15882
15929
|
isSpread: true,
|
|
15883
|
-
spreadExpr: convertExpression(attr.argument)
|
|
15930
|
+
spreadExpr: convertExpression(attr.argument),
|
|
15931
|
+
loc: getLoc(attr)
|
|
15884
15932
|
});
|
|
15885
15933
|
} else if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
|
|
15886
15934
|
let value = null;
|
|
15887
15935
|
if (attr.value) {
|
|
15888
15936
|
if (t.isStringLiteral(attr.value)) {
|
|
15889
|
-
value = { kind: "Literal", value: attr.value.value };
|
|
15937
|
+
value = { kind: "Literal", value: attr.value.value, loc: getLoc(attr.value) };
|
|
15890
15938
|
} else if (t.isJSXExpressionContainer(attr.value) && !t.isJSXEmptyExpression(attr.value.expression)) {
|
|
15891
15939
|
value = convertExpression(attr.value.expression);
|
|
15892
15940
|
}
|
|
15893
15941
|
}
|
|
15894
15942
|
attributes.push({
|
|
15895
15943
|
name: attr.name.name,
|
|
15896
|
-
value
|
|
15944
|
+
value,
|
|
15945
|
+
loc: getLoc(attr)
|
|
15897
15946
|
});
|
|
15898
15947
|
}
|
|
15899
15948
|
}
|
|
@@ -15902,38 +15951,42 @@ function convertJSXElement(node) {
|
|
|
15902
15951
|
if (t.isJSXText(child)) {
|
|
15903
15952
|
const text = child.value;
|
|
15904
15953
|
if (text.trim()) {
|
|
15905
|
-
children.push({ kind: "text", value: text });
|
|
15954
|
+
children.push({ kind: "text", value: text, loc: getLoc(child) });
|
|
15906
15955
|
}
|
|
15907
15956
|
} else if (t.isJSXExpressionContainer(child)) {
|
|
15908
15957
|
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
15909
15958
|
children.push({
|
|
15910
15959
|
kind: "expression",
|
|
15911
|
-
value: convertExpression(child.expression)
|
|
15960
|
+
value: convertExpression(child.expression),
|
|
15961
|
+
loc: getLoc(child)
|
|
15912
15962
|
});
|
|
15913
15963
|
}
|
|
15914
15964
|
} else if (t.isJSXElement(child)) {
|
|
15915
15965
|
children.push({
|
|
15916
15966
|
kind: "element",
|
|
15917
|
-
value: convertJSXElement(child)
|
|
15967
|
+
value: convertJSXElement(child),
|
|
15968
|
+
loc: getLoc(child)
|
|
15918
15969
|
});
|
|
15919
15970
|
} else if (t.isJSXFragment(child)) {
|
|
15920
15971
|
for (const fragChild of child.children) {
|
|
15921
15972
|
if (t.isJSXText(fragChild)) {
|
|
15922
15973
|
const text = fragChild.value;
|
|
15923
15974
|
if (text.trim()) {
|
|
15924
|
-
children.push({ kind: "text", value: text });
|
|
15975
|
+
children.push({ kind: "text", value: text, loc: getLoc(fragChild) });
|
|
15925
15976
|
}
|
|
15926
15977
|
} else if (t.isJSXExpressionContainer(fragChild)) {
|
|
15927
15978
|
if (!t.isJSXEmptyExpression(fragChild.expression)) {
|
|
15928
15979
|
children.push({
|
|
15929
15980
|
kind: "expression",
|
|
15930
|
-
value: convertExpression(fragChild.expression)
|
|
15981
|
+
value: convertExpression(fragChild.expression),
|
|
15982
|
+
loc: getLoc(fragChild)
|
|
15931
15983
|
});
|
|
15932
15984
|
}
|
|
15933
15985
|
} else if (t.isJSXElement(fragChild)) {
|
|
15934
15986
|
children.push({
|
|
15935
15987
|
kind: "element",
|
|
15936
|
-
value: convertJSXElement(fragChild)
|
|
15988
|
+
value: convertJSXElement(fragChild),
|
|
15989
|
+
loc: getLoc(fragChild)
|
|
15937
15990
|
});
|
|
15938
15991
|
}
|
|
15939
15992
|
}
|
|
@@ -15944,21 +15997,27 @@ function convertJSXElement(node) {
|
|
|
15944
15997
|
tagName,
|
|
15945
15998
|
isComponent,
|
|
15946
15999
|
attributes,
|
|
15947
|
-
children
|
|
16000
|
+
children,
|
|
16001
|
+
loc: getLoc(node)
|
|
15948
16002
|
};
|
|
15949
16003
|
}
|
|
15950
16004
|
function convertJSXMemberExpr(node) {
|
|
15951
16005
|
let object;
|
|
15952
16006
|
if (t.isJSXIdentifier(node.object)) {
|
|
15953
|
-
object = { kind: "Identifier", name: node.object.name };
|
|
16007
|
+
object = { kind: "Identifier", name: node.object.name, loc: getLoc(node.object) };
|
|
15954
16008
|
} else {
|
|
15955
16009
|
object = convertJSXMemberExpr(node.object);
|
|
15956
16010
|
}
|
|
15957
16011
|
return {
|
|
15958
16012
|
kind: "MemberExpression",
|
|
15959
16013
|
object,
|
|
15960
|
-
property: {
|
|
15961
|
-
|
|
16014
|
+
property: {
|
|
16015
|
+
kind: "Identifier",
|
|
16016
|
+
name: node.property.name,
|
|
16017
|
+
loc: getLoc(node.property)
|
|
16018
|
+
},
|
|
16019
|
+
computed: false,
|
|
16020
|
+
loc: getLoc(node)
|
|
15962
16021
|
};
|
|
15963
16022
|
}
|
|
15964
16023
|
|
|
@@ -15979,6 +16038,75 @@ function debugEnabled(flag) {
|
|
|
15979
16038
|
return parts.includes(normalized) || parts.includes("all");
|
|
15980
16039
|
}
|
|
15981
16040
|
|
|
16041
|
+
// src/utils.ts
|
|
16042
|
+
function isStateCall(node, t2) {
|
|
16043
|
+
return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$state";
|
|
16044
|
+
}
|
|
16045
|
+
function isEffectCall(node, t2) {
|
|
16046
|
+
return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$effect";
|
|
16047
|
+
}
|
|
16048
|
+
function getRootIdentifier(expr, t2) {
|
|
16049
|
+
if (t2.isIdentifier(expr)) {
|
|
16050
|
+
return expr;
|
|
16051
|
+
}
|
|
16052
|
+
if (t2.isMemberExpression(expr) && t2.isExpression(expr.object) && !t2.isOptionalMemberExpression(expr)) {
|
|
16053
|
+
return getRootIdentifier(expr.object, t2);
|
|
16054
|
+
}
|
|
16055
|
+
if (t2.isOptionalMemberExpression(expr) && t2.isExpression(expr.object)) {
|
|
16056
|
+
return getRootIdentifier(expr.object, t2);
|
|
16057
|
+
}
|
|
16058
|
+
if (t2.isCallExpression(expr) && t2.isExpression(expr.callee)) {
|
|
16059
|
+
return getRootIdentifier(expr.callee, t2);
|
|
16060
|
+
}
|
|
16061
|
+
if (t2.isOptionalCallExpression(expr) && t2.isExpression(expr.callee)) {
|
|
16062
|
+
return getRootIdentifier(expr.callee, t2);
|
|
16063
|
+
}
|
|
16064
|
+
if (t2.isTSAsExpression(expr) && t2.isExpression(expr.expression)) {
|
|
16065
|
+
return getRootIdentifier(expr.expression, t2);
|
|
16066
|
+
}
|
|
16067
|
+
if (t2.isTSNonNullExpression(expr) && t2.isExpression(expr.expression)) {
|
|
16068
|
+
return getRootIdentifier(expr.expression, t2);
|
|
16069
|
+
}
|
|
16070
|
+
return null;
|
|
16071
|
+
}
|
|
16072
|
+
|
|
16073
|
+
// src/fine-grained-dom.ts
|
|
16074
|
+
function normalizeDependencyKey(name) {
|
|
16075
|
+
return name.split(".").map((part) => part.replace(/_\d+$/, "")).join(".");
|
|
16076
|
+
}
|
|
16077
|
+
function applyRegionMetadata(state, options) {
|
|
16078
|
+
if (!options.region) return;
|
|
16079
|
+
const region = options.region;
|
|
16080
|
+
state.regionMetadata = region;
|
|
16081
|
+
if (region.dependencies.size > 0) {
|
|
16082
|
+
state.identifierOverrides = state.identifierOverrides ?? {};
|
|
16083
|
+
const dependencyGetter = options.dependencyGetter ?? null;
|
|
16084
|
+
if (!dependencyGetter) {
|
|
16085
|
+
return;
|
|
16086
|
+
}
|
|
16087
|
+
for (const dep of region.dependencies) {
|
|
16088
|
+
const key = normalizeDependencyKey(dep);
|
|
16089
|
+
state.identifierOverrides[key] = () => dependencyGetter(dep);
|
|
16090
|
+
const base = key.split(".")[0];
|
|
16091
|
+
if (base && !state.identifierOverrides[base]) {
|
|
16092
|
+
state.identifierOverrides[base] = () => dependencyGetter(base);
|
|
16093
|
+
}
|
|
16094
|
+
}
|
|
16095
|
+
}
|
|
16096
|
+
}
|
|
16097
|
+
function shouldMemoizeRegion(region) {
|
|
16098
|
+
if (region.dependencies.size > 0) {
|
|
16099
|
+
return true;
|
|
16100
|
+
}
|
|
16101
|
+
if (region.hasControlFlow) {
|
|
16102
|
+
return true;
|
|
16103
|
+
}
|
|
16104
|
+
if (region.hasReactiveWrites) {
|
|
16105
|
+
return true;
|
|
16106
|
+
}
|
|
16107
|
+
return false;
|
|
16108
|
+
}
|
|
16109
|
+
|
|
15982
16110
|
// src/ir/ssa.ts
|
|
15983
16111
|
function analyzeCFG(blocks) {
|
|
15984
16112
|
const predecessors = computePredecessors(blocks);
|
|
@@ -16469,7 +16597,7 @@ function collectExprReads(expr, into, paths, bound = /* @__PURE__ */ new Set(),
|
|
|
16469
16597
|
}
|
|
16470
16598
|
return;
|
|
16471
16599
|
case "CallExpression": {
|
|
16472
|
-
const isMacroCallee = expr.callee.kind === "Identifier" && (expr.callee.name === "$state" || expr.callee.name === "$effect");
|
|
16600
|
+
const isMacroCallee = expr.callee.kind === "Identifier" && (expr.callee.name === "$state" || expr.callee.name === "$effect" || expr.callee.name === "$store");
|
|
16473
16601
|
if (!isMacroCallee) {
|
|
16474
16602
|
collectExprReads(expr.callee, into, paths, bound);
|
|
16475
16603
|
}
|
|
@@ -18837,6 +18965,7 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
18837
18965
|
}
|
|
18838
18966
|
const outputNames = outputNamesOverride ?? Array.from(region.declarations).map((name) => deSSAVarName(name));
|
|
18839
18967
|
const uniqueOutputNames = [...new Set(outputNames)];
|
|
18968
|
+
const bindableOutputs = uniqueOutputNames.filter((name) => !declaredVars.has(name));
|
|
18840
18969
|
if (debugEnabled("region")) {
|
|
18841
18970
|
console.log("Region memo", region.id, {
|
|
18842
18971
|
instructions: region.instructions.map((instr) => instr.kind),
|
|
@@ -18846,11 +18975,17 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
18846
18975
|
if (uniqueOutputNames.length === 0) {
|
|
18847
18976
|
ctx.helpersUsed.add("useEffect");
|
|
18848
18977
|
ctx.needsCtx = true;
|
|
18849
|
-
const
|
|
18978
|
+
const effectCallArgs = [
|
|
18850
18979
|
t2.identifier("__fictCtx"),
|
|
18851
|
-
t2.arrowFunctionExpression([], t2.blockStatement(bodyStatements))
|
|
18852
|
-
|
|
18853
|
-
|
|
18980
|
+
t2.arrowFunctionExpression([], t2.blockStatement(bodyStatements))
|
|
18981
|
+
];
|
|
18982
|
+
{
|
|
18983
|
+
const slot = reserveHookSlot(ctx);
|
|
18984
|
+
if (slot >= 0) {
|
|
18985
|
+
effectCallArgs.push(t2.numericLiteral(slot));
|
|
18986
|
+
}
|
|
18987
|
+
}
|
|
18988
|
+
const effectCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), effectCallArgs);
|
|
18854
18989
|
statements.push(t2.expressionStatement(effectCall));
|
|
18855
18990
|
} else {
|
|
18856
18991
|
ctx.helpersUsed.add("useMemo");
|
|
@@ -18883,20 +19018,24 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
18883
19018
|
};
|
|
18884
19019
|
const returnObj = t2.objectExpression(uniqueOutputNames.map((name) => buildOutputProperty(name)));
|
|
18885
19020
|
const memoBody = t2.blockStatement([...bodyStatements, t2.returnStatement(returnObj)]);
|
|
18886
|
-
const
|
|
19021
|
+
const slot = reserveHookSlot(ctx);
|
|
19022
|
+
const memoArgs = [
|
|
18887
19023
|
t2.identifier("__fictCtx"),
|
|
18888
|
-
t2.arrowFunctionExpression([], memoBody)
|
|
18889
|
-
|
|
18890
|
-
|
|
19024
|
+
t2.arrowFunctionExpression([], memoBody)
|
|
19025
|
+
];
|
|
19026
|
+
if (slot >= 0) {
|
|
19027
|
+
memoArgs.push(t2.numericLiteral(slot));
|
|
19028
|
+
}
|
|
19029
|
+
const memoCall = t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), memoArgs);
|
|
18891
19030
|
const regionVarName = `__region_${region.id}`;
|
|
18892
19031
|
statements.push(
|
|
18893
19032
|
t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(regionVarName), memoCall)])
|
|
18894
19033
|
);
|
|
18895
19034
|
const isAccessorOutput = (name) => ctx.signalVars?.has(name) || ctx.memoVars?.has(name) || ctx.aliasVars?.has(name) || ctx.storeVars?.has(name);
|
|
18896
|
-
const getterOutputs =
|
|
19035
|
+
const getterOutputs = bindableOutputs.filter(
|
|
18897
19036
|
(name) => ctx.trackedVars.has(name) && !isAccessorOutput(name)
|
|
18898
19037
|
);
|
|
18899
|
-
const directOutputs =
|
|
19038
|
+
const directOutputs = bindableOutputs.filter((name) => !getterOutputs.includes(name));
|
|
18900
19039
|
if (debugEnabled("region")) {
|
|
18901
19040
|
console.log("Region debug", {
|
|
18902
19041
|
id: region.id,
|
|
@@ -18944,7 +19083,10 @@ function wrapInMemo(region, t2, declaredVars, ctx, bodyStatementsOverride, outpu
|
|
|
18944
19083
|
t2.callExpression(t2.identifier(RUNTIME_ALIASES.useEffect), [
|
|
18945
19084
|
t2.identifier("__fictCtx"),
|
|
18946
19085
|
t2.arrowFunctionExpression([], effectBody),
|
|
18947
|
-
|
|
19086
|
+
(() => {
|
|
19087
|
+
const slot2 = reserveHookSlot(ctx);
|
|
19088
|
+
return slot2 >= 0 ? t2.numericLiteral(slot2) : t2.identifier("undefined");
|
|
19089
|
+
})()
|
|
18948
19090
|
])
|
|
18949
19091
|
)
|
|
18950
19092
|
);
|
|
@@ -19162,11 +19304,15 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
|
|
|
19162
19304
|
ctx.helpersUsed.add("useMemo");
|
|
19163
19305
|
ctx.needsCtx = true;
|
|
19164
19306
|
const regionVarName = `__region_${region.id}`;
|
|
19165
|
-
const
|
|
19307
|
+
const slotForMemo = reserveHookSlot(ctx);
|
|
19308
|
+
const memoArgs = [
|
|
19166
19309
|
t2.identifier("__fictCtx"),
|
|
19167
|
-
t2.arrowFunctionExpression([], t2.blockStatement(memoBody))
|
|
19168
|
-
|
|
19169
|
-
|
|
19310
|
+
t2.arrowFunctionExpression([], t2.blockStatement(memoBody))
|
|
19311
|
+
];
|
|
19312
|
+
if (slotForMemo >= 0) {
|
|
19313
|
+
memoArgs.push(t2.numericLiteral(slotForMemo));
|
|
19314
|
+
}
|
|
19315
|
+
const memoCall = t2.callExpression(t2.identifier("__fictUseMemo"), memoArgs);
|
|
19170
19316
|
statements.push(
|
|
19171
19317
|
t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(regionVarName), memoCall)])
|
|
19172
19318
|
);
|
|
@@ -19188,6 +19334,9 @@ function generateLazyConditionalMemo(region, orderedOutputs, bodyStatements, con
|
|
|
19188
19334
|
return statements;
|
|
19189
19335
|
}
|
|
19190
19336
|
function reserveHookSlot(ctx) {
|
|
19337
|
+
if (ctx.dynamicHookSlotDepth && ctx.dynamicHookSlotDepth > 0) {
|
|
19338
|
+
return -1;
|
|
19339
|
+
}
|
|
19191
19340
|
const slot = ctx.nextHookSlot ?? 0;
|
|
19192
19341
|
ctx.nextHookSlot = slot + 1;
|
|
19193
19342
|
return slot;
|
|
@@ -19258,7 +19407,10 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19258
19407
|
t2.arrowFunctionExpression([], expr)
|
|
19259
19408
|
];
|
|
19260
19409
|
if (inRegionMemo) {
|
|
19261
|
-
|
|
19410
|
+
const slot = reserveHookSlot(ctx);
|
|
19411
|
+
if (slot >= 0) {
|
|
19412
|
+
args.push(t2.numericLiteral(slot));
|
|
19413
|
+
}
|
|
19262
19414
|
}
|
|
19263
19415
|
ctx.helpersUsed.add("useMemo");
|
|
19264
19416
|
ctx.needsCtx = true;
|
|
@@ -19272,17 +19424,6 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19272
19424
|
const needsMutable = ctx.mutatedVars?.has(baseName2) ?? false;
|
|
19273
19425
|
const isExternalAlias = declKind === "const" && instr.value.kind === "Identifier" && !(ctx.scopes?.byName?.has(deSSAVarName(instr.value.name)) ?? false);
|
|
19274
19426
|
const fallbackDecl = !treatAsTracked && (!dependsOnTracked2 || isDestructuringTemp) ? declKind === "const" && (needsMutable || isExternalAlias) ? "let" : declKind : normalizedDecl;
|
|
19275
|
-
const isAliasOfTracked = !isShadowDeclaration && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp;
|
|
19276
|
-
if (isAliasOfTracked) {
|
|
19277
|
-
declaredVars.add(baseName2);
|
|
19278
|
-
const sourceIdent = instr.value;
|
|
19279
|
-
return t2.variableDeclaration(fallbackDecl, [
|
|
19280
|
-
t2.variableDeclarator(
|
|
19281
|
-
t2.identifier(baseName2),
|
|
19282
|
-
t2.callExpression(t2.identifier(deSSAVarName(sourceIdent.name)), [])
|
|
19283
|
-
)
|
|
19284
|
-
]);
|
|
19285
|
-
}
|
|
19286
19427
|
declaredVars.add(baseName2);
|
|
19287
19428
|
if (treatAsTracked && !isDestructuringTemp) {
|
|
19288
19429
|
if (isStateCall2) {
|
|
@@ -19291,6 +19432,9 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19291
19432
|
]);
|
|
19292
19433
|
}
|
|
19293
19434
|
if (dependsOnTracked2) {
|
|
19435
|
+
if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
|
|
19436
|
+
aliasVars.add(baseName2);
|
|
19437
|
+
}
|
|
19294
19438
|
const derivedExpr = lowerAssignedValue(true);
|
|
19295
19439
|
if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
|
|
19296
19440
|
return t2.variableDeclaration(normalizedDecl, [
|
|
@@ -19315,6 +19459,9 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19315
19459
|
}
|
|
19316
19460
|
}
|
|
19317
19461
|
if (dependsOnTracked2 && !isDestructuringTemp) {
|
|
19462
|
+
if (instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name)) && !isDestructuringTemp) {
|
|
19463
|
+
aliasVars.add(baseName2);
|
|
19464
|
+
}
|
|
19318
19465
|
const derivedExpr = lowerAssignedValue(true);
|
|
19319
19466
|
if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
|
|
19320
19467
|
return t2.variableDeclaration(normalizedDecl, [
|
|
@@ -19349,17 +19496,35 @@ function instructionToStatement(instr, t2, declaredVars, ctx, _buildMemoCall) {
|
|
|
19349
19496
|
t2.callExpression(t2.identifier(baseName2), [lowerAssignedValue(true)])
|
|
19350
19497
|
);
|
|
19351
19498
|
}
|
|
19352
|
-
if (instr.value.kind === "Identifier" && !isDestructuringTemp) {
|
|
19353
|
-
const source = deSSAVarName(instr.value.name);
|
|
19354
|
-
if (ctx.trackedVars.has(source) && !declaredVars.has(baseName2)) {
|
|
19355
|
-
return t2.variableDeclaration(declKind ?? "const", [
|
|
19356
|
-
t2.variableDeclarator(t2.identifier(baseName2), t2.callExpression(t2.identifier(source), []))
|
|
19357
|
-
]);
|
|
19358
|
-
}
|
|
19359
|
-
}
|
|
19360
19499
|
if (aliasVars.has(baseName2) && !declaredVars.has(baseName2)) {
|
|
19361
19500
|
throw new Error(`Alias reassignment is not supported for "${baseName2}"`);
|
|
19362
19501
|
}
|
|
19502
|
+
if (dependsOnTracked2 && !declKind && !isDestructuringTemp && !isTracked && !isSignal && instr.value.kind === "Identifier" && ctx.trackedVars.has(deSSAVarName(instr.value.name))) {
|
|
19503
|
+
const derivedExpr = lowerAssignedValue(true);
|
|
19504
|
+
aliasVars.add(baseName2);
|
|
19505
|
+
if (ctx.nonReactiveScopeDepth && ctx.nonReactiveScopeDepth > 0) {
|
|
19506
|
+
return t2.expressionStatement(
|
|
19507
|
+
t2.assignmentExpression("=", t2.identifier(baseName2), derivedExpr)
|
|
19508
|
+
);
|
|
19509
|
+
}
|
|
19510
|
+
if (!isReactiveObjectCall) ctx.memoVars?.add(baseName2);
|
|
19511
|
+
if (ctx.noMemo) {
|
|
19512
|
+
return t2.expressionStatement(
|
|
19513
|
+
t2.assignmentExpression(
|
|
19514
|
+
"=",
|
|
19515
|
+
t2.identifier(baseName2),
|
|
19516
|
+
t2.arrowFunctionExpression([], derivedExpr)
|
|
19517
|
+
)
|
|
19518
|
+
);
|
|
19519
|
+
}
|
|
19520
|
+
return t2.expressionStatement(
|
|
19521
|
+
t2.assignmentExpression(
|
|
19522
|
+
"=",
|
|
19523
|
+
t2.identifier(baseName2),
|
|
19524
|
+
isMemoReturningCall ? derivedExpr : buildMemoCall(derivedExpr)
|
|
19525
|
+
)
|
|
19526
|
+
);
|
|
19527
|
+
}
|
|
19363
19528
|
if (declaredVars.has(baseName2)) {
|
|
19364
19529
|
if (aliasVars.has(baseName2)) {
|
|
19365
19530
|
throw new Error(`Alias reassignment is not supported for "${baseName2}"`);
|
|
@@ -19757,78 +19922,20 @@ function deSSAJSXChild(child, t2) {
|
|
|
19757
19922
|
return child;
|
|
19758
19923
|
}
|
|
19759
19924
|
|
|
19760
|
-
// src/utils.ts
|
|
19761
|
-
function isStateCall(node, t2) {
|
|
19762
|
-
return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$state";
|
|
19763
|
-
}
|
|
19764
|
-
function isEffectCall(node, t2) {
|
|
19765
|
-
return t2.isCallExpression(node) && t2.isIdentifier(node.callee) && node.callee.name === "$effect";
|
|
19766
|
-
}
|
|
19767
|
-
function getRootIdentifier(expr, t2) {
|
|
19768
|
-
if (t2.isIdentifier(expr)) {
|
|
19769
|
-
return expr;
|
|
19770
|
-
}
|
|
19771
|
-
if (t2.isMemberExpression(expr) && t2.isExpression(expr.object) && !t2.isOptionalMemberExpression(expr)) {
|
|
19772
|
-
return getRootIdentifier(expr.object, t2);
|
|
19773
|
-
}
|
|
19774
|
-
if (t2.isOptionalMemberExpression(expr) && t2.isExpression(expr.object)) {
|
|
19775
|
-
return getRootIdentifier(expr.object, t2);
|
|
19776
|
-
}
|
|
19777
|
-
if (t2.isCallExpression(expr) && t2.isExpression(expr.callee)) {
|
|
19778
|
-
return getRootIdentifier(expr.callee, t2);
|
|
19779
|
-
}
|
|
19780
|
-
if (t2.isOptionalCallExpression(expr) && t2.isExpression(expr.callee)) {
|
|
19781
|
-
return getRootIdentifier(expr.callee, t2);
|
|
19782
|
-
}
|
|
19783
|
-
if (t2.isTSAsExpression(expr) && t2.isExpression(expr.expression)) {
|
|
19784
|
-
return getRootIdentifier(expr.expression, t2);
|
|
19785
|
-
}
|
|
19786
|
-
if (t2.isTSNonNullExpression(expr) && t2.isExpression(expr.expression)) {
|
|
19787
|
-
return getRootIdentifier(expr.expression, t2);
|
|
19788
|
-
}
|
|
19789
|
-
return null;
|
|
19790
|
-
}
|
|
19791
|
-
|
|
19792
|
-
// src/fine-grained-dom.ts
|
|
19793
|
-
function normalizeDependencyKey(name) {
|
|
19794
|
-
return name.split(".").map((part) => part.replace(/_\d+$/, "")).join(".");
|
|
19795
|
-
}
|
|
19796
|
-
function applyRegionMetadata(state, options) {
|
|
19797
|
-
if (!options.region) return;
|
|
19798
|
-
const region = options.region;
|
|
19799
|
-
state.regionMetadata = region;
|
|
19800
|
-
if (region.dependencies.size > 0) {
|
|
19801
|
-
state.identifierOverrides = state.identifierOverrides ?? {};
|
|
19802
|
-
const dependencyGetter = options.dependencyGetter ?? null;
|
|
19803
|
-
if (!dependencyGetter) {
|
|
19804
|
-
return;
|
|
19805
|
-
}
|
|
19806
|
-
for (const dep of region.dependencies) {
|
|
19807
|
-
const key = normalizeDependencyKey(dep);
|
|
19808
|
-
state.identifierOverrides[key] = () => dependencyGetter(dep);
|
|
19809
|
-
const base = key.split(".")[0];
|
|
19810
|
-
if (base && !state.identifierOverrides[base]) {
|
|
19811
|
-
state.identifierOverrides[base] = () => dependencyGetter(base);
|
|
19812
|
-
}
|
|
19813
|
-
}
|
|
19814
|
-
}
|
|
19815
|
-
}
|
|
19816
|
-
function shouldMemoizeRegion(region) {
|
|
19817
|
-
if (region.dependencies.size > 0) {
|
|
19818
|
-
return true;
|
|
19819
|
-
}
|
|
19820
|
-
if (region.hasControlFlow) {
|
|
19821
|
-
return true;
|
|
19822
|
-
}
|
|
19823
|
-
if (region.hasReactiveWrites) {
|
|
19824
|
-
return true;
|
|
19825
|
-
}
|
|
19826
|
-
return false;
|
|
19827
|
-
}
|
|
19828
|
-
|
|
19829
19925
|
// src/ir/codegen.ts
|
|
19830
19926
|
var HOOK_SLOT_BASE = 1e3;
|
|
19831
19927
|
var HOOK_NAME_PREFIX = "use";
|
|
19928
|
+
var cloneLoc = (loc) => loc === void 0 ? void 0 : loc === null ? null : {
|
|
19929
|
+
start: { ...loc.start },
|
|
19930
|
+
end: { ...loc.end },
|
|
19931
|
+
filename: loc.filename,
|
|
19932
|
+
identifierName: loc.identifierName
|
|
19933
|
+
};
|
|
19934
|
+
function setNodeLoc(node, loc) {
|
|
19935
|
+
if (loc === void 0) return node;
|
|
19936
|
+
node.loc = cloneLoc(loc) ?? null;
|
|
19937
|
+
return node;
|
|
19938
|
+
}
|
|
19832
19939
|
function isHookName(name) {
|
|
19833
19940
|
return !!name && name.startsWith(HOOK_NAME_PREFIX);
|
|
19834
19941
|
}
|
|
@@ -19862,13 +19969,22 @@ function applyRegionToContext(ctx, region) {
|
|
|
19862
19969
|
return prevRegion;
|
|
19863
19970
|
}
|
|
19864
19971
|
function reserveHookSlot2(ctx) {
|
|
19972
|
+
if (ctx.dynamicHookSlotDepth && ctx.dynamicHookSlotDepth > 0) {
|
|
19973
|
+
return -1;
|
|
19974
|
+
}
|
|
19865
19975
|
const slot = ctx.nextHookSlot ?? HOOK_SLOT_BASE;
|
|
19866
19976
|
ctx.nextHookSlot = slot + 1;
|
|
19867
19977
|
return slot;
|
|
19868
19978
|
}
|
|
19869
19979
|
function expressionContainsJSX(expr) {
|
|
19980
|
+
if (Array.isArray(expr)) {
|
|
19981
|
+
return expr.some((item) => expressionContainsJSX(item));
|
|
19982
|
+
}
|
|
19870
19983
|
if (!expr || typeof expr !== "object") return false;
|
|
19871
19984
|
if (expr.kind === "JSXElement") return true;
|
|
19985
|
+
if (Array.isArray(expr.instructions)) {
|
|
19986
|
+
return expr.instructions.some((i) => expressionContainsJSX(i?.value ?? i));
|
|
19987
|
+
}
|
|
19872
19988
|
switch (expr.kind) {
|
|
19873
19989
|
case "CallExpression":
|
|
19874
19990
|
if (expressionContainsJSX(expr.callee)) return true;
|
|
@@ -19881,10 +19997,29 @@ function expressionContainsJSX(expr) {
|
|
|
19881
19997
|
return expressionContainsJSX(expr.test) || expressionContainsJSX(expr.consequent) || expressionContainsJSX(expr.alternate);
|
|
19882
19998
|
case "ArrowFunction":
|
|
19883
19999
|
return expressionContainsJSX(expr.body);
|
|
20000
|
+
case "FunctionExpression":
|
|
20001
|
+
if (Array.isArray(expr.body)) {
|
|
20002
|
+
return expr.body.some(
|
|
20003
|
+
(block) => block.instructions?.some((i) => expressionContainsJSX(i.value))
|
|
20004
|
+
);
|
|
20005
|
+
}
|
|
20006
|
+
return false;
|
|
19884
20007
|
default:
|
|
19885
20008
|
return false;
|
|
19886
20009
|
}
|
|
19887
20010
|
}
|
|
20011
|
+
function withNoMemoAndDynamicHooks(ctx, fn) {
|
|
20012
|
+
const prevNoMemo = ctx.noMemo;
|
|
20013
|
+
const prevDynamic = ctx.dynamicHookSlotDepth ?? 0;
|
|
20014
|
+
ctx.noMemo = true;
|
|
20015
|
+
ctx.dynamicHookSlotDepth = prevDynamic + 1;
|
|
20016
|
+
try {
|
|
20017
|
+
return fn();
|
|
20018
|
+
} finally {
|
|
20019
|
+
ctx.noMemo = prevNoMemo;
|
|
20020
|
+
ctx.dynamicHookSlotDepth = prevDynamic;
|
|
20021
|
+
}
|
|
20022
|
+
}
|
|
19888
20023
|
function functionContainsJSX(fn) {
|
|
19889
20024
|
for (const block of fn.blocks) {
|
|
19890
20025
|
for (const instr of block.instructions) {
|
|
@@ -20983,18 +21118,25 @@ function lowerTrackedExpression(expr, ctx) {
|
|
|
20983
21118
|
}
|
|
20984
21119
|
function lowerInstruction(instr, ctx) {
|
|
20985
21120
|
const { t: t2 } = ctx;
|
|
21121
|
+
const applyLoc = (stmt) => {
|
|
21122
|
+
if (!stmt) return stmt;
|
|
21123
|
+
const baseLoc = instr.loc ?? (instr.kind === "Assign" || instr.kind === "Expression" ? instr.value.loc : void 0);
|
|
21124
|
+
return setNodeLoc(stmt, baseLoc);
|
|
21125
|
+
};
|
|
20986
21126
|
if (instr.kind === "Assign") {
|
|
20987
21127
|
const baseName2 = deSSAVarName(instr.target.name);
|
|
20988
21128
|
const isFunctionDecl = instr.value.kind === "FunctionExpression" && (instr.declarationKind === "function" || !instr.declarationKind && instr.value.name === baseName2);
|
|
20989
21129
|
if (isFunctionDecl) {
|
|
20990
21130
|
const loweredFn = lowerExpression(instr.value, ctx);
|
|
20991
21131
|
if (t2.isFunctionExpression(loweredFn)) {
|
|
20992
|
-
return
|
|
20993
|
-
t2.
|
|
20994
|
-
|
|
20995
|
-
|
|
20996
|
-
|
|
20997
|
-
|
|
21132
|
+
return applyLoc(
|
|
21133
|
+
t2.functionDeclaration(
|
|
21134
|
+
t2.identifier(baseName2),
|
|
21135
|
+
loweredFn.params,
|
|
21136
|
+
loweredFn.body,
|
|
21137
|
+
loweredFn.generator ?? false,
|
|
21138
|
+
loweredFn.async ?? false
|
|
21139
|
+
)
|
|
20998
21140
|
);
|
|
20999
21141
|
}
|
|
21000
21142
|
}
|
|
@@ -21009,12 +21151,16 @@ function lowerInstruction(instr, ctx) {
|
|
|
21009
21151
|
ctx.memoVars?.add(baseName2);
|
|
21010
21152
|
}
|
|
21011
21153
|
if (declKind) {
|
|
21012
|
-
return
|
|
21013
|
-
t2.
|
|
21014
|
-
|
|
21154
|
+
return applyLoc(
|
|
21155
|
+
t2.variableDeclaration(declKind, [
|
|
21156
|
+
t2.variableDeclarator(t2.identifier(baseName2), hookMember.member)
|
|
21157
|
+
])
|
|
21158
|
+
);
|
|
21015
21159
|
}
|
|
21016
|
-
return
|
|
21017
|
-
t2.
|
|
21160
|
+
return applyLoc(
|
|
21161
|
+
t2.expressionStatement(
|
|
21162
|
+
t2.assignmentExpression("=", t2.identifier(baseName2), hookMember.member)
|
|
21163
|
+
)
|
|
21018
21164
|
);
|
|
21019
21165
|
}
|
|
21020
21166
|
if (instr.value.kind === "CallExpression" && instr.value.callee.kind === "Identifier" && isHookName(instr.value.callee.name)) {
|
|
@@ -21028,16 +21174,24 @@ function lowerInstruction(instr, ctx) {
|
|
|
21028
21174
|
}
|
|
21029
21175
|
}
|
|
21030
21176
|
if (ctx.signalVars?.has(baseName2)) {
|
|
21031
|
-
return
|
|
21032
|
-
t2.
|
|
21177
|
+
return applyLoc(
|
|
21178
|
+
t2.expressionStatement(
|
|
21179
|
+
t2.callExpression(t2.identifier(baseName2), [lowerTrackedExpression(instr.value, ctx)])
|
|
21180
|
+
)
|
|
21033
21181
|
);
|
|
21034
21182
|
}
|
|
21035
|
-
return
|
|
21036
|
-
t2.
|
|
21183
|
+
return applyLoc(
|
|
21184
|
+
t2.expressionStatement(
|
|
21185
|
+
t2.assignmentExpression(
|
|
21186
|
+
"=",
|
|
21187
|
+
t2.identifier(baseName2),
|
|
21188
|
+
lowerTrackedExpression(instr.value, ctx)
|
|
21189
|
+
)
|
|
21190
|
+
)
|
|
21037
21191
|
);
|
|
21038
21192
|
}
|
|
21039
21193
|
if (instr.kind === "Expression") {
|
|
21040
|
-
return t2.expressionStatement(lowerTrackedExpression(instr.value, ctx));
|
|
21194
|
+
return applyLoc(t2.expressionStatement(lowerTrackedExpression(instr.value, ctx)));
|
|
21041
21195
|
}
|
|
21042
21196
|
if (instr.kind === "Phi") {
|
|
21043
21197
|
return null;
|
|
@@ -21046,6 +21200,9 @@ function lowerInstruction(instr, ctx) {
|
|
|
21046
21200
|
}
|
|
21047
21201
|
function lowerTerminator(block, ctx) {
|
|
21048
21202
|
const { t: t2 } = ctx;
|
|
21203
|
+
const baseLoc = block.terminator.loc ?? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21204
|
+
block.terminator.argument?.loc;
|
|
21205
|
+
const applyLoc = (stmts) => stmts.map((stmt) => setNodeLoc(stmt, baseLoc));
|
|
21049
21206
|
switch (block.terminator.kind) {
|
|
21050
21207
|
case "Return": {
|
|
21051
21208
|
const prevRegion = ctx.currentRegion;
|
|
@@ -21058,14 +21215,14 @@ function lowerTerminator(block, ctx) {
|
|
|
21058
21215
|
}
|
|
21059
21216
|
ctx.inReturn = false;
|
|
21060
21217
|
ctx.currentRegion = prevRegion;
|
|
21061
|
-
return [t2.returnStatement(retExpr)];
|
|
21218
|
+
return applyLoc([t2.returnStatement(retExpr)]);
|
|
21062
21219
|
}
|
|
21063
21220
|
case "Throw":
|
|
21064
|
-
return [t2.throwStatement(lowerTrackedExpression(block.terminator.argument, ctx))];
|
|
21221
|
+
return applyLoc([t2.throwStatement(lowerTrackedExpression(block.terminator.argument, ctx))]);
|
|
21065
21222
|
case "Jump":
|
|
21066
|
-
return [t2.expressionStatement(t2.stringLiteral(`jump ${block.terminator.target}`))];
|
|
21223
|
+
return applyLoc([t2.expressionStatement(t2.stringLiteral(`jump ${block.terminator.target}`))]);
|
|
21067
21224
|
case "Branch":
|
|
21068
|
-
return [
|
|
21225
|
+
return applyLoc([
|
|
21069
21226
|
t2.ifStatement(
|
|
21070
21227
|
lowerTrackedExpression(block.terminator.test, ctx),
|
|
21071
21228
|
t2.blockStatement([
|
|
@@ -21075,9 +21232,9 @@ function lowerTerminator(block, ctx) {
|
|
|
21075
21232
|
t2.expressionStatement(t2.stringLiteral(`goto ${block.terminator.alternate}`))
|
|
21076
21233
|
])
|
|
21077
21234
|
)
|
|
21078
|
-
];
|
|
21235
|
+
]);
|
|
21079
21236
|
case "Switch":
|
|
21080
|
-
return [
|
|
21237
|
+
return applyLoc([
|
|
21081
21238
|
t2.switchStatement(
|
|
21082
21239
|
lowerTrackedExpression(block.terminator.discriminant, ctx),
|
|
21083
21240
|
block.terminator.cases.map(
|
|
@@ -21086,30 +21243,30 @@ function lowerTerminator(block, ctx) {
|
|
|
21086
21243
|
])
|
|
21087
21244
|
)
|
|
21088
21245
|
)
|
|
21089
|
-
];
|
|
21246
|
+
]);
|
|
21090
21247
|
case "ForOf": {
|
|
21091
21248
|
const term = block.terminator;
|
|
21092
21249
|
const varKind = term.variableKind ?? "const";
|
|
21093
21250
|
const leftPattern = term.pattern ? term.pattern : t2.identifier(term.variable);
|
|
21094
|
-
return [
|
|
21251
|
+
return applyLoc([
|
|
21095
21252
|
t2.forOfStatement(
|
|
21096
21253
|
t2.variableDeclaration(varKind, [t2.variableDeclarator(leftPattern)]),
|
|
21097
21254
|
lowerExpression(term.iterable, ctx),
|
|
21098
21255
|
t2.blockStatement([t2.expressionStatement(t2.stringLiteral(`body ${term.body}`))])
|
|
21099
21256
|
)
|
|
21100
|
-
];
|
|
21257
|
+
]);
|
|
21101
21258
|
}
|
|
21102
21259
|
case "ForIn": {
|
|
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.forInStatement(
|
|
21108
21265
|
t2.variableDeclaration(varKind, [t2.variableDeclarator(leftPattern)]),
|
|
21109
21266
|
lowerExpression(term.object, ctx),
|
|
21110
21267
|
t2.blockStatement([t2.expressionStatement(t2.stringLiteral(`body ${term.body}`))])
|
|
21111
21268
|
)
|
|
21112
|
-
];
|
|
21269
|
+
]);
|
|
21113
21270
|
}
|
|
21114
21271
|
case "Try": {
|
|
21115
21272
|
const term = block.terminator;
|
|
@@ -21125,20 +21282,20 @@ function lowerTerminator(block, ctx) {
|
|
|
21125
21282
|
const finallyBlock = term.finallyBlock !== void 0 ? t2.blockStatement([
|
|
21126
21283
|
t2.expressionStatement(t2.stringLiteral(`finally ${term.finallyBlock}`))
|
|
21127
21284
|
]) : null;
|
|
21128
|
-
return [t2.tryStatement(tryBlock, catchClause, finallyBlock)];
|
|
21285
|
+
return applyLoc([t2.tryStatement(tryBlock, catchClause, finallyBlock)]);
|
|
21129
21286
|
}
|
|
21130
21287
|
case "Unreachable":
|
|
21131
|
-
return [];
|
|
21288
|
+
return applyLoc([]);
|
|
21132
21289
|
case "Break":
|
|
21133
|
-
return [
|
|
21290
|
+
return applyLoc([
|
|
21134
21291
|
t2.breakStatement(block.terminator.label ? t2.identifier(block.terminator.label) : null)
|
|
21135
|
-
];
|
|
21292
|
+
]);
|
|
21136
21293
|
case "Continue":
|
|
21137
|
-
return [
|
|
21294
|
+
return applyLoc([
|
|
21138
21295
|
t2.continueStatement(block.terminator.label ? t2.identifier(block.terminator.label) : null)
|
|
21139
|
-
];
|
|
21296
|
+
]);
|
|
21140
21297
|
default:
|
|
21141
|
-
return [];
|
|
21298
|
+
return applyLoc([]);
|
|
21142
21299
|
}
|
|
21143
21300
|
}
|
|
21144
21301
|
function attachHelperImports(ctx, body, t2) {
|
|
@@ -21277,7 +21434,7 @@ function lowerExpression(expr, ctx, isAssigned = false) {
|
|
|
21277
21434
|
}
|
|
21278
21435
|
ctx.expressionDepth = depth;
|
|
21279
21436
|
try {
|
|
21280
|
-
return lowerExpressionImpl(expr, ctx, isAssigned);
|
|
21437
|
+
return setNodeLoc(lowerExpressionImpl(expr, ctx, isAssigned), expr.loc);
|
|
21281
21438
|
} finally {
|
|
21282
21439
|
ctx.expressionDepth = depth - 1;
|
|
21283
21440
|
}
|
|
@@ -21412,14 +21569,22 @@ function lowerExpressionImpl(expr, ctx, isAssigned = false) {
|
|
|
21412
21569
|
const calleeIsMemoAccessor = !!calleeName && ctx.memoVars?.has(calleeName);
|
|
21413
21570
|
const calleeIsSignalLike = !!calleeName && (ctx.signalVars?.has(calleeName) || ctx.storeVars?.has(calleeName));
|
|
21414
21571
|
if (calleeIsMemoAccessor && !calleeIsSignalLike && expr.arguments.length > 0) {
|
|
21415
|
-
const
|
|
21416
|
-
return t2.callExpression(t2.callExpression(t2.identifier(calleeName), []),
|
|
21572
|
+
const loweredArgs2 = expr.arguments.map((a) => lowerExpression(a, ctx));
|
|
21573
|
+
return t2.callExpression(t2.callExpression(t2.identifier(calleeName), []), loweredArgs2);
|
|
21417
21574
|
}
|
|
21418
21575
|
const lowerCallee = () => isIIFE ? withNonReactiveScope(ctx, () => lowerExpression(expr.callee, ctx)) : lowerExpression(expr.callee, ctx);
|
|
21419
|
-
|
|
21420
|
-
|
|
21421
|
-
|
|
21422
|
-
|
|
21576
|
+
const isIteratingMethod = expr.callee.kind === "MemberExpression" && (expr.callee.property.kind === "Identifier" && ["map", "reduce", "forEach", "filter", "flatMap", "some", "every", "find"].includes(
|
|
21577
|
+
expr.callee.property.name
|
|
21578
|
+
) || expr.callee.property.kind === "Literal" && ["map", "reduce", "forEach", "filter", "flatMap", "some", "every", "find"].includes(
|
|
21579
|
+
String(expr.callee.property.value)
|
|
21580
|
+
));
|
|
21581
|
+
const loweredArgs = expr.arguments.map((a, idx) => {
|
|
21582
|
+
if (idx === 0 && isIteratingMethod && (a.kind === "ArrowFunction" || a.kind === "FunctionExpression")) {
|
|
21583
|
+
return withNoMemoAndDynamicHooks(ctx, () => lowerExpression(a, ctx));
|
|
21584
|
+
}
|
|
21585
|
+
return lowerExpression(a, ctx);
|
|
21586
|
+
});
|
|
21587
|
+
return t2.callExpression(lowerCallee(), loweredArgs);
|
|
21423
21588
|
}
|
|
21424
21589
|
case "MemberExpression":
|
|
21425
21590
|
if (matchesListKeyPattern(expr, ctx)) {
|
|
@@ -21983,6 +22148,8 @@ function getDependencyPathFromNode(node, t2) {
|
|
|
21983
22148
|
if (node.computed) {
|
|
21984
22149
|
if (t2.isStringLiteral(property) || t2.isNumericLiteral(property)) {
|
|
21985
22150
|
propName = String(property.value);
|
|
22151
|
+
} else {
|
|
22152
|
+
return objectPath;
|
|
21986
22153
|
}
|
|
21987
22154
|
} else if (t2.isIdentifier(property)) {
|
|
21988
22155
|
propName = property.name;
|
|
@@ -22099,10 +22266,12 @@ function replaceIdentifiersWithOverrides(node, overrides, t2, parentKind, parent
|
|
|
22099
22266
|
return names;
|
|
22100
22267
|
};
|
|
22101
22268
|
if (!skipCurrentNode && (t2.isMemberExpression(node) || t2.isOptionalMemberExpression(node))) {
|
|
22269
|
+
const propertyNode = node.property;
|
|
22270
|
+
const isDynamicComputed = (node.computed ?? false) && !t2.isStringLiteral(propertyNode) && !t2.isNumericLiteral(propertyNode);
|
|
22102
22271
|
const path = getDependencyPathFromNode(node, t2);
|
|
22103
22272
|
const normalized = path ? normalizeDependencyKey2(path) : null;
|
|
22104
22273
|
const override = normalized && overrides[normalized] || (path ? overrides[path] : void 0);
|
|
22105
|
-
if (override && !isCallTarget) {
|
|
22274
|
+
if (override && !isCallTarget && !isDynamicComputed) {
|
|
22106
22275
|
const replacement = override();
|
|
22107
22276
|
Object.assign(node, replacement);
|
|
22108
22277
|
return;
|
|
@@ -22272,15 +22441,6 @@ function isStaticValue(expr) {
|
|
|
22272
22441
|
if (!expr) return false;
|
|
22273
22442
|
return expr.kind === "Literal";
|
|
22274
22443
|
}
|
|
22275
|
-
function isComponentLikeCallee(expr) {
|
|
22276
|
-
if (expr.kind === "Identifier") {
|
|
22277
|
-
return expr.name[0] === expr.name[0]?.toUpperCase();
|
|
22278
|
-
}
|
|
22279
|
-
if (expr.kind === "MemberExpression" || expr.kind === "OptionalMemberExpression") {
|
|
22280
|
-
return isComponentLikeCallee(expr.object);
|
|
22281
|
-
}
|
|
22282
|
-
return false;
|
|
22283
|
-
}
|
|
22284
22444
|
function isLikelyTextExpression(expr, ctx) {
|
|
22285
22445
|
let ok = true;
|
|
22286
22446
|
const isReactiveIdentifier = (name) => {
|
|
@@ -22309,15 +22469,9 @@ function isLikelyTextExpression(expr, ctx) {
|
|
|
22309
22469
|
ok = false;
|
|
22310
22470
|
return;
|
|
22311
22471
|
case "CallExpression":
|
|
22312
|
-
case "OptionalCallExpression":
|
|
22313
|
-
|
|
22314
|
-
ok = false;
|
|
22315
|
-
return;
|
|
22316
|
-
}
|
|
22317
|
-
visit(node.callee, true);
|
|
22318
|
-
node.arguments.forEach((arg) => visit(arg));
|
|
22472
|
+
case "OptionalCallExpression":
|
|
22473
|
+
ok = false;
|
|
22319
22474
|
return;
|
|
22320
|
-
}
|
|
22321
22475
|
case "MemberExpression":
|
|
22322
22476
|
case "OptionalMemberExpression":
|
|
22323
22477
|
visit(node.object, true);
|
|
@@ -22772,7 +22926,12 @@ function lowerIntrinsicElement(jsx, ctx) {
|
|
|
22772
22926
|
t2.arrowFunctionExpression([], body)
|
|
22773
22927
|
];
|
|
22774
22928
|
if (ctx.isComponentFn) {
|
|
22775
|
-
|
|
22929
|
+
{
|
|
22930
|
+
const slot = reserveHookSlot2(ctx);
|
|
22931
|
+
if (slot >= 0) {
|
|
22932
|
+
memoArgs.push(t2.numericLiteral(slot));
|
|
22933
|
+
}
|
|
22934
|
+
}
|
|
22776
22935
|
}
|
|
22777
22936
|
return t2.callExpression(t2.callExpression(t2.identifier(RUNTIME_ALIASES.useMemo), memoArgs), []);
|
|
22778
22937
|
}
|
|
@@ -23327,12 +23486,16 @@ function emitListChild(parentId, markerId, expr, statements, ctx) {
|
|
|
23327
23486
|
const hoistedStatements = ctx.hoistedTemplateStatements;
|
|
23328
23487
|
ctx.hoistedTemplates = prevHoistedTemplates;
|
|
23329
23488
|
ctx.hoistedTemplateStatements = prevHoistedTemplateStatements;
|
|
23330
|
-
if (
|
|
23331
|
-
const firstParam = callbackExpr.params
|
|
23489
|
+
if (t2.isArrowFunctionExpression(callbackExpr) || t2.isFunctionExpression(callbackExpr)) {
|
|
23490
|
+
const [firstParam, secondParam] = callbackExpr.params;
|
|
23491
|
+
const overrides = {};
|
|
23332
23492
|
if (t2.isIdentifier(firstParam)) {
|
|
23333
|
-
|
|
23334
|
-
|
|
23335
|
-
|
|
23493
|
+
overrides[firstParam.name] = () => t2.callExpression(t2.identifier(firstParam.name), []);
|
|
23494
|
+
}
|
|
23495
|
+
if (t2.isIdentifier(secondParam)) {
|
|
23496
|
+
overrides[secondParam.name] = () => t2.callExpression(t2.identifier(secondParam.name), []);
|
|
23497
|
+
}
|
|
23498
|
+
if (Object.keys(overrides).length > 0) {
|
|
23336
23499
|
if (t2.isBlockStatement(callbackExpr.body)) {
|
|
23337
23500
|
replaceIdentifiersWithOverrides(callbackExpr.body, overrides, t2, callbackExpr.type, "body");
|
|
23338
23501
|
} else {
|
|
@@ -23579,8 +23742,11 @@ function lowerHIRWithRegions(program, t2, options) {
|
|
|
23579
23742
|
for (const stmt of originalBody) {
|
|
23580
23743
|
if (t2.isVariableDeclaration(stmt)) {
|
|
23581
23744
|
for (const decl of stmt.declarations) {
|
|
23582
|
-
if (t2.isIdentifier(decl.id) && decl.init && t2.isCallExpression(decl.init) && t2.isIdentifier(decl.init.callee) && decl.init.callee.name === "$state") {
|
|
23745
|
+
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")) {
|
|
23583
23746
|
ctx.trackedVars.add(decl.id.name);
|
|
23747
|
+
if (decl.init.callee.name === "$store") {
|
|
23748
|
+
ctx.storeVars?.add(decl.id.name);
|
|
23749
|
+
}
|
|
23584
23750
|
}
|
|
23585
23751
|
}
|
|
23586
23752
|
}
|
|
@@ -24223,10 +24389,9 @@ function lowerFunctionWithRegions(fn, ctx) {
|
|
|
24223
24389
|
}
|
|
24224
24390
|
}
|
|
24225
24391
|
const params = finalParams;
|
|
24226
|
-
const funcDecl =
|
|
24227
|
-
t2.identifier(fn.name ?? "fn"),
|
|
24228
|
-
|
|
24229
|
-
t2.blockStatement(statements)
|
|
24392
|
+
const funcDecl = setNodeLoc(
|
|
24393
|
+
t2.functionDeclaration(t2.identifier(fn.name ?? "fn"), params, t2.blockStatement(statements)),
|
|
24394
|
+
fn.loc
|
|
24230
24395
|
);
|
|
24231
24396
|
ctx.needsCtx = prevNeedsCtx;
|
|
24232
24397
|
ctx.shadowedNames = prevShadowed;
|
|
@@ -24315,10 +24480,44 @@ function isInsideNestedFunction(path) {
|
|
|
24315
24480
|
function isInsideJSX(path) {
|
|
24316
24481
|
return !!path.findParent((p) => p.isJSXElement?.() || p.isJSXFragment?.());
|
|
24317
24482
|
}
|
|
24318
|
-
function
|
|
24319
|
-
if (!
|
|
24483
|
+
function parseSuppressionCodes(raw) {
|
|
24484
|
+
if (!raw) return void 0;
|
|
24485
|
+
const codes = raw.split(/[,\s]+/).map((c) => c.trim()).filter(Boolean);
|
|
24486
|
+
return codes.length > 0 ? new Set(codes) : void 0;
|
|
24487
|
+
}
|
|
24488
|
+
function parseSuppressions(comments) {
|
|
24489
|
+
if (!comments) return [];
|
|
24490
|
+
const suppressions = [];
|
|
24491
|
+
for (const comment of comments) {
|
|
24492
|
+
const match = comment.value.match(/fict-ignore(-next-line)?(?:\s+(.+))?/i);
|
|
24493
|
+
if (!match || !comment.loc) continue;
|
|
24494
|
+
suppressions.push({
|
|
24495
|
+
line: comment.loc.start.line,
|
|
24496
|
+
nextLine: !!match[1],
|
|
24497
|
+
codes: parseSuppressionCodes(match[2])
|
|
24498
|
+
});
|
|
24499
|
+
}
|
|
24500
|
+
return suppressions;
|
|
24501
|
+
}
|
|
24502
|
+
function shouldSuppressWarning(suppressions, code, line) {
|
|
24503
|
+
return suppressions.some((entry) => {
|
|
24504
|
+
const targetLine = entry.nextLine ? entry.line + 1 : entry.line;
|
|
24505
|
+
if (targetLine !== line) return false;
|
|
24506
|
+
if (!entry.codes || entry.codes.size === 0) return true;
|
|
24507
|
+
return entry.codes.has(code);
|
|
24508
|
+
});
|
|
24509
|
+
}
|
|
24510
|
+
function createWarningDispatcher(onWarn, suppressions) {
|
|
24511
|
+
if (!onWarn) return () => {
|
|
24512
|
+
};
|
|
24513
|
+
return (warning) => {
|
|
24514
|
+
if (shouldSuppressWarning(suppressions, warning.code, warning.line)) return;
|
|
24515
|
+
onWarn(warning);
|
|
24516
|
+
};
|
|
24517
|
+
}
|
|
24518
|
+
function emitWarning(node, code, message, warn, fileName) {
|
|
24320
24519
|
const loc = node.loc?.start;
|
|
24321
|
-
|
|
24520
|
+
warn({
|
|
24322
24521
|
code,
|
|
24323
24522
|
message,
|
|
24324
24523
|
fileName,
|
|
@@ -24406,8 +24605,7 @@ function isDynamicPropertyAccess(node, t2) {
|
|
|
24406
24605
|
if (!node.computed) return false;
|
|
24407
24606
|
return !(t2.isStringLiteral(node.property) || t2.isNumericLiteral(node.property));
|
|
24408
24607
|
}
|
|
24409
|
-
function runWarningPass(programPath, stateVars, derivedVars,
|
|
24410
|
-
const fileName = programPath.hub?.file?.opts?.filename || "<unknown>";
|
|
24608
|
+
function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t2) {
|
|
24411
24609
|
const isStateRoot = (expr) => {
|
|
24412
24610
|
const root = getRootIdentifier(expr, t2);
|
|
24413
24611
|
return !!(root && stateVars.has(root.name));
|
|
@@ -24423,7 +24621,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24423
24621
|
path.node,
|
|
24424
24622
|
"FICT-M",
|
|
24425
24623
|
"Direct mutation of nested property detected; use immutable update or $store helpers",
|
|
24426
|
-
|
|
24624
|
+
warn,
|
|
24427
24625
|
fileName
|
|
24428
24626
|
);
|
|
24429
24627
|
if (isDynamicPropertyAccess(left, t2)) {
|
|
@@ -24431,7 +24629,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24431
24629
|
path.node,
|
|
24432
24630
|
"FICT-H",
|
|
24433
24631
|
"Dynamic property access widens dependency tracking",
|
|
24434
|
-
|
|
24632
|
+
warn,
|
|
24435
24633
|
fileName
|
|
24436
24634
|
);
|
|
24437
24635
|
}
|
|
@@ -24446,7 +24644,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24446
24644
|
path.node,
|
|
24447
24645
|
"FICT-M",
|
|
24448
24646
|
"Direct mutation of nested property detected; use immutable update or $store helpers",
|
|
24449
|
-
|
|
24647
|
+
warn,
|
|
24450
24648
|
fileName
|
|
24451
24649
|
);
|
|
24452
24650
|
if (isDynamicPropertyAccess(arg, t2)) {
|
|
@@ -24454,7 +24652,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24454
24652
|
path.node,
|
|
24455
24653
|
"FICT-H",
|
|
24456
24654
|
"Dynamic property access widens dependency tracking",
|
|
24457
|
-
|
|
24655
|
+
warn,
|
|
24458
24656
|
fileName
|
|
24459
24657
|
);
|
|
24460
24658
|
}
|
|
@@ -24470,7 +24668,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24470
24668
|
path.node,
|
|
24471
24669
|
"FICT-H",
|
|
24472
24670
|
"Dynamic property access widens dependency tracking",
|
|
24473
|
-
|
|
24671
|
+
warn,
|
|
24474
24672
|
fileName
|
|
24475
24673
|
);
|
|
24476
24674
|
}
|
|
@@ -24499,7 +24697,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24499
24697
|
path.node,
|
|
24500
24698
|
"FICT-R005",
|
|
24501
24699
|
`Function captures reactive variable(s): ${Array.from(captured).join(", ")}. Pass them as parameters or memoize explicitly to avoid hidden dependencies.`,
|
|
24502
|
-
|
|
24700
|
+
warn,
|
|
24503
24701
|
fileName
|
|
24504
24702
|
);
|
|
24505
24703
|
}
|
|
@@ -24530,7 +24728,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24530
24728
|
path.node,
|
|
24531
24729
|
"FICT-E001",
|
|
24532
24730
|
"Effect has no reactive reads; it will run once. Consider removing $effect or adding dependencies.",
|
|
24533
|
-
|
|
24731
|
+
warn,
|
|
24534
24732
|
fileName
|
|
24535
24733
|
);
|
|
24536
24734
|
}
|
|
@@ -24556,7 +24754,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24556
24754
|
arg,
|
|
24557
24755
|
"FICT-H",
|
|
24558
24756
|
"State value passed to unknown function (black box); dependency tracking may be imprecise",
|
|
24559
|
-
|
|
24757
|
+
warn,
|
|
24560
24758
|
fileName
|
|
24561
24759
|
);
|
|
24562
24760
|
break;
|
|
@@ -24572,7 +24770,7 @@ function runWarningPass(programPath, stateVars, derivedVars, options, t2) {
|
|
|
24572
24770
|
path.node,
|
|
24573
24771
|
"FICT-H",
|
|
24574
24772
|
"Dynamic property access widens dependency tracking",
|
|
24575
|
-
|
|
24773
|
+
warn,
|
|
24576
24774
|
fileName
|
|
24577
24775
|
);
|
|
24578
24776
|
}
|
|
@@ -24622,19 +24820,97 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24622
24820
|
Program: {
|
|
24623
24821
|
exit(path) {
|
|
24624
24822
|
const fileName = path.hub?.file?.opts?.filename || "<unknown>";
|
|
24823
|
+
const comments = path.hub?.file?.ast?.comments || [];
|
|
24824
|
+
const suppressions = parseSuppressions(comments);
|
|
24825
|
+
const warn = createWarningDispatcher(options.onWarn, suppressions);
|
|
24826
|
+
const optionsWithWarnings = { ...options, onWarn: warn };
|
|
24827
|
+
const isHookName2 = (name) => !!name && /^use[A-Z]/.test(name);
|
|
24828
|
+
const getFunctionName = (fnPath) => {
|
|
24829
|
+
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;
|
|
24830
|
+
};
|
|
24831
|
+
const isComponentDefinition = (fnPath) => {
|
|
24832
|
+
const name = getFunctionName(fnPath);
|
|
24833
|
+
return name && isComponentName(name) || functionHasJSX(fnPath);
|
|
24834
|
+
};
|
|
24835
|
+
const isHookDefinition = (fnPath) => {
|
|
24836
|
+
const name = getFunctionName(fnPath);
|
|
24837
|
+
return isHookName2(name);
|
|
24838
|
+
};
|
|
24839
|
+
const isComponentOrHookDefinition = (fnPath) => isComponentDefinition(fnPath) || isHookDefinition(fnPath);
|
|
24625
24840
|
const isComponentLike = (fnPath) => {
|
|
24626
|
-
const name =
|
|
24627
|
-
return name && isComponentName(name) || functionHasJSX(fnPath) || functionUsesStateLike(fnPath, t2);
|
|
24841
|
+
const name = getFunctionName(fnPath);
|
|
24842
|
+
return name && isComponentName(name) || isHookName2(name) || functionHasJSX(fnPath) || functionUsesStateLike(fnPath, t2);
|
|
24628
24843
|
};
|
|
24629
24844
|
const memoHasSideEffects = (fn) => {
|
|
24845
|
+
const pureCalls = new Set(
|
|
24846
|
+
Array.from(SAFE_FUNCTIONS).filter(
|
|
24847
|
+
(name) => !name.startsWith("console.") && name !== "Math.random"
|
|
24848
|
+
)
|
|
24849
|
+
);
|
|
24850
|
+
const effectfulCalls = /* @__PURE__ */ new Set([
|
|
24851
|
+
"$effect",
|
|
24852
|
+
"render",
|
|
24853
|
+
"fetch",
|
|
24854
|
+
"setTimeout",
|
|
24855
|
+
"setInterval",
|
|
24856
|
+
"clearTimeout",
|
|
24857
|
+
"clearInterval",
|
|
24858
|
+
"requestAnimationFrame",
|
|
24859
|
+
"cancelAnimationFrame"
|
|
24860
|
+
]);
|
|
24861
|
+
const getCalleeName = (callee) => {
|
|
24862
|
+
if (t2.isIdentifier(callee)) return callee.name;
|
|
24863
|
+
if (t2.isMemberExpression(callee) && !callee.computed && t2.isIdentifier(callee.property) && t2.isIdentifier(callee.object)) {
|
|
24864
|
+
return `${callee.object.name}.${callee.property.name}`;
|
|
24865
|
+
}
|
|
24866
|
+
return null;
|
|
24867
|
+
};
|
|
24868
|
+
const mutatingMemberProps = /* @__PURE__ */ new Set([
|
|
24869
|
+
"push",
|
|
24870
|
+
"pop",
|
|
24871
|
+
"splice",
|
|
24872
|
+
"shift",
|
|
24873
|
+
"unshift",
|
|
24874
|
+
"sort",
|
|
24875
|
+
"reverse",
|
|
24876
|
+
"set",
|
|
24877
|
+
"add",
|
|
24878
|
+
"delete",
|
|
24879
|
+
"append",
|
|
24880
|
+
"appendChild",
|
|
24881
|
+
"remove",
|
|
24882
|
+
"removeChild",
|
|
24883
|
+
"setAttribute",
|
|
24884
|
+
"dispatchEvent",
|
|
24885
|
+
"replaceChildren",
|
|
24886
|
+
"replaceWith"
|
|
24887
|
+
]);
|
|
24888
|
+
const isEffectfulCall = (node) => {
|
|
24889
|
+
const name = getCalleeName(node.callee);
|
|
24890
|
+
if (!name) return true;
|
|
24891
|
+
if (pureCalls.has(name)) return false;
|
|
24892
|
+
if (effectfulCalls.has(name)) return true;
|
|
24893
|
+
if (name.startsWith("console.") || name.startsWith("document.") || name.startsWith("window.")) {
|
|
24894
|
+
return true;
|
|
24895
|
+
}
|
|
24896
|
+
if (t2.isMemberExpression(node.callee) && !node.callee.computed && t2.isIdentifier(node.callee.property)) {
|
|
24897
|
+
const prop = node.callee.property.name;
|
|
24898
|
+
if (mutatingMemberProps.has(prop)) return true;
|
|
24899
|
+
if (t2.isIdentifier(node.callee.object) && (node.callee.object.name === "document" || node.callee.object.name === "window")) {
|
|
24900
|
+
return true;
|
|
24901
|
+
}
|
|
24902
|
+
}
|
|
24903
|
+
return false;
|
|
24904
|
+
};
|
|
24630
24905
|
const checkNode = (node) => {
|
|
24631
24906
|
if (!node) return false;
|
|
24632
24907
|
if (t2.isAssignmentExpression(node) || t2.isUpdateExpression(node) || t2.isThrowStatement(node) || t2.isNewExpression(node)) {
|
|
24633
24908
|
return true;
|
|
24634
24909
|
}
|
|
24635
|
-
if (t2.isCallExpression(node) && (
|
|
24910
|
+
if (t2.isCallExpression(node) && isEffectfulCall(node)) {
|
|
24636
24911
|
return true;
|
|
24637
24912
|
}
|
|
24913
|
+
if (t2.isAwaitExpression(node)) return true;
|
|
24638
24914
|
if (t2.isExpressionStatement(node)) return checkNode(node.expression);
|
|
24639
24915
|
if (t2.isBlockStatement(node)) return node.body.some((stmt) => checkNode(stmt));
|
|
24640
24916
|
if (t2.isReturnStatement(node)) return checkNode(node.argument);
|
|
@@ -24658,7 +24934,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24658
24934
|
fnPath.node,
|
|
24659
24935
|
"FICT-C004",
|
|
24660
24936
|
"Component has no return statement and will render nothing.",
|
|
24661
|
-
|
|
24937
|
+
warn,
|
|
24662
24938
|
fileName
|
|
24663
24939
|
);
|
|
24664
24940
|
},
|
|
@@ -24676,7 +24952,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24676
24952
|
init,
|
|
24677
24953
|
"FICT-C004",
|
|
24678
24954
|
"Component has no return statement and will render nothing.",
|
|
24679
|
-
|
|
24955
|
+
warn,
|
|
24680
24956
|
fileName
|
|
24681
24957
|
);
|
|
24682
24958
|
}
|
|
@@ -24726,7 +25002,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24726
25002
|
}
|
|
24727
25003
|
}
|
|
24728
25004
|
if (hasKey || hasUnknownSpread) return;
|
|
24729
|
-
|
|
25005
|
+
warn({
|
|
24730
25006
|
code: "FICT-J002",
|
|
24731
25007
|
message: "Missing key prop in list rendering.",
|
|
24732
25008
|
fileName,
|
|
@@ -24751,6 +25027,12 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24751
25027
|
"Destructuring $state is not supported. Use a simple identifier."
|
|
24752
25028
|
);
|
|
24753
25029
|
}
|
|
25030
|
+
const ownerComponent = varPath.getFunctionParent();
|
|
25031
|
+
if (!ownerComponent || !isComponentOrHookDefinition(ownerComponent)) {
|
|
25032
|
+
throw varPath.buildCodeFrameError(
|
|
25033
|
+
"$state() must be declared inside a component or hook function body"
|
|
25034
|
+
);
|
|
25035
|
+
}
|
|
24754
25036
|
stateVars.add(varPath.node.id.name);
|
|
24755
25037
|
if (isInsideLoop(varPath) || isInsideConditional(varPath)) {
|
|
24756
25038
|
throw varPath.buildCodeFrameError(
|
|
@@ -24791,12 +25073,18 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24791
25073
|
fnPath.node,
|
|
24792
25074
|
"FICT-C003",
|
|
24793
25075
|
"Components should not be defined inside other components. Move this definition to module scope to preserve identity and performance.",
|
|
24794
|
-
|
|
25076
|
+
warn,
|
|
24795
25077
|
fileName
|
|
24796
25078
|
);
|
|
24797
25079
|
},
|
|
24798
25080
|
CallExpression(callPath) {
|
|
24799
25081
|
if (isStateCall(callPath.node, t2)) {
|
|
25082
|
+
const ownerComponent = callPath.getFunctionParent();
|
|
25083
|
+
if (!ownerComponent || !isComponentOrHookDefinition(ownerComponent)) {
|
|
25084
|
+
throw callPath.buildCodeFrameError(
|
|
25085
|
+
"$state() must be declared inside a component or hook function body"
|
|
25086
|
+
);
|
|
25087
|
+
}
|
|
24800
25088
|
if (isInsideLoop(callPath) || isInsideConditional(callPath)) {
|
|
24801
25089
|
throw callPath.buildCodeFrameError(
|
|
24802
25090
|
"$state() cannot be declared inside loops or conditionals"
|
|
@@ -24830,10 +25118,31 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24830
25118
|
callPath.node,
|
|
24831
25119
|
"FICT-R004",
|
|
24832
25120
|
"Reactive creation inside non-JSX control flow will not auto-dispose; wrap it in createScope/runInScope or move it into JSX-managed regions.",
|
|
24833
|
-
|
|
25121
|
+
warn,
|
|
24834
25122
|
fileName
|
|
24835
25123
|
);
|
|
24836
25124
|
}
|
|
25125
|
+
if (calleeId && isHookName2(calleeId)) {
|
|
25126
|
+
const binding = callPath.scope.getBinding(calleeId);
|
|
25127
|
+
const bindingPath = binding?.path;
|
|
25128
|
+
const bindingIsHook = !bindingPath && isHookName2(calleeId) || bindingPath?.isImportSpecifier() || bindingPath?.isImportDefaultSpecifier() || bindingPath?.isFunctionDeclaration() && isHookDefinition(bindingPath) || bindingPath?.isVariableDeclarator() && (() => {
|
|
25129
|
+
const init = bindingPath.get?.("init");
|
|
25130
|
+
return init ? isHookDefinition(init) : false;
|
|
25131
|
+
})();
|
|
25132
|
+
if (bindingIsHook) {
|
|
25133
|
+
const ownerFunction = callPath.getFunctionParent();
|
|
25134
|
+
if (!ownerFunction || !isComponentOrHookDefinition(ownerFunction)) {
|
|
25135
|
+
throw callPath.buildCodeFrameError(
|
|
25136
|
+
`${calleeId}() must be called inside a component or hook (useX)`
|
|
25137
|
+
);
|
|
25138
|
+
}
|
|
25139
|
+
if (isInsideLoop(callPath) || isInsideConditional(callPath) || isInsideNestedFunction(callPath)) {
|
|
25140
|
+
throw callPath.buildCodeFrameError(
|
|
25141
|
+
`${calleeId}() must be called at the top level of a component or hook (no loops/conditions/nested functions)`
|
|
25142
|
+
);
|
|
25143
|
+
}
|
|
25144
|
+
}
|
|
25145
|
+
}
|
|
24837
25146
|
const allowedStateCallees = /* @__PURE__ */ new Set([
|
|
24838
25147
|
"$effect",
|
|
24839
25148
|
"$memo",
|
|
@@ -24844,7 +25153,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24844
25153
|
callPath.node.arguments.forEach((arg) => {
|
|
24845
25154
|
if (t2.isIdentifier(arg) && stateVars.has(arg.name) && (!calleeId || !allowedStateCallees.has(calleeId))) {
|
|
24846
25155
|
const loc = arg.loc?.start ?? callPath.node.loc?.start;
|
|
24847
|
-
|
|
25156
|
+
warn({
|
|
24848
25157
|
code: "FICT-S002",
|
|
24849
25158
|
message: "State variable is passed as an argument; this passes a value snapshot and may escape component scope.",
|
|
24850
25159
|
fileName,
|
|
@@ -24857,7 +25166,7 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24857
25166
|
const firstArg = callPath.node.arguments[0];
|
|
24858
25167
|
if (firstArg && (t2.isArrowFunctionExpression(firstArg) || t2.isFunctionExpression(firstArg)) && memoHasSideEffects(firstArg)) {
|
|
24859
25168
|
const loc = firstArg.loc?.start ?? callPath.node.loc?.start;
|
|
24860
|
-
|
|
25169
|
+
warn({
|
|
24861
25170
|
code: "FICT-M003",
|
|
24862
25171
|
message: "Memo should not contain side effects.",
|
|
24863
25172
|
fileName,
|
|
@@ -24868,6 +25177,68 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24868
25177
|
}
|
|
24869
25178
|
}
|
|
24870
25179
|
});
|
|
25180
|
+
const aliasStack = [/* @__PURE__ */ new Set()];
|
|
25181
|
+
const currentAliasSet = () => aliasStack[aliasStack.length - 1];
|
|
25182
|
+
const rhsUsesState = (exprPath) => {
|
|
25183
|
+
if (!exprPath) return false;
|
|
25184
|
+
if (exprPath.isIdentifier() && t2.isIdentifier(exprPath.node) && stateVars.has(exprPath.node.name)) {
|
|
25185
|
+
return true;
|
|
25186
|
+
}
|
|
25187
|
+
let usesState = false;
|
|
25188
|
+
exprPath.traverse({
|
|
25189
|
+
Identifier(idPath) {
|
|
25190
|
+
if (stateVars.has(idPath.node.name)) {
|
|
25191
|
+
usesState = true;
|
|
25192
|
+
idPath.stop();
|
|
25193
|
+
}
|
|
25194
|
+
}
|
|
25195
|
+
});
|
|
25196
|
+
return usesState;
|
|
25197
|
+
};
|
|
25198
|
+
if (process.env.FICT_DEBUG_ALIAS) {
|
|
25199
|
+
console.log("[fict] alias check state vars", Array.from(stateVars));
|
|
25200
|
+
}
|
|
25201
|
+
path.traverse({
|
|
25202
|
+
Function: {
|
|
25203
|
+
enter() {
|
|
25204
|
+
aliasStack.push(/* @__PURE__ */ new Set());
|
|
25205
|
+
},
|
|
25206
|
+
exit() {
|
|
25207
|
+
aliasStack.pop();
|
|
25208
|
+
}
|
|
25209
|
+
},
|
|
25210
|
+
VariableDeclarator(varPath) {
|
|
25211
|
+
const aliasSet = currentAliasSet();
|
|
25212
|
+
if (aliasSet && t2.isIdentifier(varPath.node.id) && rhsUsesState(varPath.get("init"))) {
|
|
25213
|
+
if (process.env.FICT_DEBUG_ALIAS) {
|
|
25214
|
+
console.log("[fict] alias add from decl", varPath.node.id.name);
|
|
25215
|
+
}
|
|
25216
|
+
aliasSet.add(varPath.node.id.name);
|
|
25217
|
+
}
|
|
25218
|
+
},
|
|
25219
|
+
AssignmentExpression(assignPath) {
|
|
25220
|
+
const aliasSet = currentAliasSet();
|
|
25221
|
+
if (!aliasSet) return;
|
|
25222
|
+
if (!t2.isIdentifier(assignPath.node.left)) return;
|
|
25223
|
+
const targetName = assignPath.node.left.name;
|
|
25224
|
+
const rightPath = assignPath.get("right");
|
|
25225
|
+
if (rhsUsesState(rightPath)) {
|
|
25226
|
+
if (process.env.FICT_DEBUG_ALIAS) {
|
|
25227
|
+
console.log("[fict] alias add from assign", targetName);
|
|
25228
|
+
}
|
|
25229
|
+
aliasSet.add(targetName);
|
|
25230
|
+
return;
|
|
25231
|
+
}
|
|
25232
|
+
if (aliasSet.has(targetName)) {
|
|
25233
|
+
if (process.env.FICT_DEBUG_ALIAS) {
|
|
25234
|
+
console.log("[fict] alias reassignment detected", targetName);
|
|
25235
|
+
}
|
|
25236
|
+
throw assignPath.buildCodeFrameError(
|
|
25237
|
+
`Alias reassignment is not supported for "${targetName}"`
|
|
25238
|
+
);
|
|
25239
|
+
}
|
|
25240
|
+
}
|
|
25241
|
+
});
|
|
24871
25242
|
if (derivedVars.size > 0) {
|
|
24872
25243
|
path.traverse({
|
|
24873
25244
|
AssignmentExpression(assignPath) {
|
|
@@ -24900,13 +25271,15 @@ function createHIREntrypointVisitor(t2, options) {
|
|
|
24900
25271
|
}
|
|
24901
25272
|
});
|
|
24902
25273
|
}
|
|
24903
|
-
runWarningPass(path, stateVars, derivedVars,
|
|
25274
|
+
runWarningPass(path, stateVars, derivedVars, warn, fileName, t2);
|
|
24904
25275
|
const fileAst = t2.file(path.node);
|
|
24905
25276
|
const hir = buildHIR(fileAst);
|
|
24906
|
-
const lowered = lowerHIRWithRegions(hir, t2,
|
|
25277
|
+
const lowered = lowerHIRWithRegions(hir, t2, optionsWithWarnings);
|
|
24907
25278
|
path.node.body = lowered.program.body;
|
|
24908
25279
|
path.node.directives = lowered.program.directives;
|
|
24909
|
-
|
|
25280
|
+
if (!process.env.FICT_SKIP_SCOPE_CRAWL) {
|
|
25281
|
+
path.scope.crawl();
|
|
25282
|
+
}
|
|
24910
25283
|
stripMacroImports(path, t2);
|
|
24911
25284
|
}
|
|
24912
25285
|
}
|