unguard 0.10.4 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -314,9 +314,17 @@ function isTupleSlotDefinitelyPresent(type, index, checker) {
314
314
  return type.types.every((member) => isTupleSlotDefinitelyPresent(member, index, checker));
315
315
  }
316
316
  const apparent = checker.getApparentType(type);
317
- if (!checker.isTupleType(apparent)) return false;
317
+ if (!isTupleTypeReference(apparent, checker)) return false;
318
318
  return index < apparent.target.minLength;
319
319
  }
320
+ function isTupleTypeReference(type, checker) {
321
+ if (!checker.isTupleType(type)) return false;
322
+ if (!("target" in type)) return false;
323
+ const target = type.target;
324
+ if (typeof target !== "object" || target === null) return false;
325
+ if (!("minLength" in target)) return false;
326
+ return typeof target.minLength === "number";
327
+ }
320
328
 
321
329
  // src/rules/ts/no-optional-call.ts
322
330
  import * as ts7 from "typescript";
@@ -535,43 +543,61 @@ var duplicateInlineTypeInParams = {
535
543
  }
536
544
  };
537
545
 
538
- // src/rules/ts/no-type-assertion.ts
546
+ // src/rules/ts/no-inline-type-assertion.ts
539
547
  import * as ts14 from "typescript";
548
+ var noInlineTypeAssertion = {
549
+ kind: "ts",
550
+ id: "no-inline-type-assertion",
551
+ severity: "error",
552
+ message: "Inline object type assertions (`x as { ... }`) hide missing named types; extract a named type or fix the upstream type",
553
+ visit(node, ctx) {
554
+ if (ts14.isAsExpression(node) && ts14.isTypeLiteralNode(node.type)) {
555
+ ctx.report(node);
556
+ return;
557
+ }
558
+ if (ts14.isTypeAssertionExpression(node) && ts14.isTypeLiteralNode(node.type)) {
559
+ ctx.report(node);
560
+ }
561
+ }
562
+ };
563
+
564
+ // src/rules/ts/no-type-assertion.ts
565
+ import * as ts15 from "typescript";
540
566
  var noTypeAssertion = {
541
567
  kind: "ts",
542
568
  id: "no-type-assertion",
543
569
  severity: "error",
544
570
  message: "Double type assertion (`as unknown as T`) circumvents the type system; fix the upstream type or use a type guard",
545
571
  visit(node, ctx) {
546
- if (!ts14.isAsExpression(node)) return;
547
- if (!ts14.isAsExpression(node.expression)) return;
548
- if (node.expression.type.kind !== ts14.SyntaxKind.UnknownKeyword) return;
572
+ if (!ts15.isAsExpression(node)) return;
573
+ if (!ts15.isAsExpression(node.expression)) return;
574
+ if (node.expression.type.kind !== ts15.SyntaxKind.UnknownKeyword) return;
549
575
  ctx.report(node);
550
576
  }
551
577
  };
552
578
 
553
579
  // src/rules/ts/no-redundant-existence-guard.ts
