technical-debt-radar 1.7.0 → 1.8.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.
- package/dist/index.js +152 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12889,6 +12889,7 @@ var require_boundary_checker = __commonJS({
|
|
|
12889
12889
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
12890
12890
|
exports2.checkBoundaries = checkBoundaries;
|
|
12891
12891
|
exports2._resetPathAliasCache = _resetPathAliasCache;
|
|
12892
|
+
exports2._resetModuleParsingCache = _resetModuleParsingCache;
|
|
12892
12893
|
var shared_1 = require_dist();
|
|
12893
12894
|
var minimatch_1 = require_commonjs3();
|
|
12894
12895
|
var ts_morph_1 = require("ts-morph");
|
|
@@ -13222,6 +13223,12 @@ var require_boundary_checker = __commonJS({
|
|
|
13222
13223
|
continue;
|
|
13223
13224
|
if (typeOnly)
|
|
13224
13225
|
continue;
|
|
13226
|
+
if (isNestJS) {
|
|
13227
|
+
const importedNames = getImportedNamesFromSpecifier(sourceFile, specifier);
|
|
13228
|
+
const suppressed = importedNames.length > 0 && importedNames.every((name) => isLegitimateNestJSModuleImport(sourceModule, targetModule, name, input));
|
|
13229
|
+
if (suppressed)
|
|
13230
|
+
continue;
|
|
13231
|
+
}
|
|
13225
13232
|
violations.push({
|
|
13226
13233
|
category: "architecture",
|
|
13227
13234
|
type: "module-boundary-violation",
|
|
@@ -13461,6 +13468,117 @@ var require_boundary_checker = __commonJS({
|
|
|
13461
13468
|
function _resetPathAliasCache() {
|
|
13462
13469
|
_cachedAliases = void 0;
|
|
13463
13470
|
}
|
|
13471
|
+
var _cachedModuleParsing;
|
|
13472
|
+
function parseNestJSModules(input) {
|
|
13473
|
+
if (_cachedModuleParsing)
|
|
13474
|
+
return _cachedModuleParsing;
|
|
13475
|
+
const result = /* @__PURE__ */ new Map();
|
|
13476
|
+
const project = new ts_morph_1.Project({ useInMemoryFileSystem: true });
|
|
13477
|
+
for (const file of input.changedFiles) {
|
|
13478
|
+
if (file.status === "deleted")
|
|
13479
|
+
continue;
|
|
13480
|
+
if (!/\.module\.(ts|js)$/.test(file.path))
|
|
13481
|
+
continue;
|
|
13482
|
+
const sf = project.createSourceFile(file.path, file.content);
|
|
13483
|
+
for (const cls of sf.getClasses()) {
|
|
13484
|
+
const moduleDecorator = cls.getDecorators().find((d) => d.getName() === "Module");
|
|
13485
|
+
if (!moduleDecorator)
|
|
13486
|
+
continue;
|
|
13487
|
+
const className = cls.getName() ?? "";
|
|
13488
|
+
const pathMatch = file.path.match(/src\/([^/]+)\//);
|
|
13489
|
+
const moduleName = pathMatch ? pathMatch[1] : "";
|
|
13490
|
+
if (!moduleName)
|
|
13491
|
+
continue;
|
|
13492
|
+
const callExpr = moduleDecorator.getCallExpression?.();
|
|
13493
|
+
if (!callExpr)
|
|
13494
|
+
continue;
|
|
13495
|
+
const args = callExpr.getArguments();
|
|
13496
|
+
if (args.length === 0 || !ts_morph_1.Node.isObjectLiteralExpression(args[0]))
|
|
13497
|
+
continue;
|
|
13498
|
+
const objLit = args[0];
|
|
13499
|
+
const imports = [];
|
|
13500
|
+
const exports3 = [];
|
|
13501
|
+
const hasForwardRef = /* @__PURE__ */ new Map();
|
|
13502
|
+
const importsProp = objLit.getProperty("imports");
|
|
13503
|
+
if (importsProp && ts_morph_1.Node.isPropertyAssignment(importsProp)) {
|
|
13504
|
+
const init = importsProp.getInitializer();
|
|
13505
|
+
if (init && ts_morph_1.Node.isArrayLiteralExpression(init)) {
|
|
13506
|
+
for (const el of init.getElements()) {
|
|
13507
|
+
if (ts_morph_1.Node.isIdentifier(el)) {
|
|
13508
|
+
imports.push(el.getText());
|
|
13509
|
+
hasForwardRef.set(el.getText(), false);
|
|
13510
|
+
} else if (ts_morph_1.Node.isCallExpression(el)) {
|
|
13511
|
+
const callText = el.getText();
|
|
13512
|
+
const fwdMatch = callText.match(/forwardRef\s*\(\s*\(\)\s*=>\s*(\w+)\s*\)/);
|
|
13513
|
+
if (fwdMatch) {
|
|
13514
|
+
imports.push(fwdMatch[1]);
|
|
13515
|
+
hasForwardRef.set(fwdMatch[1], true);
|
|
13516
|
+
} else {
|
|
13517
|
+
const expr = el.getExpression();
|
|
13518
|
+
if (ts_morph_1.Node.isPropertyAccessExpression(expr)) {
|
|
13519
|
+
const obj = expr.getExpression();
|
|
13520
|
+
if (ts_morph_1.Node.isIdentifier(obj)) {
|
|
13521
|
+
imports.push(obj.getText());
|
|
13522
|
+
hasForwardRef.set(obj.getText(), false);
|
|
13523
|
+
}
|
|
13524
|
+
}
|
|
13525
|
+
}
|
|
13526
|
+
}
|
|
13527
|
+
}
|
|
13528
|
+
}
|
|
13529
|
+
}
|
|
13530
|
+
const exportsProp = objLit.getProperty("exports");
|
|
13531
|
+
if (exportsProp && ts_morph_1.Node.isPropertyAssignment(exportsProp)) {
|
|
13532
|
+
const init = exportsProp.getInitializer();
|
|
13533
|
+
if (init && ts_morph_1.Node.isArrayLiteralExpression(init)) {
|
|
13534
|
+
for (const el of init.getElements()) {
|
|
13535
|
+
if (ts_morph_1.Node.isIdentifier(el)) {
|
|
13536
|
+
exports3.push(el.getText());
|
|
13537
|
+
}
|
|
13538
|
+
}
|
|
13539
|
+
}
|
|
13540
|
+
}
|
|
13541
|
+
result.set(moduleName, { moduleName, className, imports, exports: exports3, hasForwardRef });
|
|
13542
|
+
}
|
|
13543
|
+
project.removeSourceFile(sf);
|
|
13544
|
+
}
|
|
13545
|
+
_cachedModuleParsing = result;
|
|
13546
|
+
return result;
|
|
13547
|
+
}
|
|
13548
|
+
function getImportedNamesFromSpecifier(sourceFile, specifier) {
|
|
13549
|
+
const names = [];
|
|
13550
|
+
for (const decl of sourceFile.getImportDeclarations()) {
|
|
13551
|
+
if (decl.getModuleSpecifierValue() !== specifier)
|
|
13552
|
+
continue;
|
|
13553
|
+
const defaultImport = decl.getDefaultImport();
|
|
13554
|
+
if (defaultImport)
|
|
13555
|
+
names.push(defaultImport.getText());
|
|
13556
|
+
for (const named of decl.getNamedImports()) {
|
|
13557
|
+
names.push(named.getName());
|
|
13558
|
+
}
|
|
13559
|
+
}
|
|
13560
|
+
return names;
|
|
13561
|
+
}
|
|
13562
|
+
function isLegitimateNestJSModuleImport(sourceModuleName, targetModuleName, importedClassName, input) {
|
|
13563
|
+
const modules = parseNestJSModules(input);
|
|
13564
|
+
const importingMod = modules.get(sourceModuleName);
|
|
13565
|
+
if (!importingMod)
|
|
13566
|
+
return false;
|
|
13567
|
+
const targetMod = modules.get(targetModuleName);
|
|
13568
|
+
if (!targetMod)
|
|
13569
|
+
return false;
|
|
13570
|
+
const targetClassName = targetMod.className;
|
|
13571
|
+
if (!importingMod.imports.includes(targetClassName))
|
|
13572
|
+
return false;
|
|
13573
|
+
if (importingMod.hasForwardRef.get(targetClassName))
|
|
13574
|
+
return false;
|
|
13575
|
+
if (!targetMod.exports.includes(importedClassName))
|
|
13576
|
+
return false;
|
|
13577
|
+
return true;
|
|
13578
|
+
}
|
|
13579
|
+
function _resetModuleParsingCache() {
|
|
13580
|
+
_cachedModuleParsing = void 0;
|
|
13581
|
+
}
|
|
13464
13582
|
function normalizeForMatching(filePath) {
|
|
13465
13583
|
let normalized = filePath.replace(/\\/g, "/");
|
|
13466
13584
|
if (normalized.startsWith("/")) {
|
|
@@ -19209,7 +19327,10 @@ var require_dead_code_detector = __commonJS({
|
|
|
19209
19327
|
for (const [otherFilePath, otherText] of allFileTexts) {
|
|
19210
19328
|
if (otherFilePath === filePath)
|
|
19211
19329
|
continue;
|
|
19212
|
-
if (callPattern.test(otherText))
|
|
19330
|
+
if (!callPattern.test(otherText))
|
|
19331
|
+
continue;
|
|
19332
|
+
const importPattern = new RegExp(`import\\s+.*\\b${className}\\b.*from\\s+`);
|
|
19333
|
+
if (importPattern.test(otherText)) {
|
|
19213
19334
|
hasExternalCall = true;
|
|
19214
19335
|
break;
|
|
19215
19336
|
}
|
|
@@ -19650,7 +19771,7 @@ var require_orchestrator = __commonJS({
|
|
|
19650
19771
|
(0, reliability_detector_1.detectReliabilityIssues)(filteredInput, policy),
|
|
19651
19772
|
(0, duplication_detector_1.detectDuplication)(filteredInput),
|
|
19652
19773
|
projectRoot ? (0, missing_tests_detector_1.detectMissingTests)(filteredInput, projectRoot, buildMissingTestsConfig(policy)) : Promise.resolve(null),
|
|
19653
|
-
(0, dead_code_detector_1.detectDeadCode)(filteredInput, {}, projectRoot),
|
|
19774
|
+
(0, dead_code_detector_1.detectDeadCode)(filteredInput, { excludeBarrels: false, excludeTypes: false }, projectRoot),
|
|
19654
19775
|
projectRoot ? Promise.resolve((0, coverage_delta_detector_1.detectCoverageDelta)(projectRoot)) : Promise.resolve(null)
|
|
19655
19776
|
]);
|
|
19656
19777
|
const runtimeViolations = runtimeResult.violations;
|
|
@@ -20355,19 +20476,35 @@ var RadarApiClient = class _RadarApiClient {
|
|
|
20355
20476
|
return null;
|
|
20356
20477
|
}
|
|
20357
20478
|
async fetch(path9, init) {
|
|
20358
|
-
const
|
|
20359
|
-
|
|
20360
|
-
|
|
20361
|
-
|
|
20362
|
-
|
|
20363
|
-
|
|
20364
|
-
|
|
20365
|
-
|
|
20479
|
+
const url = `${this.apiUrl}${path9}`;
|
|
20480
|
+
let res;
|
|
20481
|
+
try {
|
|
20482
|
+
res = await fetch(url, {
|
|
20483
|
+
...init,
|
|
20484
|
+
headers: {
|
|
20485
|
+
"Authorization": `Bearer ${this.token}`,
|
|
20486
|
+
"Content-Type": "application/json",
|
|
20487
|
+
...init?.headers
|
|
20488
|
+
}
|
|
20489
|
+
});
|
|
20490
|
+
} catch (err) {
|
|
20491
|
+
const cause = err?.cause?.message || err?.cause?.code || "";
|
|
20492
|
+
throw new Error(`Network error connecting to ${url}: ${err.message}${cause ? ` (${cause})` : ""}`);
|
|
20493
|
+
}
|
|
20366
20494
|
if (!res.ok) {
|
|
20367
20495
|
const body = await res.text().catch(() => "");
|
|
20368
|
-
throw new Error(`API error ${res.status}: ${body}`);
|
|
20496
|
+
throw new Error(`API error ${res.status} on ${path9}: ${body}`);
|
|
20497
|
+
}
|
|
20498
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
20499
|
+
const text = await res.text();
|
|
20500
|
+
if (!text || text.trim().length === 0) {
|
|
20501
|
+
return void 0;
|
|
20502
|
+
}
|
|
20503
|
+
try {
|
|
20504
|
+
return JSON.parse(text);
|
|
20505
|
+
} catch {
|
|
20506
|
+
return void 0;
|
|
20369
20507
|
}
|
|
20370
|
-
return res.json();
|
|
20371
20508
|
}
|
|
20372
20509
|
async verifyToken() {
|
|
20373
20510
|
return this.fetch("/cli/auth/verify");
|
|
@@ -20674,8 +20811,9 @@ async function scanCommand(targetPath, options) {
|
|
|
20674
20811
|
}).catch(() => {
|
|
20675
20812
|
});
|
|
20676
20813
|
console.log(import_chalk.default.green(" \u2713 Results synced to dashboard: https://www.technicaldebtradar.com/dashboard"));
|
|
20677
|
-
} catch {
|
|
20678
|
-
|
|
20814
|
+
} catch (err) {
|
|
20815
|
+
const detail = err?.message ? `: ${err.message}` : "";
|
|
20816
|
+
console.log(import_chalk.default.yellow(` \u26A0\uFE0F Could not sync results to dashboard${detail}`));
|
|
20679
20817
|
}
|
|
20680
20818
|
}
|
|
20681
20819
|
if (mode === "warn") {
|