technical-debt-radar 1.9.0 → 1.10.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 +157 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -231,11 +231,11 @@ var require_plans = __commonJS({
|
|
|
231
231
|
[PlanId.FREE]: {
|
|
232
232
|
id: PlanId.FREE,
|
|
233
233
|
name: "Free",
|
|
234
|
-
description: "
|
|
234
|
+
description: "5 scans/month, warn mode",
|
|
235
235
|
priceMonthly: 0,
|
|
236
236
|
priceAnnual: 0,
|
|
237
237
|
priceMonthlyIfAnnual: 0,
|
|
238
|
-
limits: { maxRepos: 2, maxMembers: 1, aiCreditsPerMonth: 0, maxOrgs: 1, scansPerMonth:
|
|
238
|
+
limits: { maxRepos: 2, maxMembers: 1, aiCreditsPerMonth: 0, maxOrgs: 1, scansPerMonth: 5 },
|
|
239
239
|
features: {
|
|
240
240
|
...ALL_CLI,
|
|
241
241
|
cliFixAI: false,
|
|
@@ -270,7 +270,7 @@ var require_plans = __commonJS({
|
|
|
270
270
|
priceMonthly: 15,
|
|
271
271
|
priceAnnual: 144,
|
|
272
272
|
priceMonthlyIfAnnual: 12,
|
|
273
|
-
limits: { maxRepos: 5, maxMembers: 1, aiCreditsPerMonth: 50, maxOrgs: 1, scansPerMonth:
|
|
273
|
+
limits: { maxRepos: 5, maxMembers: 1, aiCreditsPerMonth: 50, maxOrgs: 1, scansPerMonth: 200 },
|
|
274
274
|
features: {
|
|
275
275
|
...ALL_CLI,
|
|
276
276
|
cliFixAI: true,
|
|
@@ -305,7 +305,7 @@ var require_plans = __commonJS({
|
|
|
305
305
|
priceMonthly: 49,
|
|
306
306
|
priceAnnual: 468,
|
|
307
307
|
priceMonthlyIfAnnual: 39,
|
|
308
|
-
limits: { maxRepos: -1, maxMembers: -1, aiCreditsPerMonth: 500, maxOrgs: 3, scansPerMonth:
|
|
308
|
+
limits: { maxRepos: -1, maxMembers: -1, aiCreditsPerMonth: 500, maxOrgs: 3, scansPerMonth: 1e3 },
|
|
309
309
|
features: {
|
|
310
310
|
...ALL_CLI,
|
|
311
311
|
cliFixAI: true,
|
|
@@ -340,7 +340,7 @@ var require_plans = __commonJS({
|
|
|
340
340
|
priceMonthly: 99,
|
|
341
341
|
priceAnnual: 948,
|
|
342
342
|
priceMonthlyIfAnnual: 79,
|
|
343
|
-
limits: { maxRepos: -1, maxMembers: -1, aiCreditsPerMonth: 1800, maxOrgs: 10, scansPerMonth:
|
|
343
|
+
limits: { maxRepos: -1, maxMembers: -1, aiCreditsPerMonth: 1800, maxOrgs: 10, scansPerMonth: 5e3 },
|
|
344
344
|
features: {
|
|
345
345
|
...ALL_FEATURES_TRUE,
|
|
346
346
|
sso: false,
|
|
@@ -399,6 +399,145 @@ var require_plans = __commonJS({
|
|
|
399
399
|
}
|
|
400
400
|
});
|
|
401
401
|
|
|
402
|
+
// ../../packages/shared/dist/graph-builder.js
|
|
403
|
+
var require_graph_builder = __commonJS({
|
|
404
|
+
"../../packages/shared/dist/graph-builder.js"(exports2) {
|
|
405
|
+
"use strict";
|
|
406
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
407
|
+
exports2.buildImportGraphData = buildImportGraphData2;
|
|
408
|
+
var LAYER_COLORS = {
|
|
409
|
+
api: "#4CAF50",
|
|
410
|
+
application: "#2196F3",
|
|
411
|
+
domain: "#FF9800",
|
|
412
|
+
infrastructure: "#F44336",
|
|
413
|
+
shared: "#9C27B0",
|
|
414
|
+
common: "#9C27B0",
|
|
415
|
+
presentation: "#4CAF50",
|
|
416
|
+
business: "#2196F3",
|
|
417
|
+
"data-access": "#F44336",
|
|
418
|
+
models: "#FF9800",
|
|
419
|
+
controllers: "#4CAF50",
|
|
420
|
+
views: "#9E9E9E",
|
|
421
|
+
ports: "#2196F3",
|
|
422
|
+
adapters: "#F44336",
|
|
423
|
+
handlers: "#4CAF50",
|
|
424
|
+
commands: "#2196F3",
|
|
425
|
+
queries: "#FF9800",
|
|
426
|
+
events: "#9C27B0",
|
|
427
|
+
config: "#607D8B"
|
|
428
|
+
};
|
|
429
|
+
function buildImportGraphData2(edges, violations, files, modules) {
|
|
430
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
431
|
+
const violationsByFile = /* @__PURE__ */ new Map();
|
|
432
|
+
for (const v of violations) {
|
|
433
|
+
violationsByFile.set(v.file, (violationsByFile.get(v.file) ?? 0) + 1);
|
|
434
|
+
}
|
|
435
|
+
const fileLoc = /* @__PURE__ */ new Map();
|
|
436
|
+
for (const f of files) {
|
|
437
|
+
if (f.linesOfCode) {
|
|
438
|
+
fileLoc.set(f.path, f.linesOfCode);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const ensureNode = (filePath, layer, module3) => {
|
|
442
|
+
if (nodeMap.has(filePath))
|
|
443
|
+
return;
|
|
444
|
+
const parts = filePath.split("/");
|
|
445
|
+
const fileName = parts[parts.length - 1] ?? filePath;
|
|
446
|
+
const label = fileName.replace(/\.(ts|tsx|js|jsx)$/, "");
|
|
447
|
+
const ext = fileName.match(/\.(service|controller|module|entity|repository|guard|pipe|middleware|dto|resolver|gateway)/);
|
|
448
|
+
nodeMap.set(filePath, {
|
|
449
|
+
id: filePath,
|
|
450
|
+
label,
|
|
451
|
+
module: module3 ?? void 0,
|
|
452
|
+
layer: layer ?? void 0,
|
|
453
|
+
type: ext ? ext[1] : "file",
|
|
454
|
+
violations: violationsByFile.get(filePath) ?? 0,
|
|
455
|
+
complexity: 0,
|
|
456
|
+
linesOfCode: fileLoc.get(filePath) ?? 0,
|
|
457
|
+
isHotspot: (violationsByFile.get(filePath) ?? 0) >= 3
|
|
458
|
+
});
|
|
459
|
+
};
|
|
460
|
+
for (const edge of edges) {
|
|
461
|
+
ensureNode(edge.source, edge.sourceLayer, edge.sourceModule);
|
|
462
|
+
ensureNode(edge.target, edge.targetLayer, edge.targetModule);
|
|
463
|
+
}
|
|
464
|
+
const circularFiles = /* @__PURE__ */ new Set();
|
|
465
|
+
for (const v of violations) {
|
|
466
|
+
if (v.type === "circular_dependency") {
|
|
467
|
+
circularFiles.add(v.file);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const graphEdges = edges.map((e) => {
|
|
471
|
+
const isCircular = circularFiles.has(e.source) && circularFiles.has(e.target);
|
|
472
|
+
const matchingViolation = violations.find((v) => v.category === "architecture" && v.file === e.source && v.message.includes(e.target.split("/").pop() ?? ""));
|
|
473
|
+
const isViolation = !!matchingViolation || isCircular;
|
|
474
|
+
let type = "import";
|
|
475
|
+
let violationType = null;
|
|
476
|
+
let message = null;
|
|
477
|
+
if (isCircular) {
|
|
478
|
+
type = "circular";
|
|
479
|
+
violationType = "circular-dependency";
|
|
480
|
+
message = `Circular dependency involving ${e.source} and ${e.target}`;
|
|
481
|
+
} else if (matchingViolation) {
|
|
482
|
+
type = "violation";
|
|
483
|
+
violationType = matchingViolation.type;
|
|
484
|
+
message = matchingViolation.message;
|
|
485
|
+
}
|
|
486
|
+
return { source: e.source, target: e.target, type, isViolation, violationType, message };
|
|
487
|
+
});
|
|
488
|
+
const moduleMap = /* @__PURE__ */ new Map();
|
|
489
|
+
for (const node of nodeMap.values()) {
|
|
490
|
+
if (node.module) {
|
|
491
|
+
const existing = moduleMap.get(node.module);
|
|
492
|
+
if (existing) {
|
|
493
|
+
existing.nodeCount++;
|
|
494
|
+
existing.violations += node.violations;
|
|
495
|
+
} else {
|
|
496
|
+
const policyMod = modules?.find((m) => m.name === node.module);
|
|
497
|
+
moduleMap.set(node.module, {
|
|
498
|
+
nodeCount: 1,
|
|
499
|
+
violations: node.violations,
|
|
500
|
+
path: policyMod?.pathPattern ?? ""
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const graphModules = Array.from(moduleMap.entries()).map(([name, data]) => ({
|
|
506
|
+
name,
|
|
507
|
+
path: data.path,
|
|
508
|
+
nodeCount: data.nodeCount,
|
|
509
|
+
violations: data.violations
|
|
510
|
+
}));
|
|
511
|
+
const layerSet = /* @__PURE__ */ new Set();
|
|
512
|
+
for (const node of nodeMap.values()) {
|
|
513
|
+
if (node.layer)
|
|
514
|
+
layerSet.add(node.layer);
|
|
515
|
+
}
|
|
516
|
+
const layers = Array.from(layerSet).map((name) => ({
|
|
517
|
+
name,
|
|
518
|
+
color: LAYER_COLORS[name] ?? "#9E9E9E"
|
|
519
|
+
}));
|
|
520
|
+
const nodes = Array.from(nodeMap.values());
|
|
521
|
+
const violationEdgeCount = graphEdges.filter((e) => e.isViolation && e.type !== "circular").length;
|
|
522
|
+
const circularEdgeCount = graphEdges.filter((e) => e.type === "circular").length;
|
|
523
|
+
return {
|
|
524
|
+
nodes,
|
|
525
|
+
edges: graphEdges,
|
|
526
|
+
modules: graphModules,
|
|
527
|
+
layers,
|
|
528
|
+
stats: {
|
|
529
|
+
totalNodes: nodes.length,
|
|
530
|
+
totalEdges: graphEdges.length,
|
|
531
|
+
violationEdges: violationEdgeCount,
|
|
532
|
+
circularEdges: circularEdgeCount,
|
|
533
|
+
modules: graphModules.length,
|
|
534
|
+
layers: layers.length
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
|
|
402
541
|
// ../../packages/shared/dist/index.js
|
|
403
542
|
var require_dist = __commonJS({
|
|
404
543
|
"../../packages/shared/dist/index.js"(exports2) {
|
|
@@ -420,9 +559,14 @@ var require_dist = __commonJS({
|
|
|
420
559
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m, p);
|
|
421
560
|
};
|
|
422
561
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
562
|
+
exports2.buildImportGraphData = void 0;
|
|
423
563
|
__exportStar(require_types(), exports2);
|
|
424
564
|
__exportStar(require_constants(), exports2);
|
|
425
565
|
__exportStar(require_plans(), exports2);
|
|
566
|
+
var graph_builder_1 = require_graph_builder();
|
|
567
|
+
Object.defineProperty(exports2, "buildImportGraphData", { enumerable: true, get: function() {
|
|
568
|
+
return graph_builder_1.buildImportGraphData;
|
|
569
|
+
} });
|
|
426
570
|
}
|
|
427
571
|
});
|
|
428
572
|
|
|
@@ -20261,6 +20405,7 @@ var os2 = __toESM(require("os"));
|
|
|
20261
20405
|
var import_chalk = __toESM(require("chalk"));
|
|
20262
20406
|
var import_policy_engine = __toESM(require_dist2());
|
|
20263
20407
|
var import_analyzers = __toESM(require_dist3());
|
|
20408
|
+
var import_shared = __toESM(require_dist());
|
|
20264
20409
|
var import_analyzers2 = __toESM(require_dist3());
|
|
20265
20410
|
|
|
20266
20411
|
// src/ai/scan-summary-generator.ts
|
|
@@ -20819,6 +20964,12 @@ async function scanCommand(targetPath, options) {
|
|
|
20819
20964
|
const blocking = result.violations.filter((v) => v.gateAction === "block");
|
|
20820
20965
|
const warns = result.violations.filter((v) => v.gateAction === "warn");
|
|
20821
20966
|
const byCat = countByCategory(result.violations);
|
|
20967
|
+
const graphData = result.importGraph && result.importGraph.length > 0 ? (0, import_shared.buildImportGraphData)(
|
|
20968
|
+
result.importGraph,
|
|
20969
|
+
result.violations,
|
|
20970
|
+
changedFiles.map((f) => ({ path: f.path, linesOfCode: f.content?.split("\n").length })),
|
|
20971
|
+
policy.modules
|
|
20972
|
+
) : void 0;
|
|
20822
20973
|
const reportData = {
|
|
20823
20974
|
repoName: path2.basename(path2.resolve(targetPath)),
|
|
20824
20975
|
violations: result.violations.map((v) => ({
|
|
@@ -20842,6 +20993,7 @@ async function scanCommand(targetPath, options) {
|
|
|
20842
20993
|
duration: Date.now() - scanStart,
|
|
20843
20994
|
usedAi: shouldRunAi,
|
|
20844
20995
|
aiCreditsUsed: 0,
|
|
20996
|
+
importGraphData: graphData,
|
|
20845
20997
|
// PR metadata from CI environment (set by GitHub Action or GitLab CI)
|
|
20846
20998
|
...process.env.RADAR_PR_NUMBER ? {
|
|
20847
20999
|
prNumber: parseInt(process.env.RADAR_PR_NUMBER, 10),
|