554
- import * as ts15 from "typescript";
580
+ import * as ts16 from "typescript";
555
581
  var noRedundantExistenceGuard = {
556
582
  kind: "ts",
557
583
  id: "no-redundant-existence-guard",
558
584
  severity: "warning",
559
585
  message: "Redundant existence guard (obj && obj.prop) on a non-nullable type; remove the guard or fix the type upstream",
560
586
  visit(node, ctx) {
561
- if (!ts15.isBinaryExpression(node)) return;
562
- if (node.operatorToken.kind !== ts15.SyntaxKind.AmpersandAmpersandToken) return;
587
+ if (!ts16.isBinaryExpression(node)) return;
588
+ if (node.operatorToken.kind !== ts16.SyntaxKind.AmpersandAmpersandToken) return;
563
589
  const left = node.left;
564
590
  const right = node.right;
565
- if (ts15.isIdentifier(left) && accessesIdentifier(right, left.text)) {
591
+ if (ts16.isIdentifier(left) && accessesIdentifier(right, left.text)) {
566
592
  if (ctx.isNullable(left)) return;
567
593
  ctx.report(node);
568
594
  return;
569
595
  }
570
- if (ts15.isBinaryExpression(left) && isNullCheck(left)) {
596
+ if (ts16.isBinaryExpression(left) && isNullCheck(left)) {
571
597
  const checked = getNullCheckedIdentifier(left);
572
598
  if (checked && accessesIdentifier(right, checked)) {
573
- const identNode = ts15.isIdentifier(left.left) ? left.left : left.right;
574
- if (ts15.isIdentifier(identNode) && identNode.text === checked && !ctx.isNullable(identNode)) {
599
+ const identNode = ts16.isIdentifier(left.left) ? left.left : left.right;
600
+ if (ts16.isIdentifier(identNode) && identNode.text === checked && !ctx.isNullable(identNode)) {
575
601
  ctx.report(node);
576
602
  }
577
603
  }
@@ -580,27 +606,27 @@ var noRedundantExistenceGuard = {
580
606
  };
581
607
  function accessesIdentifier(expr, name) {
582
608
  const root = getExpressionRoot(expr);
583
- return ts15.isIdentifier(root) && root.text === name;
609
+ return ts16.isIdentifier(root) && root.text === name;
584
610
  }
585
611
  function getExpressionRoot(node) {
586
- if (ts15.isPropertyAccessExpression(node)) return getExpressionRoot(node.expression);
587
- if (ts15.isElementAccessExpression(node)) return getExpressionRoot(node.expression);
588
- if (ts15.isCallExpression(node)) return getExpressionRoot(node.expression);
612
+ if (ts16.isPropertyAccessExpression(node)) return getExpressionRoot(node.expression);
613
+ if (ts16.isElementAccessExpression(node)) return getExpressionRoot(node.expression);
614
+ if (ts16.isCallExpression(node)) return getExpressionRoot(node.expression);
589
615
  return node;
590
616
  }
591
617
  function isNullCheck(expr) {
592
618
  const op = expr.operatorToken.kind;
593
- if (op !== ts15.SyntaxKind.ExclamationEqualsToken && op !== ts15.SyntaxKind.ExclamationEqualsEqualsToken) return false;
619
+ if (op !== ts16.SyntaxKind.ExclamationEqualsToken && op !== ts16.SyntaxKind.ExclamationEqualsEqualsToken) return false;
594
620
  return isNullishLiteral(expr.right) || isNullishLiteral(expr.left);
595
621
  }
596
622
  function getNullCheckedIdentifier(expr) {
597
- if (ts15.isIdentifier(expr.left) && isNullishLiteral(expr.right)) return expr.left.text;
598
- if (ts15.isIdentifier(expr.right) && isNullishLiteral(expr.left)) return expr.right.text;
623
+ if (ts16.isIdentifier(expr.left) && isNullishLiteral(expr.right)) return expr.left.text;
624
+ if (ts16.isIdentifier(expr.right) && isNullishLiteral(expr.left)) return expr.right.text;
599
625
  return null;
600
626
  }
601
627
 
602
628
  // src/rules/ts/prefer-default-param-value.ts
603
- import * as ts16 from "typescript";
629
+ import * as ts17 from "typescript";
604
630
  var preferDefaultParamValue = {
605
631
  kind: "ts",
606
632
  id: "prefer-default-param-value",
@@ -611,21 +637,21 @@ var preferDefaultParamValue = {
611
637
  if (result === null) return;
612
638
  const { statements: stmts, fn } = result;
613
639
  const firstStmt = stmts[0];
614
- if (firstStmt === void 0 || !ts16.isExpressionStatement(firstStmt)) return;
640
+ if (firstStmt === void 0 || !ts17.isExpressionStatement(firstStmt)) return;
615
641
  const expr = firstStmt.expression;
616
- if (!ts16.isBinaryExpression(expr) || expr.operatorToken.kind !== ts16.SyntaxKind.EqualsToken) return;
642
+ if (!ts17.isBinaryExpression(expr) || expr.operatorToken.kind !== ts17.SyntaxKind.EqualsToken) return;
617
643
  const right = expr.right;
618
- if (!ts16.isBinaryExpression(right) || right.operatorToken.kind !== ts16.SyntaxKind.QuestionQuestionToken) return;
619
- if (!ts16.isIdentifier(expr.left) || !ts16.isIdentifier(right.left)) return;
644
+ if (!ts17.isBinaryExpression(right) || right.operatorToken.kind !== ts17.SyntaxKind.QuestionQuestionToken) return;
645
+ if (!ts17.isIdentifier(expr.left) || !ts17.isIdentifier(right.left)) return;
620
646
  if (expr.left.text !== right.left.text) return;
621
647
  const paramName = expr.left.text;
622
- const isParam = fn.parameters.some((p) => ts16.isIdentifier(p.name) && p.name.text === paramName);
648
+ const isParam = fn.parameters.some((p) => ts17.isIdentifier(p.name) && p.name.text === paramName);
623
649
  if (isParam) ctx.report(firstStmt);
624
650
  }
625
651
  };
626
652
 
627
653
  // src/rules/ts/prefer-required-param-with-guard.ts
628
- import * as ts17 from "typescript";
654
+ import * as ts18 from "typescript";
629
655
  var preferRequiredParamWithGuard = {
630
656
  kind: "ts",
631
657
  id: "prefer-required-param-with-guard",
@@ -636,33 +662,33 @@ var preferRequiredParamWithGuard = {
636
662
  if (result === null) return;
637
663
  const { statements: stmts, fn } = result;
638
664
  const firstStmt = stmts[0];
639
- if (firstStmt === void 0 || !ts17.isIfStatement(firstStmt)) return;
665
+ if (firstStmt === void 0 || !ts18.isIfStatement(firstStmt)) return;
640
666
  const test = firstStmt.expression;
641
667
  let guardedName = null;
642
- if (ts17.isPrefixUnaryExpression(test) && test.operator === ts17.SyntaxKind.ExclamationToken) {
643
- if (ts17.isIdentifier(test.operand)) guardedName = test.operand.text;
668
+ if (ts18.isPrefixUnaryExpression(test) && test.operator === ts18.SyntaxKind.ExclamationToken) {
669
+ if (ts18.isIdentifier(test.operand)) guardedName = test.operand.text;
644
670
  }
645
- if (ts17.isBinaryExpression(test)) {
671
+ if (ts18.isBinaryExpression(test)) {
646
672
  const op = test.operatorToken.kind;
647
- if (op === ts17.SyntaxKind.EqualsEqualsEqualsToken || op === ts17.SyntaxKind.EqualsEqualsToken) {
648
- if (ts17.isIdentifier(test.left) && ts17.isIdentifier(test.right) && test.right.text === "undefined") {
673
+ if (op === ts18.SyntaxKind.EqualsEqualsEqualsToken || op === ts18.SyntaxKind.EqualsEqualsToken) {
674
+ if (ts18.isIdentifier(test.left) && ts18.isIdentifier(test.right) && test.right.text === "undefined") {
649
675
  guardedName = test.left.text;
650
676
  }
651
677
  }
652
678
  }
653
679
  if (!guardedName) return;
654
680
  const consequent = firstStmt.thenStatement;
655
- const isGuard = ts17.isReturnStatement(consequent) || ts17.isThrowStatement(consequent) || ts17.isBlock(consequent) && consequent.statements.length === 1 && consequent.statements[0] !== void 0 && (ts17.isReturnStatement(consequent.statements[0]) || ts17.isThrowStatement(consequent.statements[0]));
681
+ const isGuard = ts18.isReturnStatement(consequent) || ts18.isThrowStatement(consequent) || ts18.isBlock(consequent) && consequent.statements.length === 1 && consequent.statements[0] !== void 0 && (ts18.isReturnStatement(consequent.statements[0]) || ts18.isThrowStatement(consequent.statements[0]));
656
682
  if (!isGuard) return;
657
683
  const isOptional = fn.parameters.some(
658
- (p) => ts17.isIdentifier(p.name) && p.name.text === guardedName && p.questionToken !== void 0
684
+ (p) => ts18.isIdentifier(p.name) && p.name.text === guardedName && p.questionToken !== void 0
659
685
  );
660
686
  if (isOptional) ctx.report(firstStmt);
661
687
  }
662
688
  };
663
689
 
664
690
  // src/rules/cross-file/duplicate-type-declaration.ts
665
- import * as ts18 from "typescript";
691
+ import * as ts19 from "typescript";
666
692
  var duplicateTypeDeclaration = {
667
693
  id: "duplicate-type-declaration",
668
694
  severity: "warning",
@@ -686,13 +712,13 @@ var duplicateTypeDeclaration = {
686
712
  }
687
713
  };
688
714
  function isTrivialObjectShape(node) {
689
- if (ts18.isTypeLiteralNode(node)) return node.members.length <= 1;
690
- if (ts18.isInterfaceDeclaration(node)) return node.members.length <= 1;
715
+ if (ts19.isTypeLiteralNode(node)) return node.members.length <= 1;
716
+ if (ts19.isInterfaceDeclaration(node)) return node.members.length <= 1;
691
717
  return false;
692
718
  }
693
719
 
694
720
  // src/rules/cross-file/duplicate-function-declaration.ts
695
- import * as ts19 from "typescript";
721
+ import * as ts20 from "typescript";
696
722
  var duplicateFunctionDeclaration = {
697
723
  id: "duplicate-function-declaration",
698
724
  severity: "warning",
@@ -717,13 +743,13 @@ var duplicateFunctionDeclaration = {
717
743
  }
718
744
  };
719
745
  function getBodyBlock(node) {
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;
746
+ if (ts20.isFunctionDeclaration(node) || ts20.isFunctionExpression(node)) return node.body;
747
+ if (ts20.isArrowFunction(node)) return ts20.isBlock(node.body) ? node.body : void 0;
748
+ if (ts20.isMethodDeclaration(node)) return node.body;
723
749
  return void 0;
724
750
  }
725
751
  function isSingleStatement(node) {
726
- if (ts19.isArrowFunction(node) && !ts19.isBlock(node.body)) return true;
752
+ if (ts20.isArrowFunction(node) && !ts20.isBlock(node.body)) return true;
727
753
  const body = getBodyBlock(node);
728
754
  return body !== void 0 && body.statements.length <= 1;
729
755
  }
@@ -731,8 +757,8 @@ function isSetter(node) {
731
757
  const body = getBodyBlock(node);
732
758
  if (!body || body.statements.length !== 1) return false;
733
759
  const stmt = body.statements[0];
734
- if (stmt === void 0 || !ts19.isExpressionStatement(stmt)) return false;
735
- return ts19.isBinaryExpression(stmt.expression) && stmt.expression.operatorToken.kind === ts19.SyntaxKind.EqualsToken;
760
+ if (stmt === void 0 || !ts20.isExpressionStatement(stmt)) return false;
761
+ return ts20.isBinaryExpression(stmt.expression) && stmt.expression.operatorToken.kind === ts20.SyntaxKind.EqualsToken;
736
762
  }
737
763
 
738
764
  // src/rules/cross-file/optional-arg-always-used.ts
@@ -767,14 +793,14 @@ var optionalArgAlwaysUsed = {
767
793
  };
768
794
 
769
795
  // src/rules/ts/no-catch-return.ts
770
- import * as ts20 from "typescript";
796
+ import * as ts21 from "typescript";
771
797
  var noCatchReturn = {
772
798
  kind: "ts",
773
799
  id: "no-catch-return",
774
800
  severity: "warning",
775
801
  message: "Catch block silently returns a fallback value with no logging; rethrow, log the error, or let it propagate",
776
802
  visit(node, ctx) {
777
- if (!ts20.isCatchClause(node)) return;
803
+ if (!ts21.isCatchClause(node)) return;
778
804
  const block = node.block;
779
805
  if (hasReturn(block) && !hasThrow(block) && !hasLogging(block)) {
780
806
  ctx.report(node);
@@ -784,57 +810,57 @@ var noCatchReturn = {
784
810
  function walkBlock(block, predicate) {
785
811
  function visit(node) {
786
812
  if (predicate(node)) return true;
787
- if (ts20.isFunctionDeclaration(node) || ts20.isFunctionExpression(node) || ts20.isArrowFunction(node)) return false;
788
- return ts20.forEachChild(node, visit) ?? false;
813
+ if (ts21.isFunctionDeclaration(node) || ts21.isFunctionExpression(node) || ts21.isArrowFunction(node)) return false;
814
+ return ts21.forEachChild(node, visit) ?? false;
789
815
  }
790
- return ts20.forEachChild(block, visit) ?? false;
816
+ return ts21.forEachChild(block, visit) ?? false;
791
817
  }
792
818
  function hasReturn(block) {
793
- return walkBlock(block, (n) => ts20.isReturnStatement(n));
819
+ return walkBlock(block, (n) => ts21.isReturnStatement(n));
794
820
  }
795
821
  function hasThrow(block) {
796
- return walkBlock(block, (n) => ts20.isThrowStatement(n));
822
+ return walkBlock(block, (n) => ts21.isThrowStatement(n));
797
823
  }
798
824
  var LOG_OBJECTS = /* @__PURE__ */ new Set(["console", "logger", "log"]);
799
825
  function hasLogging(block) {
800
826
  return walkBlock(block, (n) => {
801
- if (!ts20.isCallExpression(n)) return false;
827
+ if (!ts21.isCallExpression(n)) return false;
802
828
  const callee = n.expression;
803
- if (!ts20.isPropertyAccessExpression(callee)) return false;
804
- if (!ts20.isIdentifier(callee.expression)) return false;
829
+ if (!ts21.isPropertyAccessExpression(callee)) return false;
830
+ if (!ts21.isIdentifier(callee.expression)) return false;
805
831
  return LOG_OBJECTS.has(callee.expression.text);
806
832
  });
807
833
  }
808
834
 
809
835
  // src/rules/ts/no-error-rewrap.ts
810
- import * as ts21 from "typescript";
836
+ import * as ts22 from "typescript";
811
837
  var noErrorRewrap = {
812
838
  kind: "ts",
813
839
  id: "no-error-rewrap",
814
840
  severity: "error",
815
841
  message: "Re-wrapped error loses the original stack trace and type; use { cause: originalError } to preserve the error chain",
816
842
  visit(node, ctx) {
817
- if (!ts21.isCatchClause(node)) return;
843
+ if (!ts22.isCatchClause(node)) return;
818
844
  if (!node.variableDeclaration) return;
819
845
  const param = node.variableDeclaration.name;
820
- if (!ts21.isIdentifier(param)) return;
846
+ if (!ts22.isIdentifier(param)) return;
821
847
  const catchName = param.text;
822
848
  findRewraps(node.block, catchName, ctx);
823
849
  }
824
850
  };
825
851
  function findRewraps(block, catchName, ctx) {
826
852
  function visit(node) {
827
- if (ts21.isFunctionDeclaration(node) || ts21.isFunctionExpression(node) || ts21.isArrowFunction(node)) return;
828
- if (ts21.isThrowStatement(node) && node.expression && ts21.isNewExpression(node.expression)) {
853
+ if (ts22.isFunctionDeclaration(node) || ts22.isFunctionExpression(node) || ts22.isArrowFunction(node)) return;
854
+ if (ts22.isThrowStatement(node) && node.expression && ts22.isNewExpression(node.expression)) {
829
855
  const args = node.expression.arguments;
830
856
  if (args && args.length > 0 && referencesName(args, catchName) && !hasCauseArg(args)) {
831
857
  ctx.report(node);
832
858
  }
833
859
  return;
834
860
  }
835
- ts21.forEachChild(node, visit);
861
+ ts22.forEachChild(node, visit);
836
862
  }
837
- ts21.forEachChild(block, visit);
863
+ ts22.forEachChild(block, visit);
838
864
  }
839
865
  function referencesName(args, name) {
840
866
  for (const arg of args) {
@@ -843,15 +869,15 @@ function referencesName(args, name) {
843
869
  return false;
844
870
  }
845
871
  function containsIdentifier(node, name) {
846
- if (ts21.isIdentifier(node) && node.text === name) return true;
847
- return ts21.forEachChild(node, (child) => containsIdentifier(child, name) || void 0) ?? false;
872
+ if (ts22.isIdentifier(node) && node.text === name) return true;
873
+ return ts22.forEachChild(node, (child) => containsIdentifier(child, name) || void 0) ?? false;
848
874
  }
849
875
  function hasCauseArg(args) {
850
876
  for (const arg of args) {
851
- if (ts21.isObjectLiteralExpression(arg)) {
877
+ if (ts22.isObjectLiteralExpression(arg)) {
852
878
  for (const prop of arg.properties) {
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;
879
+ if (ts22.isPropertyAssignment(prop) && ts22.isIdentifier(prop.name) && prop.name.text === "cause") return true;
880
+ if (ts22.isShorthandPropertyAssignment(prop) && prop.name.text === "cause") return true;
855
881
  }
856
882
  }
857
883
  }
@@ -859,7 +885,7 @@ function hasCauseArg(args) {
859
885
  }
860
886
 
861
887
  // src/rules/cross-file/explicit-null-arg.ts
862
- import * as ts22 from "typescript";
888
+ import * as ts23 from "typescript";
863
889
  var explicitNullArg = {
864
890
  id: "explicit-null-arg",
865
891
  severity: "warning",
@@ -879,7 +905,7 @@ var explicitNullArg = {
879
905
  const arg = site.node.arguments[i];
880
906
  if (arg === void 0) continue;
881
907
  if (isNullishLiteral(arg)) {
882
- const val = arg.kind === ts22.SyntaxKind.NullKeyword ? "null" : "undefined";
908
+ const val = arg.kind === ts23.SyntaxKind.NullKeyword ? "null" : "undefined";
883
909
  diagnostics.push({
884
910
  ruleId: this.id,
885
911
  severity: this.severity,
@@ -952,7 +978,7 @@ function resolveCandidates(fromFile, specifier) {
952
978
  }
953
979
 
954
980
  // src/rules/cross-file/duplicate-type-name.ts
955
- import * as ts23 from "typescript";
981
+ import * as ts24 from "typescript";
956
982
  var duplicateTypeName = {
957
983
  id: "duplicate-type-name",
958
984
  severity: "warning",
@@ -963,7 +989,7 @@ var duplicateTypeName = {
963
989
  const hashes = new Set(group.map((e) => e.hash));
964
990
  if (hashes.size === 1) continue;
965
991
  const hasInferredType = group.some(
966
- (e) => !ts23.isTypeLiteralNode(e.node) && !ts23.isInterfaceDeclaration(e.node)
992
+ (e) => !ts24.isTypeLiteralNode(e.node) && !ts24.isInterfaceDeclaration(e.node)
967
993
  );
968
994
  if (hasInferredType) continue;
969
995
  reportDuplicateGroup(
@@ -1003,21 +1029,21 @@ var duplicateConstantDeclaration = {
1003
1029
  };
1004
1030
 
1005
1031
  // src/rules/ts/no-dynamic-import.ts
1006
- import * as ts24 from "typescript";
1032
+ import * as ts25 from "typescript";
1007
1033
  var noDynamicImport = {
1008
1034
  kind: "ts",
1009
1035
  id: "no-dynamic-import",
1010
1036
  severity: "error",
1011
1037
  message: "Dynamic import() breaks static analysis and hides dependencies; use a static import instead",
1012
1038
  visit(node, ctx) {
1013
- if (!ts24.isCallExpression(node)) return;
1014
- if (node.expression.kind !== ts24.SyntaxKind.ImportKeyword) return;
1039
+ if (!ts25.isCallExpression(node)) return;
1040
+ if (node.expression.kind !== ts25.SyntaxKind.ImportKeyword) return;
1015
1041
  ctx.report(node);
1016
1042
  }
1017
1043
  };
1018
1044
 
1019
1045
  // src/rules/cross-file/near-duplicate-function.ts
1020
- import * as ts25 from "typescript";
1046
+ import * as ts26 from "typescript";
1021
1047
  var nearDuplicateFunction = {
1022
1048
  id: "near-duplicate-function",
1023
1049
  severity: "warning",
@@ -1041,24 +1067,24 @@ var nearDuplicateFunction = {
1041
1067
  }
1042
1068
  };
1043
1069
  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;
1070
+ if (ts26.isFunctionDeclaration(node) || ts26.isFunctionExpression(node)) return node.body;
1071
+ if (ts26.isArrowFunction(node)) return node.body;
1072
+ if (ts26.isMethodDeclaration(node)) return node.body;
1047
1073
  return void 0;
1048
1074
  }
1049
1075
  function getTopLevelStatementCount(body) {
1050
- if (ts25.isBlock(body)) return body.statements.length;
1076
+ if (ts26.isBlock(body)) return body.statements.length;
1051
1077
  return 1;
1052
1078
  }
1053
1079
  function hasControlFlow(node) {
1054
1080
  let found = false;
1055
1081
  function visit(current) {
1056
1082
  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)) {
1083
+ if (ts26.isIfStatement(current) || ts26.isSwitchStatement(current) || ts26.isTryStatement(current) || ts26.isForStatement(current) || ts26.isForInStatement(current) || ts26.isForOfStatement(current) || ts26.isWhileStatement(current) || ts26.isDoStatement(current)) {
1058
1084
  found = true;
1059
1085
  return;
1060
1086
  }
1061
- ts25.forEachChild(current, visit);
1087
+ ts26.forEachChild(current, visit);
1062
1088
  }
1063
1089
  visit(node);
1064
1090
  return found;
@@ -1071,36 +1097,36 @@ function isSimpleStructure(entry) {
1071
1097
  }
1072
1098
 
1073
1099
  // src/rules/cross-file/trivial-wrapper.ts
1074
- import * as ts26 from "typescript";
1100
+ import * as ts27 from "typescript";
1075
1101
  function getFunctionBody2(node) {
1076
- if (ts26.isFunctionDeclaration(node) || ts26.isFunctionExpression(node)) {
1102
+ if (ts27.isFunctionDeclaration(node) || ts27.isFunctionExpression(node)) {
1077
1103
  return node.body;
1078
1104
  }
1079
- if (ts26.isArrowFunction(node)) {
1105
+ if (ts27.isArrowFunction(node)) {
1080
1106
  return node.body;
1081
1107
  }
1082
- if (ts26.isMethodDeclaration(node)) {
1108
+ if (ts27.isMethodDeclaration(node)) {
1083
1109
  return node.body;
1084
1110
  }
1085
1111
  return void 0;
1086
1112
  }
1087
1113
  function getCalleeName(expr) {
1088
- if (ts26.isIdentifier(expr)) return expr.text;
1089
- if (ts26.isPropertyAccessExpression(expr)) return expr.name.text;
1114
+ if (ts27.isIdentifier(expr)) return expr.text;
1115
+ if (ts27.isPropertyAccessExpression(expr)) return expr.name.text;
1090
1116
  return void 0;
1091
1117
  }
1092
1118
  function getTrivialCallTarget(fn) {
1093
1119
  const body = getFunctionBody2(fn.node);
1094
1120
  if (!body) return null;
1095
1121
  let callExpr;
1096
- if (ts26.isBlock(body)) {
1122
+ if (ts27.isBlock(body)) {
1097
1123
  if (body.statements.length !== 1) return null;
1098
1124
  const stmt = body.statements[0];
1099
- if (!stmt || !ts26.isReturnStatement(stmt) || !stmt.expression) return null;
1100
- if (!ts26.isCallExpression(stmt.expression)) return null;
1125
+ if (!stmt || !ts27.isReturnStatement(stmt) || !stmt.expression) return null;
1126
+ if (!ts27.isCallExpression(stmt.expression)) return null;
1101
1127
  callExpr = stmt.expression;
1102
1128
  } else {
1103
- if (!ts26.isCallExpression(body)) return null;
1129
+ if (!ts27.isCallExpression(body)) return null;
1104
1130
  callExpr = body;
1105
1131
  }
1106
1132
  const calleeName = getCalleeName(callExpr.expression);
@@ -1108,7 +1134,7 @@ function getTrivialCallTarget(fn) {
1108
1134
  const paramNames = fn.params.map((p) => p.name);
1109
1135
  const args = callExpr.arguments;
1110
1136
  for (const arg of args) {
1111
- if (!ts26.isIdentifier(arg)) return null;
1137
+ if (!ts27.isIdentifier(arg)) return null;
1112
1138
  if (!paramNames.includes(arg.text)) return null;
1113
1139
  }
1114
1140
  return { calleeName };
@@ -1278,6 +1304,177 @@ var duplicateStatementSequence = {
1278
1304
  }
1279
1305
  };
1280
1306
 
1307
+ // src/rules/cross-file/dead-overload.ts
1308
+ import * as ts28 from "typescript";
1309
+ var deadOverload = {
1310
+ id: "dead-overload",
1311
+ severity: "warning",
1312
+ message: "Overload signature has no matching call sites in the project",
1313
+ analyze(project) {
1314
+ const diagnostics = [];
1315
+ for (const [file, { sourceFile }] of project.files) {
1316
+ for (const family of collectOverloadFamilies(sourceFile, file)) {
1317
+ const matchedOverloads = /* @__PURE__ */ new Set();
1318
+ for (const site of project.callSites) {
1319
+ const declaration = site.resolvedDeclaration;
1320
+ if (declaration === void 0) continue;
1321
+ if (family.overloads.includes(declaration)) {
1322
+ matchedOverloads.add(declaration);
1323
+ }
1324
+ }
1325
+ if (matchedOverloads.size === 0) continue;
1326
+ const deadOverloads = family.overloads.filter((overload) => !matchedOverloads.has(overload));
1327
+ const liveOverloads = family.overloads.filter((overload) => matchedOverloads.has(overload));
1328
+ for (const overload of deadOverloads) {
1329
+ diagnostics.push({
1330
+ ruleId: this.id,
1331
+ severity: this.severity,
1332
+ message: buildMessage(family, overload, deadOverloads, liveOverloads),
1333
+ file,
1334
+ line: lineOf(sourceFile, overload),
1335
+ column: 1
1336
+ });
1337
+ }
1338
+ }
1339
+ }
1340
+ return diagnostics;
1341
+ }
1342
+ };
1343
+ function buildMessage(family, overload, deadOverloads, liveOverloads) {
1344
+ const base = `Overload signature for "${family.name}" has no matching call sites in the project`;
1345
+ if (!shouldMentionCascade(family, overload, deadOverloads, liveOverloads)) {
1346
+ return base;
1347
+ }
1348
+ return `${base}; removing it may let you collapse to the remaining constrained signature and drop implementation casts`;
1349
+ }
1350
+ function shouldMentionCascade(family, overload, deadOverloads, liveOverloads) {
1351
+ if (deadOverloads.length !== 1 || liveOverloads.length !== 1) return false;
1352
+ if (deadOverloads[0] !== overload) return false;
1353
+ const liveOverload = liveOverloads[0];
1354
+ if (liveOverload === void 0) return false;
1355
+ if (family.implementation.typeParameters === void 0 || liveOverload.typeParameters === void 0) return false;
1356
+ const body = family.implementation.body;
1357
+ if (body === void 0) return false;
1358
+ const implementationTypeParams = family.implementation.typeParameters;
1359
+ const liveTypeParams = liveOverload.typeParameters;
1360
+ if (implementationTypeParams.length === 0 || implementationTypeParams.length !== liveTypeParams.length) return false;
1361
+ const constrainedParams = implementationTypeParams.flatMap((typeParam, index) => {
1362
+ const liveTypeParam = liveTypeParams[index];
1363
+ if (liveTypeParam === void 0) return [];
1364
+ if (typeParam.constraint !== void 0) return [];
1365
+ if (liveTypeParam.constraint === void 0) return [];
1366
+ return [{
1367
+ paramName: typeParam.name.text,
1368
+ constraintText: normalizeText(liveTypeParam.constraint.getText(family.sourceFile))
1369
+ }];
1370
+ });
1371
+ if (constrainedParams.length === 0) return false;
1372
+ return constrainedParams.some(
1373
+ ({ paramName, constraintText }) => hasIntersectionCast(body, family.sourceFile, paramName, constraintText)
1374
+ );
1375
+ }
1376
+ function hasIntersectionCast(body, sourceFile, paramName, constraintText) {
1377
+ let found = false;
1378
+ function visit(node) {
1379
+ if (found) return;
1380
+ if (ts28.isAsExpression(node) || ts28.isTypeAssertionExpression(node)) {
1381
+ if (isConstraintIntersection(node.type, sourceFile, paramName, constraintText)) {
1382
+ found = true;
1383
+ return;
1384
+ }
1385
+ }
1386
+ ts28.forEachChild(node, visit);
1387
+ }
1388
+ visit(body);
1389
+ return found;
1390
+ }
1391
+ function isConstraintIntersection(typeNode, sourceFile, paramName, constraintText) {
1392
+ const target = unwrapParenthesizedType(typeNode);
1393
+ if (!ts28.isIntersectionTypeNode(target)) return false;
1394
+ let hasParam = false;
1395
+ let hasConstraint = false;
1396
+ for (const part of target.types) {
1397
+ const text = normalizeText(unwrapParenthesizedType(part).getText(sourceFile));
1398
+ if (text === paramName) hasParam = true;
1399
+ if (text === constraintText) hasConstraint = true;
1400
+ }
1401
+ return hasParam && hasConstraint;
1402
+ }
1403
+ function unwrapParenthesizedType(typeNode) {
1404
+ let current = typeNode;
1405
+ while (ts28.isParenthesizedTypeNode(current)) {
1406
+ current = current.type;
1407
+ }
1408
+ return current;
1409
+ }
1410
+ function collectOverloadFamilies(sourceFile, file) {
1411
+ const families = [];
1412
+ collectFromList(sourceFile.statements, sourceFile, file, families);
1413
+ function visit(node) {
1414
+ if (ts28.isClassDeclaration(node) || ts28.isClassExpression(node)) {
1415
+ collectFromList(node.members, sourceFile, file, families);
1416
+ }
1417
+ ts28.forEachChild(node, visit);
1418
+ }
1419
+ ts28.forEachChild(sourceFile, visit);
1420
+ return families;
1421
+ }
1422
+ function collectFromList(nodes, sourceFile, file, families) {
1423
+ for (let index = 0; index < nodes.length; index++) {
1424
+ const current = asOverloadDeclaration(nodes[index]);
1425
+ const name = current ? getDeclarationName(current) : null;
1426
+ if (current === null || name === null) continue;
1427
+ const run = [current];
1428
+ let nextIndex = index + 1;
1429
+ while (nextIndex < nodes.length) {
1430
+ const next = asOverloadDeclaration(nodes[nextIndex]);
1431
+ if (next === null) break;
1432
+ if (getDeclarationName(next) !== name) break;
1433
+ run.push(next);
1434
+ nextIndex++;
1435
+ }
1436
+ const family = toOverloadFamily(run, name, file, sourceFile);
1437
+ if (family !== null) {
1438
+ families.push(family);
1439
+ }
1440
+ index = nextIndex - 1;
1441
+ }
1442
+ }
1443
+ function toOverloadFamily(run, name, file, sourceFile) {
1444
+ if (run.length < 2) return null;
1445
+ const implementation = run.at(-1);
1446
+ if (implementation === void 0 || implementation.body === void 0) return null;
1447
+ if (run.slice(0, -1).some((declaration) => declaration.body !== void 0)) return null;
1448
+ return {
1449
+ name,
1450
+ file,
1451
+ sourceFile,
1452
+ overloads: run.slice(0, -1),
1453
+ implementation
1454
+ };
1455
+ }
1456
+ function asOverloadDeclaration(node) {
1457
+ if (node === void 0) return null;
1458
+ if (ts28.isFunctionDeclaration(node)) return node;
1459
+ if (ts28.isMethodDeclaration(node)) return node;
1460
+ return null;
1461
+ }
1462
+ function getDeclarationName(node) {
1463
+ if (ts28.isFunctionDeclaration(node)) {
1464
+ return node.name?.text ?? null;
1465
+ }
1466
+ if (ts28.isIdentifier(node.name) || ts28.isStringLiteral(node.name) || ts28.isNumericLiteral(node.name)) {
1467
+ return node.name.text;
1468
+ }
1469
+ return null;
1470
+ }
1471
+ function lineOf(sourceFile, node) {
1472
+ return ts28.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
1473
+ }
1474
+ function normalizeText(text) {
1475
+ return text.replace(/\s+/g, "");
1476
+ }
1477
+
1281
1478
  // src/rules/index.ts
1282
1479
  var allRules = [
1283
1480
  noEmptyCatch,
@@ -1293,6 +1490,7 @@ var allRules = [
1293
1490
  noAnyCast,
1294
1491
  noExplicitAnyAnnotation,
1295
1492
  duplicateInlineTypeInParams,
1493
+ noInlineTypeAssertion,
1296
1494
  noTypeAssertion,
1297
1495
  noRedundantExistenceGuard,
1298
1496
  preferDefaultParamValue,
@@ -1311,11 +1509,13 @@ var allRules = [
1311
1509
  trivialWrapper,
1312
1510
  unusedExport,
1313
1511
  duplicateFile,
1314
- duplicateStatementSequence
1512
+ duplicateStatementSequence,
1513
+ deadOverload
1315
1514
  ];
1316
1515
  var ruleMetadata = {
1317
1516
  "no-any-cast": { category: "type-evasion", tags: ["safety"] },
1318
1517
  "no-explicit-any-annotation": { category: "type-evasion", tags: ["safety"] },
1518
+ "no-inline-type-assertion": { category: "type-evasion", tags: ["safety"] },
1319
1519
  "no-type-assertion": { category: "type-evasion", tags: ["safety"] },
1320
1520
  "no-ts-ignore": { category: "type-evasion", tags: ["safety"] },
1321
1521
  "no-optional-property-access": { category: "defensive-code", tags: ["type-aware"] },
@@ -1345,7 +1545,8 @@ var ruleMetadata = {
1345
1545
  "trivial-wrapper": { category: "cross-file", tags: ["duplicate"] },
1346
1546
  "unused-export": { category: "cross-file", tags: ["api"] },
1347
1547
  "duplicate-file": { category: "cross-file", tags: ["duplicate"] },
1348
- "duplicate-statement-sequence": { category: "cross-file", tags: ["duplicate"] }
1548
+ "duplicate-statement-sequence": { category: "cross-file", tags: ["duplicate"] },
1549
+ "dead-overload": { category: "cross-file", tags: ["api", "type-evasion"] }
1349
1550
  };
1350
1551
  function getRuleMetadata(ruleId) {
1351
1552
  const metadata = ruleMetadata[ruleId];
@@ -1405,32 +1606,32 @@ function isFailOn(value) {
1405
1606
  }
1406
1607
 
1407
1608
  // src/collect/index.ts
1408
- import * as ts29 from "typescript";
1609
+ import * as ts31 from "typescript";
1409
1610
  import { createHash as createHash2 } from "crypto";
1410
1611
 
1411
1612
  // src/utils/hash.ts
1412
1613
  import { createHash } from "crypto";
1413
- import * as ts27 from "typescript";
1614
+ import * as ts29 from "typescript";
1414
1615
  function hashTypeShape(node, sourceFile) {
1415
1616
  const normalized = normalizeTypeNode(node, sourceFile);
1416
1617
  return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
1417
1618
  }
1418
1619
  function normalizeTypeNode(node, sourceFile) {
1419
- if (ts27.isTypeLiteralNode(node)) {
1620
+ if (ts29.isTypeLiteralNode(node)) {
1420
1621
  const normalized = node.members.map((m) => normalizeTypeNode(m, sourceFile)).sort().join(";");
1421
1622
  return `{${normalized}}`;
1422
1623
  }
1423
- if (ts27.isInterfaceDeclaration(node)) {
1624
+ if (ts29.isInterfaceDeclaration(node)) {
1424
1625
  const normalized = node.members.map((m) => normalizeTypeNode(m, sourceFile)).sort().join(";");
1425
1626
  return `{${normalized}}`;
1426
1627
  }
1427
- if (ts27.isPropertySignature(node)) {
1628
+ if (ts29.isPropertySignature(node)) {
1428
1629
  const keyName = node.name.getText(sourceFile);
1429
1630
  const optional = node.questionToken ? "?" : "";
1430
1631
  const type = node.type ? normalizeTypeNode(node.type, sourceFile) : "any";
1431
1632
  return `${keyName}${optional}:${type}`;
1432
1633
  }
1433
- if (ts27.isTypeAliasDeclaration(node)) {
1634
+ if (ts29.isTypeAliasDeclaration(node)) {
1434
1635
  return normalizeTypeNode(node.type, sourceFile);
1435
1636
  }
1436
1637
  return node.getText(sourceFile).replace(/\s+/g, " ").trim();
@@ -1463,7 +1664,7 @@ function normalizeBody(node, sourceFile, paramNames) {
1463
1664
  text = text.replace(/\s+/g, " ").trim();
1464
1665
  return text;
1465
1666
  }
1466
- function normalizeText(text) {
1667
+ function normalizeText2(text) {
1467
1668
  let t = text.replace(/\/\/[^\n]*/g, "");
1468
1669
  t = t.replace(/\/\*[\s\S]*?\*\//g, "");
1469
1670
  t = t.replace(/"(?:[^"\\]|\\.)*"/g, '"__STR__"');
@@ -1596,7 +1797,7 @@ var InlineParamTypeRegistry = class extends BaseRegistry {
1596
1797
  };
1597
1798
 
1598
1799
  // src/typecheck/walk.ts
1599
- import * as ts28 from "typescript";
1800
+ import * as ts30 from "typescript";
1600
1801
  function buildContext(rule, sourceFile, checker, source, filename, diagnostics) {
1601
1802
  return {
1602
1803
  filename,
@@ -1604,7 +1805,7 @@ function buildContext(rule, sourceFile, checker, source, filename, diagnostics)
1604
1805
  sourceFile,
1605
1806
  checker,
1606
1807
  report(node, message) {
1607
- const { line, character } = ts28.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
1808
+ const { line, character } = ts30.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile));
1608
1809
  diagnostics.push({
1609
1810
  ruleId: rule.id,
1610
1811
  severity: rule.severity,
@@ -1615,7 +1816,7 @@ function buildContext(rule, sourceFile, checker, source, filename, diagnostics)
1615
1816
  });
1616
1817
  },
1617
1818
  reportAtOffset(offset, message) {
1618
- const { line, character } = ts28.getLineAndCharacterOfPosition(sourceFile, offset);
1819
+ const { line, character } = ts30.getLineAndCharacterOfPosition(sourceFile, offset);
1619
1820
  diagnostics.push({
1620
1821
  ruleId: rule.id,
1621
1822
  severity: rule.severity,
@@ -1666,7 +1867,7 @@ function collectProject(program, tsRules, allowedFiles) {
1666
1867
  rule.visit(node, ctx);
1667
1868
  }
1668
1869
  }
1669
- ts29.forEachChild(node, visit2);
1870
+ ts31.forEachChild(node, visit2);
1670
1871
  };
1671
1872
  var visit = visit2;
1672
1873
  const file = sourceFile.fileName;
@@ -1680,7 +1881,7 @@ function collectProject(program, tsRules, allowedFiles) {
1680
1881
  rule,
1681
1882
  ctx: buildContext(rule, sourceFile, checker, source, file, diagnostics)
1682
1883
  }));
1683
- ts29.forEachChild(sourceFile, visit2);
1884
+ ts31.forEachChild(sourceFile, visit2);
1684
1885
  }
1685
1886
  const fileHashes = /* @__PURE__ */ new Map();
1686
1887
  for (const [file, { source }] of fileMap) {
@@ -1696,52 +1897,52 @@ function collectProject(program, tsRules, allowedFiles) {
1696
1897
  return { index: { types, functions, constants, callSites, imports, files: fileMap, fileHashes, statementSequences, inlineParamTypes }, diagnostics };
1697
1898
  }
1698
1899
  function hasNonPublicModifier(node) {
1699
- if (!ts29.canHaveModifiers(node)) return false;
1700
- const mods = ts29.getModifiers(node);
1900
+ if (!ts31.canHaveModifiers(node)) return false;
1901
+ const mods = ts31.getModifiers(node);
1701
1902
  if (mods === void 0) return false;
1702
1903
  return mods.some(
1703
- (m) => m.kind === ts29.SyntaxKind.PrivateKeyword || m.kind === ts29.SyntaxKind.ProtectedKeyword
1904
+ (m) => m.kind === ts31.SyntaxKind.PrivateKeyword || m.kind === ts31.SyntaxKind.ProtectedKeyword
1704
1905
  );
1705
1906
  }
1706
1907
  function isExported(node) {
1707
- if (!ts29.canHaveModifiers(node)) return false;
1708
- const mods = ts29.getModifiers(node);
1908
+ if (!ts31.canHaveModifiers(node)) return false;
1909
+ const mods = ts31.getModifiers(node);
1709
1910
  if (mods === void 0) return false;
1710
- return mods.some((m) => m.kind === ts29.SyntaxKind.ExportKeyword);
1911
+ return mods.some((m) => m.kind === ts31.SyntaxKind.ExportKeyword);
1711
1912
  }
1712
1913
  function collectTypes(node, file, sourceFile, registry) {
1713
- if (ts29.isTypeAliasDeclaration(node)) {
1714
- const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
1914
+ if (ts31.isTypeAliasDeclaration(node)) {
1915
+ const line = ts31.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
1715
1916
  registry.add(node.name.text, file, line, node.type, sourceFile, isExported(node));
1716
1917
  }
1717
- if (ts29.isInterfaceDeclaration(node)) {
1718
- const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
1918
+ if (ts31.isInterfaceDeclaration(node)) {
1919
+ const line = ts31.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
1719
1920
  registry.add(node.name.text, file, line, node, sourceFile, isExported(node));
1720
1921
  }
1721
1922
  }
1722
1923
  function isConstantValue(node) {
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);
1924
+ if (ts31.isStringLiteral(node)) return true;
1925
+ if (ts31.isNumericLiteral(node)) return true;
1926
+ if (ts31.isNoSubstitutionTemplateLiteral(node)) return true;
1927
+ if (ts31.isPrefixUnaryExpression(node)) return isConstantValue(node.operand);
1928
+ if (ts31.isBinaryExpression(node)) return isConstantValue(node.left) && isConstantValue(node.right);
1728
1929
  return false;
1729
1930
  }
1730
1931
  function collectConstants(node, file, sourceFile, registry) {
1731
- if (!ts29.isVariableStatement(node)) return;
1732
- if (!(node.declarationList.flags & ts29.NodeFlags.Const)) return;
1932
+ if (!ts31.isVariableStatement(node)) return;
1933
+ if (!(node.declarationList.flags & ts31.NodeFlags.Const)) return;
1733
1934
  const exported = isExported(node);
1734
1935
  for (const decl of node.declarationList.declarations) {
1735
- if (!decl.initializer || !ts29.isIdentifier(decl.name)) continue;
1936
+ if (!decl.initializer || !ts31.isIdentifier(decl.name)) continue;
1736
1937
  if (!isConstantValue(decl.initializer)) continue;
1737
1938
  const valueText = decl.initializer.getText(sourceFile).replace(/\s+/g, " ").trim();
1738
1939
  const valueHash = createHash2("sha256").update(valueText).digest("hex").slice(0, 16);
1739
- const line = ts29.getLineAndCharacterOfPosition(sourceFile, decl.getStart(sourceFile)).line + 1;
1940
+ const line = ts31.getLineAndCharacterOfPosition(sourceFile, decl.getStart(sourceFile)).line + 1;
1740
1941
  registry.add({ name: decl.name.text, file, line, valueHash, valueText, exported });
1741
1942
  }
1742
1943
  }
1743
1944
  function buildFunctionEntry(body, parameters, sourceFile, file, lineNode, name, extra) {
1744
- const line = ts29.getLineAndCharacterOfPosition(sourceFile, lineNode.getStart(sourceFile)).line + 1;
1945
+ const line = ts31.getLineAndCharacterOfPosition(sourceFile, lineNode.getStart(sourceFile)).line + 1;
1745
1946
  const params = extractParams(parameters, sourceFile);
1746
1947
  const paramNames = params.map((p) => p.name);
1747
1948
  const hash = hashFunctionBody(body, sourceFile);
@@ -1763,17 +1964,17 @@ function buildFunctionEntry(body, parameters, sourceFile, file, lineNode, name,
1763
1964
  };
1764
1965
  }
1765
1966
  function collectFunctions(node, file, sourceFile, checker, registry) {
1766
- if (ts29.isFunctionDeclaration(node) && node.name && node.body) {
1967
+ if (ts31.isFunctionDeclaration(node) && node.name && node.body) {
1767
1968
  registry.add(buildFunctionEntry(node.body, node.parameters, sourceFile, file, node, node.name.text, {
1768
1969
  exported: isExported(node),
1769
1970
  symbol: checker.getSymbolAtLocation(node.name),
1770
1971
  node
1771
1972
  }));
1772
1973
  }
1773
- if (ts29.isVariableStatement(node)) {
1974
+ if (ts31.isVariableStatement(node)) {
1774
1975
  const exported = isExported(node);
1775
1976
  for (const decl of node.declarationList.declarations) {
1776
- if (decl.initializer && ts29.isArrowFunction(decl.initializer) && ts29.isIdentifier(decl.name)) {
1977
+ if (decl.initializer && ts31.isArrowFunction(decl.initializer) && ts31.isIdentifier(decl.name)) {
1777
1978
  const arrow = decl.initializer;
1778
1979
  registry.add(buildFunctionEntry(arrow.body, arrow.parameters, sourceFile, file, decl, decl.name.text, {
1779
1980
  exported,
@@ -1781,7 +1982,7 @@ function collectFunctions(node, file, sourceFile, checker, registry) {
1781
1982
  node: arrow
1782
1983
  }));
1783
1984
  }
1784
- if (decl.initializer && ts29.isFunctionExpression(decl.initializer) && ts29.isIdentifier(decl.name)) {
1985
+ if (decl.initializer && ts31.isFunctionExpression(decl.initializer) && ts31.isIdentifier(decl.name)) {
1785
1986
  const fn = decl.initializer;
1786
1987
  if (fn.body) {
1787
1988
  registry.add(buildFunctionEntry(fn.body, fn.parameters, sourceFile, file, decl, decl.name.text, {
@@ -1793,22 +1994,22 @@ function collectFunctions(node, file, sourceFile, checker, registry) {
1793
1994
  }
1794
1995
  }
1795
1996
  }
1796
- if (ts29.isPropertyAssignment(node) && (ts29.isIdentifier(node.name) || ts29.isStringLiteral(node.name))) {
1997
+ if (ts31.isPropertyAssignment(node) && (ts31.isIdentifier(node.name) || ts31.isStringLiteral(node.name))) {
1797
1998
  const init = node.initializer;
1798
1999
  const propName = node.name.text;
1799
- if (ts29.isArrowFunction(init)) {
2000
+ if (ts31.isArrowFunction(init)) {
1800
2001
  registry.add(buildFunctionEntry(init.body, init.parameters, sourceFile, file, node, propName, { node: init }));
1801
2002
  }
1802
- if (ts29.isFunctionExpression(init) && init.body) {
2003
+ if (ts31.isFunctionExpression(init) && init.body) {
1803
2004
  registry.add(buildFunctionEntry(init.body, init.parameters, sourceFile, file, node, propName, { node: init }));
1804
2005
  }
1805
2006
  }
1806
- if (ts29.isArrowFunction(node) || ts29.isFunctionExpression(node)) {
2007
+ if (ts31.isArrowFunction(node) || ts31.isFunctionExpression(node)) {
1807
2008
  const parent = node.parent;
1808
- if (ts29.isVariableDeclaration(parent) && ts29.isIdentifier(parent.name)) {
1809
- } else if (ts29.isPropertyAssignment(parent)) {
2009
+ if (ts31.isVariableDeclaration(parent) && ts31.isIdentifier(parent.name)) {
2010
+ } else if (ts31.isPropertyAssignment(parent)) {
1810
2011
  } else {
1811
- const body = ts29.isArrowFunction(node) ? node.body : node.body;
2012
+ const body = ts31.isArrowFunction(node) ? node.body : node.body;
1812
2013
  if (body) {
1813
2014
  const MIN_ANON_BODY = 64;
1814
2015
  if (bodyTextLength(body, sourceFile) >= MIN_ANON_BODY) {
@@ -1818,14 +2019,14 @@ function collectFunctions(node, file, sourceFile, checker, registry) {
1818
2019
  }
1819
2020
  }
1820
2021
  }
1821
- if (ts29.isMethodDeclaration(node) && node.body && ts29.isIdentifier(node.name)) {
2022
+ if (ts31.isMethodDeclaration(node) && node.body && ts31.isIdentifier(node.name)) {
1822
2023
  const parent = node.parent;
1823
- if (ts29.isClassDeclaration(parent)) {
2024
+ if (ts31.isClassDeclaration(parent)) {
1824
2025
  if (hasNonPublicModifier(node)) return;
1825
2026
  const className = parent.name ? parent.name.text : "<anonymous>";
1826
2027
  const name = `${className}.${node.name.text}`;
1827
2028
  const implementsInterface = parent.heritageClauses?.some(
1828
- (c) => c.token === ts29.SyntaxKind.ImplementsKeyword
2029
+ (c) => c.token === ts31.SyntaxKind.ImplementsKeyword
1829
2030
  ) ?? false;
1830
2031
  registry.add(buildFunctionEntry(node.body, node.parameters, sourceFile, file, node, name, {
1831
2032
  exported: isExported(parent),
@@ -1848,16 +2049,16 @@ function extractParams(parameters, sourceFile) {
1848
2049
  }
1849
2050
  function deriveAnonymousName(node, sourceFile) {
1850
2051
  const parent = node.parent;
1851
- const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
1852
- if (ts29.isCallExpression(parent)) {
2052
+ const line = ts31.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
2053
+ if (ts31.isCallExpression(parent)) {
1853
2054
  const grandparent = parent.parent;
1854
- if (ts29.isPropertyAssignment(grandparent) && ts29.isIdentifier(grandparent.name)) {
2055
+ if (ts31.isPropertyAssignment(grandparent) && ts31.isIdentifier(grandparent.name)) {
1855
2056
  return grandparent.name.text;
1856
2057
  }
1857
2058
  let calleeName = null;
1858
- if (ts29.isIdentifier(parent.expression)) {
2059
+ if (ts31.isIdentifier(parent.expression)) {
1859
2060
  calleeName = parent.expression.text;
1860
- } else if (ts29.isPropertyAccessExpression(parent.expression)) {
2061
+ } else if (ts31.isPropertyAccessExpression(parent.expression)) {
1861
2062
  calleeName = parent.expression.name.text;
1862
2063
  }
1863
2064
  if (calleeName) {
@@ -1868,7 +2069,7 @@ function deriveAnonymousName(node, sourceFile) {
1868
2069
  return `<anonymous>:${line}`;
1869
2070
  }
1870
2071
  function collectImports(node, file, imports) {
1871
- if (ts29.isImportDeclaration(node) && ts29.isStringLiteral(node.moduleSpecifier)) {
2072
+ if (ts31.isImportDeclaration(node) && ts31.isStringLiteral(node.moduleSpecifier)) {
1872
2073
  const moduleSource = node.moduleSpecifier.text;
1873
2074
  const clause = node.importClause;
1874
2075
  if (!clause) return;
@@ -1880,7 +2081,7 @@ function collectImports(node, file, imports) {
1880
2081
  source: moduleSource
1881
2082
  });
1882
2083
  }
1883
- if (clause.namedBindings && ts29.isNamedImports(clause.namedBindings)) {
2084
+ if (clause.namedBindings && ts31.isNamedImports(clause.namedBindings)) {
1884
2085
  for (const el of clause.namedBindings.elements) {
1885
2086
  imports.push({
1886
2087
  file,
@@ -1891,9 +2092,9 @@ function collectImports(node, file, imports) {
1891
2092
  }
1892
2093
  }
1893
2094
  }
1894
- if (ts29.isExportDeclaration(node) && node.moduleSpecifier && ts29.isStringLiteral(node.moduleSpecifier)) {
2095
+ if (ts31.isExportDeclaration(node) && node.moduleSpecifier && ts31.isStringLiteral(node.moduleSpecifier)) {
1895
2096
  const moduleSource = node.moduleSpecifier.text;
1896
- if (node.exportClause && ts29.isNamedExports(node.exportClause)) {
2097
+ if (node.exportClause && ts31.isNamedExports(node.exportClause)) {
1897
2098
  for (const el of node.exportClause.elements) {
1898
2099
  imports.push({
1899
2100
  file,
@@ -1906,7 +2107,7 @@ function collectImports(node, file, imports) {
1906
2107
  }
1907
2108
  }
1908
2109
  function collectStatementSequences(node, file, sourceFile, registry) {
1909
- if (!ts29.isBlock(node)) return;
2110
+ if (!ts31.isBlock(node)) return;
1910
2111
  const stmts = node.statements;
1911
2112
  const n = stmts.length;
1912
2113
  if (n < 3) return;
@@ -1916,43 +2117,46 @@ function collectStatementSequences(node, file, sourceFile, registry) {
1916
2117
  const window = stmts.slice(start, start + size);
1917
2118
  const texts = window.map((s) => s.getText(sourceFile));
1918
2119
  const joined = texts.join("\n");
1919
- const normalized = normalizeText(joined);
2120
+ const normalized = normalizeText2(joined);
1920
2121
  if (normalized.length < 128) continue;
1921
2122
  const hash = hashText(joined.replace(/\s+/g, " ").trim());
1922
2123
  const normalizedHash = hashText(normalized);
1923
2124
  const firstStmt = window[0];
1924
2125
  const lastStmt = window[window.length - 1];
1925
2126
  if (firstStmt === void 0 || lastStmt === void 0) continue;
1926
- const line = ts29.getLineAndCharacterOfPosition(sourceFile, firstStmt.getStart(sourceFile)).line + 1;
1927
- const endLine = ts29.getLineAndCharacterOfPosition(sourceFile, lastStmt.getEnd()).line + 1;
2127
+ const line = ts31.getLineAndCharacterOfPosition(sourceFile, firstStmt.getStart(sourceFile)).line + 1;
2128
+ const endLine = ts31.getLineAndCharacterOfPosition(sourceFile, lastStmt.getEnd()).line + 1;
1928
2129
  registry.add({ file, line, endLine, hash, normalizedHash, statementCount: size, normalizedBodyLength: normalized.length });
1929
2130
  }
1930
2131
  }
1931
2132
  }
1932
2133
  function collectInlineParamTypes(node, file, sourceFile, registry) {
1933
- if (!ts29.isTypeLiteralNode(node)) return;
2134
+ if (!ts31.isTypeLiteralNode(node)) return;
1934
2135
  const parent = node.parent;
1935
- if (!parent || !ts29.isParameter(parent)) return;
2136
+ if (!parent || !ts31.isParameter(parent)) return;
1936
2137
  if (parent.type !== node) return;
1937
- const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
2138
+ const line = ts31.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
1938
2139
  registry.add(file, line, node, sourceFile);
1939
2140
  }
1940
2141
  function collectCallSites(node, file, sourceFile, checker, sites) {
1941
- if (!ts29.isCallExpression(node)) return;
2142
+ if (!ts31.isCallExpression(node)) return;
1942
2143
  let calleeName = null;
1943
- if (ts29.isIdentifier(node.expression)) {
2144
+ if (ts31.isIdentifier(node.expression)) {
1944
2145
  calleeName = node.expression.text;
1945
- } else if (ts29.isPropertyAccessExpression(node.expression)) {
2146
+ } else if (ts31.isPropertyAccessExpression(node.expression)) {
1946
2147
  calleeName = node.expression.name.text;
1947
2148
  }
1948
2149
  if (calleeName) {
1949
- const line = ts29.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
2150
+ const line = ts31.getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).line + 1;
1950
2151
  let symbol;
2152
+ let resolvedDeclaration;
1951
2153
  try {
1952
2154
  symbol = checker.getSymbolAtLocation(node.expression);
1953
- if (symbol && symbol.flags & ts29.SymbolFlags.Alias) {
2155
+ if (symbol && symbol.flags & ts31.SymbolFlags.Alias) {
1954
2156
  symbol = checker.getAliasedSymbol(symbol);
1955
2157
  }
2158
+ const signature = checker.getResolvedSignature(node);
2159
+ resolvedDeclaration = signature?.declaration;
1956
2160
  } catch {
1957
2161
  }
1958
2162
  sites.push({
@@ -1961,7 +2165,8 @@ function collectCallSites(node, file, sourceFile, checker, sites) {
1961
2165
  line,
1962
2166
  argCount: node.arguments.length,
1963
2167
  node,
1964
- symbol
2168
+ symbol,
2169
+ resolvedDeclaration
1965
2170
  });
1966
2171
  }
1967
2172
  }
@@ -1970,12 +2175,12 @@ function collectAllComments(sourceFile) {
1970
2175
  const source = sourceFile.getFullText();
1971
2176
  const seen = /* @__PURE__ */ new Set();
1972
2177
  function visit(node) {
1973
- const leading = ts29.getLeadingCommentRanges(source, node.getFullStart());
2178
+ const leading = ts31.getLeadingCommentRanges(source, node.getFullStart());
1974
2179
  if (leading) {
1975
2180
  for (const r of leading) {
1976
2181
  if (seen.has(r.pos)) continue;
1977
2182
  seen.add(r.pos);
1978
- const isLine = r.kind === ts29.SyntaxKind.SingleLineCommentTrivia;
2183
+ const isLine = r.kind === ts31.SyntaxKind.SingleLineCommentTrivia;
1979
2184
  comments.push({
1980
2185
  type: isLine ? "Line" : "Block",
1981
2186
  value: source.slice(r.pos + 2, isLine ? r.end : r.end - 2),
@@ -1984,12 +2189,12 @@ function collectAllComments(sourceFile) {
1984
2189
  });
1985
2190
  }
1986
2191
  }
1987
- const trailing = ts29.getTrailingCommentRanges(source, node.getEnd());
2192
+ const trailing = ts31.getTrailingCommentRanges(source, node.getEnd());
1988
2193
  if (trailing) {
1989
2194
  for (const r of trailing) {
1990
2195
  if (seen.has(r.pos)) continue;
1991
2196
  seen.add(r.pos);
1992
- const isLine = r.kind === ts29.SyntaxKind.SingleLineCommentTrivia;
2197
+ const isLine = r.kind === ts31.SyntaxKind.SingleLineCommentTrivia;
1993
2198
  comments.push({
1994
2199
  type: isLine ? "Line" : "Block",
1995
2200
  value: source.slice(r.pos + 2, isLine ? r.end : r.end - 2),
@@ -1998,34 +2203,34 @@ function collectAllComments(sourceFile) {
1998
2203
  });
1999
2204
  }
2000
2205
  }
2001
- ts29.forEachChild(node, visit);
2206
+ ts31.forEachChild(node, visit);
2002
2207
  }
2003
2208
  visit(sourceFile);
2004
2209
  return comments;
2005
2210
  }
2006
2211
 
2007
2212
  // src/typecheck/program.ts
2008
- import * as ts30 from "typescript";
2213
+ import * as ts32 from "typescript";
2009
2214
  import { dirname as dirname2 } from "path";
2010
2215
  function createProgramFromFiles(files) {
2011
2216
  let configPath;
2012
2217
  if (files.length > 0) {
2013
- configPath = ts30.findConfigFile(dirname2(files[0]), ts30.sys.fileExists, "tsconfig.json");
2218
+ configPath = ts32.findConfigFile(dirname2(files[0]), ts32.sys.fileExists, "tsconfig.json");
2014
2219
  }
2015
2220
  if (configPath) {
2016
- const configFile = ts30.readConfigFile(configPath, ts30.sys.readFile);
2017
- const parsed = ts30.parseJsonConfigFileContent(configFile.config, ts30.sys, dirname2(configPath));
2018
- return ts30.createProgram({
2221
+ const configFile = ts32.readConfigFile(configPath, ts32.sys.readFile);
2222
+ const parsed = ts32.parseJsonConfigFileContent(configFile.config, ts32.sys, dirname2(configPath));
2223
+ return ts32.createProgram({
2019
2224
  rootNames: files,
2020
2225
  options: { ...parsed.options, skipLibCheck: true }
2021
2226
  });
2022
2227
  }
2023
- return ts30.createProgram({
2228
+ return ts32.createProgram({
2024
2229
  rootNames: files,
2025
2230
  options: {
2026
- target: ts30.ScriptTarget.ESNext,
2027
- module: ts30.ModuleKind.ESNext,
2028
- moduleResolution: ts30.ModuleResolutionKind.Bundler,
2231
+ target: ts32.ScriptTarget.ESNext,
2232
+ module: ts32.ModuleKind.ESNext,
2233
+ moduleResolution: ts32.ModuleResolutionKind.Bundler,
2029
2234
  strict: true,
2030
2235
  skipLibCheck: true,
2031
2236
  noEmit: true
@@ -2265,4 +2470,4 @@ export {
2265
2470
  executeScan,
2266
2471
  scan
2267
2472
  };
2268
- //# sourceMappingURL=chunk-7UXUNJSF.js.map
2473
+ //# sourceMappingURL=chunk-HE647T6E.js.map