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.
@@ -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 ts18 from "typescript";
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 (ts18.isFunctionDeclaration(node) || ts18.isFunctionExpression(node)) return node.body;
688
- if (ts18.isArrowFunction(node)) return ts18.isBlock(node.body) ? node.body : void 0;
689
- if (ts18.isMethodDeclaration(node)) return node.body;
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 || !ts18.isExpressionStatement(stmt)) return false;
701
- return ts18.isBinaryExpression(stmt.expression) && stmt.expression.operatorToken.kind === ts18.SyntaxKind.EqualsToken;
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 ts19 from "typescript";
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 (!ts19.isCatchClause(node)) return;
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 (ts19.isFunctionDeclaration(node) || ts19.isFunctionExpression(node) || ts19.isArrowFunction(node)) return false;
754
- return ts19.forEachChild(node, visit) ?? false;
761
+ if (ts20.isFunctionDeclaration(node) || ts20.isFunctionExpression(node) || ts20.isArrowFunction(node)) return false;
762
+ return ts20.forEachChild(node, visit) ?? false;
755
763
  }
756
- return ts19.forEachChild(block, visit) ?? false;
764
+ return ts20.forEachChild(block, visit) ?? false;
757
765
  }
758
766
  function hasReturn(block) {
759
- return walkBlock(block, (n) => ts19.isReturnStatement(n));
767
+ return walkBlock(block, (n) => ts20.isReturnStatement(n));
760
768
  }
