technical-debt-radar 1.0.6 → 1.0.8

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.
Files changed (2) hide show
  1. package/dist/index.js +111 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -499,6 +499,7 @@ var require_parser = __commonJS({
499
499
  const standards = parseStandards(raw.standards);
500
500
  const scoring = parseScoring(raw.scoring);
501
501
  const shared_infrastructure = parseSharedInfrastructure(raw.shared_infrastructure);
502
+ const maintainability = parseMaintainability(raw.maintainability);
502
503
  const result = {
503
504
  mode,
504
505
  stack,
@@ -512,7 +513,8 @@ var require_parser = __commonJS({
512
513
  exceptions,
513
514
  standards,
514
515
  scoring,
515
- shared_infrastructure
516
+ shared_infrastructure,
517
+ maintainability
516
518
  };
517
519
  if (architecture !== void 0) {
518
520
  result.architecture = architecture;
@@ -863,6 +865,34 @@ var require_parser = __commonJS({
863
865
  return item;
864
866
  });
865
867
  }
868
+ function parseMaintainability(value) {
869
+ if (value === void 0 || value === null)
870
+ return void 0;
871
+ if (typeof value !== "object") {
872
+ throw new PolicyValidationError("maintainability must be an object");
873
+ }
874
+ const m = value;
875
+ const result = {};
876
+ if (m.require_tests !== void 0) {
877
+ if (typeof m.require_tests !== "boolean") {
878
+ throw new PolicyValidationError("maintainability.require_tests must be a boolean");
879
+ }
880
+ result.require_tests = m.require_tests;
881
+ }
882
+ if (m.require_tests_for !== void 0) {
883
+ if (!Array.isArray(m.require_tests_for)) {
884
+ throw new PolicyValidationError("maintainability.require_tests_for must be an array of strings");
885
+ }
886
+ result.require_tests_for = m.require_tests_for.map(String);
887
+ }
888
+ if (m.ignore_tests_for !== void 0) {
889
+ if (!Array.isArray(m.ignore_tests_for)) {
890
+ throw new PolicyValidationError("maintainability.ignore_tests_for must be an array of strings");
891
+ }
892
+ result.ignore_tests_for = m.ignore_tests_for.map(String);
893
+ }
894
+ return result;
895
+ }
866
896
  function parseScoring(value) {
867
897
  if (value === void 0 || value === null)
868
898
  return {};
@@ -7511,6 +7541,15 @@ var require_validator = __commonJS({
7511
7541
  shared_infrastructure: {
7512
7542
  type: "array",
7513
7543
  items: { type: "string" }
7544
+ },
7545
+ maintainability: {
7546
+ type: "object",
7547
+ properties: {
7548
+ require_tests: { type: "boolean" },
7549
+ require_tests_for: { type: "array", items: { type: "string" } },
7550
+ ignore_tests_for: { type: "array", items: { type: "string" } }
7551
+ },
7552
+ additionalProperties: false
7514
7553
  }
7515
7554
  },
7516
7555
  additionalProperties: false
@@ -9554,7 +9593,8 @@ var require_compiler = __commonJS({
9554
9593
  standards: config.standards,
9555
9594
  scoring,
9556
9595
  architecture: config.architecture,
9557
- sharedInfrastructure: config.shared_infrastructure ?? []
9596
+ sharedInfrastructure: config.shared_infrastructure ?? [],
9597
+ maintainability: config.maintainability
9558
9598
  };
9559
9599
  }
9560
9600
  function compileLayers(layers) {
@@ -11625,6 +11665,14 @@ var require_rules_generator = __commonJS({
11625
11665
  lines.push(" default: S");
11626
11666
  }
11627
11667
  lines.push("");
11668
+ lines.push("maintainability:");
11669
+ lines.push(" require_tests: true");
11670
+ lines.push(" ignore_tests_for:");
11671
+ lines.push(" - guard");
11672
+ lines.push(" - interceptor");
11673
+ lines.push(" - decorator");
11674
+ lines.push(" - strategy");
11675
+ lines.push("");
11628
11676
  return lines.join("\n");
11629
11677
  }
11630
11678
  function extractExceptions2(rulesYmlContent) {
@@ -17144,6 +17192,7 @@ var require_missing_tests_detector = __commonJS({
17144
17192
  "handler",
17145
17193
  "repository"
17146
17194
  ],
17195
+ ignoreTestsFor: [],
17147
17196
  severity: "warning"
17148
17197
  };
17149
17198
  var EXCLUDED_PATTERNS = [
@@ -17222,7 +17271,17 @@ var require_missing_tests_detector = __commonJS({
17222
17271
  const basename2 = path9.basename(f.path);
17223
17272
  if (isExcludedFromTesting(basename2))
17224
17273
  return false;
17225
- return isTestableFile(basename2, cfg.requireTestsFor);
17274
+ if (!isTestableFile(basename2, cfg.requireTestsFor))
17275
+ return false;
17276
+ if (cfg.ignoreTestsFor.length > 0) {
17277
+ const fileType = extractFileType(f.path);
17278
+ if (cfg.ignoreTestsFor.includes(fileType))
17279
+ return false;
17280
+ const normalizedPath = f.path.replace(/\\/g, "/");
17281
+ if (cfg.ignoreTestsFor.some((pattern) => normalizedPath.includes(`/${pattern}/`) || normalizedPath.includes(`/${pattern}s/`)))
17282
+ return false;
17283
+ }
17284
+ return true;
17226
17285
  });
17227
17286
  const filesWithoutTests = [];
17228
17287
  for (const file of testableFiles) {
@@ -17804,6 +17863,8 @@ var require_dead_code_detector = __commonJS({
17804
17863
  const sf = sourceFiles.get(filePath);
17805
17864
  if (sf && exp.type === "class" && isNestJSDIRegistered(sf, exp.name))
17806
17865
  continue;
17866
+ if (sf && isReferencedInOwnFile(sf, exp.name))
17867
+ continue;
17807
17868
  unusedExports.push({
17808
17869
  export: exp,
17809
17870
  file: filePath,
@@ -17985,6 +18046,30 @@ var require_dead_code_detector = __commonJS({
17985
18046
  function isTypeExport(type) {
17986
18047
  return type === "type" || type === "interface" || type === "enum";
17987
18048
  }
18049
+ function isReferencedInOwnFile(sourceFile, exportName) {
18050
+ const identifiers = sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.Identifier).filter((id) => id.getText() === exportName);
18051
+ let declarationCount = 0;
18052
+ let totalCount = 0;
18053
+ for (const id of identifiers) {
18054
+ totalCount++;
18055
+ const parent = id.getParent();
18056
+ if (!parent)
18057
+ continue;
18058
+ const parentKind = parent.getKind();
18059
+ if (parentKind === ts_morph_1.SyntaxKind.ClassDeclaration || parentKind === ts_morph_1.SyntaxKind.FunctionDeclaration || parentKind === ts_morph_1.SyntaxKind.VariableDeclaration || parentKind === ts_morph_1.SyntaxKind.EnumDeclaration || parentKind === ts_morph_1.SyntaxKind.InterfaceDeclaration || parentKind === ts_morph_1.SyntaxKind.TypeAliasDeclaration) {
18060
+ const nameNode = parent.getNameNode?.();
18061
+ if (nameNode && nameNode.getPos() === id.getPos()) {
18062
+ declarationCount++;
18063
+ continue;
18064
+ }
18065
+ }
18066
+ if (parentKind === ts_morph_1.SyntaxKind.ExportSpecifier) {
18067
+ declarationCount++;
18068
+ continue;
18069
+ }
18070
+ }
18071
+ return totalCount > declarationCount;
18072
+ }
17988
18073
  function parsePathAliases(input, projectRoot) {
17989
18074
  let tsconfigContent;
17990
18075
  const tsconfigFile = input.changedFiles.find((f) => f.status !== "deleted" && /tsconfig(?:\.build)?\.json$/.test(f.path));
@@ -18096,8 +18181,13 @@ var require_dead_code_detector = __commonJS({
18096
18181
  return resolveInProject(resolved, project) ?? resolved;
18097
18182
  }
18098
18183
  if (aliases.length > 0) {
18099
- return resolvePathAlias(specifier, aliases, project);
18184
+ const aliasResolved = resolvePathAlias(specifier, aliases, project);
18185
+ if (aliasResolved)
18186
+ return aliasResolved;
18100
18187
  }
18188
+ const directResolved = resolveInProject(specifier, project);
18189
+ if (directResolved)
18190
+ return directResolved;
18101
18191
  return void 0;
18102
18192
  }
18103
18193
  function resolveInProject(resolved, project) {
@@ -18543,7 +18633,7 @@ var require_orchestrator = __commonJS({
18543
18633
  (0, perf_pattern_detector_1.detectPerformanceRisks)(filteredInput, policy),
18544
18634
  (0, reliability_detector_1.detectReliabilityIssues)(filteredInput, policy),
18545
18635
  (0, duplication_detector_1.detectDuplication)(filteredInput),
18546
- projectRoot ? (0, missing_tests_detector_1.detectMissingTests)(filteredInput, projectRoot) : Promise.resolve(null),
18636
+ projectRoot ? (0, missing_tests_detector_1.detectMissingTests)(filteredInput, projectRoot, buildMissingTestsConfig(policy)) : Promise.resolve(null),
18547
18637
  (0, dead_code_detector_1.detectDeadCode)(filteredInput, {}, projectRoot),
18548
18638
  projectRoot ? Promise.resolve((0, coverage_delta_detector_1.detectCoverageDelta)(projectRoot)) : Promise.resolve(null)
18549
18639
  ]);
@@ -18783,6 +18873,22 @@ var require_orchestrator = __commonJS({
18783
18873
  analysisTimeMs: Date.now() - startMs
18784
18874
  };
18785
18875
  }
18876
+ function buildMissingTestsConfig(policy) {
18877
+ const m = policy.maintainability;
18878
+ if (!m)
18879
+ return {};
18880
+ const config = {};
18881
+ if (m.require_tests === false) {
18882
+ config.enabled = false;
18883
+ }
18884
+ if (m.require_tests_for && m.require_tests_for.length > 0) {
18885
+ config.requireTestsFor = m.require_tests_for;
18886
+ }
18887
+ if (m.ignore_tests_for && m.ignore_tests_for.length > 0) {
18888
+ config.ignoreTestsFor = m.ignore_tests_for;
18889
+ }
18890
+ return config;
18891
+ }
18786
18892
  function deriveProjectRoot(input) {
18787
18893
  const paths = input.changedFiles.filter((f) => f.status !== "deleted" && path9.isAbsolute(f.path)).map((f) => f.path);
18788
18894
  if (paths.length === 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "technical-debt-radar",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Stop Node.js production crashes before merge. 47 detection patterns across 5 categories.",
5
5
  "bin": {
6
6
  "radar": "dist/index.js",