unguard 0.10.1 → 0.10.3
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/{chunk-RV4V5VH5.js → chunk-7UXUNJSF.js} +193 -128
- package/dist/chunk-7UXUNJSF.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-RV4V5VH5.js.map +0 -1
|
@@ -287,10 +287,36 @@ var noNullishCoalescing = {
|
|
|
287
287
|
visit(node, ctx) {
|
|
288
288
|
if (!ts6.isBinaryExpression(node)) return;
|
|
289
289
|
if (node.operatorToken.kind !== ts6.SyntaxKind.QuestionQuestionToken) return;
|
|
290
|
+
if (isPossiblyMissingArrayBindingValue(node.left, ctx)) return;
|
|
290
291
|
if (ctx.isNullable(node.left)) return;
|
|
291
292
|
ctx.report(node);
|
|
292
293
|
}
|
|
293
294
|
};
|
|
295
|
+
function isPossiblyMissingArrayBindingValue(node, ctx) {
|
|
296
|
+
if (!ts6.isIdentifier(node)) return false;
|
|
297
|
+
const symbol = ctx.checker.getSymbolAtLocation(node);
|
|
298
|
+
if (!symbol) return false;
|
|
299
|
+
for (const declaration of symbol.declarations ?? []) {
|
|
300
|
+
if (!ts6.isBindingElement(declaration)) continue;
|
|
301
|
+
if (declaration.initializer || declaration.dotDotDotToken) continue;
|
|
302
|
+
if (!ts6.isArrayBindingPattern(declaration.parent)) continue;
|
|
303
|
+
const pattern = declaration.parent;
|
|
304
|
+
const index = pattern.elements.indexOf(declaration);
|
|
305
|
+
if (index < 0) continue;
|
|
306
|
+
if (!isTupleSlotDefinitelyPresent(ctx.checker.getTypeAtLocation(pattern), index, ctx.checker)) {
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
function isTupleSlotDefinitelyPresent(type, index, checker) {
|
|
313
|
+
if (type.isUnion()) {
|
|
314
|
+
return type.types.every((member) => isTupleSlotDefinitelyPresent(member, index, checker));
|
|
315
|
+
}
|
|
316
|
+
const apparent = checker.getApparentType(type);
|
|
317
|
+
if (!checker.isTupleType(apparent)) return false;
|
|
318
|
+
return index < apparent.target.minLength;
|
|
319
|
+
}
|
|
294
320
|
|
|
295
321
|
// src/rules/ts/no-optional-call.ts
|
|
296
322
|
import * as ts7 from "typescript";
|
|
@@ -636,6 +662,7 @@ var preferRequiredParamWithGuard = {
|
|
|
636
662
|
};
|
|
637
663
|
|
|
638
664
|
// src/rules/cross-file/duplicate-type-declaration.ts
|
|
665
|
+
import * as ts18 from "typescript";
|
|
639
666
|
var duplicateTypeDeclaration = {
|
|
640
667
|
id: "duplicate-type-declaration",
|
|
641
668
|
severity: "warning",
|
|
@@ -645,6 +672,7 @@ var duplicateTypeDeclaration = {
|
|
|
645
672
|
for (const group of project.types.getDuplicateGroups()) {
|
|
646
673
|
const files = new Set(group.map((e) => e.file));
|
|
647
674
|
if (files.size < 2) continue;
|
|
675
|
+
if (group.every((e) => isTrivialObjectShape(e.node))) continue;
|
|
648
676
|
reportDuplicateGroup(
|
|
649
677
|
group,
|
|
650
678
|
this.id,
|
|
@@ -657,9 +685,14 @@ var duplicateTypeDeclaration = {
|
|
|
657
685
|
return diagnostics;
|
|
658
686
|
}
|
|
659
687
|
};
|
|
688
|
+
function isTrivialObjectShape(node) {
|
|
689
|
+
if (ts18.isTypeLiteralNode(node)) return node.members.length <= 1;
|
|
690
|
+
if (ts18.isInterfaceDeclaration(node)) return node.members.length <= 1;
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
660
693
|
|
|
661
694
|
// src/rules/cross-file/duplicate-function-declaration.ts
|
|
662
|
-
import * as
|
|
695
|
+
import * as ts19 from "typescript";
|
|
663
696
|
var duplicateFunctionDeclaration = {
|
|
664
697
|
id: "duplicate-function-declaration",
|
|
665
698
|
severity: "warning",
|
|
@@ -684,12 +717,13 @@ var duplicateFunctionDeclaration = {
|
|
|
684
717
|
}
|
|
685
718
|
};
|
|
686
719
|
function getBodyBlock(node) {
|
|
687
|
-
if (
|
|
688
|
-
if (
|
|
689
|
-
if (
|
|
720
|
+
if (ts19.isFunctionDeclaration(node) || ts19.isFunctionExpression(node)) return node.body;
|
|
721
|
+
if (ts19.isArrowFunction(node)) return ts19.isBlock(node.body) ? node.body : void 0;
|
|
722
|
+
if (ts19.isMethodDeclaration(node)) return node.body;
|
|
690
723
|
return void 0;
|
|
691
724
|
}
|
|
692
725
|
function isSingleStatement(node) {
|
|
726
|
+
if (ts19.isArrowFunction(node) && !ts19.isBlock(node.body)) return true;
|
|
693
727
|
const body = getBodyBlock(node);
|
|
694
728
|
return body !== void 0 && body.statements.length <= 1;
|
|
695
729
|
}
|
|
@@ -697,8 +731,8 @@ function isSetter(node) {
|
|
|
697
731
|
const body = getBodyBlock(node);
|
|
698
732
|
if (!body || body.statements.length !== 1) return false;
|
|
699
733
|
const stmt = body.statements[0];
|
|
700
|
-
if (stmt === void 0 || !
|
|
701
|
-
return
|
|
734
|
+
if (stmt === void 0 || !ts19.isExpressionStatement(stmt)) return false;
|
|
735
|
+
return ts19.isBinaryExpression(stmt.expression) && stmt.expression.operatorToken.kind === ts19.SyntaxKind.EqualsToken;
|
|
702
736
|
}
|
|
703
737
|
|
|
704
738
|
// src/rules/cross-file/optional-arg-always-used.ts
|
|
@@ -733,14 +767,14 @@ var optionalArgAlwaysUsed = {
|
|
|
733
767
|
};
|
|
734
768
|
|
|
735
769
|
// src/rules/ts/no-catch-return.ts
|
|
736
|
-
import * as
|
|
770
|
+
import * as ts20 from "typescript";
|
|
737
771
|
var noCatchReturn = {
|
|
738
772
|
kind: "ts",
|
|
739
773
|
id: "no-catch-return",
|
|
740
774
|
severity: "warning",
|
|
741
775
|
message: "Catch block silently returns a fallback value with no logging; rethrow, log the error, or let it propagate",
|
|
742
776
|
visit(node, ctx) {
|
|
743
|
-
if (!
|
|
777
|
+
if (!ts20.isCatchClause(node)) return;
|
|
744
778
|
const block = node.block;
|
|
745
779
|
if (hasReturn(block) && !hasThrow(block) && !hasLogging(block)) {
|
|
746
780
|
ctx.report(node);
|
|
@@ -750,57 +784,57 @@ var noCatchReturn = {
|
|
|
750
784
|
function walkBlock(block, predicate) {
|
|
751
785
|
function visit(node) {
|
|
752
786
|
if (predicate(node)) return true;
|
|
753
|
-
if (
|
|
754
|
-
return
|
|
787
|
+
if (ts20.isFunctionDeclaration(node) || ts20.isFunctionExpression(node) || ts20.isArrowFunction(node)) return false;
|
|
788
|
+
return ts20.forEachChild(node, visit) ?? false;
|
|
755
789
|
}
|
|
756
|
-
return
|
|
790
|
+
return ts20.forEachChild(block, visit) ?? false;
|
|
757
791
|
}
|
|
758
792
|
function hasReturn(block) {
|
|
759
|
-
return walkBlock(block, (n) =>
|
|
793
|
+
return walkBlock(block, (n) => ts20.isReturnStatement(n));
|
|
760
794
|
}
|
|
761
795
|
function hasThrow(block) {
|
|
762
|
-
return walkBlock(block, (n) =>
|
|
796
|
+
return walkBlock(block, (n) => ts20.isThrowStatement(n));
|
|
763
797
|
}
|
|
764
798
|
var LOG_OBJECTS = /* @__PURE__ */ new Set(["console", "logger", "log"]);
|
|
765
799
|
function hasLogging(block) {
|
|
766
800
|
return walkBlock(block, (n) => {
|
|
767
|
-
if (!
|
|
801
|
+
if (!ts20.isCallExpression(n)) return false;
|
|
768
802
|
const callee = n.expression;
|
|
769
|
-
if (!
|
|
770
|
-
if (!
|
|
803
|
+
if (!ts20.isPropertyAccessExpression(callee)) return false;
|
|
804
|
+
if (!ts20.isIdentifier(callee.expression)) return false;
|
|
771
805
|
return LOG_OBJECTS.has(callee.expression.text);
|
|
772
806
|
});
|
|
773
807
|
}
|
|
774
808
|
|
|
775
809
|
// src/rules/ts/no-error-rewrap.ts
|
|
776
|
-
import * as
|
|
810
|
+
import * as ts21 from "typescript";
|
|
777
811
|
var noErrorRewrap = {
|
|
778
812
|
kind: "ts",
|
|
779
813
|
id: "no-error-rewrap",
|
|
780
814
|
severity: "error",
|
|
781
815
|
message: "Re-wrapped error loses the original stack trace and type; use { cause: originalError } to preserve the error chain",
|
|
782
816
|
visit(node, ctx) {
|
|
783
|
-
if (!
|
|
817
|
+
if (!ts21.isCatchClause(node)) return;
|
|
784
818
|
if (!node.variableDeclaration) return;
|
|
785
819
|
const param = node.variableDeclaration.name;
|
|
786
|
-
if (!
|
|
820
|
+
if (!ts21.isIdentifier(param)) return;
|
|
787
821
|
const catchName = param.text;
|
|
788
822
|
findRewraps(node.block, catchName, ctx);
|
|
789
823
|
}
|
|
790
824
|
};
|
|
791
825
|
function findRewraps(block, catchName, ctx) {
|
|
792
826
|
function visit(node) {
|
|
793
|
-
if (
|
|
794
|
-
if (
|
|
827
|
+
if (ts21.isFunctionDeclaration(node) || ts21.isFunctionExpression(node) || ts21.isArrowFunction(node)) return;
|
|
828
|
+
if (ts21.isThrowStatement(node) && node.expression && ts21.isNewExpression(node.expression)) {
|
|
795
829
|
const args = node.expression.arguments;
|
|
796
830
|
if (args && args.length > 0 && referencesName(args, catchName) && !hasCauseArg(args)) {
|
|
797
831
|
ctx.report(node);
|
|
798
832
|
}
|
|
799
833
|
return;
|
|
800
834
|
}
|
|
801
|
-
|
|
835
|
+
ts21.forEachChild(node, visit);
|
|
802
836
|
}
|
|
803
|
-
|
|
837
|
+
ts21.forEachChild(block, visit);
|
|
804
838
|
}
|
|
805
839
|
function referencesName(args, name) {
|
|
806
840
|
for (const arg of args) {
|
|
@@ -809,15 +843,15 @@ function referencesName(args, name) {
|
|
|
809
843
|
return false;
|
|
810
844
|
}
|
|
811
845
|
function containsIdentifier(node, name) {
|
|
812
|
-
if (
|
|
813
|
-
return
|
|
846
|
+
if (ts21.isIdentifier(node) && node.text === name) return true;
|
|
847
|
+
return ts21.forEachChild(node, (child) => containsIdentifier(child, name) || void 0) ?? false;
|
|
814
848
|
}
|
|
815
849
|
function hasCauseArg(args) {
|
|
816
850
|
for (const arg of args) {
|
|
817
|
-
if (
|
|
851
|
+
if (ts21.isObjectLiteralExpression(arg)) {
|
|
818
852
|
for (const prop of arg.properties) {
|
|
819
|
-
if (
|
|
820
|
-
if (
|
|
853
|
+
if (ts21.isPropertyAssignment(prop) && ts21.isIdentifier(prop.name) && prop.name.text === "cause") return true;
|
|
854
|
+
if (ts21.isShorthandPropertyAssignment(prop) && prop.name.text === "cause") return true;
|
|
821
855
|
}
|
|
822
856
|
}
|
|
823
857
|
}
|
|
@@ -825,7 +859,7 @@ function hasCauseArg(args) {
|
|
|
825
859
|
}
|
|
826
860
|
|
|
827
861
|
// src/rules/cross-file/explicit-null-arg.ts
|
|
828
|
-
import * as
|
|
862
|
+
import * as ts22 from "typescript";
|
|
829
863
|
var explicitNullArg = {
|
|
830
864
|
id: "explicit-null-arg",
|
|
831
865
|
severity: "warning",
|
|
@@ -845,7 +879,7 @@ var explicitNullArg = {
|
|
|
845
879
|
const arg = site.node.arguments[i];
|
|
846
880
|
if (arg === void 0) continue;
|
|
847
881
|
if (isNullishLiteral(arg)) {
|
|
848
|
-
const val = arg.kind ===
|
|
882
|
+
const val = arg.kind === ts22.SyntaxKind.NullKeyword ? "null" : "undefined";
|
|
849
883
|
diagnostics.push({
|
|
850
884
|
ruleId: this.id,
|
|
851
885
|
severity: this.severity,
|
|
@@ -918,7 +952,7 @@ function resolveCandidates(fromFile, specifier) {
|
|
|
918
952
|
}
|
|
919
953
|
|
|
920
954
|
// src/rules/cross-file/duplicate-type-name.ts
|
|
921
|
-
import * as
|
|
955
|
+
import * as ts23 from "typescript";
|
|
922
956
|
var duplicateTypeName = {
|
|
923
957
|
id: "duplicate-type-name",
|
|
924
958
|
severity: "warning",
|
|
@@ -929,7 +963,7 @@ var duplicateTypeName = {
|
|
|
929
963
|
const hashes = new Set(group.map((e) => e.hash));
|
|
930
964
|
if (hashes.size === 1) continue;
|
|
931
965
|
const hasInferredType = group.some(
|
|
932
|
-
(e) => !
|
|
966
|
+
(e) => !ts23.isTypeLiteralNode(e.node) && !ts23.isInterfaceDeclaration(e.node)
|
|
933
967
|
);
|
|
934
968
|
if (hasInferredType) continue;
|
|
935
969
|
reportDuplicateGroup(
|
|
@@ -969,20 +1003,21 @@ var duplicateConstantDeclaration = {
|
|
|
969
1003
|
};
|
|
970
1004
|
|
|
971
1005
|
// src/rules/ts/no-dynamic-import.ts
|
|
972
|
-
import * as
|
|
1006
|
+
import * as ts24 from "typescript";
|
|
973
1007
|
var noDynamicImport = {
|
|
974
1008
|
kind: "ts",
|
|
975
1009
|
id: "no-dynamic-import",
|
|
976
1010
|
severity: "error",
|
|
977
1011
|
message: "Dynamic import() breaks static analysis and hides dependencies; use a static import instead",
|
|
978
1012
|
visit(node, ctx) {
|
|
979
|
-
if (!
|
|
980
|
-
if (node.expression.kind !==
|
|
1013
|
+
if (!ts24.isCallExpression(node)) return;
|
|
1014
|
+
if (node.expression.kind !== ts24.SyntaxKind.ImportKeyword) return;
|
|
981
1015
|
ctx.report(node);
|
|
982
1016
|
}
|
|
983
1017
|
};
|
|
984
1018
|
|
|
985
1019
|
// src/rules/cross-file/near-duplicate-function.ts
|
|
1020
|
+
import * as ts25 from "typescript";
|
|
986
1021
|
var nearDuplicateFunction = {
|
|
987
1022
|
id: "near-duplicate-function",
|
|
988
1023
|
severity: "warning",
|
|
@@ -992,6 +1027,7 @@ var nearDuplicateFunction = {
|
|
|
992
1027
|
for (const group of project.functions.getNearDuplicateGroups()) {
|
|
993
1028
|
const MIN_NORMALIZED_BODY = 32;
|
|
994
1029
|
if (group.every((e) => e.normalizedBodyLength < MIN_NORMALIZED_BODY)) continue;
|
|
1030
|
+
if (group.every(isSimpleStructure)) continue;
|
|
995
1031
|
reportDuplicateGroup(
|
|
996
1032
|
group,
|
|
997
1033
|
this.id,
|
|
@@ -1004,38 +1040,67 @@ var nearDuplicateFunction = {
|
|
|
1004
1040
|
return diagnostics;
|
|
1005
1041
|
}
|
|
1006
1042
|
};
|
|
1043
|
+
function getFunctionBody(node) {
|
|
1044
|
+
if (ts25.isFunctionDeclaration(node) || ts25.isFunctionExpression(node)) return node.body;
|
|
1045
|
+
if (ts25.isArrowFunction(node)) return node.body;
|
|
1046
|
+
if (ts25.isMethodDeclaration(node)) return node.body;
|
|
1047
|
+
return void 0;
|
|
1048
|
+
}
|
|
1049
|
+
function getTopLevelStatementCount(body) {
|
|
1050
|
+
if (ts25.isBlock(body)) return body.statements.length;
|
|
1051
|
+
return 1;
|
|
1052
|
+
}
|
|
1053
|
+
function hasControlFlow(node) {
|
|
1054
|
+
let found = false;
|
|
1055
|
+
function visit(current) {
|
|
1056
|
+
if (found) return;
|
|
1057
|
+
if (ts25.isIfStatement(current) || ts25.isSwitchStatement(current) || ts25.isTryStatement(current) || ts25.isForStatement(current) || ts25.isForInStatement(current) || ts25.isForOfStatement(current) || ts25.isWhileStatement(current) || ts25.isDoStatement(current)) {
|
|
1058
|
+
found = true;
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
ts25.forEachChild(current, visit);
|
|
1062
|
+
}
|
|
1063
|
+
visit(node);
|
|
1064
|
+
return found;
|
|
1065
|
+
}
|
|
1066
|
+
function isSimpleStructure(entry) {
|
|
1067
|
+
const body = getFunctionBody(entry.node);
|
|
1068
|
+
if (!body) return false;
|
|
1069
|
+
if (hasControlFlow(body)) return false;
|
|
1070
|
+
return getTopLevelStatementCount(body) <= 2;
|
|
1071
|
+
}
|
|
1007
1072
|
|
|
1008
1073
|
// src/rules/cross-file/trivial-wrapper.ts
|
|
1009
|
-
import * as
|
|
1010
|
-
function
|
|
1011
|
-
if (
|
|
1074
|
+
import * as ts26 from "typescript";
|
|
1075
|
+
function getFunctionBody2(node) {
|
|
1076
|
+
if (ts26.isFunctionDeclaration(node) || ts26.isFunctionExpression(node)) {
|
|
1012
1077
|
return node.body;
|
|
1013
1078
|
}
|
|
1014
|
-
if (
|
|
1079
|
+
if (ts26.isArrowFunction(node)) {
|
|
1015
1080
|
return node.body;
|
|
1016
1081
|
}
|
|
1017
|
-
if (
|
|
1082
|
+
if (ts26.isMethodDeclaration(node)) {
|
|
1018
1083
|
return node.body;
|
|
1019
1084
|
}
|
|
1020
1085
|
return void 0;
|
|
1021
1086
|
}
|
|
1022
1087
|
function getCalleeName(expr) {
|
|
1023
|
-
if (
|
|
1024
|
-
if (
|
|
1088
|
+
if (ts26.isIdentifier(expr)) return expr.text;
|
|
1089
|
+
if (ts26.isPropertyAccessExpression(expr)) return expr.name.text;
|
|
1025
1090
|
return void 0;
|
|
1026
1091
|
}
|
|
1027
1092
|
function getTrivialCallTarget(fn) {
|
|
1028
|
-
const body =
|
|
1093
|
+
const body = getFunctionBody2(fn.node);
|
|
1029
1094
|
if (!body) return null;
|
|
1030
1095
|
let callExpr;
|
|
1031
|
-
if (
|
|
1096
|
+
if (ts26.isBlock(body)) {
|
|
1032
1097
|
if (body.statements.length !== 1) return null;
|
|
1033
1098
|
const stmt = body.statements[0];
|
|
1034
|
-
if (!stmt || !
|
|
1035
|
-
if (!
|
|
1099
|
+
if (!stmt || !ts26.isReturnStatement(stmt) || !stmt.expression) return null;
|
|
1100
|
+
if (!ts26.isCallExpression(stmt.expression)) return null;
|
|
1036
1101
|
callExpr = stmt.expression;
|
|
1037
1102
|
} else {
|
|
1038
|
-
if (!
|
|
1103
|
+
if (!ts26.isCallExpression(body)) return null;
|
|
1039
1104
|
callExpr = body;
|
|
1040
1105
|
}
|
|
1041
1106
|
const calleeName = getCalleeName(callExpr.expression);
|
|
@@ -1043,7 +1108,7 @@ function getTrivialCallTarget(fn) {
|
|
|
1043
1108
|
const paramNames = fn.params.map((p) => p.name);
|
|
1044
1109
|
const args = callExpr.arguments;
|
|
1045
1110
|
for (const arg of args) {
|
|
1046
|
-
if (!
|
|
1111
|
+
if (!ts26.isIdentifier(arg)) return null;
|
|
1047
1112
|
if (!paramNames.includes(arg.text)) return null;
|
|
1048
1113
|
}
|
|
1049
1114
|
return { calleeName };
|
|
@@ -1340,32 +1405,32 @@ function isFailOn(value) {
|
|
|
1340
1405
|
}
|
|
1341
1406
|
|
|
1342
1407
|
// src/collect/index.ts
|
|
1343
|
-
import * as
|
|
1408
|
+
import * as ts29 from "typescript";
|
|
1344
1409
|
import { createHash as createHash2 } from "crypto";
|
|
1345
1410
|
|
|
1346
1411
|
// src/utils/hash.ts
|
|
1347
1412
|
import { createHash } from "crypto";
|
|
1348
|
-
import * as
|
|
1413
|
+
import * as ts27 from "typescript";
|
|
1349
1414
|
function hashTypeShape(node, sourceFile) {
|
|
1350
1415
|
const normalized = normalizeTypeNode(node, sourceFile);
|
|
1351
1416
|
return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
1352
1417
|
}
|
|
1353
1418
|
function normalizeTypeNode(node, sourceFile) {
|
|
1354
|
-
if (
|
|
1419
|
+
if (ts27.isTypeLiteralNode(node)) {
|
|
1355
1420
|
const normalized = node.members.map((m) => normalizeTypeNode(m, sourceFile)).sort().join(";");
|
|
1356
1421
|
return `{${normalized}}`;
|
|
1357
1422
|
}
|
|
1358
|
-
if (
|
|
1423
|
+
if (ts27.isInterfaceDeclaration(node)) {
|
|
1359
1424
|
const normalized = node.members.map((m) => normalizeTypeNode(m, sourceFile)).sort().join(";");
|
|
1360
1425
|
return `{${normalized}}`;
|
|
1361
1426
|
}
|
|
1362
|
-
if (
|
|
1427
|
+
if (ts27.isPropertySignature(node)) {
|
|
1363
1428
|
const keyName = node.name.getText(sourceFile);
|
|
1364
1429
|
const optional = node.questionToken ? "?" : "";
|
|
1365
1430
|
const type = node.type ? normalizeTypeNode(node.type, sourceFile) : "any";
|
|
1366
1431
|
return `${keyName}${optional}:${type}`;
|
|
1367
1432
|
}
|
|
1368
|
-
if (
|
|
1433
|
+
if (ts27.isTypeAliasDeclaration(node)) {
|
|
1369
1434
|
return normalizeTypeNode(node.type, sourceFile);
|
|
1370
1435
|
}
|
|
1371
1436
|
return node.getText(sourceFile).replace(/\s+/g, " ").trim();
|
|
@@ -1531,7 +1596,7 @@ var InlineParamTypeRegistry = class extends BaseRegistry {
|
|
|
1531
1596
|
};
|
|
1532
1597
|
|
|
1533
1598
|
// src/typecheck/walk.ts
|
|
1534
|
-
import * as
|
|
1599
|
+
import * as ts28 from "typescript";
|
|
1535
1600
|
function buildContext(rule, sourceFile, checker, source, filename, diagnostics) {
|
|
1536
1601
|
return {
|
|
1537
1602
|
filename,
|
|
@@ -1539,7 +1604,7 @@ function buildContext(rule, sourceFile, checker, source, filename, diagnostics)
|
|
|
1539
1604
|
sourceFile,
|
|
1540
1605
|
checker,
|
|
1541
1606
|
report(node, message) {
|
|
1542
|
-
const { line, character } =
|
|
1607
|
+
const { line, character } = ts28.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
|
|
1543
1608
|
diagnostics.push({
|
|
1544
1609
|
ruleId: rule.id,
|
|
1545
1610
|
severity: rule.severity,
|
|
@@ -1550,7 +1615,7 @@ function buildContext(rule, sourceFile, checker, source, filename, diagnostics)
|
|
|
1550
1615
|
});
|
|
1551
1616
|
},
|
|
1552
1617
|
reportAtOffset(offset, message) {
|
|
1553
|
-
const { line, character } =
|
|
1618
|
+
const { line, character } = ts28.getLineAndCharacterOfPosition(sourceFile, offset);
|
|
1554
1619
|
diagnostics.push({
|
|
1555
1620
|
ruleId: rule.id,
|
|
1556
1621
|
severity: rule.severity,
|
|
@@ -1601,7 +1666,7 @@ function collectProject(program, tsRules, allowedFiles) {
|
|
|
1601
1666
|
rule.visit(node, ctx);
|
|
1602
1667
|
}
|
|
1603
1668
|
}
|
|
1604
|
-
|
|
1669
|
+
ts29.forEachChild(node, visit2);
|
|
1605
1670
|
};
|
|
1606
1671
|
var visit = visit2;
|
|
1607
1672
|
const file = sourceFile.fileName;
|
|
@@ -1615,7 +1680,7 @@ function collectProject(program, tsRules, allowedFiles) {
|
|
|
1615
1680
|
rule,
|
|
1616
1681
|
ctx: buildContext(rule, sourceFile, checker, source, file, diagnostics)
|
|
1617
1682
|
}));
|
|
1618
|
-
|
|
1683
|
+
ts29.forEachChild(sourceFile, visit2);
|
|
1619
1684
|
}
|
|
1620
1685
|
const fileHashes = /* @__PURE__ */ new Map();
|
|
1621
1686
|
for (const [file, { source }] of fileMap) {
|
|
@@ -1631,52 +1696,52 @@ function collectProject(program, tsRules, allowedFiles) {
|
|
|
1631
1696
|
return { index: { types, functions, constants, callSites, imports, files: fileMap, fileHashes, statementSequences, inlineParamTypes }, diagnostics };
|
|
1632
1697
|
}
|
|
1633
1698
|
function hasNonPublicModifier(node) {
|
|
1634
|
-
if (!
|
|
1635
|
-
const mods =
|
|
1699
|
+
if (!ts29.canHaveModifiers(node)) return false;
|
|
1700
|
+
const mods = ts29.getModifiers(node);
|
|
1636
1701
|
if (mods === void 0) return false;
|
|
1637
1702
|
return mods.some(
|
|
1638
|
-
(m) => m.kind ===
|
|
1703
|
+
(m) => m.kind === ts29.SyntaxKind.PrivateKeyword || m.kind === ts29.SyntaxKind.ProtectedKeyword
|
|
1639
1704
|
);
|
|
1640
1705
|
}
|
|
1641
1706
|
function isExported(node) {
|
|
1642
|
-
if (!
|
|
1643
|
-
const mods =
|
|
1707
|
+
if (!ts29.canHaveModifiers(node)) return false;
|
|
1708
|
+
const mods = ts29.getModifiers(node);
|
|
1644
1709
|
if (mods === void 0) return false;
|
|
1645
|
-
return mods.some((m) => m.kind ===
|
|
1710
|
+
return mods.some((m) => m.kind === ts29.SyntaxKind.ExportKeyword);
|
|
1646
1711
|
}
|
|
1647
1712
|
function collectTypes(node, file, sourceFile, registry) {
|
|
1648
|
-
if (
|
|
1649
|
-
const line =
|
|
1713
|
+
if (ts29.isTypeAliasDeclaration(node)) {
|
|
1714
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
|
|
1650
1715
|
registry.add(node.name.text, file, line, node.type, sourceFile, isExported(node));
|
|
1651
1716
|
}
|
|
1652
|
-
if (
|
|
1653
|
-
const line =
|
|
1717
|
+
if (ts29.isInterfaceDeclaration(node)) {
|
|
1718
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
|
|
1654
1719
|
registry.add(node.name.text, file, line, node, sourceFile, isExported(node));
|
|
1655
1720
|
}
|
|
1656
1721
|
}
|
|
1657
1722
|
function isConstantValue(node) {
|
|
1658
|
-
if (
|
|
1659
|
-
if (
|
|
1660
|
-
if (
|
|
1661
|
-
if (
|
|
1662
|
-
if (
|
|
1723
|
+
if (ts29.isStringLiteral(node)) return true;
|
|
1724
|
+
if (ts29.isNumericLiteral(node)) return true;
|
|
1725
|
+
if (ts29.isNoSubstitutionTemplateLiteral(node)) return true;
|
|
1726
|
+
if (ts29.isPrefixUnaryExpression(node)) return isConstantValue(node.operand);
|
|
1727
|
+
if (ts29.isBinaryExpression(node)) return isConstantValue(node.left) && isConstantValue(node.right);
|
|
1663
1728
|
return false;
|
|
1664
1729
|
}
|
|
1665
1730
|
function collectConstants(node, file, sourceFile, registry) {
|
|
1666
|
-
if (!
|
|
1667
|
-
if (!(node.declarationList.flags &
|
|
1731
|
+
if (!ts29.isVariableStatement(node)) return;
|
|
1732
|
+
if (!(node.declarationList.flags & ts29.NodeFlags.Const)) return;
|
|
1668
1733
|
const exported = isExported(node);
|
|
1669
1734
|
for (const decl of node.declarationList.declarations) {
|
|
1670
|
-
if (!decl.initializer || !
|
|
1735
|
+
if (!decl.initializer || !ts29.isIdentifier(decl.name)) continue;
|
|
1671
1736
|
if (!isConstantValue(decl.initializer)) continue;
|
|
1672
1737
|
const valueText = decl.initializer.getText(sourceFile).replace(/\s+/g, " ").trim();
|
|
1673
1738
|
const valueHash = createHash2("sha256").update(valueText).digest("hex").slice(0, 16);
|
|
1674
|
-
const line =
|
|
1739
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, decl.getStart(sourceFile)).line + 1;
|
|
1675
1740
|
registry.add({ name: decl.name.text, file, line, valueHash, valueText, exported });
|
|
1676
1741
|
}
|
|
1677
1742
|
}
|
|
1678
1743
|
function buildFunctionEntry(body, parameters, sourceFile, file, lineNode, name, extra) {
|
|
1679
|
-
const line =
|
|
1744
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, lineNode.getStart(sourceFile)).line + 1;
|
|
1680
1745
|
const params = extractParams(parameters, sourceFile);
|
|
1681
1746
|
const paramNames = params.map((p) => p.name);
|
|
1682
1747
|
const hash = hashFunctionBody(body, sourceFile);
|
|
@@ -1698,17 +1763,17 @@ function buildFunctionEntry(body, parameters, sourceFile, file, lineNode, name,
|
|
|
1698
1763
|
};
|
|
1699
1764
|
}
|
|
1700
1765
|
function collectFunctions(node, file, sourceFile, checker, registry) {
|
|
1701
|
-
if (
|
|
1766
|
+
if (ts29.isFunctionDeclaration(node) && node.name && node.body) {
|
|
1702
1767
|
registry.add(buildFunctionEntry(node.body, node.parameters, sourceFile, file, node, node.name.text, {
|
|
1703
1768
|
exported: isExported(node),
|
|
1704
1769
|
symbol: checker.getSymbolAtLocation(node.name),
|
|
1705
1770
|
node
|
|
1706
1771
|
}));
|
|
1707
1772
|
}
|
|
1708
|
-
if (
|
|
1773
|
+
if (ts29.isVariableStatement(node)) {
|
|
1709
1774
|
const exported = isExported(node);
|
|
1710
1775
|
for (const decl of node.declarationList.declarations) {
|
|
1711
|
-
if (decl.initializer &&
|
|
1776
|
+
if (decl.initializer && ts29.isArrowFunction(decl.initializer) && ts29.isIdentifier(decl.name)) {
|
|
1712
1777
|
const arrow = decl.initializer;
|
|
1713
1778
|
registry.add(buildFunctionEntry(arrow.body, arrow.parameters, sourceFile, file, decl, decl.name.text, {
|
|
1714
1779
|
exported,
|
|
@@ -1716,7 +1781,7 @@ function collectFunctions(node, file, sourceFile, checker, registry) {
|
|
|
1716
1781
|
node: arrow
|
|
1717
1782
|
}));
|
|
1718
1783
|
}
|
|
1719
|
-
if (decl.initializer &&
|
|
1784
|
+
if (decl.initializer && ts29.isFunctionExpression(decl.initializer) && ts29.isIdentifier(decl.name)) {
|
|
1720
1785
|
const fn = decl.initializer;
|
|
1721
1786
|
if (fn.body) {
|
|
1722
1787
|
registry.add(buildFunctionEntry(fn.body, fn.parameters, sourceFile, file, decl, decl.name.text, {
|
|
@@ -1728,22 +1793,22 @@ function collectFunctions(node, file, sourceFile, checker, registry) {
|
|
|
1728
1793
|
}
|
|
1729
1794
|
}
|
|
1730
1795
|
}
|
|
1731
|
-
if (
|
|
1796
|
+
if (ts29.isPropertyAssignment(node) && (ts29.isIdentifier(node.name) || ts29.isStringLiteral(node.name))) {
|
|
1732
1797
|
const init = node.initializer;
|
|
1733
1798
|
const propName = node.name.text;
|
|
1734
|
-
if (
|
|
1799
|
+
if (ts29.isArrowFunction(init)) {
|
|
1735
1800
|
registry.add(buildFunctionEntry(init.body, init.parameters, sourceFile, file, node, propName, { node: init }));
|
|
1736
1801
|
}
|
|
1737
|
-
if (
|
|
1802
|
+
if (ts29.isFunctionExpression(init) && init.body) {
|
|
1738
1803
|
registry.add(buildFunctionEntry(init.body, init.parameters, sourceFile, file, node, propName, { node: init }));
|
|
1739
1804
|
}
|
|
1740
1805
|
}
|
|
1741
|
-
if (
|
|
1806
|
+
if (ts29.isArrowFunction(node) || ts29.isFunctionExpression(node)) {
|
|
1742
1807
|
const parent = node.parent;
|
|
1743
|
-
if (
|
|
1744
|
-
} else if (
|
|
1808
|
+
if (ts29.isVariableDeclaration(parent) && ts29.isIdentifier(parent.name)) {
|
|
1809
|
+
} else if (ts29.isPropertyAssignment(parent)) {
|
|
1745
1810
|
} else {
|
|
1746
|
-
const body =
|
|
1811
|
+
const body = ts29.isArrowFunction(node) ? node.body : node.body;
|
|
1747
1812
|
if (body) {
|
|
1748
1813
|
const MIN_ANON_BODY = 64;
|
|
1749
1814
|
if (bodyTextLength(body, sourceFile) >= MIN_ANON_BODY) {
|
|
@@ -1753,14 +1818,14 @@ function collectFunctions(node, file, sourceFile, checker, registry) {
|
|
|
1753
1818
|
}
|
|
1754
1819
|
}
|
|
1755
1820
|
}
|
|
1756
|
-
if (
|
|
1821
|
+
if (ts29.isMethodDeclaration(node) && node.body && ts29.isIdentifier(node.name)) {
|
|
1757
1822
|
const parent = node.parent;
|
|
1758
|
-
if (
|
|
1823
|
+
if (ts29.isClassDeclaration(parent)) {
|
|
1759
1824
|
if (hasNonPublicModifier(node)) return;
|
|
1760
1825
|
const className = parent.name ? parent.name.text : "<anonymous>";
|
|
1761
1826
|
const name = `${className}.${node.name.text}`;
|
|
1762
1827
|
const implementsInterface = parent.heritageClauses?.some(
|
|
1763
|
-
(c) => c.token ===
|
|
1828
|
+
(c) => c.token === ts29.SyntaxKind.ImplementsKeyword
|
|
1764
1829
|
) ?? false;
|
|
1765
1830
|
registry.add(buildFunctionEntry(node.body, node.parameters, sourceFile, file, node, name, {
|
|
1766
1831
|
exported: isExported(parent),
|
|
@@ -1783,16 +1848,16 @@ function extractParams(parameters, sourceFile) {
|
|
|
1783
1848
|
}
|
|
1784
1849
|
function deriveAnonymousName(node, sourceFile) {
|
|
1785
1850
|
const parent = node.parent;
|
|
1786
|
-
const line =
|
|
1787
|
-
if (
|
|
1851
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
|
|
1852
|
+
if (ts29.isCallExpression(parent)) {
|
|
1788
1853
|
const grandparent = parent.parent;
|
|
1789
|
-
if (
|
|
1854
|
+
if (ts29.isPropertyAssignment(grandparent) && ts29.isIdentifier(grandparent.name)) {
|
|
1790
1855
|
return grandparent.name.text;
|
|
1791
1856
|
}
|
|
1792
1857
|
let calleeName = null;
|
|
1793
|
-
if (
|
|
1858
|
+
if (ts29.isIdentifier(parent.expression)) {
|
|
1794
1859
|
calleeName = parent.expression.text;
|
|
1795
|
-
} else if (
|
|
1860
|
+
} else if (ts29.isPropertyAccessExpression(parent.expression)) {
|
|
1796
1861
|
calleeName = parent.expression.name.text;
|
|
1797
1862
|
}
|
|
1798
1863
|
if (calleeName) {
|
|
@@ -1803,7 +1868,7 @@ function deriveAnonymousName(node, sourceFile) {
|
|
|
1803
1868
|
return `<anonymous>:${line}`;
|
|
1804
1869
|
}
|
|
1805
1870
|
function collectImports(node, file, imports) {
|
|
1806
|
-
if (
|
|
1871
|
+
if (ts29.isImportDeclaration(node) && ts29.isStringLiteral(node.moduleSpecifier)) {
|
|
1807
1872
|
const moduleSource = node.moduleSpecifier.text;
|
|
1808
1873
|
const clause = node.importClause;
|
|
1809
1874
|
if (!clause) return;
|
|
@@ -1815,7 +1880,7 @@ function collectImports(node, file, imports) {
|
|
|
1815
1880
|
source: moduleSource
|
|
1816
1881
|
});
|
|
1817
1882
|
}
|
|
1818
|
-
if (clause.namedBindings &&
|
|
1883
|
+
if (clause.namedBindings && ts29.isNamedImports(clause.namedBindings)) {
|
|
1819
1884
|
for (const el of clause.namedBindings.elements) {
|
|
1820
1885
|
imports.push({
|
|
1821
1886
|
file,
|
|
@@ -1826,9 +1891,9 @@ function collectImports(node, file, imports) {
|
|
|
1826
1891
|
}
|
|
1827
1892
|
}
|
|
1828
1893
|
}
|
|
1829
|
-
if (
|
|
1894
|
+
if (ts29.isExportDeclaration(node) && node.moduleSpecifier && ts29.isStringLiteral(node.moduleSpecifier)) {
|
|
1830
1895
|
const moduleSource = node.moduleSpecifier.text;
|
|
1831
|
-
if (node.exportClause &&
|
|
1896
|
+
if (node.exportClause && ts29.isNamedExports(node.exportClause)) {
|
|
1832
1897
|
for (const el of node.exportClause.elements) {
|
|
1833
1898
|
imports.push({
|
|
1834
1899
|
file,
|
|
@@ -1841,7 +1906,7 @@ function collectImports(node, file, imports) {
|
|
|
1841
1906
|
}
|
|
1842
1907
|
}
|
|
1843
1908
|
function collectStatementSequences(node, file, sourceFile, registry) {
|
|
1844
|
-
if (!
|
|
1909
|
+
if (!ts29.isBlock(node)) return;
|
|
1845
1910
|
const stmts = node.statements;
|
|
1846
1911
|
const n = stmts.length;
|
|
1847
1912
|
if (n < 3) return;
|
|
@@ -1858,34 +1923,34 @@ function collectStatementSequences(node, file, sourceFile, registry) {
|
|
|
1858
1923
|
const firstStmt = window[0];
|
|
1859
1924
|
const lastStmt = window[window.length - 1];
|
|
1860
1925
|
if (firstStmt === void 0 || lastStmt === void 0) continue;
|
|
1861
|
-
const line =
|
|
1862
|
-
const endLine =
|
|
1926
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, firstStmt.getStart(sourceFile)).line + 1;
|
|
1927
|
+
const endLine = ts29.getLineAndCharacterOfPosition(sourceFile, lastStmt.getEnd()).line + 1;
|
|
1863
1928
|
registry.add({ file, line, endLine, hash, normalizedHash, statementCount: size, normalizedBodyLength: normalized.length });
|
|
1864
1929
|
}
|
|
1865
1930
|
}
|
|
1866
1931
|
}
|
|
1867
1932
|
function collectInlineParamTypes(node, file, sourceFile, registry) {
|
|
1868
|
-
if (!
|
|
1933
|
+
if (!ts29.isTypeLiteralNode(node)) return;
|
|
1869
1934
|
const parent = node.parent;
|
|
1870
|
-
if (!parent || !
|
|
1935
|
+
if (!parent || !ts29.isParameter(parent)) return;
|
|
1871
1936
|
if (parent.type !== node) return;
|
|
1872
|
-
const line =
|
|
1937
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
|
|
1873
1938
|
registry.add(file, line, node, sourceFile);
|
|
1874
1939
|
}
|
|
1875
1940
|
function collectCallSites(node, file, sourceFile, checker, sites) {
|
|
1876
|
-
if (!
|
|
1941
|
+
if (!ts29.isCallExpression(node)) return;
|
|
1877
1942
|
let calleeName = null;
|
|
1878
|
-
if (
|
|
1943
|
+
if (ts29.isIdentifier(node.expression)) {
|
|
1879
1944
|
calleeName = node.expression.text;
|
|
1880
|
-
} else if (
|
|
1945
|
+
} else if (ts29.isPropertyAccessExpression(node.expression)) {
|
|
1881
1946
|
calleeName = node.expression.name.text;
|
|
1882
1947
|
}
|
|
1883
1948
|
if (calleeName) {
|
|
1884
|
-
const line =
|
|
1949
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
|
|
1885
1950
|
let symbol;
|
|
1886
1951
|
try {
|
|
1887
1952
|
symbol = checker.getSymbolAtLocation(node.expression);
|
|
1888
|
-
if (symbol && symbol.flags &
|
|
1953
|
+
if (symbol && symbol.flags & ts29.SymbolFlags.Alias) {
|
|
1889
1954
|
symbol = checker.getAliasedSymbol(symbol);
|
|
1890
1955
|
}
|
|
1891
1956
|
} catch {
|
|
@@ -1905,12 +1970,12 @@ function collectAllComments(sourceFile) {
|
|
|
1905
1970
|
const source = sourceFile.getFullText();
|
|
1906
1971
|
const seen = /* @__PURE__ */ new Set();
|
|
1907
1972
|
function visit(node) {
|
|
1908
|
-
const leading =
|
|
1973
|
+
const leading = ts29.getLeadingCommentRanges(source, node.getFullStart());
|
|
1909
1974
|
if (leading) {
|
|
1910
1975
|
for (const r of leading) {
|
|
1911
1976
|
if (seen.has(r.pos)) continue;
|
|
1912
1977
|
seen.add(r.pos);
|
|
1913
|
-
const isLine = r.kind ===
|
|
1978
|
+
const isLine = r.kind === ts29.SyntaxKind.SingleLineCommentTrivia;
|
|
1914
1979
|
comments.push({
|
|
1915
1980
|
type: isLine ? "Line" : "Block",
|
|
1916
1981
|
value: source.slice(r.pos + 2, isLine ? r.end : r.end - 2),
|
|
@@ -1919,12 +1984,12 @@ function collectAllComments(sourceFile) {
|
|
|
1919
1984
|
});
|
|
1920
1985
|
}
|
|
1921
1986
|
}
|
|
1922
|
-
const trailing =
|
|
1987
|
+
const trailing = ts29.getTrailingCommentRanges(source, node.getEnd());
|
|
1923
1988
|
if (trailing) {
|
|
1924
1989
|
for (const r of trailing) {
|
|
1925
1990
|
if (seen.has(r.pos)) continue;
|
|
1926
1991
|
seen.add(r.pos);
|
|
1927
|
-
const isLine = r.kind ===
|
|
1992
|
+
const isLine = r.kind === ts29.SyntaxKind.SingleLineCommentTrivia;
|
|
1928
1993
|
comments.push({
|
|
1929
1994
|
type: isLine ? "Line" : "Block",
|
|
1930
1995
|
value: source.slice(r.pos + 2, isLine ? r.end : r.end - 2),
|
|
@@ -1933,34 +1998,34 @@ function collectAllComments(sourceFile) {
|
|
|
1933
1998
|
});
|
|
1934
1999
|
}
|
|
1935
2000
|
}
|
|
1936
|
-
|
|
2001
|
+
ts29.forEachChild(node, visit);
|
|
1937
2002
|
}
|
|
1938
2003
|
visit(sourceFile);
|
|
1939
2004
|
return comments;
|
|
1940
2005
|
}
|
|
1941
2006
|
|
|
1942
2007
|
// src/typecheck/program.ts
|
|
1943
|
-
import * as
|
|
2008
|
+
import * as ts30 from "typescript";
|
|
1944
2009
|
import { dirname as dirname2 } from "path";
|
|
1945
2010
|
function createProgramFromFiles(files) {
|
|
1946
2011
|
let configPath;
|
|
1947
2012
|
if (files.length > 0) {
|
|
1948
|
-
configPath =
|
|
2013
|
+
configPath = ts30.findConfigFile(dirname2(files[0]), ts30.sys.fileExists, "tsconfig.json");
|
|
1949
2014
|
}
|
|
1950
2015
|
if (configPath) {
|
|
1951
|
-
const configFile =
|
|
1952
|
-
const parsed =
|
|
1953
|
-
return
|
|
2016
|
+
const configFile = ts30.readConfigFile(configPath, ts30.sys.readFile);
|
|
2017
|
+
const parsed = ts30.parseJsonConfigFileContent(configFile.config, ts30.sys, dirname2(configPath));
|
|
2018
|
+
return ts30.createProgram({
|
|
1954
2019
|
rootNames: files,
|
|
1955
2020
|
options: { ...parsed.options, skipLibCheck: true }
|
|
1956
2021
|
});
|
|
1957
2022
|
}
|
|
1958
|
-
return
|
|
2023
|
+
return ts30.createProgram({
|
|
1959
2024
|
rootNames: files,
|
|
1960
2025
|
options: {
|
|
1961
|
-
target:
|
|
1962
|
-
module:
|
|
1963
|
-
moduleResolution:
|
|
2026
|
+
target: ts30.ScriptTarget.ESNext,
|
|
2027
|
+
module: ts30.ModuleKind.ESNext,
|
|
2028
|
+
moduleResolution: ts30.ModuleResolutionKind.Bundler,
|
|
1964
2029
|
strict: true,
|
|
1965
2030
|
skipLibCheck: true,
|
|
1966
2031
|
noEmit: true
|
|
@@ -2200,4 +2265,4 @@ export {
|
|
|
2200
2265
|
executeScan,
|
|
2201
2266
|
scan
|
|
2202
2267
|
};
|
|
2203
|
-
//# sourceMappingURL=chunk-
|
|
2268
|
+
//# sourceMappingURL=chunk-7UXUNJSF.js.map
|