unguard 0.13.0 → 0.13.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.
@@ -632,6 +632,7 @@ var optionalArgAlwaysUsed = {
632
632
 
633
633
  // src/rules/cross-file/repeated-literal-property.ts
634
634
  import * as ts8 from "typescript";
635
+ var MODULE_SCOPE = -1;
635
636
  var repeatedLiteralProperty = {
636
637
  id: "repeated-literal-property",
637
638
  severity: "warning",
@@ -651,7 +652,8 @@ var repeatedLiteralProperty = {
651
652
  valueMap.set(result.literalText, list);
652
653
  }
653
654
  const line = ts8.getLineAndCharacterOfPosition(sourceFile, prop.getStart(sourceFile)).line + 1;
654
- list.push({ line, isAsConst: result.isAsConst });
655
+ const scopeId = findEnclosingFunctionStart(prop, sourceFile);
656
+ list.push({ line, isAsConst: result.isAsConst, scopeId });
655
657
  }
656
658
  }
657
659
  ts8.forEachChild(node, visit2);
@@ -661,31 +663,40 @@ var repeatedLiteralProperty = {
661
663
  ts8.forEachChild(sourceFile, visit2);
662
664
  for (const [value, occurrences] of valueMap) {
663
665
  const hasAsConst = occurrences.some((o) => o.isAsConst);
666
+ const uniqueScopes = new Set(occurrences.map((o) => o.scopeId));
664
667
  const threshold = hasAsConst ? 3 : 5;
665
- if (occurrences.length < threshold) continue;
668
+ if (uniqueScopes.size < threshold) continue;
666
669
  const sorted = [...occurrences].sort((a, b) => a.line - b.line);
667
- for (const occ of sorted) {
668
- const otherLines = sorted.filter((o) => o !== occ).map((o) => o.line).join(", ");
669
- diagnostics.push({
670
- ruleId: this.id,
671
- severity: this.severity,
672
- message: `${JSON.stringify(value)}${hasAsConst ? " as const" : ""} repeated ${occurrences.length} times as property value (also at lines ${otherLines})`,
673
- file,
674
- line: occ.line,
675
- column: 1
676
- });
677
- }
670
+ const first = sorted[0];
671
+ if (first === void 0) continue;
672
+ const otherLines = sorted.slice(1).map((o) => o.line).join(", ");
673
+ diagnostics.push({
674
+ ruleId: this.id,
675
+ severity: this.severity,
676
+ message: `${JSON.stringify(value)}${hasAsConst ? " as const" : ""} repeated across ${uniqueScopes.size} scopes as property value (also at lines ${otherLines})`,
677
+ file,
678
+ line: first.line,
679
+ column: 1
680
+ });
678
681
  }
679
682
  }
680
683
  return diagnostics;
681
684
  }
682
685
  };
686
+ function findEnclosingFunctionStart(node, sourceFile) {
687
+ let current = node.parent;
688
+ while (current) {
689
+ if (ts8.isFunctionDeclaration(current) || ts8.isFunctionExpression(current) || ts8.isArrowFunction(current) || ts8.isMethodDeclaration(current)) {
690
+ return current.getStart(sourceFile);
691
+ }
692
+ current = current.parent;
693
+ }
694
+ return MODULE_SCOPE;
695
+ }
683
696
  function extractLiteral(node, sourceFile) {
684
- if (ts8.isStringLiteral(node) || ts8.isNumericLiteral(node) || ts8.isNoSubstitutionTemplateLiteral(node)) {
697
+ if (ts8.isStringLiteral(node) || ts8.isNoSubstitutionTemplateLiteral(node)) {
685
698
  return { literalText: node.text, isAsConst: false };
686
699
  }
687
- if (node.kind === ts8.SyntaxKind.TrueKeyword) return { literalText: "true", isAsConst: false };
688
- if (node.kind === ts8.SyntaxKind.FalseKeyword) return { literalText: "false", isAsConst: false };
689
700
  if (ts8.isAsExpression(node) && node.type.getText(sourceFile).trim() === "const") {
690
701
  const inner = extractLiteral(node.expression, sourceFile);
691
702
  if (inner.literalText !== null) {
@@ -763,17 +774,17 @@ var repeatedReturnShape = {
763
774
  const unique = [...byFunction.values()];
764
775
  if (unique.length < THRESHOLD) continue;
765
776
  const sorted = unique.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line);
766
- for (const entry of sorted) {
767
- const others = sorted.filter((e) => e !== entry).map((e) => `${e.functionName} (${e.file}:${e.line})`).join(", ");
768
- diagnostics.push({
769
- ruleId: this.id,
770
- severity: this.severity,
771
- message: `${unique.length} functions return shape {${entry.props.join(", ")}}; consider a shared return type (${others})`,
772
- file: entry.file,
773
- line: entry.line,
774
- column: 1
775
- });
776
- }
777
+ const first = sorted[0];
778
+ if (first === void 0) continue;
779
+ const others = sorted.slice(1).map((e) => `${e.functionName} (${e.file}:${e.line})`).join(", ");
780
+ diagnostics.push({
781
+ ruleId: this.id,
782
+ severity: this.severity,
783
+ message: `${unique.length} functions return shape {${first.props.join(", ")}}; consider a shared return type (${others})`,
784
+ file: first.file,
785
+ line: first.line,
786
+ column: 1
787
+ });
777
788
  }
778
789
  return diagnostics;
779
790
  }
@@ -817,7 +828,7 @@ function collectReturnShapes(funcNode, file, funcLine, functionName, sourceFile,
817
828
  }
818
829
  function addShape(objLiteral, file, funcLine, functionName, sourceFile, shapeMap) {
819
830
  const props = extractPropertyNames(objLiteral);
820
- if (props === null || props.length === 0) return;
831
+ if (props === null || props.length < 2) return;
821
832
  const { sorted, list } = getShapeGroup(shapeMap, props);
822
833
  list.push({ file, line: funcLine, functionName, props: sorted });
823
834
  }
@@ -2918,4 +2929,4 @@ export {
2918
2929
  executeScan,
2919
2930
  scan
2920
2931
  };
2921
- //# sourceMappingURL=chunk-KNKWDZ6H.js.map
2932
+ //# sourceMappingURL=chunk-2QER6GG7.js.map