@fictjs/compiler 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1226 -233
- package/dist/index.js +1226 -233
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -107,7 +107,7 @@ var require_generated = __commonJS({
|
|
|
107
107
|
});
|
|
108
108
|
exports2.isAccessor = isAccessor;
|
|
109
109
|
exports2.isAnyTypeAnnotation = isAnyTypeAnnotation;
|
|
110
|
-
exports2.isArgumentPlaceholder =
|
|
110
|
+
exports2.isArgumentPlaceholder = isArgumentPlaceholder2;
|
|
111
111
|
exports2.isArrayExpression = isArrayExpression2;
|
|
112
112
|
exports2.isArrayPattern = isArrayPattern4;
|
|
113
113
|
exports2.isArrayTypeAnnotation = isArrayTypeAnnotation;
|
|
@@ -131,7 +131,7 @@ var require_generated = __commonJS({
|
|
|
131
131
|
exports2.isClass = isClass;
|
|
132
132
|
exports2.isClassAccessorProperty = isClassAccessorProperty;
|
|
133
133
|
exports2.isClassBody = isClassBody;
|
|
134
|
-
exports2.isClassDeclaration =
|
|
134
|
+
exports2.isClassDeclaration = isClassDeclaration3;
|
|
135
135
|
exports2.isClassExpression = isClassExpression2;
|
|
136
136
|
exports2.isClassImplements = isClassImplements;
|
|
137
137
|
exports2.isClassMethod = isClassMethod;
|
|
@@ -161,7 +161,7 @@ var require_generated = __commonJS({
|
|
|
161
161
|
exports2.isDirectiveLiteral = isDirectiveLiteral;
|
|
162
162
|
exports2.isDoExpression = isDoExpression;
|
|
163
163
|
exports2.isDoWhileStatement = isDoWhileStatement2;
|
|
164
|
-
exports2.isEmptyStatement =
|
|
164
|
+
exports2.isEmptyStatement = isEmptyStatement2;
|
|
165
165
|
exports2.isEmptyTypeAnnotation = isEmptyTypeAnnotation;
|
|
166
166
|
exports2.isEnumBody = isEnumBody;
|
|
167
167
|
exports2.isEnumBooleanBody = isEnumBooleanBody;
|
|
@@ -232,14 +232,14 @@ var require_generated = __commonJS({
|
|
|
232
232
|
exports2.isJSXFragment = isJSXFragment2;
|
|
233
233
|
exports2.isJSXIdentifier = isJSXIdentifier2;
|
|
234
234
|
exports2.isJSXMemberExpression = isJSXMemberExpression2;
|
|
235
|
-
exports2.isJSXNamespacedName =
|
|
235
|
+
exports2.isJSXNamespacedName = isJSXNamespacedName2;
|
|
236
236
|
exports2.isJSXOpeningElement = isJSXOpeningElement;
|
|
237
237
|
exports2.isJSXOpeningFragment = isJSXOpeningFragment;
|
|
238
238
|
exports2.isJSXSpreadAttribute = isJSXSpreadAttribute2;
|
|
239
|
-
exports2.isJSXSpreadChild =
|
|
239
|
+
exports2.isJSXSpreadChild = isJSXSpreadChild2;
|
|
240
240
|
exports2.isJSXText = isJSXText2;
|
|
241
241
|
exports2.isLVal = isLVal;
|
|
242
|
-
exports2.isLabeledStatement =
|
|
242
|
+
exports2.isLabeledStatement = isLabeledStatement2;
|
|
243
243
|
exports2.isLiteral = isLiteral;
|
|
244
244
|
exports2.isLogicalExpression = isLogicalExpression2;
|
|
245
245
|
exports2.isLoop = isLoop;
|
|
@@ -277,7 +277,7 @@ var require_generated = __commonJS({
|
|
|
277
277
|
exports2.isOptionalMemberExpression = isOptionalMemberExpression2;
|
|
278
278
|
exports2.isParenthesizedExpression = isParenthesizedExpression2;
|
|
279
279
|
exports2.isPattern = isPattern2;
|
|
280
|
-
exports2.isPatternLike =
|
|
280
|
+
exports2.isPatternLike = isPatternLike3;
|
|
281
281
|
exports2.isPipelineBareFunction = isPipelineBareFunction;
|
|
282
282
|
exports2.isPipelinePrimaryTopicReference = isPipelinePrimaryTopicReference;
|
|
283
283
|
exports2.isPipelineTopicExpression = isPipelineTopicExpression;
|
|
@@ -485,7 +485,7 @@ var require_generated = __commonJS({
|
|
|
485
485
|
if (node.type !== "DoWhileStatement") return false;
|
|
486
486
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
487
487
|
}
|
|
488
|
-
function
|
|
488
|
+
function isEmptyStatement2(node, opts) {
|
|
489
489
|
if (!node) return false;
|
|
490
490
|
if (node.type !== "EmptyStatement") return false;
|
|
491
491
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
@@ -530,7 +530,7 @@ var require_generated = __commonJS({
|
|
|
530
530
|
if (node.type !== "IfStatement") return false;
|
|
531
531
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
532
532
|
}
|
|
533
|
-
function
|
|
533
|
+
function isLabeledStatement2(node, opts) {
|
|
534
534
|
if (!node) return false;
|
|
535
535
|
if (node.type !== "LabeledStatement") return false;
|
|
536
536
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
@@ -695,7 +695,7 @@ var require_generated = __commonJS({
|
|
|
695
695
|
if (node.type !== "ClassExpression") return false;
|
|
696
696
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
697
697
|
}
|
|
698
|
-
function
|
|
698
|
+
function isClassDeclaration3(node, opts) {
|
|
699
699
|
if (!node) return false;
|
|
700
700
|
if (node.type !== "ClassDeclaration") return false;
|
|
701
701
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
@@ -1210,7 +1210,7 @@ var require_generated = __commonJS({
|
|
|
1210
1210
|
if (node.type !== "JSXExpressionContainer") return false;
|
|
1211
1211
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
1212
1212
|
}
|
|
1213
|
-
function
|
|
1213
|
+
function isJSXSpreadChild2(node, opts) {
|
|
1214
1214
|
if (!node) return false;
|
|
1215
1215
|
if (node.type !== "JSXSpreadChild") return false;
|
|
1216
1216
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
@@ -1225,7 +1225,7 @@ var require_generated = __commonJS({
|
|
|
1225
1225
|
if (node.type !== "JSXMemberExpression") return false;
|
|
1226
1226
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
1227
1227
|
}
|
|
1228
|
-
function
|
|
1228
|
+
function isJSXNamespacedName2(node, opts) {
|
|
1229
1229
|
if (!node) return false;
|
|
1230
1230
|
if (node.type !== "JSXNamespacedName") return false;
|
|
1231
1231
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
@@ -1275,7 +1275,7 @@ var require_generated = __commonJS({
|
|
|
1275
1275
|
if (node.type !== "V8IntrinsicIdentifier") return false;
|
|
1276
1276
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
1277
1277
|
}
|
|
1278
|
-
function
|
|
1278
|
+
function isArgumentPlaceholder2(node, opts) {
|
|
1279
1279
|
if (!node) return false;
|
|
1280
1280
|
if (node.type !== "ArgumentPlaceholder") return false;
|
|
1281
1281
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
@@ -2216,7 +2216,7 @@ var require_generated = __commonJS({
|
|
|
2216
2216
|
}
|
|
2217
2217
|
return opts == null || (0, _shallowEqual.default)(node, opts);
|
|
2218
2218
|
}
|
|
2219
|
-
function
|
|
2219
|
+
function isPatternLike3(node, opts) {
|
|
2220
2220
|
if (!node) return false;
|
|
2221
2221
|
switch (node.type) {
|
|
2222
2222
|
case "Identifier":
|
|
@@ -7191,7 +7191,7 @@ var require_lowercase = __commonJS({
|
|
|
7191
7191
|
exports2.classAccessorProperty = classAccessorProperty;
|
|
7192
7192
|
exports2.classBody = classBody;
|
|
7193
7193
|
exports2.classDeclaration = classDeclaration;
|
|
7194
|
-
exports2.classExpression =
|
|
7194
|
+
exports2.classExpression = classExpression2;
|
|
7195
7195
|
exports2.classImplements = classImplements;
|
|
7196
7196
|
exports2.classMethod = classMethod;
|
|
7197
7197
|
exports2.classPrivateMethod = classPrivateMethod;
|
|
@@ -8053,7 +8053,7 @@ var require_lowercase = __commonJS({
|
|
|
8053
8053
|
validate(defs.body, node, "body", body, 1);
|
|
8054
8054
|
return node;
|
|
8055
8055
|
}
|
|
8056
|
-
function
|
|
8056
|
+
function classExpression2(id = null, superClass = null, body, decorators = null) {
|
|
8057
8057
|
const node = {
|
|
8058
8058
|
type: "ClassExpression",
|
|
8059
8059
|
id,
|
|
@@ -14611,6 +14611,14 @@ function parseFictReturnAnnotation(node) {
|
|
|
14611
14611
|
}
|
|
14612
14612
|
function extractIdentifiersFromPattern(pattern) {
|
|
14613
14613
|
const ids = [];
|
|
14614
|
+
if (t.isRestElement(pattern)) {
|
|
14615
|
+
if (t.isIdentifier(pattern.argument)) {
|
|
14616
|
+
ids.push({ kind: "Identifier", name: pattern.argument.name });
|
|
14617
|
+
} else if (t.isPatternLike(pattern.argument)) {
|
|
14618
|
+
ids.push(...extractIdentifiersFromPattern(pattern.argument));
|
|
14619
|
+
}
|
|
14620
|
+
return ids;
|
|
14621
|
+
}
|
|
14614
14622
|
if (t.isObjectPattern(pattern)) {
|
|
14615
14623
|
for (const prop of pattern.properties) {
|
|
14616
14624
|
if (t.isObjectProperty(prop)) {
|
|
@@ -14619,14 +14627,18 @@ function extractIdentifiersFromPattern(pattern) {
|
|
|
14619
14627
|
} else if (t.isAssignmentPattern(prop.value)) {
|
|
14620
14628
|
if (t.isIdentifier(prop.value.left)) {
|
|
14621
14629
|
ids.push({ kind: "Identifier", name: prop.value.left.name });
|
|
14622
|
-
} else if (t.
|
|
14630
|
+
} else if (t.isPatternLike(prop.value.left)) {
|
|
14623
14631
|
ids.push(...extractIdentifiersFromPattern(prop.value.left));
|
|
14624
14632
|
}
|
|
14625
|
-
} else if (t.
|
|
14633
|
+
} else if (t.isPatternLike(prop.value)) {
|
|
14626
14634
|
ids.push(...extractIdentifiersFromPattern(prop.value));
|
|
14627
14635
|
}
|
|
14628
|
-
} else if (t.isRestElement(prop)
|
|
14629
|
-
|
|
14636
|
+
} else if (t.isRestElement(prop)) {
|
|
14637
|
+
if (t.isIdentifier(prop.argument)) {
|
|
14638
|
+
ids.push({ kind: "Identifier", name: prop.argument.name });
|
|
14639
|
+
} else if (t.isPatternLike(prop.argument)) {
|
|
14640
|
+
ids.push(...extractIdentifiersFromPattern(prop.argument));
|
|
14641
|
+
}
|
|
14630
14642
|
}
|
|
14631
14643
|
}
|
|
14632
14644
|
} else if (t.isArrayPattern(pattern)) {
|
|
@@ -14634,16 +14646,20 @@ function extractIdentifiersFromPattern(pattern) {
|
|
|
14634
14646
|
if (!elem) continue;
|
|
14635
14647
|
if (t.isIdentifier(elem)) {
|
|
14636
14648
|
ids.push({ kind: "Identifier", name: elem.name });
|
|
14637
|
-
} else if (t.
|
|
14649
|
+
} else if (t.isRestElement(elem)) {
|
|
14650
|
+
if (t.isIdentifier(elem.argument)) {
|
|
14651
|
+
ids.push({ kind: "Identifier", name: elem.argument.name });
|
|
14652
|
+
} else if (t.isPatternLike(elem.argument)) {
|
|
14653
|
+
ids.push(...extractIdentifiersFromPattern(elem.argument));
|
|
14654
|
+
}
|
|
14655
|
+
} else if (t.isPatternLike(elem)) {
|
|
14638
14656
|
ids.push(...extractIdentifiersFromPattern(elem));
|
|
14639
|
-
} else if (t.isRestElement(elem) && t.isIdentifier(elem.argument)) {
|
|
14640
|
-
ids.push({ kind: "Identifier", name: elem.argument.name });
|
|
14641
14657
|
}
|
|
14642
14658
|
}
|
|
14643
14659
|
} else if (t.isAssignmentPattern(pattern)) {
|
|
14644
14660
|
if (t.isIdentifier(pattern.left)) {
|
|
14645
14661
|
ids.push({ kind: "Identifier", name: pattern.left.name });
|
|
14646
|
-
} else if (t.
|
|
14662
|
+
} else if (t.isPatternLike(pattern.left)) {
|
|
14647
14663
|
ids.push(...extractIdentifiersFromPattern(pattern.left));
|
|
14648
14664
|
}
|
|
14649
14665
|
}
|
|
@@ -14829,8 +14845,12 @@ function convertFunction(name, params, body, options) {
|
|
|
14829
14845
|
} else if (t.isObjectPattern(p.left) || t.isArrayPattern(p.left)) {
|
|
14830
14846
|
paramIds.push(...extractIdentifiersFromPattern(p.left));
|
|
14831
14847
|
}
|
|
14832
|
-
} else if (t.isRestElement(p)
|
|
14833
|
-
|
|
14848
|
+
} else if (t.isRestElement(p)) {
|
|
14849
|
+
if (t.isIdentifier(p.argument)) {
|
|
14850
|
+
paramIds.push({ kind: "Identifier", name: p.argument.name });
|
|
14851
|
+
} else if (t.isPattern(p.argument)) {
|
|
14852
|
+
paramIds.push(...extractIdentifiersFromPattern(p.argument));
|
|
14853
|
+
}
|
|
14834
14854
|
}
|
|
14835
14855
|
}
|
|
14836
14856
|
const bodyStatements = [...body];
|
|
@@ -14915,8 +14935,21 @@ function convertFunction(name, params, body, options) {
|
|
|
14915
14935
|
const excludeKeys = [];
|
|
14916
14936
|
decl.id.properties.forEach((prop) => {
|
|
14917
14937
|
if (t.isObjectProperty(prop)) {
|
|
14938
|
+
if (prop.computed) {
|
|
14939
|
+
reportUnsupportedExpression(
|
|
14940
|
+
prop.key,
|
|
14941
|
+
"Computed keys in object destructuring are not supported in HIR conversion."
|
|
14942
|
+
);
|
|
14943
|
+
return;
|
|
14944
|
+
}
|
|
14918
14945
|
const keyName = t.isIdentifier(prop.key) ? prop.key.name : t.isStringLiteral(prop.key) ? prop.key.value : t.isNumericLiteral(prop.key) ? String(prop.key.value) : null;
|
|
14919
|
-
if (!keyName)
|
|
14946
|
+
if (!keyName) {
|
|
14947
|
+
reportUnsupportedExpression(
|
|
14948
|
+
prop.key,
|
|
14949
|
+
"Unsupported object destructuring key in HIR conversion."
|
|
14950
|
+
);
|
|
14951
|
+
return;
|
|
14952
|
+
}
|
|
14920
14953
|
excludeKeys.push(t.stringLiteral(keyName));
|
|
14921
14954
|
if (t.isIdentifier(prop.value)) {
|
|
14922
14955
|
const memberExpr = t.memberExpression(
|
|
@@ -14930,8 +14963,21 @@ function convertFunction(name, params, body, options) {
|
|
|
14930
14963
|
value: convertExpression(memberExpr),
|
|
14931
14964
|
declarationKind: declKind
|
|
14932
14965
|
});
|
|
14966
|
+
} else {
|
|
14967
|
+
reportUnsupportedExpression(
|
|
14968
|
+
prop.value,
|
|
14969
|
+
"Unsupported object destructuring pattern in HIR conversion."
|
|
14970
|
+
);
|
|
14971
|
+
return;
|
|
14972
|
+
}
|
|
14973
|
+
} else if (t.isRestElement(prop)) {
|
|
14974
|
+
if (!t.isIdentifier(prop.argument)) {
|
|
14975
|
+
reportUnsupportedExpression(
|
|
14976
|
+
prop.argument,
|
|
14977
|
+
"Rest destructuring patterns must be identifiers in HIR conversion."
|
|
14978
|
+
);
|
|
14979
|
+
return;
|
|
14933
14980
|
}
|
|
14934
|
-
} else if (t.isRestElement(prop) && t.isIdentifier(prop.argument)) {
|
|
14935
14981
|
const restExpr = t.callExpression(t.identifier("__fictPropsRest"), [
|
|
14936
14982
|
useTemp ? t.identifier(tempName) : babelSourceExpr,
|
|
14937
14983
|
t.arrayExpression(excludeKeys)
|
|
@@ -14942,6 +14988,12 @@ function convertFunction(name, params, body, options) {
|
|
|
14942
14988
|
value: convertExpression(restExpr),
|
|
14943
14989
|
declarationKind: declKind
|
|
14944
14990
|
});
|
|
14991
|
+
} else {
|
|
14992
|
+
reportUnsupportedExpression(
|
|
14993
|
+
prop,
|
|
14994
|
+
"Unsupported object destructuring property in HIR conversion."
|
|
14995
|
+
);
|
|
14996
|
+
return;
|
|
14945
14997
|
}
|
|
14946
14998
|
});
|
|
14947
14999
|
}
|
|
@@ -14967,7 +15019,14 @@ function convertFunction(name, params, body, options) {
|
|
|
14967
15019
|
value: convertExpression(memberExpr),
|
|
14968
15020
|
declarationKind: declKind
|
|
14969
15021
|
});
|
|
14970
|
-
} else if (t.isRestElement(elem)
|
|
15022
|
+
} else if (t.isRestElement(elem)) {
|
|
15023
|
+
if (!t.isIdentifier(elem.argument)) {
|
|
15024
|
+
reportUnsupportedExpression(
|
|
15025
|
+
elem.argument,
|
|
15026
|
+
"Rest destructuring patterns must be identifiers in HIR conversion."
|
|
15027
|
+
);
|
|
15028
|
+
return;
|
|
15029
|
+
}
|
|
14971
15030
|
const sliceCall = t.callExpression(
|
|
14972
15031
|
t.memberExpression(t.identifier(tempName), t.identifier("slice")),
|
|
14973
15032
|
[t.numericLiteral(index)]
|
|
@@ -14978,6 +15037,12 @@ function convertFunction(name, params, body, options) {
|
|
|
14978
15037
|
value: convertExpression(sliceCall),
|
|
14979
15038
|
declarationKind: declKind
|
|
14980
15039
|
});
|
|
15040
|
+
} else {
|
|
15041
|
+
reportUnsupportedExpression(
|
|
15042
|
+
elem,
|
|
15043
|
+
"Unsupported array destructuring pattern in HIR conversion."
|
|
15044
|
+
);
|
|
15045
|
+
return;
|
|
14981
15046
|
}
|
|
14982
15047
|
});
|
|
14983
15048
|
}
|
|
@@ -15140,11 +15205,15 @@ function convertFunction(name, params, body, options) {
|
|
|
15140
15205
|
if (t.isSwitchStatement(stmt)) {
|
|
15141
15206
|
const exitBlock = createBlock();
|
|
15142
15207
|
blocks.push(exitBlock.block);
|
|
15208
|
+
const caseBlocks = stmt.cases.map(() => createBlock());
|
|
15209
|
+
for (const caseBlock of caseBlocks) {
|
|
15210
|
+
blocks.push(caseBlock.block);
|
|
15211
|
+
}
|
|
15143
15212
|
const cases = [];
|
|
15144
15213
|
let defaultTarget;
|
|
15145
|
-
for (
|
|
15146
|
-
const
|
|
15147
|
-
|
|
15214
|
+
for (let index = 0; index < stmt.cases.length; index++) {
|
|
15215
|
+
const switchCase = stmt.cases[index];
|
|
15216
|
+
const caseBlock = caseBlocks[index];
|
|
15148
15217
|
if (switchCase.test) {
|
|
15149
15218
|
cases.push({
|
|
15150
15219
|
test: convertExpression(switchCase.test),
|
|
@@ -15153,20 +15222,26 @@ function convertFunction(name, params, body, options) {
|
|
|
15153
15222
|
} else {
|
|
15154
15223
|
defaultTarget = caseBlock.block.id;
|
|
15155
15224
|
}
|
|
15225
|
+
}
|
|
15226
|
+
cfgContext.loopStack.push({
|
|
15227
|
+
breakTarget: exitBlock.block.id
|
|
15228
|
+
});
|
|
15229
|
+
for (let index = 0; index < stmt.cases.length; index++) {
|
|
15230
|
+
const switchCase = stmt.cases[index];
|
|
15231
|
+
const caseBlock = caseBlocks[index];
|
|
15232
|
+
const nextCaseBlock = caseBlocks[index + 1];
|
|
15233
|
+
const fallthroughTarget = nextCaseBlock ? nextCaseBlock.block.id : exitBlock.block.id;
|
|
15156
15234
|
let caseBuilder = caseBlock;
|
|
15157
15235
|
for (const s of switchCase.consequent) {
|
|
15158
|
-
if (
|
|
15159
|
-
caseBuilder.block.terminator = { kind: "Jump", target: exitBlock.block.id };
|
|
15160
|
-
caseBuilder.sealed = true;
|
|
15161
|
-
break;
|
|
15162
|
-
}
|
|
15236
|
+
if (caseBuilder.sealed) break;
|
|
15163
15237
|
caseBuilder = processStatement(s, caseBuilder, exitBlock.block.id, cfgContext);
|
|
15164
15238
|
}
|
|
15165
15239
|
if (!caseBuilder.sealed) {
|
|
15166
|
-
caseBuilder.block.terminator = { kind: "Jump", target:
|
|
15240
|
+
caseBuilder.block.terminator = { kind: "Jump", target: fallthroughTarget };
|
|
15167
15241
|
caseBuilder.sealed = true;
|
|
15168
15242
|
}
|
|
15169
15243
|
}
|
|
15244
|
+
cfgContext.loopStack.pop();
|
|
15170
15245
|
if (defaultTarget === void 0) {
|
|
15171
15246
|
cases.push({ target: exitBlock.block.id });
|
|
15172
15247
|
} else {
|
|
@@ -15299,6 +15374,10 @@ function convertFunction(name, params, body, options) {
|
|
|
15299
15374
|
current = exitBlock;
|
|
15300
15375
|
continue;
|
|
15301
15376
|
}
|
|
15377
|
+
current = processStatement(stmt, current, current.block.id, cfgContext);
|
|
15378
|
+
if (current.sealed) {
|
|
15379
|
+
current = startNewBlock();
|
|
15380
|
+
}
|
|
15302
15381
|
}
|
|
15303
15382
|
if (!current.sealed) {
|
|
15304
15383
|
current.block.terminator = { kind: "Unreachable" };
|
|
@@ -15385,6 +15464,30 @@ function handleExpressionStatement(expr, push) {
|
|
|
15385
15464
|
}
|
|
15386
15465
|
return false;
|
|
15387
15466
|
}
|
|
15467
|
+
function findBreakContext(ctx, label) {
|
|
15468
|
+
if (label) {
|
|
15469
|
+
for (let i = ctx.loopStack.length - 1; i >= 0; i--) {
|
|
15470
|
+
const entry = ctx.loopStack[i];
|
|
15471
|
+
if (entry?.label === label) return entry;
|
|
15472
|
+
}
|
|
15473
|
+
return void 0;
|
|
15474
|
+
}
|
|
15475
|
+
return ctx.loopStack[ctx.loopStack.length - 1];
|
|
15476
|
+
}
|
|
15477
|
+
function findContinueContext(ctx, label) {
|
|
15478
|
+
if (label) {
|
|
15479
|
+
for (let i = ctx.loopStack.length - 1; i >= 0; i--) {
|
|
15480
|
+
const entry = ctx.loopStack[i];
|
|
15481
|
+
if (entry?.label === label && entry.continueTarget !== void 0) return entry;
|
|
15482
|
+
}
|
|
15483
|
+
return void 0;
|
|
15484
|
+
}
|
|
15485
|
+
for (let i = ctx.loopStack.length - 1; i >= 0; i--) {
|
|
15486
|
+
const entry = ctx.loopStack[i];
|
|
15487
|
+
if (entry?.continueTarget !== void 0) return entry;
|
|
15488
|
+
}
|
|
15489
|
+
return void 0;
|
|
15490
|
+
}
|
|
15388
15491
|
function fillStatements(stmt, bb, jumpTarget, ctx) {
|
|
15389
15492
|
if (t.isBlockStatement(stmt)) {
|
|
15390
15493
|
let current = bb;
|
|
@@ -15410,8 +15513,50 @@ function fillStatements(stmt, bb, jumpTarget, ctx) {
|
|
|
15410
15513
|
}
|
|
15411
15514
|
return result;
|
|
15412
15515
|
}
|
|
15413
|
-
function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
15516
|
+
function processStatement(stmt, bb, jumpTarget, ctx, labelOverride) {
|
|
15414
15517
|
const push = (instr) => bb.block.instructions.push(instr);
|
|
15518
|
+
if (t.isLabeledStatement(stmt) && ctx) {
|
|
15519
|
+
const label = stmt.label.name;
|
|
15520
|
+
const body = stmt.body;
|
|
15521
|
+
if (t.isWhileStatement(body) || t.isForStatement(body) || t.isDoWhileStatement(body) || t.isForInStatement(body) || t.isForOfStatement(body) || t.isSwitchStatement(body)) {
|
|
15522
|
+
return processStatement(body, bb, jumpTarget, ctx, label);
|
|
15523
|
+
}
|
|
15524
|
+
ctx.loopStack.push({
|
|
15525
|
+
breakTarget: jumpTarget,
|
|
15526
|
+
label
|
|
15527
|
+
});
|
|
15528
|
+
try {
|
|
15529
|
+
return processStatement(body, bb, jumpTarget, ctx);
|
|
15530
|
+
} finally {
|
|
15531
|
+
ctx.loopStack.pop();
|
|
15532
|
+
}
|
|
15533
|
+
}
|
|
15534
|
+
if (t.isEmptyStatement(stmt)) {
|
|
15535
|
+
return bb;
|
|
15536
|
+
}
|
|
15537
|
+
if (t.isBlockStatement(stmt)) {
|
|
15538
|
+
const shouldScopeLabel = !!labelOverride && !!ctx;
|
|
15539
|
+
if (shouldScopeLabel) {
|
|
15540
|
+
ctx.loopStack.push({
|
|
15541
|
+
breakTarget: jumpTarget,
|
|
15542
|
+
label: labelOverride
|
|
15543
|
+
});
|
|
15544
|
+
}
|
|
15545
|
+
let current = bb;
|
|
15546
|
+
try {
|
|
15547
|
+
for (const inner of stmt.body) {
|
|
15548
|
+
current = processStatement(inner, current, jumpTarget, ctx);
|
|
15549
|
+
if (current.sealed) {
|
|
15550
|
+
return current;
|
|
15551
|
+
}
|
|
15552
|
+
}
|
|
15553
|
+
return current;
|
|
15554
|
+
} finally {
|
|
15555
|
+
if (shouldScopeLabel) {
|
|
15556
|
+
ctx.loopStack.pop();
|
|
15557
|
+
}
|
|
15558
|
+
}
|
|
15559
|
+
}
|
|
15415
15560
|
if (t.isExpressionStatement(stmt)) {
|
|
15416
15561
|
if (!handleExpressionStatement(stmt.expression, push)) {
|
|
15417
15562
|
push({ kind: "Expression", value: convertExpression(stmt.expression) });
|
|
@@ -15526,6 +15671,21 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15526
15671
|
});
|
|
15527
15672
|
return bb;
|
|
15528
15673
|
}
|
|
15674
|
+
if (t.isClassDeclaration(stmt) && stmt.id) {
|
|
15675
|
+
const classExpr = t.classExpression(
|
|
15676
|
+
stmt.id,
|
|
15677
|
+
stmt.superClass,
|
|
15678
|
+
stmt.body,
|
|
15679
|
+
stmt.decorators ?? null
|
|
15680
|
+
);
|
|
15681
|
+
push({
|
|
15682
|
+
kind: "Assign",
|
|
15683
|
+
target: { kind: "Identifier", name: stmt.id.name },
|
|
15684
|
+
value: convertExpression(classExpr),
|
|
15685
|
+
declarationKind: "let"
|
|
15686
|
+
});
|
|
15687
|
+
return bb;
|
|
15688
|
+
}
|
|
15529
15689
|
if (t.isReturnStatement(stmt)) {
|
|
15530
15690
|
bb.block.terminator = {
|
|
15531
15691
|
kind: "Return",
|
|
@@ -15544,7 +15704,7 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15544
15704
|
}
|
|
15545
15705
|
if (t.isBreakStatement(stmt) && ctx) {
|
|
15546
15706
|
const label = stmt.label?.name;
|
|
15547
|
-
const loopCtx =
|
|
15707
|
+
const loopCtx = findBreakContext(ctx, label);
|
|
15548
15708
|
if (loopCtx) {
|
|
15549
15709
|
bb.block.terminator = { kind: "Break", target: loopCtx.breakTarget, label };
|
|
15550
15710
|
bb.sealed = true;
|
|
@@ -15556,7 +15716,7 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15556
15716
|
}
|
|
15557
15717
|
if (t.isContinueStatement(stmt) && ctx) {
|
|
15558
15718
|
const label = stmt.label?.name;
|
|
15559
|
-
const loopCtx =
|
|
15719
|
+
const loopCtx = findContinueContext(ctx, label);
|
|
15560
15720
|
if (loopCtx) {
|
|
15561
15721
|
bb.block.terminator = { kind: "Continue", target: loopCtx.continueTarget, label };
|
|
15562
15722
|
bb.sealed = true;
|
|
@@ -15605,7 +15765,8 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15605
15765
|
condBlock.sealed = true;
|
|
15606
15766
|
ctx.loopStack.push({
|
|
15607
15767
|
breakTarget: exitBlock.block.id,
|
|
15608
|
-
continueTarget: condBlock.block.id
|
|
15768
|
+
continueTarget: condBlock.block.id,
|
|
15769
|
+
label: labelOverride
|
|
15609
15770
|
});
|
|
15610
15771
|
fillStatements(stmt.body, bodyBlock, condBlock.block.id, ctx);
|
|
15611
15772
|
ctx.loopStack.pop();
|
|
@@ -15650,8 +15811,9 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15650
15811
|
condBlock.sealed = true;
|
|
15651
15812
|
ctx.loopStack.push({
|
|
15652
15813
|
breakTarget: exitBlock.block.id,
|
|
15653
|
-
continueTarget: updateBlock.block.id
|
|
15814
|
+
continueTarget: updateBlock.block.id,
|
|
15654
15815
|
// continue goes to update in for loop
|
|
15816
|
+
label: labelOverride
|
|
15655
15817
|
});
|
|
15656
15818
|
fillStatements(stmt.body, bodyBlock, updateBlock.block.id, ctx);
|
|
15657
15819
|
ctx.loopStack.pop();
|
|
@@ -15674,7 +15836,8 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15674
15836
|
bb.sealed = true;
|
|
15675
15837
|
ctx.loopStack.push({
|
|
15676
15838
|
breakTarget: exitBlock.block.id,
|
|
15677
|
-
continueTarget: condBlock.block.id
|
|
15839
|
+
continueTarget: condBlock.block.id,
|
|
15840
|
+
label: labelOverride
|
|
15678
15841
|
});
|
|
15679
15842
|
fillStatements(stmt.body, bodyBlock, condBlock.block.id, ctx);
|
|
15680
15843
|
ctx.loopStack.pop();
|
|
@@ -15722,7 +15885,8 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15722
15885
|
bb.sealed = true;
|
|
15723
15886
|
ctx.loopStack.push({
|
|
15724
15887
|
breakTarget: exitBlock.block.id,
|
|
15725
|
-
continueTarget: bodyBlock.block.id
|
|
15888
|
+
continueTarget: bodyBlock.block.id,
|
|
15889
|
+
label: labelOverride
|
|
15726
15890
|
});
|
|
15727
15891
|
fillStatements(stmt.body, bodyBlock, exitBlock.block.id, ctx);
|
|
15728
15892
|
ctx.loopStack.pop();
|
|
@@ -15762,7 +15926,8 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15762
15926
|
bb.sealed = true;
|
|
15763
15927
|
ctx.loopStack.push({
|
|
15764
15928
|
breakTarget: exitBlock.block.id,
|
|
15765
|
-
continueTarget: bodyBlock.block.id
|
|
15929
|
+
continueTarget: bodyBlock.block.id,
|
|
15930
|
+
label: labelOverride
|
|
15766
15931
|
});
|
|
15767
15932
|
fillStatements(stmt.body, bodyBlock, exitBlock.block.id, ctx);
|
|
15768
15933
|
ctx.loopStack.pop();
|
|
@@ -15771,11 +15936,15 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15771
15936
|
if (t.isSwitchStatement(stmt) && ctx) {
|
|
15772
15937
|
const exitBlock = ctx.createBlock();
|
|
15773
15938
|
ctx.blocks.push(exitBlock.block);
|
|
15939
|
+
const caseBlocks = stmt.cases.map(() => ctx.createBlock());
|
|
15940
|
+
for (const caseBlock of caseBlocks) {
|
|
15941
|
+
ctx.blocks.push(caseBlock.block);
|
|
15942
|
+
}
|
|
15774
15943
|
const cases = [];
|
|
15775
15944
|
let defaultTarget;
|
|
15776
|
-
for (
|
|
15777
|
-
const
|
|
15778
|
-
|
|
15945
|
+
for (let index = 0; index < stmt.cases.length; index++) {
|
|
15946
|
+
const switchCase = stmt.cases[index];
|
|
15947
|
+
const caseBlock = caseBlocks[index];
|
|
15779
15948
|
if (switchCase.test) {
|
|
15780
15949
|
cases.push({
|
|
15781
15950
|
test: convertExpression(switchCase.test),
|
|
@@ -15784,20 +15953,27 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15784
15953
|
} else {
|
|
15785
15954
|
defaultTarget = caseBlock.block.id;
|
|
15786
15955
|
}
|
|
15956
|
+
}
|
|
15957
|
+
ctx.loopStack.push({
|
|
15958
|
+
breakTarget: exitBlock.block.id,
|
|
15959
|
+
label: labelOverride
|
|
15960
|
+
});
|
|
15961
|
+
for (let index = 0; index < stmt.cases.length; index++) {
|
|
15962
|
+
const switchCase = stmt.cases[index];
|
|
15963
|
+
const caseBlock = caseBlocks[index];
|
|
15964
|
+
const nextCaseBlock = caseBlocks[index + 1];
|
|
15965
|
+
const fallthroughTarget = nextCaseBlock ? nextCaseBlock.block.id : exitBlock.block.id;
|
|
15787
15966
|
let current = caseBlock;
|
|
15788
15967
|
for (const s of switchCase.consequent) {
|
|
15789
|
-
if (
|
|
15790
|
-
current.block.terminator = { kind: "Jump", target: exitBlock.block.id };
|
|
15791
|
-
current.sealed = true;
|
|
15792
|
-
break;
|
|
15793
|
-
}
|
|
15968
|
+
if (current.sealed) break;
|
|
15794
15969
|
current = processStatement(s, current, exitBlock.block.id, ctx);
|
|
15795
15970
|
}
|
|
15796
15971
|
if (!current.sealed) {
|
|
15797
|
-
current.block.terminator = { kind: "Jump", target:
|
|
15972
|
+
current.block.terminator = { kind: "Jump", target: fallthroughTarget };
|
|
15798
15973
|
current.sealed = true;
|
|
15799
15974
|
}
|
|
15800
15975
|
}
|
|
15976
|
+
ctx.loopStack.pop();
|
|
15801
15977
|
if (defaultTarget === void 0) {
|
|
15802
15978
|
cases.push({ target: exitBlock.block.id });
|
|
15803
15979
|
} else {
|
|
@@ -15846,30 +16022,41 @@ function processStatement(stmt, bb, jumpTarget, ctx) {
|
|
|
15846
16022
|
}
|
|
15847
16023
|
return exitBlock;
|
|
15848
16024
|
}
|
|
15849
|
-
|
|
15850
|
-
bb.block.
|
|
15851
|
-
|
|
15852
|
-
}
|
|
15853
|
-
return bb;
|
|
16025
|
+
throw new HIRError(`Unsupported statement in HIR lowering: ${stmt.type}`, "BUILD_ERROR", {
|
|
16026
|
+
blockId: bb.block.id
|
|
16027
|
+
});
|
|
15854
16028
|
}
|
|
15855
16029
|
function convertExpression(node, options) {
|
|
15856
16030
|
const loc = getLoc(node);
|
|
15857
|
-
const convertCallArguments = (args, reactiveScope) =>
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
|
|
15862
|
-
|
|
15863
|
-
|
|
15864
|
-
|
|
15865
|
-
|
|
15866
|
-
|
|
15867
|
-
|
|
16031
|
+
const convertCallArguments = (args, reactiveScope) => {
|
|
16032
|
+
const converted = [];
|
|
16033
|
+
for (const arg of args) {
|
|
16034
|
+
if (t.isSpreadElement(arg)) {
|
|
16035
|
+
converted.push({
|
|
16036
|
+
kind: "SpreadElement",
|
|
16037
|
+
argument: convertExpression(arg.argument),
|
|
16038
|
+
loc: getLoc(arg)
|
|
16039
|
+
});
|
|
16040
|
+
continue;
|
|
16041
|
+
}
|
|
16042
|
+
if (t.isExpression(arg)) {
|
|
16043
|
+
if (reactiveScope && arg === args[0] && (t.isArrowFunctionExpression(arg) || t.isFunctionExpression(arg))) {
|
|
16044
|
+
converted.push(convertExpression(arg, { reactiveScope }));
|
|
16045
|
+
continue;
|
|
16046
|
+
}
|
|
16047
|
+
converted.push(convertExpression(arg));
|
|
16048
|
+
continue;
|
|
16049
|
+
}
|
|
16050
|
+
if (t.isArgumentPlaceholder?.(arg)) {
|
|
16051
|
+
return reportUnsupportedExpression(
|
|
16052
|
+
arg,
|
|
16053
|
+
"Argument placeholders are not supported in HIR conversion."
|
|
16054
|
+
);
|
|
15868
16055
|
}
|
|
15869
|
-
return
|
|
16056
|
+
return reportUnsupportedExpression(arg, "Unsupported call argument in HIR conversion.");
|
|
15870
16057
|
}
|
|
15871
|
-
return
|
|
15872
|
-
}
|
|
16058
|
+
return converted;
|
|
16059
|
+
};
|
|
15873
16060
|
const resolveReactiveScope = (callee) => {
|
|
15874
16061
|
const reactiveScopes = activeBuildOptions?.reactiveScopes;
|
|
15875
16062
|
if (!reactiveScopes || reactiveScopes.size === 0) return void 0;
|
|
@@ -15881,6 +16068,9 @@ function convertExpression(node, options) {
|
|
|
15881
16068
|
}
|
|
15882
16069
|
return void 0;
|
|
15883
16070
|
};
|
|
16071
|
+
if (t.isChainExpression?.(node) || node.type === "ChainExpression") {
|
|
16072
|
+
return convertExpression(node.expression, options);
|
|
16073
|
+
}
|
|
15884
16074
|
if (t.isParenthesizedExpression(node) && t.isExpression(node.expression)) {
|
|
15885
16075
|
return convertExpression(node.expression);
|
|
15886
16076
|
}
|
|
@@ -15938,7 +16128,13 @@ function convertExpression(node, options) {
|
|
|
15938
16128
|
return call;
|
|
15939
16129
|
}
|
|
15940
16130
|
if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) {
|
|
15941
|
-
|
|
16131
|
+
if (t.isPrivateName(node.property)) {
|
|
16132
|
+
return reportUnsupportedExpression(
|
|
16133
|
+
node.property,
|
|
16134
|
+
"Private field access is not supported in HIR conversion."
|
|
16135
|
+
);
|
|
16136
|
+
}
|
|
16137
|
+
const propertyNode = node.property;
|
|
15942
16138
|
const isOptional = t.isOptionalMemberExpression(node);
|
|
15943
16139
|
const object = convertExpression(node.object);
|
|
15944
16140
|
const property = t.isExpression(propertyNode) ? convertExpression(propertyNode) : { kind: "Literal", value: void 0 };
|
|
@@ -16004,67 +16200,106 @@ function convertExpression(node, options) {
|
|
|
16004
16200
|
return cond;
|
|
16005
16201
|
}
|
|
16006
16202
|
if (t.isArrayExpression(node)) {
|
|
16203
|
+
if ((node.elements ?? []).some((el) => el == null)) {
|
|
16204
|
+
return reportUnsupportedExpression(
|
|
16205
|
+
node,
|
|
16206
|
+
"Array literal holes are not supported in HIR conversion. Use explicit undefined values instead."
|
|
16207
|
+
);
|
|
16208
|
+
}
|
|
16209
|
+
const elements = [];
|
|
16210
|
+
for (const el of node.elements ?? []) {
|
|
16211
|
+
if (!el) continue;
|
|
16212
|
+
if (t.isSpreadElement(el)) {
|
|
16213
|
+
elements.push({
|
|
16214
|
+
kind: "SpreadElement",
|
|
16215
|
+
argument: convertExpression(el.argument),
|
|
16216
|
+
loc: getLoc(el)
|
|
16217
|
+
});
|
|
16218
|
+
continue;
|
|
16219
|
+
}
|
|
16220
|
+
if (t.isExpression(el)) {
|
|
16221
|
+
elements.push(convertExpression(el));
|
|
16222
|
+
continue;
|
|
16223
|
+
}
|
|
16224
|
+
return reportUnsupportedExpression(el, "Unsupported array literal element in HIR conversion.");
|
|
16225
|
+
}
|
|
16007
16226
|
const arr = {
|
|
16008
16227
|
kind: "ArrayExpression",
|
|
16009
|
-
elements
|
|
16010
|
-
if (!el) return void 0;
|
|
16011
|
-
if (t.isSpreadElement(el)) {
|
|
16012
|
-
return {
|
|
16013
|
-
kind: "SpreadElement",
|
|
16014
|
-
argument: convertExpression(el.argument),
|
|
16015
|
-
loc: getLoc(el)
|
|
16016
|
-
};
|
|
16017
|
-
}
|
|
16018
|
-
if (t.isExpression(el)) return convertExpression(el);
|
|
16019
|
-
return void 0;
|
|
16020
|
-
}).filter(Boolean),
|
|
16228
|
+
elements,
|
|
16021
16229
|
loc
|
|
16022
16230
|
};
|
|
16023
16231
|
return arr;
|
|
16024
16232
|
}
|
|
16025
16233
|
if (t.isObjectExpression(node)) {
|
|
16234
|
+
const properties = [];
|
|
16026
16235
|
const obj = {
|
|
16027
16236
|
kind: "ObjectExpression",
|
|
16028
|
-
properties
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16032
|
-
|
|
16033
|
-
|
|
16034
|
-
|
|
16237
|
+
properties,
|
|
16238
|
+
loc
|
|
16239
|
+
};
|
|
16240
|
+
for (const prop of node.properties) {
|
|
16241
|
+
if (t.isSpreadElement(prop)) {
|
|
16242
|
+
properties.push({
|
|
16243
|
+
kind: "SpreadElement",
|
|
16244
|
+
argument: convertExpression(prop.argument),
|
|
16245
|
+
loc: getLoc(prop)
|
|
16246
|
+
});
|
|
16247
|
+
continue;
|
|
16248
|
+
}
|
|
16249
|
+
if (t.isObjectMethod(prop)) {
|
|
16250
|
+
const keyExpr = prop.computed ? t.isExpression(prop.key) ? convertExpression(prop.key) : void 0 : t.isIdentifier(prop.key) ? { kind: "Identifier", name: prop.key.name } : t.isStringLiteral(prop.key) ? { kind: "Literal", value: prop.key.value } : t.isNumericLiteral(prop.key) ? { kind: "Literal", value: prop.key.value } : t.isBigIntLiteral(prop.key) ? { kind: "Literal", value: BigInt(prop.key.value) } : void 0;
|
|
16251
|
+
if (!keyExpr) {
|
|
16252
|
+
return reportUnsupportedExpression(
|
|
16253
|
+
prop.key,
|
|
16254
|
+
"Unsupported object literal key in HIR conversion."
|
|
16255
|
+
);
|
|
16035
16256
|
}
|
|
16036
|
-
|
|
16037
|
-
|
|
16038
|
-
|
|
16039
|
-
|
|
16040
|
-
|
|
16041
|
-
|
|
16042
|
-
|
|
16043
|
-
|
|
16044
|
-
|
|
16045
|
-
|
|
16257
|
+
const fnExpr = t.functionExpression(
|
|
16258
|
+
null,
|
|
16259
|
+
prop.params,
|
|
16260
|
+
prop.body,
|
|
16261
|
+
prop.generator,
|
|
16262
|
+
prop.async
|
|
16263
|
+
);
|
|
16264
|
+
properties.push({
|
|
16265
|
+
kind: "Property",
|
|
16266
|
+
key: keyExpr,
|
|
16267
|
+
value: convertExpression(fnExpr),
|
|
16268
|
+
computed: prop.computed,
|
|
16269
|
+
propertyKind: prop.kind ?? "method",
|
|
16270
|
+
loc: getLoc(prop)
|
|
16271
|
+
});
|
|
16272
|
+
continue;
|
|
16273
|
+
}
|
|
16274
|
+
if (t.isObjectProperty(prop)) {
|
|
16275
|
+
const keyExpr = prop.computed ? t.isExpression(prop.key) ? convertExpression(prop.key) : void 0 : t.isIdentifier(prop.key) ? { kind: "Identifier", name: prop.key.name } : t.isStringLiteral(prop.key) ? { kind: "Literal", value: prop.key.value } : t.isNumericLiteral(prop.key) ? { kind: "Literal", value: prop.key.value } : t.isBigIntLiteral(prop.key) ? { kind: "Literal", value: BigInt(prop.key.value) } : void 0;
|
|
16276
|
+
if (!keyExpr) {
|
|
16277
|
+
return reportUnsupportedExpression(
|
|
16278
|
+
prop.key,
|
|
16279
|
+
"Unsupported object literal key in HIR conversion."
|
|
16046
16280
|
);
|
|
16047
|
-
return {
|
|
16048
|
-
kind: "Property",
|
|
16049
|
-
key: keyExpr2,
|
|
16050
|
-
value: convertExpression(fnExpr),
|
|
16051
|
-
loc: getLoc(prop)
|
|
16052
|
-
};
|
|
16053
16281
|
}
|
|
16054
|
-
if (!t.
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
|
|
16058
|
-
|
|
16282
|
+
if (!t.isExpression(prop.value)) {
|
|
16283
|
+
return reportUnsupportedExpression(
|
|
16284
|
+
prop.value,
|
|
16285
|
+
"Unsupported object literal value in HIR conversion."
|
|
16286
|
+
);
|
|
16287
|
+
}
|
|
16288
|
+
properties.push({
|
|
16059
16289
|
kind: "Property",
|
|
16060
16290
|
key: keyExpr,
|
|
16061
16291
|
value: convertExpression(prop.value),
|
|
16292
|
+
computed: prop.computed,
|
|
16062
16293
|
shorthand: prop.shorthand && t.isIdentifier(prop.value),
|
|
16063
16294
|
loc: getLoc(prop)
|
|
16064
|
-
};
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16295
|
+
});
|
|
16296
|
+
continue;
|
|
16297
|
+
}
|
|
16298
|
+
return reportUnsupportedExpression(
|
|
16299
|
+
prop,
|
|
16300
|
+
"Unsupported object literal property in HIR conversion."
|
|
16301
|
+
);
|
|
16302
|
+
}
|
|
16068
16303
|
return obj;
|
|
16069
16304
|
}
|
|
16070
16305
|
if (t.isJSXElement(node)) {
|
|
@@ -16092,6 +16327,11 @@ function convertExpression(node, options) {
|
|
|
16092
16327
|
value: convertJSXElement(child),
|
|
16093
16328
|
loc: getLoc(child)
|
|
16094
16329
|
});
|
|
16330
|
+
} else if (t.isJSXSpreadChild(child)) {
|
|
16331
|
+
return reportUnsupportedExpression(
|
|
16332
|
+
child,
|
|
16333
|
+
"JSX spread children are not supported in HIR conversion."
|
|
16334
|
+
);
|
|
16095
16335
|
} else if (t.isJSXFragment(child)) {
|
|
16096
16336
|
for (const fragChild of child.children) {
|
|
16097
16337
|
if (t.isJSXText(fragChild)) {
|
|
@@ -16113,6 +16353,11 @@ function convertExpression(node, options) {
|
|
|
16113
16353
|
value: convertJSXElement(fragChild),
|
|
16114
16354
|
loc: getLoc(fragChild)
|
|
16115
16355
|
});
|
|
16356
|
+
} else if (t.isJSXSpreadChild(fragChild)) {
|
|
16357
|
+
return reportUnsupportedExpression(
|
|
16358
|
+
fragChild,
|
|
16359
|
+
"JSX spread children are not supported in HIR conversion."
|
|
16360
|
+
);
|
|
16116
16361
|
}
|
|
16117
16362
|
}
|
|
16118
16363
|
}
|
|
@@ -16308,7 +16553,10 @@ function convertJSXElement(node) {
|
|
|
16308
16553
|
tagName = convertJSXMemberExpr(opening.name);
|
|
16309
16554
|
isComponent = true;
|
|
16310
16555
|
} else {
|
|
16311
|
-
|
|
16556
|
+
return reportUnsupportedExpression(
|
|
16557
|
+
opening.name,
|
|
16558
|
+
`Unsupported JSX tag syntax '${opening.name.type}' in HIR conversion`
|
|
16559
|
+
);
|
|
16312
16560
|
}
|
|
16313
16561
|
const attributes = [];
|
|
16314
16562
|
for (const attr of opening.attributes) {
|
|
@@ -16320,17 +16568,33 @@ function convertJSXElement(node) {
|
|
|
16320
16568
|
spreadExpr: convertExpression(attr.argument),
|
|
16321
16569
|
loc: getLoc(attr)
|
|
16322
16570
|
});
|
|
16323
|
-
} else if (t.isJSXAttribute(attr)
|
|
16571
|
+
} else if (t.isJSXAttribute(attr)) {
|
|
16572
|
+
const nameNode = attr.name;
|
|
16573
|
+
let attrName = null;
|
|
16574
|
+
if (t.isJSXIdentifier(attr.name)) {
|
|
16575
|
+
attrName = attr.name.name;
|
|
16576
|
+
} else if (t.isJSXNamespacedName(attr.name)) {
|
|
16577
|
+
attrName = `${attr.name.namespace.name}:${attr.name.name.name}`;
|
|
16578
|
+
} else {
|
|
16579
|
+
return reportUnsupportedExpression(
|
|
16580
|
+
nameNode,
|
|
16581
|
+
"Unsupported JSX attribute name in HIR conversion"
|
|
16582
|
+
);
|
|
16583
|
+
}
|
|
16324
16584
|
let value = null;
|
|
16325
16585
|
if (attr.value) {
|
|
16326
16586
|
if (t.isStringLiteral(attr.value)) {
|
|
16327
16587
|
value = { kind: "Literal", value: attr.value.value, loc: getLoc(attr.value) };
|
|
16328
16588
|
} else if (t.isJSXExpressionContainer(attr.value) && !t.isJSXEmptyExpression(attr.value.expression)) {
|
|
16329
16589
|
value = convertExpression(attr.value.expression);
|
|
16590
|
+
} else if (t.isJSXElement(attr.value)) {
|
|
16591
|
+
value = convertJSXElement(attr.value);
|
|
16592
|
+
} else if (t.isJSXFragment(attr.value)) {
|
|
16593
|
+
value = convertExpression(attr.value);
|
|
16330
16594
|
}
|
|
16331
16595
|
}
|
|
16332
16596
|
attributes.push({
|
|
16333
|
-
name:
|
|
16597
|
+
name: attrName,
|
|
16334
16598
|
value,
|
|
16335
16599
|
loc: getLoc(attr)
|
|
16336
16600
|
});
|
|
@@ -16357,6 +16621,11 @@ function convertJSXElement(node) {
|
|
|
16357
16621
|
value: convertJSXElement(child),
|
|
16358
16622
|
loc: getLoc(child)
|
|
16359
16623
|
});
|
|
16624
|
+
} else if (t.isJSXSpreadChild(child)) {
|
|
16625
|
+
return reportUnsupportedExpression(
|
|
16626
|
+
child,
|
|
16627
|
+
"JSX spread children are not supported in HIR conversion."
|
|
16628
|
+
);
|
|
16360
16629
|
} else if (t.isJSXFragment(child)) {
|
|
16361
16630
|
for (const fragChild of child.children) {
|
|
16362
16631
|
if (t.isJSXText(fragChild)) {
|
|
@@ -16378,6 +16647,11 @@ function convertJSXElement(node) {
|
|
|
16378
16647
|
value: convertJSXElement(fragChild),
|
|
16379
16648
|
loc: getLoc(fragChild)
|
|
16380
16649
|
});
|
|
16650
|
+
} else if (t.isJSXSpreadChild(fragChild)) {
|
|
16651
|
+
return reportUnsupportedExpression(
|
|
16652
|
+
fragChild,
|
|
16653
|
+
"JSX spread children are not supported in HIR conversion."
|
|
16654
|
+
);
|
|
16381
16655
|
}
|
|
16382
16656
|
}
|
|
16383
16657
|
}
|
|
@@ -16613,7 +16887,7 @@ var DiagnosticMessages = {
|
|
|
16613
16887
|
["FICT-R001" /* FICT_R001 */]: "Expression crosses reactive region boundary.",
|
|
16614
16888
|
["FICT-R002" /* FICT_R002 */]: "Scope escape detected, value may not be tracked.",
|
|
16615
16889
|
["FICT-R003" /* FICT_R003 */]: "Expression cannot be memoized automatically.",
|
|
16616
|
-
["FICT-R004" /* FICT_R004 */]: "Reactive creation inside non-JSX control flow
|
|
16890
|
+
["FICT-R004" /* FICT_R004 */]: "Reactive creation inside non-JSX control flow may not auto-dispose in complex paths. Prefer createScope/runInScope (or JSX-managed regions) for explicit lifecycle control.",
|
|
16617
16891
|
["FICT-R005" /* FICT_R005 */]: "Function captures reactive variables from outer scope; pass them as parameters or memoize explicitly to avoid hidden dependencies.",
|
|
16618
16892
|
["FICT-X001" /* FICT_X001 */]: "Object is recreated on each render, consider memoizing.",
|
|
16619
16893
|
["FICT-X002" /* FICT_X002 */]: "Array is recreated on each render, consider memoizing.",
|
|
@@ -16643,7 +16917,7 @@ var DiagnosticSeverities = {
|
|
|
16643
16917
|
["FICT-R001" /* FICT_R001 */]: "info" /* Info */,
|
|
16644
16918
|
["FICT-R002" /* FICT_R002 */]: "warning" /* Warning */,
|
|
16645
16919
|
["FICT-R003" /* FICT_R003 */]: "info" /* Info */,
|
|
16646
|
-
["FICT-R004" /* FICT_R004 */]: "
|
|
16920
|
+
["FICT-R004" /* FICT_R004 */]: "error" /* Error */,
|
|
16647
16921
|
["FICT-R005" /* FICT_R005 */]: "warning" /* Warning */,
|
|
16648
16922
|
["FICT-X001" /* FICT_X001 */]: "hint" /* Hint */,
|
|
16649
16923
|
["FICT-X002" /* FICT_X002 */]: "hint" /* Hint */,
|
|
@@ -17123,7 +17397,11 @@ function rewriteExprWithMap(expr, rewrites) {
|
|
|
17123
17397
|
if (p.kind === "SpreadElement") {
|
|
17124
17398
|
return { ...p, argument: rewriteExprWithMap(p.argument, rewrites) };
|
|
17125
17399
|
}
|
|
17126
|
-
return {
|
|
17400
|
+
return {
|
|
17401
|
+
...p,
|
|
17402
|
+
key: p.computed ? rewriteExprWithMap(p.key, rewrites) : p.key,
|
|
17403
|
+
value: rewriteExprWithMap(p.value, rewrites)
|
|
17404
|
+
};
|
|
17127
17405
|
})
|
|
17128
17406
|
};
|
|
17129
17407
|
case "ImportExpression":
|
|
@@ -17270,7 +17548,11 @@ function toSSA(fn) {
|
|
|
17270
17548
|
if (p.kind === "SpreadElement") {
|
|
17271
17549
|
return { ...p, argument: renameExpr(p.argument) };
|
|
17272
17550
|
}
|
|
17273
|
-
return {
|
|
17551
|
+
return {
|
|
17552
|
+
...p,
|
|
17553
|
+
key: p.computed ? renameExpr(p.key) : p.key,
|
|
17554
|
+
value: renameExpr(p.value)
|
|
17555
|
+
};
|
|
17274
17556
|
})
|
|
17275
17557
|
};
|
|
17276
17558
|
default:
|
|
@@ -18700,16 +18982,104 @@ function structurizeBranchUntilJoin(ctx, block, term, outerJoin) {
|
|
|
18700
18982
|
return ifNode;
|
|
18701
18983
|
}
|
|
18702
18984
|
function structurizeSwitch(ctx, block, term) {
|
|
18985
|
+
const uniqueTargets = Array.from(new Set(term.cases.map((c) => c.target)));
|
|
18986
|
+
const joinBlock = findSwitchJoinBlock(ctx, uniqueTargets);
|
|
18703
18987
|
const cases = [];
|
|
18988
|
+
const emittedBeforeSwitch = new Set(ctx.emitted);
|
|
18989
|
+
const emittedBySwitchCases = /* @__PURE__ */ new Set();
|
|
18704
18990
|
for (const c of term.cases) {
|
|
18705
|
-
const
|
|
18706
|
-
|
|
18991
|
+
const caseCtx = {
|
|
18992
|
+
...ctx,
|
|
18993
|
+
emitted: new Set(emittedBeforeSwitch),
|
|
18994
|
+
processing: new Set(ctx.processing)
|
|
18995
|
+
};
|
|
18996
|
+
const body = joinBlock !== void 0 ? structurizeBlockUntilJoin(caseCtx, c.target, joinBlock) : structurizeBlock(caseCtx, c.target);
|
|
18997
|
+
for (const emittedBlock of caseCtx.emitted) {
|
|
18998
|
+
if (!emittedBeforeSwitch.has(emittedBlock)) {
|
|
18999
|
+
emittedBySwitchCases.add(emittedBlock);
|
|
19000
|
+
}
|
|
19001
|
+
}
|
|
19002
|
+
const normalizedBody = appendSwitchCaseBreak(body);
|
|
19003
|
+
cases.push({ test: c.test ?? null, body: normalizedBody });
|
|
18707
19004
|
}
|
|
18708
|
-
|
|
19005
|
+
for (const emittedBlock of emittedBySwitchCases) {
|
|
19006
|
+
ctx.emitted.add(emittedBlock);
|
|
19007
|
+
}
|
|
19008
|
+
const switchNode = {
|
|
18709
19009
|
kind: "switch",
|
|
18710
19010
|
discriminant: term.discriminant,
|
|
18711
19011
|
cases
|
|
18712
19012
|
};
|
|
19013
|
+
if (joinBlock !== void 0 && !ctx.emitted.has(joinBlock)) {
|
|
19014
|
+
const joinNode = structurizeBlock(ctx, joinBlock);
|
|
19015
|
+
return { kind: "sequence", nodes: [switchNode, joinNode] };
|
|
19016
|
+
}
|
|
19017
|
+
return switchNode;
|
|
19018
|
+
}
|
|
19019
|
+
function findSwitchJoinBlock(ctx, caseTargets) {
|
|
19020
|
+
const uniqueTargets = Array.from(new Set(caseTargets));
|
|
19021
|
+
if (uniqueTargets.length === 0) return void 0;
|
|
19022
|
+
const reachableByCase = uniqueTargets.map(
|
|
19023
|
+
(target) => collectReachableBlocks(ctx, target, /* @__PURE__ */ new Set())
|
|
19024
|
+
);
|
|
19025
|
+
const reachableUnion = /* @__PURE__ */ new Set();
|
|
19026
|
+
for (const set of reachableByCase) {
|
|
19027
|
+
for (const id of set) reachableUnion.add(id);
|
|
19028
|
+
}
|
|
19029
|
+
const minCaseCoverage = uniqueTargets.length > 1 ? 2 : 1;
|
|
19030
|
+
const candidates = [];
|
|
19031
|
+
for (const id of reachableUnion) {
|
|
19032
|
+
if (uniqueTargets.includes(id)) continue;
|
|
19033
|
+
let reachableCases = 0;
|
|
19034
|
+
for (const set of reachableByCase) {
|
|
19035
|
+
if (set.has(id)) reachableCases++;
|
|
19036
|
+
}
|
|
19037
|
+
if (reachableCases < minCaseCoverage) continue;
|
|
19038
|
+
const predecessors = ctx.predecessors.get(id) ?? [];
|
|
19039
|
+
const predecessorCount = predecessors.filter((pred) => reachableUnion.has(pred)).length;
|
|
19040
|
+
candidates.push({
|
|
19041
|
+
id,
|
|
19042
|
+
reachableCases,
|
|
19043
|
+
predecessorCount,
|
|
19044
|
+
isJoinPoint: predecessors.length > 1
|
|
19045
|
+
});
|
|
19046
|
+
}
|
|
19047
|
+
if (candidates.length === 0) return void 0;
|
|
19048
|
+
candidates.sort((a, b) => {
|
|
19049
|
+
if (a.reachableCases !== b.reachableCases) return b.reachableCases - a.reachableCases;
|
|
19050
|
+
if (a.predecessorCount !== b.predecessorCount) return b.predecessorCount - a.predecessorCount;
|
|
19051
|
+
if (a.isJoinPoint !== b.isJoinPoint) return Number(b.isJoinPoint) - Number(a.isJoinPoint);
|
|
19052
|
+
return a.id - b.id;
|
|
19053
|
+
});
|
|
19054
|
+
return candidates[0]?.id;
|
|
19055
|
+
}
|
|
19056
|
+
function appendSwitchCaseBreak(body) {
|
|
19057
|
+
if (isSwitchCaseTerminated(body)) return body;
|
|
19058
|
+
if (body.kind === "sequence") {
|
|
19059
|
+
return { kind: "sequence", nodes: [...body.nodes, { kind: "break" }] };
|
|
19060
|
+
}
|
|
19061
|
+
return { kind: "sequence", nodes: [body, { kind: "break" }] };
|
|
19062
|
+
}
|
|
19063
|
+
function isSwitchCaseTerminated(node) {
|
|
19064
|
+
if (!node) return false;
|
|
19065
|
+
switch (node.kind) {
|
|
19066
|
+
case "return":
|
|
19067
|
+
case "throw":
|
|
19068
|
+
case "break":
|
|
19069
|
+
case "continue":
|
|
19070
|
+
return true;
|
|
19071
|
+
case "sequence":
|
|
19072
|
+
return node.nodes.length > 0 && isSwitchCaseTerminated(node.nodes[node.nodes.length - 1]);
|
|
19073
|
+
case "block":
|
|
19074
|
+
return node.statements.length > 0 && isSwitchCaseTerminated(node.statements[node.statements.length - 1]);
|
|
19075
|
+
case "if":
|
|
19076
|
+
return isSwitchCaseTerminated(node.consequent) && isSwitchCaseTerminated(node.alternate ?? void 0);
|
|
19077
|
+
case "try":
|
|
19078
|
+
if (node.finalizer && isSwitchCaseTerminated(node.finalizer)) return true;
|
|
19079
|
+
return isSwitchCaseTerminated(node.block) && isSwitchCaseTerminated(node.handler?.body ?? void 0);
|
|
19080
|
+
default:
|
|
19081
|
+
return false;
|
|
19082
|
+
}
|
|
18713
19083
|
}
|
|
18714
19084
|
function structurizeForOf(ctx, block, term) {
|
|
18715
19085
|
const body = structurizeBlock(ctx, term.body);
|
|
@@ -18911,6 +19281,7 @@ function resolveKeySet(expr, ctx, shapes) {
|
|
|
18911
19281
|
const values = [];
|
|
18912
19282
|
for (const prop of arg.properties) {
|
|
18913
19283
|
if (prop.kind !== "Property") return null;
|
|
19284
|
+
if (prop.computed) return null;
|
|
18914
19285
|
if (prop.key.kind === "Identifier") {
|
|
18915
19286
|
values.push(prop.key.name);
|
|
18916
19287
|
} else if (prop.key.kind === "Literal") {
|
|
@@ -19310,7 +19681,10 @@ function analyzeExpression(expr, shapes, propertyReads, ctx) {
|
|
|
19310
19681
|
}
|
|
19311
19682
|
analyzeExpression(prop.argument, shapes, propertyReads, ctx);
|
|
19312
19683
|
} else if (prop.kind === "Property") {
|
|
19313
|
-
if (prop.
|
|
19684
|
+
if (prop.computed) {
|
|
19685
|
+
shape.dynamicAccess = true;
|
|
19686
|
+
analyzeExpression(prop.key, shapes, propertyReads, ctx);
|
|
19687
|
+
} else if (prop.key.kind === "Identifier") {
|
|
19314
19688
|
shape.knownKeys.add(prop.key.name);
|
|
19315
19689
|
} else if (prop.key.kind === "Literal" && typeof prop.key.value === "string") {
|
|
19316
19690
|
shape.knownKeys.add(prop.key.value);
|
|
@@ -19550,6 +19924,7 @@ function markEscaping(expr, shapes) {
|
|
|
19550
19924
|
if (prop.kind === "SpreadElement") {
|
|
19551
19925
|
markEscaping(prop.argument, shapes);
|
|
19552
19926
|
} else if (prop.kind === "Property") {
|
|
19927
|
+
if (prop.computed) markEscaping(prop.key, shapes);
|
|
19553
19928
|
markEscaping(prop.value, shapes);
|
|
19554
19929
|
}
|
|
19555
19930
|
}
|
|
@@ -19654,7 +20029,7 @@ function expressionContainsReactiveCreation(expr, memoMacroNames) {
|
|
|
19654
20029
|
return expr.elements.some((el) => el && expressionContainsReactiveCreation(el, memoMacroNames));
|
|
19655
20030
|
case "ObjectExpression":
|
|
19656
20031
|
return expr.properties.some(
|
|
19657
|
-
(prop) => prop.kind === "SpreadElement" ? expressionContainsReactiveCreation(prop.argument, memoMacroNames) : expressionContainsReactiveCreation(prop.value, memoMacroNames)
|
|
20032
|
+
(prop) => prop.kind === "SpreadElement" ? expressionContainsReactiveCreation(prop.argument, memoMacroNames) : prop.computed && expressionContainsReactiveCreation(prop.key, memoMacroNames) || expressionContainsReactiveCreation(prop.value, memoMacroNames)
|
|
19658
20033
|
);
|
|
19659
20034
|
case "ArrowFunction":
|
|
19660
20035
|
if (expr.isExpression) {
|
|
@@ -19940,7 +20315,7 @@ function expressionUsesTracked(expr, ctx) {
|
|
|
19940
20315
|
case "ObjectExpression":
|
|
19941
20316
|
return expr.properties.some((p) => {
|
|
19942
20317
|
if (p.kind === "SpreadElement") return expressionUsesTracked(p.argument, ctx);
|
|
19943
|
-
return expressionUsesTracked(p.value, ctx);
|
|
20318
|
+
return p.computed && expressionUsesTracked(p.key, ctx) || expressionUsesTracked(p.value, ctx);
|
|
19944
20319
|
});
|
|
19945
20320
|
case "TemplateLiteral":
|
|
19946
20321
|
return expr.expressions.some((e) => expressionUsesTracked(e, ctx));
|
|
@@ -20033,6 +20408,16 @@ function lowerStructuredNodeInternal(node, t4, ctx, declaredVars, regionResult)
|
|
|
20033
20408
|
} : void 0;
|
|
20034
20409
|
return lowerNodeWithRegionContext(node, t4, ctx, declaredVars, regionCtx);
|
|
20035
20410
|
}
|
|
20411
|
+
function ensureSwitchCaseBreak(stmts, t4) {
|
|
20412
|
+
if (stmts.length === 0) {
|
|
20413
|
+
return stmts;
|
|
20414
|
+
}
|
|
20415
|
+
const tail = stmts[stmts.length - 1];
|
|
20416
|
+
if (tail && (t4.isBreakStatement(tail) || t4.isReturnStatement(tail) || t4.isThrowStatement(tail) || t4.isContinueStatement(tail))) {
|
|
20417
|
+
return stmts;
|
|
20418
|
+
}
|
|
20419
|
+
return [...stmts, t4.breakStatement()];
|
|
20420
|
+
}
|
|
20036
20421
|
function lowerNodeWithRegionContext(node, t4, ctx, declaredVars, regionCtx) {
|
|
20037
20422
|
switch (node.kind) {
|
|
20038
20423
|
case "sequence": {
|
|
@@ -20222,10 +20607,20 @@ function lowerNodeWithRegionContext(node, t4, ctx, declaredVars, regionCtx) {
|
|
|
20222
20607
|
return [t4.forInStatement(left, right, body)];
|
|
20223
20608
|
}
|
|
20224
20609
|
case "switch": {
|
|
20225
|
-
const
|
|
20226
|
-
|
|
20227
|
-
|
|
20228
|
-
|
|
20610
|
+
const prevConditional = ctx.inConditional ?? 0;
|
|
20611
|
+
ctx.inConditional = prevConditional + 1;
|
|
20612
|
+
let cases;
|
|
20613
|
+
try {
|
|
20614
|
+
cases = node.cases.map((c) => {
|
|
20615
|
+
const stmts = ensureSwitchCaseBreak(
|
|
20616
|
+
lowerNodeWithRegionContext(c.body, t4, ctx, declaredVars, regionCtx),
|
|
20617
|
+
t4
|
|
20618
|
+
);
|
|
20619
|
+
return t4.switchCase(c.test ? lowerExpressionWithDeSSA(c.test, ctx) : null, stmts);
|
|
20620
|
+
});
|
|
20621
|
+
} finally {
|
|
20622
|
+
ctx.inConditional = prevConditional;
|
|
20623
|
+
}
|
|
20229
20624
|
return [t4.switchStatement(lowerExpressionWithDeSSA(node.discriminant, ctx), cases)];
|
|
20230
20625
|
}
|
|
20231
20626
|
case "try": {
|
|
@@ -20514,19 +20909,29 @@ function lowerStructuredNodeForRegion(node, region, t4, ctx, declaredVars, regio
|
|
|
20514
20909
|
return [t4.forInStatement(left, right, t4.blockStatement(body))];
|
|
20515
20910
|
}
|
|
20516
20911
|
case "switch": {
|
|
20517
|
-
const
|
|
20518
|
-
|
|
20519
|
-
|
|
20520
|
-
|
|
20521
|
-
|
|
20522
|
-
|
|
20523
|
-
|
|
20524
|
-
|
|
20525
|
-
|
|
20526
|
-
|
|
20527
|
-
|
|
20528
|
-
|
|
20529
|
-
|
|
20912
|
+
const prevConditional = ctx.inConditional ?? 0;
|
|
20913
|
+
ctx.inConditional = prevConditional + 1;
|
|
20914
|
+
let cases;
|
|
20915
|
+
try {
|
|
20916
|
+
cases = node.cases.map((c) => {
|
|
20917
|
+
const stmts = ensureSwitchCaseBreak(
|
|
20918
|
+
lowerStructuredNodeForRegion(
|
|
20919
|
+
c.body,
|
|
20920
|
+
region,
|
|
20921
|
+
t4,
|
|
20922
|
+
ctx,
|
|
20923
|
+
declaredVars,
|
|
20924
|
+
regionCtx,
|
|
20925
|
+
skipInstructions
|
|
20926
|
+
),
|
|
20927
|
+
t4
|
|
20928
|
+
);
|
|
20929
|
+
if (stmts.length === 0) return null;
|
|
20930
|
+
return t4.switchCase(c.test ? lowerExpressionWithDeSSA(c.test, ctx) : null, stmts);
|
|
20931
|
+
}).filter((c) => !!c);
|
|
20932
|
+
} finally {
|
|
20933
|
+
ctx.inConditional = prevConditional;
|
|
20934
|
+
}
|
|
20530
20935
|
if (cases.length === 0) return [];
|
|
20531
20936
|
return [t4.switchStatement(lowerExpressionWithDeSSA(node.discriminant, ctx), cases)];
|
|
20532
20937
|
}
|
|
@@ -20979,6 +21384,7 @@ function collectExprDependencies(expr) {
|
|
|
20979
21384
|
if (p.kind === "SpreadElement") {
|
|
20980
21385
|
visit(p.argument);
|
|
20981
21386
|
} else {
|
|
21387
|
+
if (p.computed) visit(p.key);
|
|
20982
21388
|
visit(p.value);
|
|
20983
21389
|
}
|
|
20984
21390
|
});
|
|
@@ -21842,7 +22248,10 @@ function expressionContainsJSX(expr) {
|
|
|
21842
22248
|
case "ArrayExpression":
|
|
21843
22249
|
return expr.elements?.some((el) => expressionContainsJSX(el)) ?? false;
|
|
21844
22250
|
case "ObjectExpression":
|
|
21845
|
-
return expr.properties?.some((p) =>
|
|
22251
|
+
return expr.properties?.some((p) => {
|
|
22252
|
+
if (p.kind === "SpreadElement") return expressionContainsJSX(p.argument);
|
|
22253
|
+
return (p.computed ?? false) && expressionContainsJSX(p.key) || expressionContainsJSX(p.value);
|
|
22254
|
+
}) ?? false;
|
|
21846
22255
|
case "ConditionalExpression":
|
|
21847
22256
|
return expressionContainsJSX(expr.test) || expressionContainsJSX(expr.consequent) || expressionContainsJSX(expr.alternate);
|
|
21848
22257
|
case "ArrowFunction":
|
|
@@ -21956,7 +22365,7 @@ function expressionHasAwait(expr) {
|
|
|
21956
22365
|
return expr.elements.some((el) => el && expressionHasAwait(el));
|
|
21957
22366
|
case "ObjectExpression":
|
|
21958
22367
|
return expr.properties.some(
|
|
21959
|
-
(prop) => prop.kind === "Property" && expressionHasAwait(prop.value) || prop.kind === "SpreadElement" && expressionHasAwait(prop.argument)
|
|
22368
|
+
(prop) => prop.kind === "Property" && ((prop.computed ?? false) && expressionHasAwait(prop.key) || expressionHasAwait(prop.value)) || prop.kind === "SpreadElement" && expressionHasAwait(prop.argument)
|
|
21960
22369
|
);
|
|
21961
22370
|
case "TemplateLiteral":
|
|
21962
22371
|
return expr.expressions.some((ex) => expressionHasAwait(ex));
|
|
@@ -22027,6 +22436,7 @@ function collectCalledIdentifiers(fn) {
|
|
|
22027
22436
|
if (p.kind === "SpreadElement") {
|
|
22028
22437
|
visitExpr(p.argument);
|
|
22029
22438
|
} else {
|
|
22439
|
+
if (p.computed) visitExpr(p.key);
|
|
22030
22440
|
visitExpr(p.value);
|
|
22031
22441
|
}
|
|
22032
22442
|
});
|
|
@@ -22253,6 +22663,7 @@ function analyzeHookReturnInfo(fn, ctx) {
|
|
|
22253
22663
|
if (expr.kind === "ObjectExpression") {
|
|
22254
22664
|
expr.properties.forEach((prop) => {
|
|
22255
22665
|
if (prop.kind !== "Property") return;
|
|
22666
|
+
if (prop.computed) return;
|
|
22256
22667
|
const keyName = prop.key.kind === "Identifier" ? prop.key.name : prop.key.kind === "Literal" ? String(prop.key.value) : void 0;
|
|
22257
22668
|
if (!keyName) return;
|
|
22258
22669
|
if (prop.value.kind === "Identifier") {
|
|
@@ -22561,6 +22972,7 @@ function collectExpressionIdentifiers(expr, into) {
|
|
|
22561
22972
|
collectExpressionIdentifiers(prop.argument, into);
|
|
22562
22973
|
return;
|
|
22563
22974
|
}
|
|
22975
|
+
if (prop.computed) collectExpressionIdentifiers(prop.key, into);
|
|
22564
22976
|
collectExpressionIdentifiers(prop.value, into);
|
|
22565
22977
|
});
|
|
22566
22978
|
return;
|
|
@@ -22678,6 +23090,7 @@ function collectExpressionIdentifiersDeep(expr, into, bound = /* @__PURE__ */ ne
|
|
|
22678
23090
|
collectExpressionIdentifiersDeep(prop.argument, into, bound);
|
|
22679
23091
|
return;
|
|
22680
23092
|
}
|
|
23093
|
+
if (prop.computed) collectExpressionIdentifiersDeep(prop.key, into, bound);
|
|
22681
23094
|
collectExpressionIdentifiersDeep(prop.value, into, bound);
|
|
22682
23095
|
});
|
|
22683
23096
|
return;
|
|
@@ -24184,6 +24597,28 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
24184
24597
|
if (p.kind === "SpreadElement") {
|
|
24185
24598
|
return t4.spreadElement(lowerExpression(p.argument, ctx));
|
|
24186
24599
|
}
|
|
24600
|
+
const keyIsIdentifier = !p.computed && p.key.kind === "Identifier";
|
|
24601
|
+
const keyIdent = keyIsIdentifier ? p.key.name : "";
|
|
24602
|
+
const keyNode = p.computed ? lowerExpression(p.key, ctx) : keyIsIdentifier ? t4.identifier(keyIdent) : lowerExpression(p.key, ctx);
|
|
24603
|
+
if (p.propertyKind && p.propertyKind !== "init") {
|
|
24604
|
+
const valueExpr2 = lowerExpression(p.value, ctx);
|
|
24605
|
+
if (!t4.isFunctionExpression(valueExpr2)) {
|
|
24606
|
+
throw new HIRError(
|
|
24607
|
+
`Object method property did not lower to function expression.`,
|
|
24608
|
+
"CODEGEN_ERROR"
|
|
24609
|
+
);
|
|
24610
|
+
}
|
|
24611
|
+
const method = t4.objectMethod(
|
|
24612
|
+
p.propertyKind === "method" ? "method" : p.propertyKind,
|
|
24613
|
+
keyNode,
|
|
24614
|
+
valueExpr2.params,
|
|
24615
|
+
valueExpr2.body,
|
|
24616
|
+
!!p.computed
|
|
24617
|
+
);
|
|
24618
|
+
method.async = valueExpr2.async;
|
|
24619
|
+
method.generator = valueExpr2.generator;
|
|
24620
|
+
return method;
|
|
24621
|
+
}
|
|
24187
24622
|
const usesTracked = !!ctx.inPropsContext && (!ctx.nonReactiveScopeDepth || ctx.nonReactiveScopeDepth === 0) && p.value.kind !== "ArrowFunction" && p.value.kind !== "FunctionExpression" && expressionUsesTracked(p.value, ctx);
|
|
24188
24623
|
const valueExprRaw = usesTracked ? lowerTrackedExpression(p.value, ctx) : lowerExpression(p.value, ctx);
|
|
24189
24624
|
const shouldMemoProp = usesTracked && !t4.isIdentifier(valueExprRaw) && !t4.isMemberExpression(valueExprRaw) && !t4.isLiteral(valueExprRaw);
|
|
@@ -24199,13 +24634,11 @@ function lowerExpressionImpl(expr, ctx, _isAssigned = false) {
|
|
|
24199
24634
|
t4.arrowFunctionExpression([], valueExprRaw)
|
|
24200
24635
|
]);
|
|
24201
24636
|
})() : valueExprRaw;
|
|
24202
|
-
const
|
|
24203
|
-
const keyNode = p.key.kind === "Identifier" ? t4.identifier(keyName) : t4.stringLiteral(keyName);
|
|
24204
|
-
const useShorthand = p.shorthand && t4.isIdentifier(valueExpr) && p.key.kind === "Identifier" && deSSAVarName(keyName) === valueExpr.name;
|
|
24637
|
+
const useShorthand = p.shorthand && t4.isIdentifier(valueExpr) && keyIsIdentifier && deSSAVarName(keyIdent) === valueExpr.name;
|
|
24205
24638
|
return t4.objectProperty(
|
|
24206
24639
|
useShorthand ? t4.identifier(valueExpr.name) : keyNode,
|
|
24207
24640
|
valueExpr,
|
|
24208
|
-
|
|
24641
|
+
!!p.computed,
|
|
24209
24642
|
useShorthand
|
|
24210
24643
|
);
|
|
24211
24644
|
})
|
|
@@ -24675,6 +25108,7 @@ function collectExpressionDependencies(expr, deps) {
|
|
|
24675
25108
|
if (p.kind === "SpreadElement") {
|
|
24676
25109
|
collectExpressionDependencies(p.argument, deps);
|
|
24677
25110
|
} else {
|
|
25111
|
+
if (p.computed) collectExpressionDependencies(p.key, deps);
|
|
24678
25112
|
collectExpressionDependencies(p.value, deps);
|
|
24679
25113
|
}
|
|
24680
25114
|
});
|
|
@@ -25199,6 +25633,7 @@ function countExpressionNodes(expr) {
|
|
|
25199
25633
|
case "ObjectExpression":
|
|
25200
25634
|
for (const prop of expr.properties) {
|
|
25201
25635
|
if (prop.kind === "Property") {
|
|
25636
|
+
if (prop.computed) count += countExpressionNodes(prop.key);
|
|
25202
25637
|
count += countExpressionNodes(prop.value);
|
|
25203
25638
|
} else if (prop.kind === "SpreadElement") {
|
|
25204
25639
|
count += countExpressionNodes(prop.argument);
|
|
@@ -26560,7 +26995,7 @@ function hirExpressionUsesIdentifiers(expr, names) {
|
|
|
26560
26995
|
if (prop.kind === "SpreadElement") {
|
|
26561
26996
|
return hirExpressionUsesIdentifiers(prop.argument, names);
|
|
26562
26997
|
}
|
|
26563
|
-
return hirExpressionUsesIdentifiers(prop.key, names) || hirExpressionUsesIdentifiers(prop.value, names);
|
|
26998
|
+
return (prop.computed ?? false) && hirExpressionUsesIdentifiers(prop.key, names) || hirExpressionUsesIdentifiers(prop.value, names);
|
|
26564
26999
|
});
|
|
26565
27000
|
case "TemplateLiteral":
|
|
26566
27001
|
return expr.expressions.some((e) => hirExpressionUsesIdentifiers(e, names));
|
|
@@ -27370,18 +27805,82 @@ function lowerTopLevelStatementBlock(statements, ctx, t4, name = "__module_segme
|
|
|
27370
27805
|
}
|
|
27371
27806
|
function transformControlFlowReturns(statements, ctx) {
|
|
27372
27807
|
const { t: t4 } = ctx;
|
|
27808
|
+
const reactiveAccessorNames = /* @__PURE__ */ new Set([
|
|
27809
|
+
...ctx.trackedVars,
|
|
27810
|
+
...ctx.signalVars ?? [],
|
|
27811
|
+
...ctx.memoVars ?? [],
|
|
27812
|
+
...ctx.aliasVars ?? [],
|
|
27813
|
+
...ctx.storeVars ?? []
|
|
27814
|
+
]);
|
|
27373
27815
|
const toStatements = (node) => t4.isBlockStatement(node) ? node.body : [node];
|
|
27374
27816
|
const endsWithReturn = (stmts) => {
|
|
27375
27817
|
if (stmts.length === 0) return false;
|
|
27376
27818
|
const tail = stmts[stmts.length - 1];
|
|
27377
27819
|
if (t4.isReturnStatement(tail)) return true;
|
|
27820
|
+
if (t4.isBlockStatement(tail)) {
|
|
27821
|
+
return endsWithReturn(tail.body);
|
|
27822
|
+
}
|
|
27378
27823
|
if (t4.isIfStatement(tail) && tail.consequent && tail.alternate) {
|
|
27379
27824
|
const conseqStmts = toStatements(tail.consequent);
|
|
27380
27825
|
const altStmts = toStatements(tail.alternate);
|
|
27381
27826
|
return endsWithReturn(conseqStmts) && endsWithReturn(altStmts);
|
|
27382
27827
|
}
|
|
27828
|
+
if (t4.isTryStatement(tail)) {
|
|
27829
|
+
if (tail.finalizer && endsWithReturn(tail.finalizer.body)) return true;
|
|
27830
|
+
if (!tail.handler) return false;
|
|
27831
|
+
return endsWithReturn(tail.block.body) && endsWithReturn(tail.handler.body.body);
|
|
27832
|
+
}
|
|
27383
27833
|
return false;
|
|
27384
27834
|
};
|
|
27835
|
+
function hasNodeMatch(nodes, predicate) {
|
|
27836
|
+
let found = false;
|
|
27837
|
+
const visit = (node) => {
|
|
27838
|
+
if (!node || found) return;
|
|
27839
|
+
if (predicate(node)) {
|
|
27840
|
+
found = true;
|
|
27841
|
+
return;
|
|
27842
|
+
}
|
|
27843
|
+
const keys = t4.VISITOR_KEYS;
|
|
27844
|
+
const visitorKeys = keys?.[node.type] ?? [];
|
|
27845
|
+
for (const key of visitorKeys) {
|
|
27846
|
+
const value = node[key];
|
|
27847
|
+
if (Array.isArray(value)) {
|
|
27848
|
+
for (const child of value) {
|
|
27849
|
+
if (child && typeof child === "object" && "type" in child) {
|
|
27850
|
+
visit(child);
|
|
27851
|
+
}
|
|
27852
|
+
if (found) return;
|
|
27853
|
+
}
|
|
27854
|
+
} else if (value && typeof value === "object" && "type" in value) {
|
|
27855
|
+
visit(value);
|
|
27856
|
+
}
|
|
27857
|
+
if (found) return;
|
|
27858
|
+
}
|
|
27859
|
+
};
|
|
27860
|
+
for (const node of nodes) {
|
|
27861
|
+
visit(node);
|
|
27862
|
+
if (found) return true;
|
|
27863
|
+
}
|
|
27864
|
+
return found;
|
|
27865
|
+
}
|
|
27866
|
+
const containsReturnStatement = (nodes) => hasNodeMatch(nodes, (node) => t4.isReturnStatement(node));
|
|
27867
|
+
const containsReactiveAccessorRead = (nodes) => hasNodeMatch(nodes, (node) => {
|
|
27868
|
+
if (!t4.isCallExpression(node) && !t4.isOptionalCallExpression(node)) return false;
|
|
27869
|
+
const callee = node.callee;
|
|
27870
|
+
return t4.isIdentifier(callee) && reactiveAccessorNames.has(callee.name);
|
|
27871
|
+
});
|
|
27872
|
+
const emitControlFlowFallbackWarning = (node, kind) => {
|
|
27873
|
+
const onWarn = ctx.options?.onWarn;
|
|
27874
|
+
if (!onWarn) return;
|
|
27875
|
+
const loc = node.loc?.start;
|
|
27876
|
+
onWarn({
|
|
27877
|
+
code: "FICT-R003" /* FICT_R003 */,
|
|
27878
|
+
message: `Reactive ${kind}-return lowering was skipped for this branch. The branch structure will not update reactively; refactor to a supported ${kind} form or use explicit runtime conditionals.`,
|
|
27879
|
+
fileName: ctx.options?.filename ?? "<unknown>",
|
|
27880
|
+
line: loc?.line ?? 0,
|
|
27881
|
+
column: loc ? loc.column + 1 : 0
|
|
27882
|
+
});
|
|
27883
|
+
};
|
|
27385
27884
|
function buildReturnBlock(stmts) {
|
|
27386
27885
|
if (stmts.length === 0) return null;
|
|
27387
27886
|
for (let i = 0; i < stmts.length; i++) {
|
|
@@ -27396,33 +27895,55 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
27396
27895
|
if (!endsWithReturn(stmts)) return null;
|
|
27397
27896
|
return stmts;
|
|
27398
27897
|
}
|
|
27399
|
-
function buildBranchFunction(stmts) {
|
|
27898
|
+
function buildBranchFunction(stmts, options) {
|
|
27400
27899
|
const block = buildReturnBlock(stmts);
|
|
27401
27900
|
if (!block) return null;
|
|
27901
|
+
if (options?.disallowRenderHooks && containsRenderOnlyHooks(block)) return null;
|
|
27402
27902
|
return t4.arrowFunctionExpression([], t4.blockStatement(block));
|
|
27403
27903
|
}
|
|
27404
|
-
function
|
|
27405
|
-
|
|
27406
|
-
|
|
27407
|
-
|
|
27408
|
-
|
|
27409
|
-
|
|
27410
|
-
|
|
27411
|
-
|
|
27412
|
-
|
|
27413
|
-
|
|
27414
|
-
|
|
27415
|
-
|
|
27904
|
+
function containsRenderOnlyHooks(nodes) {
|
|
27905
|
+
let found = false;
|
|
27906
|
+
const visit = (node) => {
|
|
27907
|
+
if (!node || found) return;
|
|
27908
|
+
if (t4.isCallExpression(node) || t4.isOptionalCallExpression(node)) {
|
|
27909
|
+
const callee = node.callee;
|
|
27910
|
+
if (t4.isIdentifier(callee) && callee.name.startsWith("__fictUse")) {
|
|
27911
|
+
if (callee.name !== "__fictUseEffect") {
|
|
27912
|
+
found = true;
|
|
27913
|
+
return;
|
|
27914
|
+
}
|
|
27915
|
+
}
|
|
27916
|
+
}
|
|
27917
|
+
const keys = t4.VISITOR_KEYS;
|
|
27918
|
+
const visitorKeys = keys?.[node.type] ?? [];
|
|
27919
|
+
for (const key of visitorKeys) {
|
|
27920
|
+
const value = node[key];
|
|
27921
|
+
if (Array.isArray(value)) {
|
|
27922
|
+
for (const child of value) {
|
|
27923
|
+
if (child && typeof child === "object" && "type" in child) {
|
|
27924
|
+
visit(child);
|
|
27925
|
+
}
|
|
27926
|
+
if (found) return;
|
|
27927
|
+
}
|
|
27928
|
+
} else if (value && typeof value === "object" && "type" in value) {
|
|
27929
|
+
visit(value);
|
|
27930
|
+
}
|
|
27931
|
+
if (found) return;
|
|
27932
|
+
}
|
|
27933
|
+
};
|
|
27934
|
+
for (const node of nodes) {
|
|
27935
|
+
visit(node);
|
|
27936
|
+
if (found) break;
|
|
27416
27937
|
}
|
|
27417
|
-
|
|
27418
|
-
|
|
27419
|
-
|
|
27938
|
+
return found;
|
|
27939
|
+
}
|
|
27940
|
+
function buildConditionalBindingExpr(testExpr, trueFn, falseFn) {
|
|
27420
27941
|
ctx.helpersUsed.add("conditional");
|
|
27421
27942
|
ctx.helpersUsed.add("createElement");
|
|
27422
27943
|
ctx.helpersUsed.add("onDestroy");
|
|
27423
27944
|
const bindingId = genTemp(ctx, "cond");
|
|
27424
27945
|
const args = [
|
|
27425
|
-
t4.arrowFunctionExpression([],
|
|
27946
|
+
t4.arrowFunctionExpression([], testExpr),
|
|
27426
27947
|
trueFn,
|
|
27427
27948
|
t4.identifier(RUNTIME_ALIASES.createElement),
|
|
27428
27949
|
falseFn
|
|
@@ -27444,15 +27965,210 @@ function transformControlFlowReturns(statements, ctx) {
|
|
|
27444
27965
|
[]
|
|
27445
27966
|
);
|
|
27446
27967
|
}
|
|
27447
|
-
|
|
27448
|
-
const
|
|
27968
|
+
function buildConditionalExpr(ifStmt, rest) {
|
|
27969
|
+
const consequentStmts = toStatements(ifStmt.consequent);
|
|
27970
|
+
if (!endsWithReturn(consequentStmts)) return null;
|
|
27971
|
+
let alternateStmts = null;
|
|
27972
|
+
if (ifStmt.alternate) {
|
|
27973
|
+
if (rest.length > 0) return null;
|
|
27974
|
+
alternateStmts = toStatements(ifStmt.alternate);
|
|
27975
|
+
if (!endsWithReturn(alternateStmts)) return null;
|
|
27976
|
+
} else {
|
|
27977
|
+
if (rest.length === 0) return null;
|
|
27978
|
+
alternateStmts = rest;
|
|
27979
|
+
if (!buildReturnBlock(alternateStmts)) return null;
|
|
27980
|
+
}
|
|
27981
|
+
const trueFn = buildBranchFunction(consequentStmts);
|
|
27982
|
+
const falseFn = alternateStmts ? buildBranchFunction(alternateStmts) : null;
|
|
27983
|
+
if (!trueFn || !falseFn) return null;
|
|
27984
|
+
return buildConditionalBindingExpr(ifStmt.test, trueFn, falseFn);
|
|
27985
|
+
}
|
|
27986
|
+
function isSupportedSwitchDiscriminant(_expr) {
|
|
27987
|
+
return true;
|
|
27988
|
+
}
|
|
27989
|
+
function buildSwitchConditionalExpr(switchStmt, rest) {
|
|
27990
|
+
const discriminant = switchStmt.discriminant;
|
|
27991
|
+
if (!isSupportedSwitchDiscriminant(discriminant)) return null;
|
|
27992
|
+
const trailingStatements = rest.length > 0 ? buildReturnBlock([...rest]) : [];
|
|
27993
|
+
if (rest.length > 0 && !trailingStatements) return null;
|
|
27994
|
+
const caseEntryCache = /* @__PURE__ */ new Map();
|
|
27995
|
+
const resolveCaseEntry = (startIndex) => {
|
|
27996
|
+
if (caseEntryCache.has(startIndex)) {
|
|
27997
|
+
return caseEntryCache.get(startIndex) ?? null;
|
|
27998
|
+
}
|
|
27999
|
+
const entry = [];
|
|
28000
|
+
for (let i = startIndex; i < switchStmt.cases.length; i++) {
|
|
28001
|
+
const currentCase = switchStmt.cases[i];
|
|
28002
|
+
const consequent = currentCase.consequent;
|
|
28003
|
+
for (let stmtIndex = 0; stmtIndex < consequent.length; stmtIndex++) {
|
|
28004
|
+
const stmt = consequent[stmtIndex];
|
|
28005
|
+
if (t4.isBreakStatement(stmt)) {
|
|
28006
|
+
if (stmt.label || stmtIndex !== consequent.length - 1) {
|
|
28007
|
+
caseEntryCache.set(startIndex, null);
|
|
28008
|
+
return null;
|
|
28009
|
+
}
|
|
28010
|
+
if (!trailingStatements || trailingStatements.length === 0) {
|
|
28011
|
+
caseEntryCache.set(startIndex, null);
|
|
28012
|
+
return null;
|
|
28013
|
+
}
|
|
28014
|
+
const withTrailing2 = [...entry, ...trailingStatements];
|
|
28015
|
+
caseEntryCache.set(startIndex, withTrailing2);
|
|
28016
|
+
return withTrailing2;
|
|
28017
|
+
}
|
|
28018
|
+
if (t4.isContinueStatement(stmt)) {
|
|
28019
|
+
caseEntryCache.set(startIndex, null);
|
|
28020
|
+
return null;
|
|
28021
|
+
}
|
|
28022
|
+
entry.push(stmt);
|
|
28023
|
+
}
|
|
28024
|
+
if (endsWithReturn(entry)) {
|
|
28025
|
+
caseEntryCache.set(startIndex, entry);
|
|
28026
|
+
return entry;
|
|
28027
|
+
}
|
|
28028
|
+
}
|
|
28029
|
+
if (!trailingStatements || trailingStatements.length === 0) {
|
|
28030
|
+
caseEntryCache.set(startIndex, null);
|
|
28031
|
+
return null;
|
|
28032
|
+
}
|
|
28033
|
+
const withTrailing = [...entry, ...trailingStatements];
|
|
28034
|
+
caseEntryCache.set(startIndex, withTrailing);
|
|
28035
|
+
return withTrailing;
|
|
28036
|
+
};
|
|
28037
|
+
const branches = [];
|
|
28038
|
+
let defaultStatements = null;
|
|
28039
|
+
for (let i = 0; i < switchStmt.cases.length; i++) {
|
|
28040
|
+
const caseNode = switchStmt.cases[i];
|
|
28041
|
+
const statements2 = resolveCaseEntry(i);
|
|
28042
|
+
if (!statements2) return null;
|
|
28043
|
+
if (caseNode.test) {
|
|
28044
|
+
branches.push({
|
|
28045
|
+
tests: [caseNode.test],
|
|
28046
|
+
statements: statements2
|
|
28047
|
+
});
|
|
28048
|
+
} else {
|
|
28049
|
+
defaultStatements = statements2;
|
|
28050
|
+
}
|
|
28051
|
+
}
|
|
28052
|
+
if (branches.length === 0 && !defaultStatements) return null;
|
|
28053
|
+
const fallbackStatements = defaultStatements ?? trailingStatements;
|
|
28054
|
+
if (!fallbackStatements || fallbackStatements.length === 0) return null;
|
|
28055
|
+
const fallbackFn = buildBranchFunction(fallbackStatements, { disallowRenderHooks: true });
|
|
28056
|
+
if (!fallbackFn) return null;
|
|
28057
|
+
ctx.helpersUsed.add("memo");
|
|
28058
|
+
const discriminantAccessor = genTemp(ctx, "switchDisc");
|
|
28059
|
+
const discriminantMemoDecl = t4.variableDeclaration("const", [
|
|
28060
|
+
t4.variableDeclarator(
|
|
28061
|
+
discriminantAccessor,
|
|
28062
|
+
t4.callExpression(t4.identifier(RUNTIME_ALIASES.memo), [
|
|
28063
|
+
t4.arrowFunctionExpression(
|
|
28064
|
+
[],
|
|
28065
|
+
t4.cloneNode(discriminant, true)
|
|
28066
|
+
)
|
|
28067
|
+
])
|
|
28068
|
+
)
|
|
28069
|
+
]);
|
|
28070
|
+
let currentExpr = t4.callExpression(
|
|
28071
|
+
t4.arrowFunctionExpression(
|
|
28072
|
+
[],
|
|
28073
|
+
t4.blockStatement(fallbackFn.body.body)
|
|
28074
|
+
),
|
|
28075
|
+
[]
|
|
28076
|
+
);
|
|
28077
|
+
for (let i = branches.length - 1; i >= 0; i--) {
|
|
28078
|
+
const branch = branches[i];
|
|
28079
|
+
const trueFn = buildBranchFunction(branch.statements, { disallowRenderHooks: true });
|
|
28080
|
+
if (!trueFn) return null;
|
|
28081
|
+
const falseFn = t4.arrowFunctionExpression(
|
|
28082
|
+
[],
|
|
28083
|
+
t4.blockStatement([t4.returnStatement(currentExpr)])
|
|
28084
|
+
);
|
|
28085
|
+
const comparisons = branch.tests.map(
|
|
28086
|
+
(test) => t4.binaryExpression(
|
|
28087
|
+
"===",
|
|
28088
|
+
t4.callExpression(t4.cloneNode(discriminantAccessor), []),
|
|
28089
|
+
t4.cloneNode(test, true)
|
|
28090
|
+
)
|
|
28091
|
+
);
|
|
28092
|
+
if (comparisons.length === 0) return null;
|
|
28093
|
+
const testExpr = comparisons.slice(1).reduce(
|
|
28094
|
+
(acc, expr) => t4.logicalExpression("||", acc, expr),
|
|
28095
|
+
comparisons[0]
|
|
28096
|
+
);
|
|
28097
|
+
currentExpr = buildConditionalBindingExpr(testExpr, trueFn, falseFn);
|
|
28098
|
+
}
|
|
28099
|
+
return t4.callExpression(
|
|
28100
|
+
t4.arrowFunctionExpression(
|
|
28101
|
+
[],
|
|
28102
|
+
t4.blockStatement([discriminantMemoDecl, t4.returnStatement(currentExpr)])
|
|
28103
|
+
),
|
|
28104
|
+
[]
|
|
28105
|
+
);
|
|
28106
|
+
}
|
|
28107
|
+
let nestedChanged = false;
|
|
28108
|
+
const rewrittenStatements = statements.map((stmt) => {
|
|
28109
|
+
if (!t4.isTryStatement(stmt)) return stmt;
|
|
28110
|
+
const transformedTryBlock = transformControlFlowReturns(stmt.block.body, ctx);
|
|
28111
|
+
const nextTryBlockBody = transformedTryBlock ?? stmt.block.body;
|
|
28112
|
+
let nextHandler = stmt.handler;
|
|
28113
|
+
if (stmt.handler) {
|
|
28114
|
+
const transformedCatchBlock = transformControlFlowReturns(stmt.handler.body.body, ctx);
|
|
28115
|
+
if (transformedCatchBlock) {
|
|
28116
|
+
nextHandler = t4.catchClause(
|
|
28117
|
+
stmt.handler.param ? t4.cloneNode(stmt.handler.param, true) : null,
|
|
28118
|
+
t4.blockStatement(transformedCatchBlock)
|
|
28119
|
+
);
|
|
28120
|
+
}
|
|
28121
|
+
}
|
|
28122
|
+
let nextFinalizer = stmt.finalizer;
|
|
28123
|
+
if (stmt.finalizer) {
|
|
28124
|
+
const transformedFinalizer = transformControlFlowReturns(stmt.finalizer.body, ctx);
|
|
28125
|
+
if (transformedFinalizer) {
|
|
28126
|
+
nextFinalizer = t4.blockStatement(transformedFinalizer);
|
|
28127
|
+
}
|
|
28128
|
+
}
|
|
28129
|
+
if (!transformedTryBlock && nextHandler === stmt.handler && nextFinalizer === stmt.finalizer) {
|
|
28130
|
+
return stmt;
|
|
28131
|
+
}
|
|
28132
|
+
nestedChanged = true;
|
|
28133
|
+
return t4.tryStatement(
|
|
28134
|
+
t4.blockStatement(nextTryBlockBody),
|
|
28135
|
+
nextHandler,
|
|
28136
|
+
nextFinalizer ? t4.cloneNode(nextFinalizer, true) : null
|
|
28137
|
+
);
|
|
28138
|
+
});
|
|
28139
|
+
for (let i = 0; i < rewrittenStatements.length; i++) {
|
|
28140
|
+
const stmt = rewrittenStatements[i];
|
|
27449
28141
|
if (!t4.isIfStatement(stmt)) continue;
|
|
27450
|
-
const
|
|
27451
|
-
|
|
27452
|
-
|
|
28142
|
+
const rest = rewrittenStatements.slice(i + 1);
|
|
28143
|
+
const conditionalExpr = buildConditionalExpr(stmt, rest);
|
|
28144
|
+
if (!conditionalExpr) {
|
|
28145
|
+
const hasReturn = containsReturnStatement([stmt, ...rest]);
|
|
28146
|
+
const hasReactiveReads = containsReactiveAccessorRead([stmt, ...rest]);
|
|
28147
|
+
if (hasReturn && hasReactiveReads) {
|
|
28148
|
+
emitControlFlowFallbackWarning(stmt, "if");
|
|
28149
|
+
}
|
|
28150
|
+
continue;
|
|
28151
|
+
}
|
|
28152
|
+
const prefix = rewrittenStatements.slice(0, i);
|
|
27453
28153
|
return [...prefix, t4.returnStatement(conditionalExpr)];
|
|
27454
28154
|
}
|
|
27455
|
-
|
|
28155
|
+
for (let i = 0; i < rewrittenStatements.length; i++) {
|
|
28156
|
+
const stmt = rewrittenStatements[i];
|
|
28157
|
+
if (!t4.isSwitchStatement(stmt)) continue;
|
|
28158
|
+
const rest = rewrittenStatements.slice(i + 1);
|
|
28159
|
+
const conditionalExpr = buildSwitchConditionalExpr(stmt, rest);
|
|
28160
|
+
if (!conditionalExpr) {
|
|
28161
|
+
const hasReturn = containsReturnStatement([stmt, ...rest]);
|
|
28162
|
+
const hasReactiveReads = containsReactiveAccessorRead([stmt, ...rest]);
|
|
28163
|
+
if (hasReturn && hasReactiveReads) {
|
|
28164
|
+
emitControlFlowFallbackWarning(stmt, "switch");
|
|
28165
|
+
}
|
|
28166
|
+
continue;
|
|
28167
|
+
}
|
|
28168
|
+
const prefix = rewrittenStatements.slice(0, i);
|
|
28169
|
+
return [...prefix, t4.returnStatement(conditionalExpr)];
|
|
28170
|
+
}
|
|
28171
|
+
return nestedChanged ? rewrittenStatements : null;
|
|
27456
28172
|
}
|
|
27457
28173
|
function lowerFunctionWithRegions(fn, ctx, options) {
|
|
27458
28174
|
const { t: t4 } = ctx;
|
|
@@ -28314,6 +29030,7 @@ function collectRootNodesFromExpression(expr, onBinding, onEffect) {
|
|
|
28314
29030
|
if (prop.kind === "SpreadElement") {
|
|
28315
29031
|
visit(prop.argument, shadowed);
|
|
28316
29032
|
} else {
|
|
29033
|
+
if (prop.computed) visit(prop.key, shadowed);
|
|
28317
29034
|
visit(prop.value, shadowed);
|
|
28318
29035
|
}
|
|
28319
29036
|
});
|
|
@@ -28458,6 +29175,14 @@ function collectDependenciesFromExpression(expr, deps, includeFunctionBodies, sh
|
|
|
28458
29175
|
shadowed
|
|
28459
29176
|
);
|
|
28460
29177
|
} else {
|
|
29178
|
+
if (prop.computed) {
|
|
29179
|
+
collectDependenciesFromExpression(
|
|
29180
|
+
prop.key,
|
|
29181
|
+
deps,
|
|
29182
|
+
includeFunctionBodies,
|
|
29183
|
+
shadowed
|
|
29184
|
+
);
|
|
29185
|
+
}
|
|
28461
29186
|
collectDependenciesFromExpression(
|
|
28462
29187
|
prop.value,
|
|
28463
29188
|
deps,
|
|
@@ -29420,7 +30145,7 @@ function expressionDependsOnReactive(expr, ctx) {
|
|
|
29420
30145
|
if (prop.kind === "SpreadElement") {
|
|
29421
30146
|
return expressionDependsOnReactive(prop.argument, ctx);
|
|
29422
30147
|
}
|
|
29423
|
-
return expressionDependsOnReactive(prop.value, ctx);
|
|
30148
|
+
return prop.computed && expressionDependsOnReactive(prop.key, ctx) || expressionDependsOnReactive(prop.value, ctx);
|
|
29424
30149
|
});
|
|
29425
30150
|
case "TemplateLiteral":
|
|
29426
30151
|
return expr.expressions.some((e) => expressionDependsOnReactive(e, ctx));
|
|
@@ -29520,6 +30245,7 @@ function collectWriteTargets(expr) {
|
|
|
29520
30245
|
if (prop.kind === "SpreadElement") {
|
|
29521
30246
|
visit(prop.argument);
|
|
29522
30247
|
} else {
|
|
30248
|
+
if (prop.computed) visit(prop.key);
|
|
29523
30249
|
visit(prop.value);
|
|
29524
30250
|
}
|
|
29525
30251
|
});
|
|
@@ -29593,6 +30319,7 @@ function collectMemberCallTargets(expr) {
|
|
|
29593
30319
|
if (prop.kind === "SpreadElement") {
|
|
29594
30320
|
visit(prop.argument);
|
|
29595
30321
|
} else {
|
|
30322
|
+
if (prop.computed) visit(prop.key);
|
|
29596
30323
|
visit(prop.value);
|
|
29597
30324
|
}
|
|
29598
30325
|
});
|
|
@@ -29720,7 +30447,7 @@ function expressionContainsImpureMarkers(expr) {
|
|
|
29720
30447
|
if (prop.kind === "SpreadElement") {
|
|
29721
30448
|
return expressionContainsImpureMarkers(prop.argument);
|
|
29722
30449
|
}
|
|
29723
|
-
return expressionContainsImpureMarkers(prop.value);
|
|
30450
|
+
return prop.computed && expressionContainsImpureMarkers(prop.key) || expressionContainsImpureMarkers(prop.value);
|
|
29724
30451
|
});
|
|
29725
30452
|
case "TemplateLiteral":
|
|
29726
30453
|
return expr.expressions.some((e) => expressionContainsImpureMarkers(e));
|
|
@@ -29925,6 +30652,7 @@ function extractConstObjectFields(expr, constants) {
|
|
|
29925
30652
|
const fields = /* @__PURE__ */ new Map();
|
|
29926
30653
|
for (const prop of expr.properties) {
|
|
29927
30654
|
if (prop.kind === "SpreadElement") return null;
|
|
30655
|
+
if (prop.computed) return null;
|
|
29928
30656
|
const key = getObjectLiteralKey(prop.key);
|
|
29929
30657
|
if (!key) return null;
|
|
29930
30658
|
const value = evaluateLiteral(prop.value, constants);
|
|
@@ -30052,6 +30780,7 @@ function replaceConstMemberExpressions(expr, constObjects, constArrays) {
|
|
|
30052
30780
|
}
|
|
30053
30781
|
return {
|
|
30054
30782
|
...prop,
|
|
30783
|
+
key: prop.computed ? replaceConstMemberExpressions(prop.key, constObjects, constArrays) : prop.key,
|
|
30055
30784
|
value: replaceConstMemberExpressions(
|
|
30056
30785
|
prop.value,
|
|
30057
30786
|
constObjects,
|
|
@@ -30302,6 +31031,7 @@ function simplifyChildren(expr, constants, options) {
|
|
|
30302
31031
|
if (prop.kind === "Property") {
|
|
30303
31032
|
return {
|
|
30304
31033
|
...prop,
|
|
31034
|
+
key: prop.computed ? simplifyAlgebraically(prop.key, constants, options) : prop.key,
|
|
30305
31035
|
value: simplifyAlgebraically(prop.value, constants, options)
|
|
30306
31036
|
};
|
|
30307
31037
|
}
|
|
@@ -30420,8 +31150,8 @@ function replaceIdentifiersWithConstants(expr, constants, context = {}) {
|
|
|
30420
31150
|
}
|
|
30421
31151
|
return {
|
|
30422
31152
|
...prop,
|
|
30423
|
-
|
|
30424
|
-
|
|
31153
|
+
key: prop.computed ? replaceIdentifiersWithConstants(prop.key, constants) : prop.key,
|
|
31154
|
+
value: replaceIdentifiersWithConstants(prop.value, constants)
|
|
30425
31155
|
};
|
|
30426
31156
|
})
|
|
30427
31157
|
};
|
|
@@ -30973,6 +31703,7 @@ function walkExpression(expr, add, ctx) {
|
|
|
30973
31703
|
if (prop.kind === "SpreadElement") {
|
|
30974
31704
|
walkExpression(prop.argument, add, ctx);
|
|
30975
31705
|
} else {
|
|
31706
|
+
if (prop.computed) walkExpression(prop.key, add, ctx);
|
|
30976
31707
|
walkExpression(prop.value, add, ctx);
|
|
30977
31708
|
}
|
|
30978
31709
|
});
|
|
@@ -31112,7 +31843,9 @@ function hashExpression(expr) {
|
|
|
31112
31843
|
return `arr:${expr.elements.map((el) => el ? hashExpression(el) : "null").join(",")}`;
|
|
31113
31844
|
case "ObjectExpression":
|
|
31114
31845
|
return `obj:${expr.properties.map(
|
|
31115
|
-
(p) => p.kind === "SpreadElement" ? `...${hashExpression(p.argument)}` : `${hashExpression(p.key)}:${hashExpression(
|
|
31846
|
+
(p) => p.kind === "SpreadElement" ? `...${hashExpression(p.argument)}` : `${p.computed ? "[]" : "."}${hashExpression(p.key)}:${hashExpression(
|
|
31847
|
+
p.value
|
|
31848
|
+
)}`
|
|
31116
31849
|
).join(",")}`;
|
|
31117
31850
|
case "TemplateLiteral":
|
|
31118
31851
|
return `tpl:${expr.quasis.join("|")}:${expr.expressions.map((e) => hashExpression(e)).join("|")}`;
|
|
@@ -31159,7 +31892,7 @@ function isPureExpression(expr, ctx) {
|
|
|
31159
31892
|
case "ObjectExpression":
|
|
31160
31893
|
return expr.properties.every((prop) => {
|
|
31161
31894
|
if (prop.kind === "SpreadElement") return isPureExpression(prop.argument, ctx);
|
|
31162
|
-
return isPureExpression(prop.value, ctx);
|
|
31895
|
+
return (!prop.computed || isPureExpression(prop.key, ctx)) && isPureExpression(prop.value, ctx);
|
|
31163
31896
|
});
|
|
31164
31897
|
case "MemberExpression":
|
|
31165
31898
|
case "OptionalMemberExpression":
|
|
@@ -31371,7 +32104,7 @@ function replaceIdentifier(expr, target, replacement, inFunctionBody) {
|
|
|
31371
32104
|
}
|
|
31372
32105
|
return {
|
|
31373
32106
|
...prop,
|
|
31374
|
-
key: prop.key,
|
|
32107
|
+
key: prop.computed ? replaceIdentifier(prop.key, target, replacement, inFunctionBody) : prop.key,
|
|
31375
32108
|
value: replaceIdentifier(prop.value, target, replacement, inFunctionBody)
|
|
31376
32109
|
};
|
|
31377
32110
|
})
|
|
@@ -31706,7 +32439,9 @@ function shouldSuppressWarning(suppressions, code, line) {
|
|
|
31706
32439
|
return entry.codes.has(code);
|
|
31707
32440
|
});
|
|
31708
32441
|
}
|
|
32442
|
+
var DEFAULT_ERROR_WARNING_CODES = /* @__PURE__ */ new Set(["FICT-R004"]);
|
|
31709
32443
|
function hasErrorEscalation(options) {
|
|
32444
|
+
if (DEFAULT_ERROR_WARNING_CODES.size > 0) return true;
|
|
31710
32445
|
if (options.warningsAsErrors === true) return true;
|
|
31711
32446
|
if (Array.isArray(options.warningsAsErrors) && options.warningsAsErrors.length > 0) return true;
|
|
31712
32447
|
if (options.warningLevels) {
|
|
@@ -31721,6 +32456,7 @@ function resolveWarningLevel(code, options) {
|
|
|
31721
32456
|
if (Array.isArray(options.warningsAsErrors) && options.warningsAsErrors.includes(code)) {
|
|
31722
32457
|
return "error";
|
|
31723
32458
|
}
|
|
32459
|
+
if (DEFAULT_ERROR_WARNING_CODES.has(code)) return "error";
|
|
31724
32460
|
return "warn";
|
|
31725
32461
|
}
|
|
31726
32462
|
function formatWarningAsError(warning) {
|
|
@@ -31834,18 +32570,66 @@ function isDynamicPropertyAccess(node, t4) {
|
|
|
31834
32570
|
if (!node.computed) return false;
|
|
31835
32571
|
return !(t4.isStringLiteral(node.property) || t4.isNumericLiteral(node.property));
|
|
31836
32572
|
}
|
|
31837
|
-
function runWarningPass(programPath,
|
|
31838
|
-
const
|
|
32573
|
+
function runWarningPass(programPath, stateBindingIds, stateRootBindingIds, reactiveBindingIds, effectMacroNames, warn, fileName, t4) {
|
|
32574
|
+
const hasTrackedBinding = (path2, name, tracked) => {
|
|
32575
|
+
const binding = path2.scope.getBinding(name);
|
|
32576
|
+
return !!(binding && tracked.has(binding.identifier));
|
|
32577
|
+
};
|
|
32578
|
+
const isStateRoot = (expr, path2) => {
|
|
32579
|
+
const root = getRootIdentifier(expr, t4);
|
|
32580
|
+
if (!root) return false;
|
|
32581
|
+
return hasTrackedBinding(path2, root.name, stateRootBindingIds);
|
|
32582
|
+
};
|
|
32583
|
+
const isReactiveRoot = (expr, path2) => {
|
|
31839
32584
|
const root = getRootIdentifier(expr, t4);
|
|
31840
|
-
|
|
32585
|
+
if (!root) return false;
|
|
32586
|
+
return hasTrackedBinding(path2, root.name, reactiveBindingIds);
|
|
32587
|
+
};
|
|
32588
|
+
const argumentHasReactive = (argPath) => {
|
|
32589
|
+
if (argPath.isSpreadElement()) {
|
|
32590
|
+
const inner = argPath.get("argument");
|
|
32591
|
+
return argumentHasReactive(inner);
|
|
32592
|
+
}
|
|
32593
|
+
if (argPath.isJSXElement() || argPath.isJSXFragment()) return false;
|
|
32594
|
+
if (argPath.isIdentifier()) {
|
|
32595
|
+
return hasTrackedBinding(argPath, argPath.node.name, reactiveBindingIds);
|
|
32596
|
+
}
|
|
32597
|
+
if (!argPath.isExpression()) return false;
|
|
32598
|
+
let found = false;
|
|
32599
|
+
argPath.traverse({
|
|
32600
|
+
Function(path2) {
|
|
32601
|
+
path2.skip();
|
|
32602
|
+
},
|
|
32603
|
+
JSXElement(path2) {
|
|
32604
|
+
path2.skip();
|
|
32605
|
+
},
|
|
32606
|
+
JSXFragment(path2) {
|
|
32607
|
+
path2.skip();
|
|
32608
|
+
},
|
|
32609
|
+
Identifier(idPath) {
|
|
32610
|
+
if (idPath.parentPath.isMemberExpression({ property: idPath.node }) && !idPath.parent.computed) {
|
|
32611
|
+
return;
|
|
32612
|
+
}
|
|
32613
|
+
if (idPath.parentPath.isObjectProperty({ key: idPath.node }) && !idPath.parent.computed && !idPath.parent.shorthand) {
|
|
32614
|
+
return;
|
|
32615
|
+
}
|
|
32616
|
+
const binding = idPath.scope.getBinding(idPath.node.name);
|
|
32617
|
+
if (binding && reactiveBindingIds.has(binding.identifier)) {
|
|
32618
|
+
found = true;
|
|
32619
|
+
idPath.stop();
|
|
32620
|
+
}
|
|
32621
|
+
}
|
|
32622
|
+
});
|
|
32623
|
+
return found;
|
|
31841
32624
|
};
|
|
31842
|
-
const reactiveNames = /* @__PURE__ */ new Set([...stateVars, ...derivedVars]);
|
|
31843
32625
|
programPath.traverse({
|
|
31844
32626
|
AssignmentExpression(path2) {
|
|
31845
32627
|
const { left } = path2.node;
|
|
31846
32628
|
if (t4.isIdentifier(left)) return;
|
|
31847
32629
|
if (t4.isMemberExpression(left) || t4.isOptionalMemberExpression(left)) {
|
|
31848
|
-
|
|
32630
|
+
const stateRoot = isStateRoot(left.object, path2);
|
|
32631
|
+
const reactiveRoot = isReactiveRoot(left.object, path2);
|
|
32632
|
+
if (stateRoot || reactiveRoot) {
|
|
31849
32633
|
emitWarning(
|
|
31850
32634
|
path2.node,
|
|
31851
32635
|
"FICT-M",
|
|
@@ -31862,13 +32646,16 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
|
|
|
31862
32646
|
fileName
|
|
31863
32647
|
);
|
|
31864
32648
|
}
|
|
32649
|
+
return;
|
|
31865
32650
|
}
|
|
31866
32651
|
}
|
|
31867
32652
|
},
|
|
31868
32653
|
UpdateExpression(path2) {
|
|
31869
32654
|
const arg = path2.node.argument;
|
|
31870
32655
|
if (t4.isMemberExpression(arg) || t4.isOptionalMemberExpression(arg)) {
|
|
31871
|
-
|
|
32656
|
+
const stateRoot = isStateRoot(arg.object, path2);
|
|
32657
|
+
const reactiveRoot = isReactiveRoot(arg.object, path2);
|
|
32658
|
+
if (stateRoot || reactiveRoot) {
|
|
31872
32659
|
emitWarning(
|
|
31873
32660
|
path2.node,
|
|
31874
32661
|
"FICT-M",
|
|
@@ -31885,6 +32672,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
|
|
|
31885
32672
|
fileName
|
|
31886
32673
|
);
|
|
31887
32674
|
}
|
|
32675
|
+
return;
|
|
31888
32676
|
}
|
|
31889
32677
|
}
|
|
31890
32678
|
},
|
|
@@ -31892,7 +32680,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
|
|
|
31892
32680
|
if (!path2.node.computed) return;
|
|
31893
32681
|
if (path2.parentPath.isAssignmentExpression({ left: path2.node })) return;
|
|
31894
32682
|
if (path2.parentPath.isUpdateExpression({ argument: path2.node })) return;
|
|
31895
|
-
if (isDynamicPropertyAccess(path2.node, t4) &&
|
|
32683
|
+
if (isDynamicPropertyAccess(path2.node, t4) && isReactiveRoot(path2.node.object, path2)) {
|
|
31896
32684
|
emitWarning(
|
|
31897
32685
|
path2.node,
|
|
31898
32686
|
"FICT-H",
|
|
@@ -31912,9 +32700,9 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
|
|
|
31912
32700
|
},
|
|
31913
32701
|
Identifier(idPath) {
|
|
31914
32702
|
const name = idPath.node.name;
|
|
31915
|
-
if (!reactiveNames.has(name)) return;
|
|
31916
32703
|
const binding = idPath.scope.getBinding(name);
|
|
31917
32704
|
if (!binding) return;
|
|
32705
|
+
if (!reactiveBindingIds.has(binding.identifier)) return;
|
|
31918
32706
|
if (binding.scope === idPath.scope || binding.scope === path2.scope) return;
|
|
31919
32707
|
captured.add(name);
|
|
31920
32708
|
}
|
|
@@ -31932,7 +32720,8 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
|
|
|
31932
32720
|
}
|
|
31933
32721
|
},
|
|
31934
32722
|
CallExpression(path2) {
|
|
31935
|
-
|
|
32723
|
+
const isEffect = isEffectCall(path2.node, t4, effectMacroNames);
|
|
32724
|
+
if (isEffect) {
|
|
31936
32725
|
const argPath = path2.get("arguments.0");
|
|
31937
32726
|
if (argPath?.isFunctionExpression() || argPath?.isArrowFunctionExpression()) {
|
|
31938
32727
|
let hasReactiveDependency = false;
|
|
@@ -31946,7 +32735,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
|
|
|
31946
32735
|
}
|
|
31947
32736
|
const binding = idPath.scope.getBinding(idPath.node.name);
|
|
31948
32737
|
if (binding && binding.scope === argPath.scope) return;
|
|
31949
|
-
if (
|
|
32738
|
+
if (binding && reactiveBindingIds.has(binding.identifier)) {
|
|
31950
32739
|
hasReactiveDependency = true;
|
|
31951
32740
|
idPath.stop();
|
|
31952
32741
|
}
|
|
@@ -31976,13 +32765,16 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
|
|
|
31976
32765
|
}
|
|
31977
32766
|
const isSafe = calleeName && SAFE_FUNCTIONS.has(calleeName);
|
|
31978
32767
|
if (isSafe) return;
|
|
31979
|
-
|
|
31980
|
-
|
|
31981
|
-
if (
|
|
32768
|
+
const argPaths = path2.get("arguments");
|
|
32769
|
+
for (const argPath of argPaths) {
|
|
32770
|
+
if (argPath.isIdentifier() && hasTrackedBinding(argPath, argPath.node.name, stateBindingIds)) {
|
|
32771
|
+
continue;
|
|
32772
|
+
}
|
|
32773
|
+
if (argumentHasReactive(argPath)) {
|
|
31982
32774
|
emitWarning(
|
|
31983
|
-
|
|
31984
|
-
"FICT-
|
|
31985
|
-
"
|
|
32775
|
+
argPath.node,
|
|
32776
|
+
"FICT-R002",
|
|
32777
|
+
"Reactive value escapes scope when passed to an unknown function; dependency tracking may be imprecise",
|
|
31986
32778
|
warn,
|
|
31987
32779
|
fileName
|
|
31988
32780
|
);
|
|
@@ -31994,7 +32786,7 @@ function runWarningPass(programPath, stateVars, derivedVars, warn, fileName, t4)
|
|
|
31994
32786
|
if (!path2.node.computed) return;
|
|
31995
32787
|
if (path2.parentPath.isAssignmentExpression({ left: path2.node })) return;
|
|
31996
32788
|
if (path2.parentPath.isUpdateExpression({ argument: path2.node })) return;
|
|
31997
|
-
if (isDynamicPropertyAccess(path2.node, t4) &&
|
|
32789
|
+
if (isDynamicPropertyAccess(path2.node, t4) && isReactiveRoot(path2.node.object, path2)) {
|
|
31998
32790
|
emitWarning(
|
|
31999
32791
|
path2.node,
|
|
32000
32792
|
"FICT-H",
|
|
@@ -32123,6 +32915,17 @@ function createHIREntrypointVisitor(t4, options) {
|
|
|
32123
32915
|
const name = getFunctionName(fnPath);
|
|
32124
32916
|
return name && isComponentName2(name) || isHookName2(name) || functionHasJSX(fnPath) || functionUsesStateLike(fnPath, t4);
|
|
32125
32917
|
};
|
|
32918
|
+
const isBoundDefinition = (fnPath) => fnPath.isFunctionDeclaration() || fnPath.parentPath.isVariableDeclarator() && fnPath.parentPath.node.init === fnPath.node;
|
|
32919
|
+
const isExportDefaultDefinition = (fnPath) => fnPath.parentPath?.isExportDefaultDeclaration() && fnPath.parentPath.node.declaration === fnPath.node;
|
|
32920
|
+
const isNamedComponentOrHookDefinition = (fnPath) => {
|
|
32921
|
+
if (!isBoundDefinition(fnPath)) return false;
|
|
32922
|
+
const name = getFunctionName(fnPath);
|
|
32923
|
+
return !!name && (isComponentName2(name) || isHookName2(name));
|
|
32924
|
+
};
|
|
32925
|
+
const isComponentDefinitionForProps = (fnPath) => {
|
|
32926
|
+
if (!isComponentDefinition(fnPath)) return false;
|
|
32927
|
+
return isBoundDefinition(fnPath) || isExportDefaultDefinition(fnPath);
|
|
32928
|
+
};
|
|
32126
32929
|
const memoHasSideEffects = (fn) => {
|
|
32127
32930
|
const pureCalls = new Set(
|
|
32128
32931
|
Array.from(SAFE_FUNCTIONS).filter(
|
|
@@ -32243,6 +33046,7 @@ function createHIREntrypointVisitor(t4, options) {
|
|
|
32243
33046
|
const stateMacroNames = /* @__PURE__ */ new Set(["$state"]);
|
|
32244
33047
|
const effectMacroNames = /* @__PURE__ */ new Set(["$effect"]);
|
|
32245
33048
|
const memoMacroNames = /* @__PURE__ */ new Set(["$memo", "createMemo"]);
|
|
33049
|
+
const importedReactiveBindingIds = /* @__PURE__ */ new Set();
|
|
32246
33050
|
path2.traverse({
|
|
32247
33051
|
ImportDeclaration(importPath) {
|
|
32248
33052
|
if (importPath.node.source.value !== "fict" && importPath.node.source.value !== "fict/slim")
|
|
@@ -32263,6 +33067,44 @@ function createHIREntrypointVisitor(t4, options) {
|
|
|
32263
33067
|
}
|
|
32264
33068
|
}
|
|
32265
33069
|
});
|
|
33070
|
+
path2.traverse({
|
|
33071
|
+
ImportDeclaration(importPath) {
|
|
33072
|
+
const meta = resolveModuleMetadata(
|
|
33073
|
+
importPath.node.source.value,
|
|
33074
|
+
fileName,
|
|
33075
|
+
optionsWithWarnings
|
|
33076
|
+
);
|
|
33077
|
+
if (!meta) return;
|
|
33078
|
+
const hasReactiveExports = Object.keys(meta.exports).length > 0;
|
|
33079
|
+
for (const spec of importPath.node.specifiers) {
|
|
33080
|
+
if (t4.isImportSpecifier(spec)) {
|
|
33081
|
+
const importedName = t4.isIdentifier(spec.imported) ? spec.imported.name : String(spec.imported.value);
|
|
33082
|
+
if (meta.exports[importedName]) {
|
|
33083
|
+
const binding = importPath.scope.getBinding(spec.local.name);
|
|
33084
|
+
if (binding) {
|
|
33085
|
+
importedReactiveBindingIds.add(binding.identifier);
|
|
33086
|
+
}
|
|
33087
|
+
}
|
|
33088
|
+
continue;
|
|
33089
|
+
}
|
|
33090
|
+
if (t4.isImportDefaultSpecifier(spec)) {
|
|
33091
|
+
if (meta.exports.default) {
|
|
33092
|
+
const binding = importPath.scope.getBinding(spec.local.name);
|
|
33093
|
+
if (binding) {
|
|
33094
|
+
importedReactiveBindingIds.add(binding.identifier);
|
|
33095
|
+
}
|
|
33096
|
+
}
|
|
33097
|
+
continue;
|
|
33098
|
+
}
|
|
33099
|
+
if (t4.isImportNamespaceSpecifier(spec) && hasReactiveExports) {
|
|
33100
|
+
const binding = importPath.scope.getBinding(spec.local.name);
|
|
33101
|
+
if (binding) {
|
|
33102
|
+
importedReactiveBindingIds.add(binding.identifier);
|
|
33103
|
+
}
|
|
33104
|
+
}
|
|
33105
|
+
}
|
|
33106
|
+
}
|
|
33107
|
+
});
|
|
32266
33108
|
path2.traverse({
|
|
32267
33109
|
JSXExpressionContainer(exprPath) {
|
|
32268
33110
|
const expr = exprPath.node.expression;
|
|
@@ -32273,10 +33115,10 @@ function createHIREntrypointVisitor(t4, options) {
|
|
|
32273
33115
|
const cb = expr.arguments[0];
|
|
32274
33116
|
if (!cb || !t4.isArrowFunctionExpression(cb) && !t4.isFunctionExpression(cb)) return;
|
|
32275
33117
|
const getReturnedJsx = (fn) => {
|
|
32276
|
-
if (t4.isJSXElement(fn.body)) return fn.body;
|
|
33118
|
+
if (t4.isJSXElement(fn.body) || t4.isJSXFragment(fn.body)) return fn.body;
|
|
32277
33119
|
if (t4.isBlockStatement(fn.body)) {
|
|
32278
33120
|
const ret = fn.body.body.find((stmt) => t4.isReturnStatement(stmt));
|
|
32279
|
-
if (ret && t4.isReturnStatement(ret) && ret.argument && t4.isJSXElement(ret.argument)) {
|
|
33121
|
+
if (ret && t4.isReturnStatement(ret) && ret.argument && (t4.isJSXElement(ret.argument) || t4.isJSXFragment(ret.argument))) {
|
|
32280
33122
|
return ret.argument;
|
|
32281
33123
|
}
|
|
32282
33124
|
}
|
|
@@ -32284,6 +33126,16 @@ function createHIREntrypointVisitor(t4, options) {
|
|
|
32284
33126
|
};
|
|
32285
33127
|
const jsx = getReturnedJsx(cb);
|
|
32286
33128
|
if (!jsx) return;
|
|
33129
|
+
if (t4.isJSXFragment(jsx)) {
|
|
33130
|
+
warn({
|
|
33131
|
+
code: "FICT-J002",
|
|
33132
|
+
message: "Missing key prop in list rendering.",
|
|
33133
|
+
fileName,
|
|
33134
|
+
line: expr.loc?.start.line ?? 0,
|
|
33135
|
+
column: expr.loc ? expr.loc.start.column + 1 : 0
|
|
33136
|
+
});
|
|
33137
|
+
return;
|
|
33138
|
+
}
|
|
32287
33139
|
let hasKey = false;
|
|
32288
33140
|
let hasUnknownSpread = false;
|
|
32289
33141
|
for (const attr of jsx.openingElement.attributes) {
|
|
@@ -32306,8 +33158,48 @@ function createHIREntrypointVisitor(t4, options) {
|
|
|
32306
33158
|
}
|
|
32307
33159
|
});
|
|
32308
33160
|
const stateVars = /* @__PURE__ */ new Set();
|
|
32309
|
-
const
|
|
33161
|
+
const stateBindingIds = /* @__PURE__ */ new Set();
|
|
33162
|
+
const derivedBindingIds = /* @__PURE__ */ new Set();
|
|
32310
33163
|
const destructuredAliases = /* @__PURE__ */ new Set();
|
|
33164
|
+
const aliasBindingIds = /* @__PURE__ */ new Set();
|
|
33165
|
+
const stateAliasBindingIds = /* @__PURE__ */ new Set();
|
|
33166
|
+
const propsBindingIds = /* @__PURE__ */ new Set();
|
|
33167
|
+
const hasTrackedBinding = (path3, name, tracked) => {
|
|
33168
|
+
const binding = path3.scope.getBinding(name);
|
|
33169
|
+
return !!(binding && tracked.has(binding.identifier));
|
|
33170
|
+
};
|
|
33171
|
+
const trackBindingByName = (path3, name, tracked) => {
|
|
33172
|
+
const binding = path3.scope.getBinding(name);
|
|
33173
|
+
if (binding) tracked.add(binding.identifier);
|
|
33174
|
+
};
|
|
33175
|
+
const hasReactiveAliasSourceBinding = (path3, name) => hasTrackedBinding(path3, name, stateBindingIds) || hasTrackedBinding(path3, name, derivedBindingIds) || hasTrackedBinding(path3, name, aliasBindingIds) || hasTrackedBinding(path3, name, destructuredAliases) || hasTrackedBinding(path3, name, importedReactiveBindingIds);
|
|
33176
|
+
const hasStateRootBinding = (path3, name) => hasTrackedBinding(path3, name, stateBindingIds) || hasTrackedBinding(path3, name, stateAliasBindingIds);
|
|
33177
|
+
const unwrapIdentifier = (node) => {
|
|
33178
|
+
if (!node) return null;
|
|
33179
|
+
let current = node;
|
|
33180
|
+
while (true) {
|
|
33181
|
+
if (t4.isTSAsExpression(current)) {
|
|
33182
|
+
current = current.expression;
|
|
33183
|
+
continue;
|
|
33184
|
+
}
|
|
33185
|
+
if (t4.isTSNonNullExpression(current)) {
|
|
33186
|
+
current = current.expression;
|
|
33187
|
+
continue;
|
|
33188
|
+
}
|
|
33189
|
+
if (t4.isTypeCastExpression?.(current)) {
|
|
33190
|
+
current = current.expression;
|
|
33191
|
+
continue;
|
|
33192
|
+
}
|
|
33193
|
+
break;
|
|
33194
|
+
}
|
|
33195
|
+
return t4.isIdentifier(current) ? current : null;
|
|
33196
|
+
};
|
|
33197
|
+
const isStateRootIdentifier = (exprPath) => {
|
|
33198
|
+
if (!exprPath) return null;
|
|
33199
|
+
const id = unwrapIdentifier(exprPath.node);
|
|
33200
|
+
if (!id) return null;
|
|
33201
|
+
return hasStateRootBinding(exprPath, id.name) ? id : null;
|
|
33202
|
+
};
|
|
32311
33203
|
path2.traverse({
|
|
32312
33204
|
VariableDeclarator(varPath) {
|
|
32313
33205
|
const init = varPath.node.init;
|
|
@@ -32343,6 +33235,7 @@ For module-level shared state, use one of these alternatives:
|
|
|
32343
33235
|
);
|
|
32344
33236
|
}
|
|
32345
33237
|
stateVars.add(varPath.node.id.name);
|
|
33238
|
+
trackBindingByName(varPath, varPath.node.id.name, stateBindingIds);
|
|
32346
33239
|
if (isInsideLoop(varPath) || isInsideConditional(varPath)) {
|
|
32347
33240
|
throw varPath.buildCodeFrameError(
|
|
32348
33241
|
`$state() cannot be declared inside loops or conditionals.
|
|
@@ -32365,25 +33258,36 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
32365
33258
|
let dependsOnState = false;
|
|
32366
33259
|
varPath.get("init").traverse({
|
|
32367
33260
|
Identifier(idPath) {
|
|
32368
|
-
if (
|
|
33261
|
+
if (hasTrackedBinding(idPath, idPath.node.name, stateBindingIds)) {
|
|
32369
33262
|
dependsOnState = true;
|
|
32370
33263
|
idPath.stop();
|
|
32371
33264
|
}
|
|
32372
33265
|
}
|
|
32373
33266
|
});
|
|
32374
33267
|
if (dependsOnState) {
|
|
32375
|
-
|
|
33268
|
+
trackBindingByName(varPath, varPath.node.id.name, derivedBindingIds);
|
|
32376
33269
|
}
|
|
32377
33270
|
}
|
|
32378
|
-
} else if ((t4.isObjectPattern(varPath.node.id) || t4.isArrayPattern(varPath.node.id)) && t4.isIdentifier(init) && stateVars.has(init.name)) {
|
|
32379
|
-
collectPatternIdentifiers(varPath.node.id).forEach((id) => destructuredAliases.add(id));
|
|
32380
33271
|
}
|
|
32381
33272
|
},
|
|
32382
33273
|
Function(fnPath) {
|
|
33274
|
+
if (isComponentDefinitionForProps(fnPath)) {
|
|
33275
|
+
for (const param of fnPath.node.params) {
|
|
33276
|
+
if (t4.isIdentifier(param)) {
|
|
33277
|
+
trackBindingByName(fnPath, param.name, propsBindingIds);
|
|
33278
|
+
continue;
|
|
33279
|
+
}
|
|
33280
|
+
if (t4.isPatternLike(param)) {
|
|
33281
|
+
collectPatternIdentifiers(param).forEach(
|
|
33282
|
+
(name) => trackBindingByName(fnPath, name, propsBindingIds)
|
|
33283
|
+
);
|
|
33284
|
+
}
|
|
33285
|
+
}
|
|
33286
|
+
}
|
|
32383
33287
|
const parentFn = fnPath.getFunctionParent();
|
|
32384
33288
|
if (!parentFn) return;
|
|
32385
33289
|
if (!isComponentLike(parentFn)) return;
|
|
32386
|
-
if (!
|
|
33290
|
+
if (!isNamedComponentOrHookDefinition(fnPath)) return;
|
|
32387
33291
|
emitWarning(
|
|
32388
33292
|
fnPath.node,
|
|
32389
33293
|
"FICT-C003",
|
|
@@ -32478,7 +33382,7 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
32478
33382
|
emitWarning(
|
|
32479
33383
|
callPath.node,
|
|
32480
33384
|
"FICT-R004",
|
|
32481
|
-
"Reactive creation inside non-JSX control flow
|
|
33385
|
+
"Reactive creation inside non-JSX control flow may not auto-dispose in complex paths. Prefer createScope/runInScope (or JSX-managed regions) for explicit lifecycle control.",
|
|
32482
33386
|
warn,
|
|
32483
33387
|
fileName
|
|
32484
33388
|
);
|
|
@@ -32512,7 +33416,7 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
32512
33416
|
"createEffect"
|
|
32513
33417
|
]);
|
|
32514
33418
|
callPath.node.arguments.forEach((arg) => {
|
|
32515
|
-
if (t4.isIdentifier(arg) &&
|
|
33419
|
+
if (t4.isIdentifier(arg) && hasTrackedBinding(callPath, arg.name, stateBindingIds) && (!calleeId || !allowedStateCallees.has(calleeId))) {
|
|
32516
33420
|
const loc = arg.loc?.start ?? callPath.node.loc?.start;
|
|
32517
33421
|
warn({
|
|
32518
33422
|
code: "FICT-S002",
|
|
@@ -32540,15 +33444,42 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
32540
33444
|
});
|
|
32541
33445
|
const aliasStack = [/* @__PURE__ */ new Set()];
|
|
32542
33446
|
const currentAliasSet = () => aliasStack[aliasStack.length - 1];
|
|
32543
|
-
const
|
|
33447
|
+
const getBindingIdentifier = (path3, name) => {
|
|
33448
|
+
const binding = path3.scope.getBinding(name);
|
|
33449
|
+
return binding ? binding.identifier : null;
|
|
33450
|
+
};
|
|
33451
|
+
const addAliasBinding = (path3, name) => {
|
|
33452
|
+
const aliasSet = currentAliasSet();
|
|
33453
|
+
if (!aliasSet) return;
|
|
33454
|
+
const bindingId = getBindingIdentifier(path3, name);
|
|
33455
|
+
if (!bindingId) return;
|
|
33456
|
+
aliasSet.add(bindingId);
|
|
33457
|
+
aliasBindingIds.add(bindingId);
|
|
33458
|
+
};
|
|
33459
|
+
const addStateAliasBinding = (path3, name) => {
|
|
33460
|
+
const bindingId = getBindingIdentifier(path3, name);
|
|
33461
|
+
if (!bindingId) return;
|
|
33462
|
+
stateAliasBindingIds.add(bindingId);
|
|
33463
|
+
};
|
|
33464
|
+
const isAliasBinding = (path3, name) => {
|
|
33465
|
+
const aliasSet = currentAliasSet();
|
|
33466
|
+
if (!aliasSet) return false;
|
|
33467
|
+
const bindingId = getBindingIdentifier(path3, name);
|
|
33468
|
+
return !!(bindingId && aliasSet.has(bindingId));
|
|
33469
|
+
};
|
|
33470
|
+
const isDestructuredAliasBinding = (path3, name) => {
|
|
33471
|
+
const bindingId = getBindingIdentifier(path3, name);
|
|
33472
|
+
return !!(bindingId && destructuredAliases.has(bindingId));
|
|
33473
|
+
};
|
|
33474
|
+
const rhsUsesReactive = (exprPath) => {
|
|
32544
33475
|
if (!exprPath) return false;
|
|
32545
|
-
if (exprPath.isIdentifier() && t4.isIdentifier(exprPath.node) &&
|
|
33476
|
+
if (exprPath.isIdentifier() && t4.isIdentifier(exprPath.node) && hasReactiveAliasSourceBinding(exprPath, exprPath.node.name)) {
|
|
32546
33477
|
return true;
|
|
32547
33478
|
}
|
|
32548
33479
|
let usesState = false;
|
|
32549
33480
|
exprPath.traverse({
|
|
32550
33481
|
Identifier(idPath) {
|
|
32551
|
-
if (
|
|
33482
|
+
if (hasReactiveAliasSourceBinding(idPath, idPath.node.name)) {
|
|
32552
33483
|
usesState = true;
|
|
32553
33484
|
idPath.stop();
|
|
32554
33485
|
}
|
|
@@ -32567,26 +33498,47 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
32567
33498
|
}
|
|
32568
33499
|
},
|
|
32569
33500
|
VariableDeclarator(varPath) {
|
|
32570
|
-
const
|
|
32571
|
-
|
|
33501
|
+
const initPath = varPath.get("init");
|
|
33502
|
+
const stateRootId = isStateRootIdentifier(initPath);
|
|
33503
|
+
if (t4.isIdentifier(varPath.node.id) && rhsUsesReactive(initPath)) {
|
|
32572
33504
|
debugLog("alias", "add from decl", varPath.node.id.name);
|
|
32573
|
-
|
|
33505
|
+
addAliasBinding(varPath, varPath.node.id.name);
|
|
33506
|
+
}
|
|
33507
|
+
if (t4.isIdentifier(varPath.node.id) && stateRootId) {
|
|
33508
|
+
addStateAliasBinding(varPath, varPath.node.id.name);
|
|
33509
|
+
}
|
|
33510
|
+
if (t4.isObjectPattern(varPath.node.id) || t4.isArrayPattern(varPath.node.id)) {
|
|
33511
|
+
if (rhsUsesReactive(initPath)) {
|
|
33512
|
+
const targets = collectPatternIdentifiers(varPath.node.id);
|
|
33513
|
+
for (const target of targets) {
|
|
33514
|
+
debugLog("alias", "add from destructuring decl", target);
|
|
33515
|
+
addAliasBinding(varPath, target);
|
|
33516
|
+
}
|
|
33517
|
+
}
|
|
33518
|
+
if (stateRootId) {
|
|
33519
|
+
collectPatternIdentifiers(varPath.node.id).forEach(
|
|
33520
|
+
(id) => trackBindingByName(varPath, id, destructuredAliases)
|
|
33521
|
+
);
|
|
33522
|
+
}
|
|
32574
33523
|
}
|
|
32575
33524
|
},
|
|
32576
33525
|
AssignmentExpression(assignPath) {
|
|
32577
|
-
const aliasSet = currentAliasSet();
|
|
32578
|
-
if (!aliasSet) return;
|
|
32579
33526
|
const rightPath = assignPath.get("right");
|
|
32580
|
-
const usesState =
|
|
33527
|
+
const usesState = rhsUsesReactive(rightPath);
|
|
33528
|
+
const stateRootId = isStateRootIdentifier(rightPath);
|
|
32581
33529
|
const left = assignPath.node.left;
|
|
32582
33530
|
if (t4.isIdentifier(left)) {
|
|
32583
33531
|
const targetName = left.name;
|
|
32584
33532
|
if (usesState) {
|
|
32585
33533
|
debugLog("alias", "add from assign", targetName);
|
|
32586
|
-
|
|
33534
|
+
addAliasBinding(assignPath, targetName);
|
|
33535
|
+
if (stateRootId) {
|
|
33536
|
+
addStateAliasBinding(assignPath, targetName);
|
|
33537
|
+
}
|
|
32587
33538
|
return;
|
|
32588
33539
|
}
|
|
32589
|
-
if (
|
|
33540
|
+
if (isAliasBinding(assignPath, targetName)) {
|
|
33541
|
+
if (isDestructuredAliasBinding(assignPath, targetName)) return;
|
|
32590
33542
|
debugLog("alias", "reassignment detected", targetName);
|
|
32591
33543
|
throw assignPath.buildCodeFrameError(
|
|
32592
33544
|
`Alias reassignment is not supported for "${targetName}"`
|
|
@@ -32600,11 +33552,18 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
32600
33552
|
if (usesState) {
|
|
32601
33553
|
for (const target of targets) {
|
|
32602
33554
|
debugLog("alias", "add from destructuring assign", target);
|
|
32603
|
-
|
|
33555
|
+
addAliasBinding(assignPath, target);
|
|
33556
|
+
}
|
|
33557
|
+
if (stateRootId) {
|
|
33558
|
+
targets.forEach(
|
|
33559
|
+
(target) => trackBindingByName(assignPath, target, destructuredAliases)
|
|
33560
|
+
);
|
|
32604
33561
|
}
|
|
32605
33562
|
return;
|
|
32606
33563
|
}
|
|
32607
|
-
const reassigned = targets.find(
|
|
33564
|
+
const reassigned = targets.find(
|
|
33565
|
+
(target) => isAliasBinding(assignPath, target) && !isDestructuredAliasBinding(assignPath, target)
|
|
33566
|
+
);
|
|
32608
33567
|
if (reassigned) {
|
|
32609
33568
|
debugLog("alias", "reassignment detected", reassigned);
|
|
32610
33569
|
throw assignPath.buildCodeFrameError(
|
|
@@ -32612,20 +33571,31 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
32612
33571
|
);
|
|
32613
33572
|
}
|
|
32614
33573
|
}
|
|
33574
|
+
},
|
|
33575
|
+
UpdateExpression(updatePath) {
|
|
33576
|
+
const arg = updatePath.node.argument;
|
|
33577
|
+
if (t4.isIdentifier(arg) && isAliasBinding(updatePath, arg.name) && !isDestructuredAliasBinding(updatePath, arg.name)) {
|
|
33578
|
+
debugLog("alias", "reassignment detected", arg.name);
|
|
33579
|
+
throw updatePath.buildCodeFrameError(
|
|
33580
|
+
`Alias reassignment is not supported for "${arg.name}"`
|
|
33581
|
+
);
|
|
33582
|
+
}
|
|
32615
33583
|
}
|
|
32616
33584
|
});
|
|
32617
|
-
if (
|
|
33585
|
+
if (derivedBindingIds.size > 0) {
|
|
32618
33586
|
path2.traverse({
|
|
32619
33587
|
AssignmentExpression(assignPath) {
|
|
32620
33588
|
const { left } = assignPath.node;
|
|
32621
|
-
if (t4.isIdentifier(left) &&
|
|
33589
|
+
if (t4.isIdentifier(left) && hasTrackedBinding(assignPath, left.name, derivedBindingIds)) {
|
|
32622
33590
|
throw assignPath.buildCodeFrameError(
|
|
32623
33591
|
`Cannot reassign derived value '${left.name}'. Derived values are read-only.`
|
|
32624
33592
|
);
|
|
32625
33593
|
}
|
|
32626
33594
|
if (t4.isObjectPattern(left) || t4.isArrayPattern(left)) {
|
|
32627
33595
|
const targets = collectPatternIdentifiers(left);
|
|
32628
|
-
const derivedTarget = targets.find(
|
|
33596
|
+
const derivedTarget = targets.find(
|
|
33597
|
+
(target) => hasTrackedBinding(assignPath, target, derivedBindingIds)
|
|
33598
|
+
);
|
|
32629
33599
|
if (derivedTarget) {
|
|
32630
33600
|
throw assignPath.buildCodeFrameError(
|
|
32631
33601
|
`Cannot reassign derived value '${derivedTarget}'. Derived values are read-only.`
|
|
@@ -32639,14 +33609,16 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
32639
33609
|
path2.traverse({
|
|
32640
33610
|
AssignmentExpression(assignPath) {
|
|
32641
33611
|
const { left } = assignPath.node;
|
|
32642
|
-
if (t4.isIdentifier(left) &&
|
|
33612
|
+
if (t4.isIdentifier(left) && hasTrackedBinding(assignPath, left.name, destructuredAliases)) {
|
|
32643
33613
|
throw assignPath.buildCodeFrameError(
|
|
32644
33614
|
`Cannot write to destructured state alias '${left.name}'. Update the original state (e.g. state.count++ or immutable update).`
|
|
32645
33615
|
);
|
|
32646
33616
|
}
|
|
32647
33617
|
if (t4.isObjectPattern(left) || t4.isArrayPattern(left)) {
|
|
32648
33618
|
const targets = collectPatternIdentifiers(left);
|
|
32649
|
-
const aliasTarget = targets.find(
|
|
33619
|
+
const aliasTarget = targets.find(
|
|
33620
|
+
(target) => hasTrackedBinding(assignPath, target, destructuredAliases)
|
|
33621
|
+
);
|
|
32650
33622
|
if (aliasTarget) {
|
|
32651
33623
|
throw assignPath.buildCodeFrameError(
|
|
32652
33624
|
`Cannot write to destructured state alias '${aliasTarget}'. Update the original state (e.g. state.count++ or immutable update).`
|
|
@@ -32656,7 +33628,7 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
32656
33628
|
},
|
|
32657
33629
|
UpdateExpression(updatePath) {
|
|
32658
33630
|
const arg = updatePath.node.argument;
|
|
32659
|
-
if (t4.isIdentifier(arg) &&
|
|
33631
|
+
if (t4.isIdentifier(arg) && hasTrackedBinding(updatePath, arg.name, destructuredAliases)) {
|
|
32660
33632
|
throw updatePath.buildCodeFrameError(
|
|
32661
33633
|
`Cannot write to destructured state alias '${arg.name}'. Update the original state (e.g. state.count++ or immutable update).`
|
|
32662
33634
|
);
|
|
@@ -32666,7 +33638,28 @@ or extract the nested logic into a custom hook (useXxx).`
|
|
|
32666
33638
|
}
|
|
32667
33639
|
const shouldRunWarnings = dev || hasErrorEscalation(options);
|
|
32668
33640
|
if (shouldRunWarnings) {
|
|
32669
|
-
|
|
33641
|
+
const stateRootBindingIds = /* @__PURE__ */ new Set([
|
|
33642
|
+
...stateBindingIds,
|
|
33643
|
+
...stateAliasBindingIds
|
|
33644
|
+
]);
|
|
33645
|
+
const reactiveBindingIds = /* @__PURE__ */ new Set([
|
|
33646
|
+
...stateBindingIds,
|
|
33647
|
+
...derivedBindingIds,
|
|
33648
|
+
...aliasBindingIds,
|
|
33649
|
+
...destructuredAliases,
|
|
33650
|
+
...propsBindingIds,
|
|
33651
|
+
...importedReactiveBindingIds
|
|
33652
|
+
]);
|
|
33653
|
+
runWarningPass(
|
|
33654
|
+
path2,
|
|
33655
|
+
stateBindingIds,
|
|
33656
|
+
stateRootBindingIds,
|
|
33657
|
+
reactiveBindingIds,
|
|
33658
|
+
effectMacroNames,
|
|
33659
|
+
warn,
|
|
33660
|
+
fileName,
|
|
33661
|
+
t4
|
|
33662
|
+
);
|
|
32670
33663
|
}
|
|
32671
33664
|
const fileAst = t4.file(path2.node);
|
|
32672
33665
|
const hir = buildHIR(
|