761
769
  function hasThrow(block) {
762
- return walkBlock(block, (n) => ts19.isThrowStatement(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 (!ts19.isCallExpression(n)) return false;
775
+ if (!ts20.isCallExpression(n)) return false;
768
776
  const callee = n.expression;
769
- if (!ts19.isPropertyAccessExpression(callee)) return false;
770
- if (!ts19.isIdentifier(callee.expression)) return false;
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 ts20 from "typescript";
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 (!ts20.isCatchClause(node)) return;
791
+ if (!ts21.isCatchClause(node)) return;
784
792
  if (!node.variableDeclaration) return;
785
793
  const param = node.variableDeclaration.name;
786
- if (!ts20.isIdentifier(param)) return;
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 (ts20.isFunctionDeclaration(node) || ts20.isFunctionExpression(node) || ts20.isArrowFunction(node)) return;
794
- if (ts20.isThrowStatement(node) && node.expression && ts20.isNewExpression(node.expression)) {
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
- ts20.forEachChild(node, visit);
809
+ ts21.forEachChild(node, visit);
802
810
  }
803
- ts20.forEachChild(block, visit);
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 (ts20.isIdentifier(node) && node.text === name) return true;
813
- return ts20.forEachChild(node, (child) => containsIdentifier(child, name) || void 0) ?? false;
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 (ts20.isObjectLiteralExpression(arg)) {
825
+ if (ts21.isObjectLiteralExpression(arg)) {
818
826
  for (const prop of arg.properties) {
819
- if (ts20.isPropertyAssignment(prop) && ts20.isIdentifier(prop.name) && prop.name.text === "cause") return true;
820
- if (ts20.isShorthandPropertyAssignment(prop) && prop.name.text === "cause") return true;
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 ts21 from "typescript";
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 === ts21.SyntaxKind.NullKeyword ? "null" : "undefined";
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 ts22 from "typescript";
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) => !ts22.isTypeLiteralNode(e.node) && !ts22.isInterfaceDeclaration(e.node)
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 ts23 from "typescript";
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 (!ts23.isCallExpression(node)) return;
980
- if (node.expression.kind !== ts23.SyntaxKind.ImportKeyword) return;
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 ts24 from "typescript";
1010
- function getFunctionBody(node) {
1011
- if (ts24.isFunctionDeclaration(node) || ts24.isFunctionExpression(node)) {
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 (ts24.isArrowFunction(node)) {
1053
+ if (ts26.isArrowFunction(node)) {
1015
1054
  return node.body;
1016
1055
  }
1017
- if (ts24.isMethodDeclaration(node)) {
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 (ts24.isIdentifier(expr)) return expr.text;
1024
- if (ts24.isPropertyAccessExpression(expr)) return expr.name.text;
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 = getFunctionBody(fn.node);
1067
+ const body = getFunctionBody2(fn.node);
1029
1068
  if (!body) return null;
1030
1069
  let callExpr;
1031
- if (ts24.isBlock(body)) {
1070
+ if (ts26.isBlock(body)) {
1032
1071
  if (body.statements.length !== 1) return null;
1033
1072
  const stmt = body.statements[0];
1034
- if (!stmt || !ts24.isReturnStatement(stmt) || !stmt.expression) return null;
1035
- if (!ts24.isCallExpression(stmt.expression)) return null;
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 (!ts24.isCallExpression(body)) return null;
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 (!ts24.isIdentifier(arg)) return null;
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 ts27 from "typescript";
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 ts25 from "typescript";
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 (ts25.isTypeLiteralNode(node)) {
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 (ts25.isInterfaceDeclaration(node)) {
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 (ts25.isPropertySignature(node)) {
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 (ts25.isTypeAliasDeclaration(node)) {
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 ts26 from "typescript";
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 } = ts26.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
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 } = ts26.getLineAndCharacterOfPosition(sourceFile, offset);
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
- ts27.forEachChild(node, visit2);
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
- ts27.forEachChild(sourceFile, visit2);
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 (!ts27.canHaveModifiers(node)) return false;
1634
- const mods = ts27.getModifiers(node);
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 === ts27.SyntaxKind.PrivateKeyword || m.kind === ts27.SyntaxKind.ProtectedKeyword
1677
+ (m) => m.kind === ts29.SyntaxKind.PrivateKeyword || m.kind === ts29.SyntaxKind.ProtectedKeyword
1638
1678
  );
1639
1679
  }
1640
1680
  function isExported(node) {
1641
- if (!ts27.canHaveModifiers(node)) return false;
1642
- const mods = ts27.getModifiers(node);
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 === ts27.SyntaxKind.ExportKeyword);
1684
+ return mods.some((m) => m.kind === ts29.SyntaxKind.ExportKeyword);
1645
1685
  }
1646
1686
  function collectTypes(node, file, sourceFile, registry) {
1647
- if (ts27.isTypeAliasDeclaration(node)) {
1648
- const line = ts27.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
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 (ts27.isInterfaceDeclaration(node)) {
1652
- const line = ts27.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
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 (ts27.isStringLiteral(node)) return true;
1658
- if (ts27.isNumericLiteral(node)) return true;
1659
- if (ts27.isNoSubstitutionTemplateLiteral(node)) return true;
1660
- if (ts27.isPrefixUnaryExpression(node)) return isConstantValue(node.operand);
1661
- if (ts27.isBinaryExpression(node)) return isConstantValue(node.left) && isConstantValue(node.right);
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 (!ts27.isVariableStatement(node)) return;
1666
- if (!(node.declarationList.flags & ts27.NodeFlags.Const)) return;
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 || !ts27.isIdentifier(decl.name)) continue;
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 = ts27.getLineAndCharacterOfPosition(sourceFile, decl.getStart(sourceFile)).line + 1;
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 = ts27.getLineAndCharacterOfPosition(sourceFile, lineNode.getStart(sourceFile)).line + 1;
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 (ts27.isFunctionDeclaration(node) && node.name && node.body) {
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 (ts27.isVariableStatement(node)) {
1747
+ if (ts29.isVariableStatement(node)) {
1708
1748
  const exported = isExported(node);
1709
1749
  for (const decl of node.declarationList.declarations) {
1710
- if (decl.initializer && ts27.isArrowFunction(decl.initializer) && ts27.isIdentifier(decl.name)) {
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 && ts27.isFunctionExpression(decl.initializer) && ts27.isIdentifier(decl.name)) {
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 (ts27.isPropertyAssignment(node) && (ts27.isIdentifier(node.name) || ts27.isStringLiteral(node.name))) {
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 (ts27.isArrowFunction(init)) {
1773
+ if (ts29.isArrowFunction(init)) {
1734
1774
  registry.add(buildFunctionEntry(init.body, init.parameters, sourceFile, file, node, propName, { node: init }));
1735
1775
  }
1736
- if (ts27.isFunctionExpression(init) && init.body) {
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 (ts27.isArrowFunction(node) || ts27.isFunctionExpression(node)) {
1780
+ if (ts29.isArrowFunction(node) || ts29.isFunctionExpression(node)) {
1741
1781
  const parent = node.parent;
1742
- if (ts27.isVariableDeclaration(parent) && ts27.isIdentifier(parent.name)) {
1743
- } else if (ts27.isPropertyAssignment(parent)) {
1782
+ if (ts29.isVariableDeclaration(parent) && ts29.isIdentifier(parent.name)) {
1783
+ } else if (ts29.isPropertyAssignment(parent)) {
1744
1784
  } else {
1745
- const body = ts27.isArrowFunction(node) ? node.body : node.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 (ts27.isMethodDeclaration(node) && node.body && ts27.isIdentifier(node.name)) {
1795
+ if (ts29.isMethodDeclaration(node) && node.body && ts29.isIdentifier(node.name)) {
1756
1796
  const parent = node.parent;
1757
- if (ts27.isClassDeclaration(parent)) {
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 === ts27.SyntaxKind.ImplementsKeyword
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 = ts27.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
1786
- if (ts27.isCallExpression(parent)) {
1825
+ const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
1826
+ if (ts29.isCallExpression(parent)) {
1787
1827
  const grandparent = parent.parent;
1788
- if (ts27.isPropertyAssignment(grandparent) && ts27.isIdentifier(grandparent.name)) {
1828
+ if (ts29.isPropertyAssignment(grandparent) && ts29.isIdentifier(grandparent.name)) {
1789
1829
  return grandparent.name.text;
1790
1830
  }
1791
1831
  let calleeName = null;
1792
- if (ts27.isIdentifier(parent.expression)) {
1832
+ if (ts29.isIdentifier(parent.expression)) {
1793
1833
  calleeName = parent.expression.text;
1794
- } else if (ts27.isPropertyAccessExpression(parent.expression)) {
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 (ts27.isImportDeclaration(node) && ts27.isStringLiteral(node.moduleSpecifier)) {
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 && ts27.isNamedImports(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 (ts27.isExportDeclaration(node) && node.moduleSpecifier && ts27.isStringLiteral(node.moduleSpecifier)) {
1868
+ if (ts29.isExportDeclaration(node) && node.moduleSpecifier && ts29.isStringLiteral(node.moduleSpecifier)) {
1829
1869
  const moduleSource = node.moduleSpecifier.text;
1830
- if (node.exportClause && ts27.isNamedExports(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 (!ts27.isBlock(node)) return;
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 = ts27.getLineAndCharacterOfPosition(sourceFile, firstStmt.getStart(sourceFile)).line + 1;
1861
- const endLine = ts27.getLineAndCharacterOfPosition(sourceFile, lastStmt.getEnd()).line + 1;
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 (!ts27.isTypeLiteralNode(node)) return;
1907
+ if (!ts29.isTypeLiteralNode(node)) return;
1868
1908
  const parent = node.parent;
1869
- if (!parent || !ts27.isParameter(parent)) return;
1909
+ if (!parent || !ts29.isParameter(parent)) return;
1870
1910
  if (parent.type !== node) return;
1871
- const line = ts27.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
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 (!ts27.isCallExpression(node)) return;
1915
+ if (!ts29.isCallExpression(node)) return;
1876
1916
  let calleeName = null;
1877
- if (ts27.isIdentifier(node.expression)) {
1917
+ if (ts29.isIdentifier(node.expression)) {
1878
1918
  calleeName = node.expression.text;
1879
- } else if (ts27.isPropertyAccessExpression(node.expression)) {
1919
+ } else if (ts29.isPropertyAccessExpression(node.expression)) {
1880
1920
  calleeName = node.expression.name.text;
1881
1921
  }
1882
1922
  if (calleeName) {
1883
- const line = ts27.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
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 & ts27.SymbolFlags.Alias) {
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 = ts27.getLeadingCommentRanges(source, node.getFullStart());
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 === ts27.SyntaxKind.SingleLineCommentTrivia;
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 = ts27.getTrailingCommentRanges(source, node.getEnd());
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 === ts27.SyntaxKind.SingleLineCommentTrivia;
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
- ts27.forEachChild(node, visit);
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 ts28 from "typescript";
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 = ts28.findConfigFile(dirname2(files[0]), ts28.sys.fileExists, "tsconfig.json");
1987
+ configPath = ts30.findConfigFile(dirname2(files[0]), ts30.sys.fileExists, "tsconfig.json");
1948
1988
  }
1949
1989
  if (configPath) {
1950
- const configFile = ts28.readConfigFile(configPath, ts28.sys.readFile);
1951
- const parsed = ts28.parseJsonConfigFileContent(configFile.config, ts28.sys, dirname2(configPath));
1952
- return ts28.createProgram({
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 ts28.createProgram({
1997
+ return ts30.createProgram({
1958
1998
  rootNames: files,
1959
1999
  options: {
1960
- target: ts28.ScriptTarget.ESNext,
1961
- module: ts28.ModuleKind.ESNext,
1962
- moduleResolution: ts28.ModuleResolutionKind.Bundler,
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 { index, diagnostics } = collectProject(program, tsRules);
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-5GVEUYZF.js.map
2242
+ //# sourceMappingURL=chunk-NNUATKJZ.js.map