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.
- package/dist/index.js +111 -5
- 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
|
-
|
|
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
|
-
|
|
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)
|