unguard 0.10.0 → 0.10.2
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-5GVEUYZF.js → chunk-NNUATKJZ.js} +171 -130
- package/dist/chunk-NNUATKJZ.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-5GVEUYZF.js.map +0 -1
|
@@ -636,6 +636,7 @@ var preferRequiredParamWithGuard = {
|
|
|
636
636
|
};
|
|
637
637
|
|
|
638
638
|
// src/rules/cross-file/duplicate-type-declaration.ts
|
|
639
|
+
import * as ts18 from "typescript";
|
|
639
640
|
var duplicateTypeDeclaration = {
|
|
640
641
|
id: "duplicate-type-declaration",
|
|
641
642
|
severity: "warning",
|
|
@@ -645,6 +646,7 @@ var duplicateTypeDeclaration = {
|
|
|
645
646
|
for (const group of project.types.getDuplicateGroups()) {
|
|
646
647
|
const files = new Set(group.map((e) => e.file));
|
|
647
648
|
if (files.size < 2) continue;
|
|
649
|
+
if (group.every((e) => isTrivialObjectShape(e.node))) continue;
|
|
648
650
|
reportDuplicateGroup(
|
|
649
651
|
group,
|
|
650
652
|
this.id,
|
|
@@ -657,9 +659,14 @@ var duplicateTypeDeclaration = {
|
|
|
657
659
|
return diagnostics;
|
|
658
660
|
}
|
|
659
661
|
};
|
|
662
|
+
function isTrivialObjectShape(node) {
|
|
663
|
+
if (ts18.isTypeLiteralNode(node)) return node.members.length <= 1;
|
|
664
|
+
if (ts18.isInterfaceDeclaration(node)) return node.members.length <= 1;
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
660
667
|
|
|
661
668
|
// src/rules/cross-file/duplicate-function-declaration.ts
|
|
662
|
-
import * as
|
|
669
|
+
import * as ts19 from "typescript";
|
|
663
670
|
var duplicateFunctionDeclaration = {
|
|
664
671
|
id: "duplicate-function-declaration",
|
|
665
672
|
severity: "warning",
|
|
@@ -684,12 +691,13 @@ var duplicateFunctionDeclaration = {
|
|
|
684
691
|
}
|
|
685
692
|
};
|
|
686
693
|
function getBodyBlock(node) {
|
|
687
|
-
if (
|
|
688
|
-
if (
|
|
689
|
-
if (
|
|
694
|
+
if (ts19.isFunctionDeclaration(node) || ts19.isFunctionExpression(node)) return node.body;
|
|
695
|
+
if (ts19.isArrowFunction(node)) return ts19.isBlock(node.body) ? node.body : void 0;
|
|
696
|
+
if (ts19.isMethodDeclaration(node)) return node.body;
|
|
690
697
|
return void 0;
|
|
691
698
|
}
|
|
692
699
|
function isSingleStatement(node) {
|
|
700
|
+
if (ts19.isArrowFunction(node) && !ts19.isBlock(node.body)) return true;
|
|
693
701
|
const body = getBodyBlock(node);
|
|
694
702
|
return body !== void 0 && body.statements.length <= 1;
|
|
695
703
|
}
|
|
@@ -697,8 +705,8 @@ function isSetter(node) {
|
|
|
697
705
|
const body = getBodyBlock(node);
|
|
698
706
|
if (!body || body.statements.length !== 1) return false;
|
|
699
707
|
const stmt = body.statements[0];
|
|
700
|
-
if (stmt === void 0 || !
|
|
701
|
-
return
|
|
708
|
+
if (stmt === void 0 || !ts19.isExpressionStatement(stmt)) return false;
|
|
709
|
+
return ts19.isBinaryExpression(stmt.expression) && stmt.expression.operatorToken.kind === ts19.SyntaxKind.EqualsToken;
|
|
702
710
|
}
|
|
703
711
|
|
|
704
712
|
// src/rules/cross-file/optional-arg-always-used.ts
|
|
@@ -733,14 +741,14 @@ var optionalArgAlwaysUsed = {
|
|
|
733
741
|
};
|
|
734
742
|
|
|
735
743
|
// src/rules/ts/no-catch-return.ts
|
|
736
|
-
import * as
|
|
744
|
+
import * as ts20 from "typescript";
|
|
737
745
|
var noCatchReturn = {
|
|
738
746
|
kind: "ts",
|
|
739
747
|
id: "no-catch-return",
|
|
740
748
|
severity: "warning",
|
|
741
749
|
message: "Catch block silently returns a fallback value with no logging; rethrow, log the error, or let it propagate",
|
|
742
750
|
visit(node, ctx) {
|
|
743
|
-
if (!
|
|
751
|
+
if (!ts20.isCatchClause(node)) return;
|
|
744
752
|
const block = node.block;
|
|
745
753
|
if (hasReturn(block) && !hasThrow(block) && !hasLogging(block)) {
|
|
746
754
|
ctx.report(node);
|
|
@@ -750,57 +758,57 @@ var noCatchReturn = {
|
|
|
750
758
|
function walkBlock(block, predicate) {
|
|
751
759
|
function visit(node) {
|
|
752
760
|
if (predicate(node)) return true;
|
|
753
|
-
if (
|
|
754
|
-
return
|
|
761
|
+
if (ts20.isFunctionDeclaration(node) || ts20.isFunctionExpression(node) || ts20.isArrowFunction(node)) return false;
|
|
762
|
+
return ts20.forEachChild(node, visit) ?? false;
|
|
755
763
|
}
|
|
756
|
-
return
|
|
764
|
+
return ts20.forEachChild(block, visit) ?? false;
|
|
757
765
|
}
|
|
758
766
|
function hasReturn(block) {
|
|
759
|
-
return walkBlock(block, (n) =>
|
|
767
|
+
return walkBlock(block, (n) => ts20.isReturnStatement(n));
|
|
760
768
|
}
|
|
761
769
|
function hasThrow(block) {
|
|
762
|
-
return walkBlock(block, (n) =>
|
|
770
|
+
return walkBlock(block, (n) => ts20.isThrowStatement(n));
|
|
763
771
|
}
|
|
764
772
|
var LOG_OBJECTS = /* @__PURE__ */ new Set(["console", "logger", "log"]);
|
|
765
773
|
function hasLogging(block) {
|
|
766
774
|
return walkBlock(block, (n) => {
|
|
767
|
-
if (!
|
|
775
|
+
if (!ts20.isCallExpression(n)) return false;
|
|
768
776
|
const callee = n.expression;
|
|
769
|
-
if (!
|
|
770
|
-
if (!
|
|
777
|
+
if (!ts20.isPropertyAccessExpression(callee)) return false;
|
|
778
|
+
if (!ts20.isIdentifier(callee.expression)) return false;
|
|
771
779
|
return LOG_OBJECTS.has(callee.expression.text);
|
|
772
780
|
});
|
|
773
781
|
}
|
|
774
782
|
|
|
775
783
|
// src/rules/ts/no-error-rewrap.ts
|
|
776
|
-
import * as
|
|
784
|
+
import * as ts21 from "typescript";
|
|
777
785
|
var noErrorRewrap = {
|
|
778
786
|
kind: "ts",
|
|
779
787
|
id: "no-error-rewrap",
|
|
780
788
|
severity: "error",
|
|
781
789
|
message: "Re-wrapped error loses the original stack trace and type; use { cause: originalError } to preserve the error chain",
|
|
782
790
|
visit(node, ctx) {
|
|
783
|
-
if (!
|
|
791
|
+
if (!ts21.isCatchClause(node)) return;
|
|
784
792
|
if (!node.variableDeclaration) return;
|
|
785
793
|
const param = node.variableDeclaration.name;
|
|
786
|
-
if (!
|
|
794
|
+
if (!ts21.isIdentifier(param)) return;
|
|
787
795
|
const catchName = param.text;
|
|
788
796
|
findRewraps(node.block, catchName, ctx);
|
|
789
797
|
}
|
|
790
798
|
};
|
|
791
799
|
function findRewraps(block, catchName, ctx) {
|
|
792
800
|
function visit(node) {
|
|
793
|
-
if (
|
|
794
|
-
if (
|
|
801
|
+
if (ts21.isFunctionDeclaration(node) || ts21.isFunctionExpression(node) || ts21.isArrowFunction(node)) return;
|
|
802
|
+
if (ts21.isThrowStatement(node) && node.expression && ts21.isNewExpression(node.expression)) {
|
|
795
803
|
const args = node.expression.arguments;
|
|
796
804
|
if (args && args.length > 0 && referencesName(args, catchName) && !hasCauseArg(args)) {
|
|
797
805
|
ctx.report(node);
|
|
798
806
|
}
|
|
799
807
|
return;
|
|
800
808
|
}
|
|
801
|
-
|
|
809
|
+
ts21.forEachChild(node, visit);
|
|
802
810
|
}
|
|
803
|
-
|
|
811
|
+
ts21.forEachChild(block, visit);
|
|
804
812
|
}
|
|
805
813
|
function referencesName(args, name) {
|
|
806
814
|
for (const arg of args) {
|
|
@@ -809,15 +817,15 @@ function referencesName(args, name) {
|
|
|
809
817
|
return false;
|
|
810
818
|
}
|
|
811
819
|
function containsIdentifier(node, name) {
|
|
812
|
-
if (
|
|
813
|
-
return
|
|
820
|
+
if (ts21.isIdentifier(node) && node.text === name) return true;
|
|
821
|
+
return ts21.forEachChild(node, (child) => containsIdentifier(child, name) || void 0) ?? false;
|
|
814
822
|
}
|
|
815
823
|
function hasCauseArg(args) {
|
|
816
824
|
for (const arg of args) {
|
|
817
|
-
if (
|
|
825
|
+
if (ts21.isObjectLiteralExpression(arg)) {
|
|
818
826
|
for (const prop of arg.properties) {
|
|
819
|
-
if (
|
|
820
|
-
if (
|
|
827
|
+
if (ts21.isPropertyAssignment(prop) && ts21.isIdentifier(prop.name) && prop.name.text === "cause") return true;
|
|
828
|
+
if (ts21.isShorthandPropertyAssignment(prop) && prop.name.text === "cause") return true;
|
|
821
829
|
}
|
|
822
830
|
}
|
|
823
831
|
}
|
|
@@ -825,7 +833,7 @@ function hasCauseArg(args) {
|
|
|
825
833
|
}
|
|
826
834
|
|
|
827
835
|
// src/rules/cross-file/explicit-null-arg.ts
|
|
828
|
-
import * as
|
|
836
|
+
import * as ts22 from "typescript";
|
|
829
837
|
var explicitNullArg = {
|
|
830
838
|
id: "explicit-null-arg",
|
|
831
839
|
severity: "warning",
|
|
@@ -845,7 +853,7 @@ var explicitNullArg = {
|
|
|
845
853
|
const arg = site.node.arguments[i];
|
|
846
854
|
if (arg === void 0) continue;
|
|
847
855
|
if (isNullishLiteral(arg)) {
|
|
848
|
-
const val = arg.kind ===
|
|
856
|
+
const val = arg.kind === ts22.SyntaxKind.NullKeyword ? "null" : "undefined";
|
|
849
857
|
diagnostics.push({
|
|
850
858
|
ruleId: this.id,
|
|
851
859
|
severity: this.severity,
|
|
@@ -918,7 +926,7 @@ function resolveCandidates(fromFile, specifier) {
|
|
|
918
926
|
}
|
|
919
927
|
|
|
920
928
|
// src/rules/cross-file/duplicate-type-name.ts
|
|
921
|
-
import * as
|
|
929
|
+
import * as ts23 from "typescript";
|
|
922
930
|
var duplicateTypeName = {
|
|
923
931
|
id: "duplicate-type-name",
|
|
924
932
|
severity: "warning",
|
|
@@ -929,7 +937,7 @@ var duplicateTypeName = {
|
|
|
929
937
|
const hashes = new Set(group.map((e) => e.hash));
|
|
930
938
|
if (hashes.size === 1) continue;
|
|
931
939
|
const hasInferredType = group.some(
|
|
932
|
-
(e) => !
|
|
940
|
+
(e) => !ts23.isTypeLiteralNode(e.node) && !ts23.isInterfaceDeclaration(e.node)
|
|
933
941
|
);
|
|
934
942
|
if (hasInferredType) continue;
|
|
935
943
|
reportDuplicateGroup(
|
|
@@ -969,20 +977,21 @@ var duplicateConstantDeclaration = {
|
|
|
969
977
|
};
|
|
970
978
|
|
|
971
979
|
// src/rules/ts/no-dynamic-import.ts
|
|
972
|
-
import * as
|
|
980
|
+
import * as ts24 from "typescript";
|
|
973
981
|
var noDynamicImport = {
|
|
974
982
|
kind: "ts",
|
|
975
983
|
id: "no-dynamic-import",
|
|
976
984
|
severity: "error",
|
|
977
985
|
message: "Dynamic import() breaks static analysis and hides dependencies; use a static import instead",
|
|
978
986
|
visit(node, ctx) {
|
|
979
|
-
if (!
|
|
980
|
-
if (node.expression.kind !==
|
|
987
|
+
if (!ts24.isCallExpression(node)) return;
|
|
988
|
+
if (node.expression.kind !== ts24.SyntaxKind.ImportKeyword) return;
|
|
981
989
|
ctx.report(node);
|
|
982
990
|
}
|
|
983
991
|
};
|
|
984
992
|
|
|
985
993
|
// src/rules/cross-file/near-duplicate-function.ts
|
|
994
|
+
import * as ts25 from "typescript";
|
|
986
995
|
var nearDuplicateFunction = {
|
|
987
996
|
id: "near-duplicate-function",
|
|
988
997
|
severity: "warning",
|
|
@@ -992,6 +1001,7 @@ var nearDuplicateFunction = {
|
|
|
992
1001
|
for (const group of project.functions.getNearDuplicateGroups()) {
|
|
993
1002
|
const MIN_NORMALIZED_BODY = 32;
|
|
994
1003
|
if (group.every((e) => e.normalizedBodyLength < MIN_NORMALIZED_BODY)) continue;
|
|
1004
|
+
if (group.every(isSimpleStructure)) continue;
|
|
995
1005
|
reportDuplicateGroup(
|
|
996
1006
|
group,
|
|
997
1007
|
this.id,
|
|
@@ -1004,38 +1014,67 @@ var nearDuplicateFunction = {
|
|
|
1004
1014
|
return diagnostics;
|
|
1005
1015
|
}
|
|
1006
1016
|
};
|
|
1017
|
+
function getFunctionBody(node) {
|
|
1018
|
+
if (ts25.isFunctionDeclaration(node) || ts25.isFunctionExpression(node)) return node.body;
|
|
1019
|
+
if (ts25.isArrowFunction(node)) return node.body;
|
|
1020
|
+
if (ts25.isMethodDeclaration(node)) return node.body;
|
|
1021
|
+
return void 0;
|
|
1022
|
+
}
|
|
1023
|
+
function getTopLevelStatementCount(body) {
|
|
1024
|
+
if (ts25.isBlock(body)) return body.statements.length;
|
|
1025
|
+
return 1;
|
|
1026
|
+
}
|
|
1027
|
+
function hasControlFlow(node) {
|
|
1028
|
+
let found = false;
|
|
1029
|
+
function visit(current) {
|
|
1030
|
+
if (found) return;
|
|
1031
|
+
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)) {
|
|
1032
|
+
found = true;
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
ts25.forEachChild(current, visit);
|
|
1036
|
+
}
|
|
1037
|
+
visit(node);
|
|
1038
|
+
return found;
|
|
1039
|
+
}
|
|
1040
|
+
function isSimpleStructure(entry) {
|
|
1041
|
+
const body = getFunctionBody(entry.node);
|
|
1042
|
+
if (!body) return false;
|
|
1043
|
+
if (hasControlFlow(body)) return false;
|
|
1044
|
+
return getTopLevelStatementCount(body) <= 2;
|
|
1045
|
+
}
|
|
1007
1046
|
|
|
1008
1047
|
// src/rules/cross-file/trivial-wrapper.ts
|
|
1009
|
-
import * as
|
|
1010
|
-
function
|
|
1011
|
-
if (
|
|
1048
|
+
import * as ts26 from "typescript";
|
|
1049
|
+
function getFunctionBody2(node) {
|
|
1050
|
+
if (ts26.isFunctionDeclaration(node) || ts26.isFunctionExpression(node)) {
|
|
1012
1051
|
return node.body;
|
|
1013
1052
|
}
|
|
1014
|
-
if (
|
|
1053
|
+
if (ts26.isArrowFunction(node)) {
|
|
1015
1054
|
return node.body;
|
|
1016
1055
|
}
|
|
1017
|
-
if (
|
|
1056
|
+
if (ts26.isMethodDeclaration(node)) {
|
|
1018
1057
|
return node.body;
|
|
1019
1058
|
}
|
|
1020
1059
|
return void 0;
|
|
1021
1060
|
}
|
|
1022
1061
|
function getCalleeName(expr) {
|
|
1023
|
-
if (
|
|
1024
|
-
if (
|
|
1062
|
+
if (ts26.isIdentifier(expr)) return expr.text;
|
|
1063
|
+
if (ts26.isPropertyAccessExpression(expr)) return expr.name.text;
|
|
1025
1064
|
return void 0;
|
|
1026
1065
|
}
|
|
1027
1066
|
function getTrivialCallTarget(fn) {
|
|
1028
|
-
const body =
|
|
1067
|
+
const body = getFunctionBody2(fn.node);
|
|
1029
1068
|
if (!body) return null;
|
|
1030
1069
|
let callExpr;
|
|
1031
|
-
if (
|
|
1070
|
+
if (ts26.isBlock(body)) {
|
|
1032
1071
|
if (body.statements.length !== 1) return null;
|
|
1033
1072
|
const stmt = body.statements[0];
|
|
1034
|
-
if (!stmt || !
|
|
1035
|
-
if (!
|
|
1073
|
+
if (!stmt || !ts26.isReturnStatement(stmt) || !stmt.expression) return null;
|
|
1074
|
+
if (!ts26.isCallExpression(stmt.expression)) return null;
|
|
1036
1075
|
callExpr = stmt.expression;
|
|
1037
1076
|
} else {
|
|
1038
|
-
if (!
|
|
1077
|
+
if (!ts26.isCallExpression(body)) return null;
|
|
1039
1078
|
callExpr = body;
|
|
1040
1079
|
}
|
|
1041
1080
|
const calleeName = getCalleeName(callExpr.expression);
|
|
@@ -1043,7 +1082,7 @@ function getTrivialCallTarget(fn) {
|
|
|
1043
1082
|
const paramNames = fn.params.map((p) => p.name);
|
|
1044
1083
|
const args = callExpr.arguments;
|
|
1045
1084
|
for (const arg of args) {
|
|
1046
|
-
if (!
|
|
1085
|
+
if (!ts26.isIdentifier(arg)) return null;
|
|
1047
1086
|
if (!paramNames.includes(arg.text)) return null;
|
|
1048
1087
|
}
|
|
1049
1088
|
return { calleeName };
|
|
@@ -1340,32 +1379,32 @@ function isFailOn(value) {
|
|
|
1340
1379
|
}
|
|
1341
1380
|
|
|
1342
1381
|
// src/collect/index.ts
|
|
1343
|
-
import * as
|
|
1382
|
+
import * as ts29 from "typescript";
|
|
1344
1383
|
import { createHash as createHash2 } from "crypto";
|
|
1345
1384
|
|
|
1346
1385
|
// src/utils/hash.ts
|
|
1347
1386
|
import { createHash } from "crypto";
|
|
1348
|
-
import * as
|
|
1387
|
+
import * as ts27 from "typescript";
|
|
1349
1388
|
function hashTypeShape(node, sourceFile) {
|
|
1350
1389
|
const normalized = normalizeTypeNode(node, sourceFile);
|
|
1351
1390
|
return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
1352
1391
|
}
|
|
1353
1392
|
function normalizeTypeNode(node, sourceFile) {
|
|
1354
|
-
if (
|
|
1393
|
+
if (ts27.isTypeLiteralNode(node)) {
|
|
1355
1394
|
const normalized = node.members.map((m) => normalizeTypeNode(m, sourceFile)).sort().join(";");
|
|
1356
1395
|
return `{${normalized}}`;
|
|
1357
1396
|
}
|
|
1358
|
-
if (
|
|
1397
|
+
if (ts27.isInterfaceDeclaration(node)) {
|
|
1359
1398
|
const normalized = node.members.map((m) => normalizeTypeNode(m, sourceFile)).sort().join(";");
|
|
1360
1399
|
return `{${normalized}}`;
|
|
1361
1400
|
}
|
|
1362
|
-
if (
|
|
1401
|
+
if (ts27.isPropertySignature(node)) {
|
|
1363
1402
|
const keyName = node.name.getText(sourceFile);
|
|
1364
1403
|
const optional = node.questionToken ? "?" : "";
|
|
1365
1404
|
const type = node.type ? normalizeTypeNode(node.type, sourceFile) : "any";
|
|
1366
1405
|
return `${keyName}${optional}:${type}`;
|
|
1367
1406
|
}
|
|
1368
|
-
if (
|
|
1407
|
+
if (ts27.isTypeAliasDeclaration(node)) {
|
|
1369
1408
|
return normalizeTypeNode(node.type, sourceFile);
|
|
1370
1409
|
}
|
|
1371
1410
|
return node.getText(sourceFile).replace(/\s+/g, " ").trim();
|
|
@@ -1531,7 +1570,7 @@ var InlineParamTypeRegistry = class extends BaseRegistry {
|
|
|
1531
1570
|
};
|
|
1532
1571
|
|
|
1533
1572
|
// src/typecheck/walk.ts
|
|
1534
|
-
import * as
|
|
1573
|
+
import * as ts28 from "typescript";
|
|
1535
1574
|
function buildContext(rule, sourceFile, checker, source, filename, diagnostics) {
|
|
1536
1575
|
return {
|
|
1537
1576
|
filename,
|
|
@@ -1539,7 +1578,7 @@ function buildContext(rule, sourceFile, checker, source, filename, diagnostics)
|
|
|
1539
1578
|
sourceFile,
|
|
1540
1579
|
checker,
|
|
1541
1580
|
report(node, message) {
|
|
1542
|
-
const { line, character } =
|
|
1581
|
+
const { line, character } = ts28.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
|
|
1543
1582
|
diagnostics.push({
|
|
1544
1583
|
ruleId: rule.id,
|
|
1545
1584
|
severity: rule.severity,
|
|
@@ -1550,7 +1589,7 @@ function buildContext(rule, sourceFile, checker, source, filename, diagnostics)
|
|
|
1550
1589
|
});
|
|
1551
1590
|
},
|
|
1552
1591
|
reportAtOffset(offset, message) {
|
|
1553
|
-
const { line, character } =
|
|
1592
|
+
const { line, character } = ts28.getLineAndCharacterOfPosition(sourceFile, offset);
|
|
1554
1593
|
diagnostics.push({
|
|
1555
1594
|
ruleId: rule.id,
|
|
1556
1595
|
severity: rule.severity,
|
|
@@ -1576,7 +1615,7 @@ function buildContext(rule, sourceFile, checker, source, filename, diagnostics)
|
|
|
1576
1615
|
}
|
|
1577
1616
|
|
|
1578
1617
|
// src/collect/index.ts
|
|
1579
|
-
function collectProject(program, tsRules) {
|
|
1618
|
+
function collectProject(program, tsRules, allowedFiles) {
|
|
1580
1619
|
const checker = program.getTypeChecker();
|
|
1581
1620
|
const types = new TypeRegistry();
|
|
1582
1621
|
const functions = new FunctionRegistry();
|
|
@@ -1601,12 +1640,13 @@ function collectProject(program, tsRules) {
|
|
|
1601
1640
|
rule.visit(node, ctx);
|
|
1602
1641
|
}
|
|
1603
1642
|
}
|
|
1604
|
-
|
|
1643
|
+
ts29.forEachChild(node, visit2);
|
|
1605
1644
|
};
|
|
1606
1645
|
var visit = visit2;
|
|
1607
1646
|
const file = sourceFile.fileName;
|
|
1608
1647
|
if (sourceFile.isDeclarationFile) continue;
|
|
1609
1648
|
if (file.includes("node_modules")) continue;
|
|
1649
|
+
if (allowedFiles && !allowedFiles.has(file)) continue;
|
|
1610
1650
|
const source = sourceFile.getFullText();
|
|
1611
1651
|
const comments = collectAllComments(sourceFile);
|
|
1612
1652
|
fileMap.set(file, { source, sourceFile, comments });
|
|
@@ -1614,7 +1654,7 @@ function collectProject(program, tsRules) {
|
|
|
1614
1654
|
rule,
|
|
1615
1655
|
ctx: buildContext(rule, sourceFile, checker, source, file, diagnostics)
|
|
1616
1656
|
}));
|
|
1617
|
-
|
|
1657
|
+
ts29.forEachChild(sourceFile, visit2);
|
|
1618
1658
|
}
|
|
1619
1659
|
const fileHashes = /* @__PURE__ */ new Map();
|
|
1620
1660
|
for (const [file, { source }] of fileMap) {
|
|
@@ -1630,52 +1670,52 @@ function collectProject(program, tsRules) {
|
|
|
1630
1670
|
return { index: { types, functions, constants, callSites, imports, files: fileMap, fileHashes, statementSequences, inlineParamTypes }, diagnostics };
|
|
1631
1671
|
}
|
|
1632
1672
|
function hasNonPublicModifier(node) {
|
|
1633
|
-
if (!
|
|
1634
|
-
const mods =
|
|
1673
|
+
if (!ts29.canHaveModifiers(node)) return false;
|
|
1674
|
+
const mods = ts29.getModifiers(node);
|
|
1635
1675
|
if (mods === void 0) return false;
|
|
1636
1676
|
return mods.some(
|
|
1637
|
-
(m) => m.kind ===
|
|
1677
|
+
(m) => m.kind === ts29.SyntaxKind.PrivateKeyword || m.kind === ts29.SyntaxKind.ProtectedKeyword
|
|
1638
1678
|
);
|
|
1639
1679
|
}
|
|
1640
1680
|
function isExported(node) {
|
|
1641
|
-
if (!
|
|
1642
|
-
const mods =
|
|
1681
|
+
if (!ts29.canHaveModifiers(node)) return false;
|
|
1682
|
+
const mods = ts29.getModifiers(node);
|
|
1643
1683
|
if (mods === void 0) return false;
|
|
1644
|
-
return mods.some((m) => m.kind ===
|
|
1684
|
+
return mods.some((m) => m.kind === ts29.SyntaxKind.ExportKeyword);
|
|
1645
1685
|
}
|
|
1646
1686
|
function collectTypes(node, file, sourceFile, registry) {
|
|
1647
|
-
if (
|
|
1648
|
-
const line =
|
|
1687
|
+
if (ts29.isTypeAliasDeclaration(node)) {
|
|
1688
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
|
|
1649
1689
|
registry.add(node.name.text, file, line, node.type, sourceFile, isExported(node));
|
|
1650
1690
|
}
|
|
1651
|
-
if (
|
|
1652
|
-
const line =
|
|
1691
|
+
if (ts29.isInterfaceDeclaration(node)) {
|
|
1692
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
|
|
1653
1693
|
registry.add(node.name.text, file, line, node, sourceFile, isExported(node));
|
|
1654
1694
|
}
|
|
1655
1695
|
}
|
|
1656
1696
|
function isConstantValue(node) {
|
|
1657
|
-
if (
|
|
1658
|
-
if (
|
|
1659
|
-
if (
|
|
1660
|
-
if (
|
|
1661
|
-
if (
|
|
1697
|
+
if (ts29.isStringLiteral(node)) return true;
|
|
1698
|
+
if (ts29.isNumericLiteral(node)) return true;
|
|
1699
|
+
if (ts29.isNoSubstitutionTemplateLiteral(node)) return true;
|
|
1700
|
+
if (ts29.isPrefixUnaryExpression(node)) return isConstantValue(node.operand);
|
|
1701
|
+
if (ts29.isBinaryExpression(node)) return isConstantValue(node.left) && isConstantValue(node.right);
|
|
1662
1702
|
return false;
|
|
1663
1703
|
}
|
|
1664
1704
|
function collectConstants(node, file, sourceFile, registry) {
|
|
1665
|
-
if (!
|
|
1666
|
-
if (!(node.declarationList.flags &
|
|
1705
|
+
if (!ts29.isVariableStatement(node)) return;
|
|
1706
|
+
if (!(node.declarationList.flags & ts29.NodeFlags.Const)) return;
|
|
1667
1707
|
const exported = isExported(node);
|
|
1668
1708
|
for (const decl of node.declarationList.declarations) {
|
|
1669
|
-
if (!decl.initializer || !
|
|
1709
|
+
if (!decl.initializer || !ts29.isIdentifier(decl.name)) continue;
|
|
1670
1710
|
if (!isConstantValue(decl.initializer)) continue;
|
|
1671
1711
|
const valueText = decl.initializer.getText(sourceFile).replace(/\s+/g, " ").trim();
|
|
1672
1712
|
const valueHash = createHash2("sha256").update(valueText).digest("hex").slice(0, 16);
|
|
1673
|
-
const line =
|
|
1713
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, decl.getStart(sourceFile)).line + 1;
|
|
1674
1714
|
registry.add({ name: decl.name.text, file, line, valueHash, valueText, exported });
|
|
1675
1715
|
}
|
|
1676
1716
|
}
|
|
1677
1717
|
function buildFunctionEntry(body, parameters, sourceFile, file, lineNode, name, extra) {
|
|
1678
|
-
const line =
|
|
1718
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, lineNode.getStart(sourceFile)).line + 1;
|
|
1679
1719
|
const params = extractParams(parameters, sourceFile);
|
|
1680
1720
|
const paramNames = params.map((p) => p.name);
|
|
1681
1721
|
const hash = hashFunctionBody(body, sourceFile);
|
|
@@ -1697,17 +1737,17 @@ function buildFunctionEntry(body, parameters, sourceFile, file, lineNode, name,
|
|
|
1697
1737
|
};
|
|
1698
1738
|
}
|
|
1699
1739
|
function collectFunctions(node, file, sourceFile, checker, registry) {
|
|
1700
|
-
if (
|
|
1740
|
+
if (ts29.isFunctionDeclaration(node) && node.name && node.body) {
|
|
1701
1741
|
registry.add(buildFunctionEntry(node.body, node.parameters, sourceFile, file, node, node.name.text, {
|
|
1702
1742
|
exported: isExported(node),
|
|
1703
1743
|
symbol: checker.getSymbolAtLocation(node.name),
|
|
1704
1744
|
node
|
|
1705
1745
|
}));
|
|
1706
1746
|
}
|
|
1707
|
-
if (
|
|
1747
|
+
if (ts29.isVariableStatement(node)) {
|
|
1708
1748
|
const exported = isExported(node);
|
|
1709
1749
|
for (const decl of node.declarationList.declarations) {
|
|
1710
|
-
if (decl.initializer &&
|
|
1750
|
+
if (decl.initializer && ts29.isArrowFunction(decl.initializer) && ts29.isIdentifier(decl.name)) {
|
|
1711
1751
|
const arrow = decl.initializer;
|
|
1712
1752
|
registry.add(buildFunctionEntry(arrow.body, arrow.parameters, sourceFile, file, decl, decl.name.text, {
|
|
1713
1753
|
exported,
|
|
@@ -1715,7 +1755,7 @@ function collectFunctions(node, file, sourceFile, checker, registry) {
|
|
|
1715
1755
|
node: arrow
|
|
1716
1756
|
}));
|
|
1717
1757
|
}
|
|
1718
|
-
if (decl.initializer &&
|
|
1758
|
+
if (decl.initializer && ts29.isFunctionExpression(decl.initializer) && ts29.isIdentifier(decl.name)) {
|
|
1719
1759
|
const fn = decl.initializer;
|
|
1720
1760
|
if (fn.body) {
|
|
1721
1761
|
registry.add(buildFunctionEntry(fn.body, fn.parameters, sourceFile, file, decl, decl.name.text, {
|
|
@@ -1727,22 +1767,22 @@ function collectFunctions(node, file, sourceFile, checker, registry) {
|
|
|
1727
1767
|
}
|
|
1728
1768
|
}
|
|
1729
1769
|
}
|
|
1730
|
-
if (
|
|
1770
|
+
if (ts29.isPropertyAssignment(node) && (ts29.isIdentifier(node.name) || ts29.isStringLiteral(node.name))) {
|
|
1731
1771
|
const init = node.initializer;
|
|
1732
1772
|
const propName = node.name.text;
|
|
1733
|
-
if (
|
|
1773
|
+
if (ts29.isArrowFunction(init)) {
|
|
1734
1774
|
registry.add(buildFunctionEntry(init.body, init.parameters, sourceFile, file, node, propName, { node: init }));
|
|
1735
1775
|
}
|
|
1736
|
-
if (
|
|
1776
|
+
if (ts29.isFunctionExpression(init) && init.body) {
|
|
1737
1777
|
registry.add(buildFunctionEntry(init.body, init.parameters, sourceFile, file, node, propName, { node: init }));
|
|
1738
1778
|
}
|
|
1739
1779
|
}
|
|
1740
|
-
if (
|
|
1780
|
+
if (ts29.isArrowFunction(node) || ts29.isFunctionExpression(node)) {
|
|
1741
1781
|
const parent = node.parent;
|
|
1742
|
-
if (
|
|
1743
|
-
} else if (
|
|
1782
|
+
if (ts29.isVariableDeclaration(parent) && ts29.isIdentifier(parent.name)) {
|
|
1783
|
+
} else if (ts29.isPropertyAssignment(parent)) {
|
|
1744
1784
|
} else {
|
|
1745
|
-
const body =
|
|
1785
|
+
const body = ts29.isArrowFunction(node) ? node.body : node.body;
|
|
1746
1786
|
if (body) {
|
|
1747
1787
|
const MIN_ANON_BODY = 64;
|
|
1748
1788
|
if (bodyTextLength(body, sourceFile) >= MIN_ANON_BODY) {
|
|
@@ -1752,14 +1792,14 @@ function collectFunctions(node, file, sourceFile, checker, registry) {
|
|
|
1752
1792
|
}
|
|
1753
1793
|
}
|
|
1754
1794
|
}
|
|
1755
|
-
if (
|
|
1795
|
+
if (ts29.isMethodDeclaration(node) && node.body && ts29.isIdentifier(node.name)) {
|
|
1756
1796
|
const parent = node.parent;
|
|
1757
|
-
if (
|
|
1797
|
+
if (ts29.isClassDeclaration(parent)) {
|
|
1758
1798
|
if (hasNonPublicModifier(node)) return;
|
|
1759
1799
|
const className = parent.name ? parent.name.text : "<anonymous>";
|
|
1760
1800
|
const name = `${className}.${node.name.text}`;
|
|
1761
1801
|
const implementsInterface = parent.heritageClauses?.some(
|
|
1762
|
-
(c) => c.token ===
|
|
1802
|
+
(c) => c.token === ts29.SyntaxKind.ImplementsKeyword
|
|
1763
1803
|
) ?? false;
|
|
1764
1804
|
registry.add(buildFunctionEntry(node.body, node.parameters, sourceFile, file, node, name, {
|
|
1765
1805
|
exported: isExported(parent),
|
|
@@ -1782,16 +1822,16 @@ function extractParams(parameters, sourceFile) {
|
|
|
1782
1822
|
}
|
|
1783
1823
|
function deriveAnonymousName(node, sourceFile) {
|
|
1784
1824
|
const parent = node.parent;
|
|
1785
|
-
const line =
|
|
1786
|
-
if (
|
|
1825
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
|
|
1826
|
+
if (ts29.isCallExpression(parent)) {
|
|
1787
1827
|
const grandparent = parent.parent;
|
|
1788
|
-
if (
|
|
1828
|
+
if (ts29.isPropertyAssignment(grandparent) && ts29.isIdentifier(grandparent.name)) {
|
|
1789
1829
|
return grandparent.name.text;
|
|
1790
1830
|
}
|
|
1791
1831
|
let calleeName = null;
|
|
1792
|
-
if (
|
|
1832
|
+
if (ts29.isIdentifier(parent.expression)) {
|
|
1793
1833
|
calleeName = parent.expression.text;
|
|
1794
|
-
} else if (
|
|
1834
|
+
} else if (ts29.isPropertyAccessExpression(parent.expression)) {
|
|
1795
1835
|
calleeName = parent.expression.name.text;
|
|
1796
1836
|
}
|
|
1797
1837
|
if (calleeName) {
|
|
@@ -1802,7 +1842,7 @@ function deriveAnonymousName(node, sourceFile) {
|
|
|
1802
1842
|
return `<anonymous>:${line}`;
|
|
1803
1843
|
}
|
|
1804
1844
|
function collectImports(node, file, imports) {
|
|
1805
|
-
if (
|
|
1845
|
+
if (ts29.isImportDeclaration(node) && ts29.isStringLiteral(node.moduleSpecifier)) {
|
|
1806
1846
|
const moduleSource = node.moduleSpecifier.text;
|
|
1807
1847
|
const clause = node.importClause;
|
|
1808
1848
|
if (!clause) return;
|
|
@@ -1814,7 +1854,7 @@ function collectImports(node, file, imports) {
|
|
|
1814
1854
|
source: moduleSource
|
|
1815
1855
|
});
|
|
1816
1856
|
}
|
|
1817
|
-
if (clause.namedBindings &&
|
|
1857
|
+
if (clause.namedBindings && ts29.isNamedImports(clause.namedBindings)) {
|
|
1818
1858
|
for (const el of clause.namedBindings.elements) {
|
|
1819
1859
|
imports.push({
|
|
1820
1860
|
file,
|
|
@@ -1825,9 +1865,9 @@ function collectImports(node, file, imports) {
|
|
|
1825
1865
|
}
|
|
1826
1866
|
}
|
|
1827
1867
|
}
|
|
1828
|
-
if (
|
|
1868
|
+
if (ts29.isExportDeclaration(node) && node.moduleSpecifier && ts29.isStringLiteral(node.moduleSpecifier)) {
|
|
1829
1869
|
const moduleSource = node.moduleSpecifier.text;
|
|
1830
|
-
if (node.exportClause &&
|
|
1870
|
+
if (node.exportClause && ts29.isNamedExports(node.exportClause)) {
|
|
1831
1871
|
for (const el of node.exportClause.elements) {
|
|
1832
1872
|
imports.push({
|
|
1833
1873
|
file,
|
|
@@ -1840,7 +1880,7 @@ function collectImports(node, file, imports) {
|
|
|
1840
1880
|
}
|
|
1841
1881
|
}
|
|
1842
1882
|
function collectStatementSequences(node, file, sourceFile, registry) {
|
|
1843
|
-
if (!
|
|
1883
|
+
if (!ts29.isBlock(node)) return;
|
|
1844
1884
|
const stmts = node.statements;
|
|
1845
1885
|
const n = stmts.length;
|
|
1846
1886
|
if (n < 3) return;
|
|
@@ -1857,34 +1897,34 @@ function collectStatementSequences(node, file, sourceFile, registry) {
|
|
|
1857
1897
|
const firstStmt = window[0];
|
|
1858
1898
|
const lastStmt = window[window.length - 1];
|
|
1859
1899
|
if (firstStmt === void 0 || lastStmt === void 0) continue;
|
|
1860
|
-
const line =
|
|
1861
|
-
const endLine =
|
|
1900
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, firstStmt.getStart(sourceFile)).line + 1;
|
|
1901
|
+
const endLine = ts29.getLineAndCharacterOfPosition(sourceFile, lastStmt.getEnd()).line + 1;
|
|
1862
1902
|
registry.add({ file, line, endLine, hash, normalizedHash, statementCount: size, normalizedBodyLength: normalized.length });
|
|
1863
1903
|
}
|
|
1864
1904
|
}
|
|
1865
1905
|
}
|
|
1866
1906
|
function collectInlineParamTypes(node, file, sourceFile, registry) {
|
|
1867
|
-
if (!
|
|
1907
|
+
if (!ts29.isTypeLiteralNode(node)) return;
|
|
1868
1908
|
const parent = node.parent;
|
|
1869
|
-
if (!parent || !
|
|
1909
|
+
if (!parent || !ts29.isParameter(parent)) return;
|
|
1870
1910
|
if (parent.type !== node) return;
|
|
1871
|
-
const line =
|
|
1911
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
|
|
1872
1912
|
registry.add(file, line, node, sourceFile);
|
|
1873
1913
|
}
|
|
1874
1914
|
function collectCallSites(node, file, sourceFile, checker, sites) {
|
|
1875
|
-
if (!
|
|
1915
|
+
if (!ts29.isCallExpression(node)) return;
|
|
1876
1916
|
let calleeName = null;
|
|
1877
|
-
if (
|
|
1917
|
+
if (ts29.isIdentifier(node.expression)) {
|
|
1878
1918
|
calleeName = node.expression.text;
|
|
1879
|
-
} else if (
|
|
1919
|
+
} else if (ts29.isPropertyAccessExpression(node.expression)) {
|
|
1880
1920
|
calleeName = node.expression.name.text;
|
|
1881
1921
|
}
|
|
1882
1922
|
if (calleeName) {
|
|
1883
|
-
const line =
|
|
1923
|
+
const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
|
|
1884
1924
|
let symbol;
|
|
1885
1925
|
try {
|
|
1886
1926
|
symbol = checker.getSymbolAtLocation(node.expression);
|
|
1887
|
-
if (symbol && symbol.flags &
|
|
1927
|
+
if (symbol && symbol.flags & ts29.SymbolFlags.Alias) {
|
|
1888
1928
|
symbol = checker.getAliasedSymbol(symbol);
|
|
1889
1929
|
}
|
|
1890
1930
|
} catch {
|
|
@@ -1904,12 +1944,12 @@ function collectAllComments(sourceFile) {
|
|
|
1904
1944
|
const source = sourceFile.getFullText();
|
|
1905
1945
|
const seen = /* @__PURE__ */ new Set();
|
|
1906
1946
|
function visit(node) {
|
|
1907
|
-
const leading =
|
|
1947
|
+
const leading = ts29.getLeadingCommentRanges(source, node.getFullStart());
|
|
1908
1948
|
if (leading) {
|
|
1909
1949
|
for (const r of leading) {
|
|
1910
1950
|
if (seen.has(r.pos)) continue;
|
|
1911
1951
|
seen.add(r.pos);
|
|
1912
|
-
const isLine = r.kind ===
|
|
1952
|
+
const isLine = r.kind === ts29.SyntaxKind.SingleLineCommentTrivia;
|
|
1913
1953
|
comments.push({
|
|
1914
1954
|
type: isLine ? "Line" : "Block",
|
|
1915
1955
|
value: source.slice(r.pos + 2, isLine ? r.end : r.end - 2),
|
|
@@ -1918,12 +1958,12 @@ function collectAllComments(sourceFile) {
|
|
|
1918
1958
|
});
|
|
1919
1959
|
}
|
|
1920
1960
|
}
|
|
1921
|
-
const trailing =
|
|
1961
|
+
const trailing = ts29.getTrailingCommentRanges(source, node.getEnd());
|
|
1922
1962
|
if (trailing) {
|
|
1923
1963
|
for (const r of trailing) {
|
|
1924
1964
|
if (seen.has(r.pos)) continue;
|
|
1925
1965
|
seen.add(r.pos);
|
|
1926
|
-
const isLine = r.kind ===
|
|
1966
|
+
const isLine = r.kind === ts29.SyntaxKind.SingleLineCommentTrivia;
|
|
1927
1967
|
comments.push({
|
|
1928
1968
|
type: isLine ? "Line" : "Block",
|
|
1929
1969
|
value: source.slice(r.pos + 2, isLine ? r.end : r.end - 2),
|
|
@@ -1932,34 +1972,34 @@ function collectAllComments(sourceFile) {
|
|
|
1932
1972
|
});
|
|
1933
1973
|
}
|
|
1934
1974
|
}
|
|
1935
|
-
|
|
1975
|
+
ts29.forEachChild(node, visit);
|
|
1936
1976
|
}
|
|
1937
1977
|
visit(sourceFile);
|
|
1938
1978
|
return comments;
|
|
1939
1979
|
}
|
|
1940
1980
|
|
|
1941
1981
|
// src/typecheck/program.ts
|
|
1942
|
-
import * as
|
|
1982
|
+
import * as ts30 from "typescript";
|
|
1943
1983
|
import { dirname as dirname2 } from "path";
|
|
1944
1984
|
function createProgramFromFiles(files) {
|
|
1945
1985
|
let configPath;
|
|
1946
1986
|
if (files.length > 0) {
|
|
1947
|
-
configPath =
|
|
1987
|
+
configPath = ts30.findConfigFile(dirname2(files[0]), ts30.sys.fileExists, "tsconfig.json");
|
|
1948
1988
|
}
|
|
1949
1989
|
if (configPath) {
|
|
1950
|
-
const configFile =
|
|
1951
|
-
const parsed =
|
|
1952
|
-
return
|
|
1990
|
+
const configFile = ts30.readConfigFile(configPath, ts30.sys.readFile);
|
|
1991
|
+
const parsed = ts30.parseJsonConfigFileContent(configFile.config, ts30.sys, dirname2(configPath));
|
|
1992
|
+
return ts30.createProgram({
|
|
1953
1993
|
rootNames: files,
|
|
1954
1994
|
options: { ...parsed.options, skipLibCheck: true }
|
|
1955
1995
|
});
|
|
1956
1996
|
}
|
|
1957
|
-
return
|
|
1997
|
+
return ts30.createProgram({
|
|
1958
1998
|
rootNames: files,
|
|
1959
1999
|
options: {
|
|
1960
|
-
target:
|
|
1961
|
-
module:
|
|
1962
|
-
moduleResolution:
|
|
2000
|
+
target: ts30.ScriptTarget.ESNext,
|
|
2001
|
+
module: ts30.ModuleKind.ESNext,
|
|
2002
|
+
moduleResolution: ts30.ModuleResolutionKind.Bundler,
|
|
1963
2003
|
strict: true,
|
|
1964
2004
|
skipLibCheck: true,
|
|
1965
2005
|
noEmit: true
|
|
@@ -1973,7 +2013,8 @@ function analyzeFiles(files, rules) {
|
|
|
1973
2013
|
const crossFileRules = rules.filter((r) => !isTSRule(r));
|
|
1974
2014
|
const program = files.length > 0 ? createProgramFromFiles(files) : null;
|
|
1975
2015
|
if (!program) return [];
|
|
1976
|
-
const
|
|
2016
|
+
const allowedFiles = new Set(files);
|
|
2017
|
+
const { index, diagnostics } = collectProject(program, tsRules, allowedFiles);
|
|
1977
2018
|
for (const rule of crossFileRules) {
|
|
1978
2019
|
const crossDiagnostics = rule.analyze(index);
|
|
1979
2020
|
for (const diagnostic of crossDiagnostics) {
|
|
@@ -2198,4 +2239,4 @@ export {
|
|
|
2198
2239
|
executeScan,
|
|
2199
2240
|
scan
|
|
2200
2241
|
};
|
|
2201
|
-
//# sourceMappingURL=chunk-
|
|
2242
|
+
//# sourceMappingURL=chunk-NNUATKJZ.js.map
|