tech-debt-score 0.1.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.
Files changed (135) hide show
  1. package/DEVELOPMENT.md +147 -0
  2. package/LICENSE +21 -0
  3. package/README.md +200 -0
  4. package/SETUP_COMPLETE.md +188 -0
  5. package/TECHNICAL_DESIGN.md +563 -0
  6. package/dist/adapters/input/FileSystemReader.d.ts +11 -0
  7. package/dist/adapters/input/FileSystemReader.d.ts.map +1 -0
  8. package/dist/adapters/input/FileSystemReader.js +41 -0
  9. package/dist/adapters/input/FileSystemReader.js.map +1 -0
  10. package/dist/adapters/input/TypeScriptParser.d.ts +17 -0
  11. package/dist/adapters/input/TypeScriptParser.d.ts.map +1 -0
  12. package/dist/adapters/input/TypeScriptParser.js +305 -0
  13. package/dist/adapters/input/TypeScriptParser.js.map +1 -0
  14. package/dist/adapters/output/JsonExporter.d.ts +11 -0
  15. package/dist/adapters/output/JsonExporter.d.ts.map +1 -0
  16. package/dist/adapters/output/JsonExporter.js +46 -0
  17. package/dist/adapters/output/JsonExporter.js.map +1 -0
  18. package/dist/adapters/output/TerminalReporter.d.ts +13 -0
  19. package/dist/adapters/output/TerminalReporter.d.ts.map +1 -0
  20. package/dist/adapters/output/TerminalReporter.js +82 -0
  21. package/dist/adapters/output/TerminalReporter.js.map +1 -0
  22. package/dist/application/config/AnalysisConfig.d.ts +36 -0
  23. package/dist/application/config/AnalysisConfig.d.ts.map +1 -0
  24. package/dist/application/config/AnalysisConfig.js +19 -0
  25. package/dist/application/config/AnalysisConfig.js.map +1 -0
  26. package/dist/application/ports/IFileReader.d.ts +32 -0
  27. package/dist/application/ports/IFileReader.d.ts.map +1 -0
  28. package/dist/application/ports/IFileReader.js +6 -0
  29. package/dist/application/ports/IFileReader.js.map +1 -0
  30. package/dist/application/ports/IParser.d.ts +35 -0
  31. package/dist/application/ports/IParser.d.ts.map +1 -0
  32. package/dist/application/ports/IParser.js +6 -0
  33. package/dist/application/ports/IParser.js.map +1 -0
  34. package/dist/application/ports/IReporter.d.ts +24 -0
  35. package/dist/application/ports/IReporter.d.ts.map +1 -0
  36. package/dist/application/ports/IReporter.js +6 -0
  37. package/dist/application/ports/IReporter.js.map +1 -0
  38. package/dist/application/services/AnalysisService.d.ts +31 -0
  39. package/dist/application/services/AnalysisService.d.ts.map +1 -0
  40. package/dist/application/services/AnalysisService.js +161 -0
  41. package/dist/application/services/AnalysisService.js.map +1 -0
  42. package/dist/application/services/DependencyAnalyzer.d.ts +29 -0
  43. package/dist/application/services/DependencyAnalyzer.d.ts.map +1 -0
  44. package/dist/application/services/DependencyAnalyzer.js +128 -0
  45. package/dist/application/services/DependencyAnalyzer.js.map +1 -0
  46. package/dist/application/services/DuplicationDetector.d.ts +46 -0
  47. package/dist/application/services/DuplicationDetector.d.ts.map +1 -0
  48. package/dist/application/services/DuplicationDetector.js +165 -0
  49. package/dist/application/services/DuplicationDetector.js.map +1 -0
  50. package/dist/cli/commands/analyze.d.ts +2 -0
  51. package/dist/cli/commands/analyze.d.ts.map +1 -0
  52. package/dist/cli/commands/analyze.js +58 -0
  53. package/dist/cli/commands/analyze.js.map +1 -0
  54. package/dist/cli/index.d.ts +9 -0
  55. package/dist/cli/index.d.ts.map +1 -0
  56. package/dist/cli/index.js +76 -0
  57. package/dist/cli/index.js.map +1 -0
  58. package/dist/domain/entities/Finding.d.ts +42 -0
  59. package/dist/domain/entities/Finding.d.ts.map +1 -0
  60. package/dist/domain/entities/Finding.js +40 -0
  61. package/dist/domain/entities/Finding.js.map +1 -0
  62. package/dist/domain/entities/Metric.d.ts +38 -0
  63. package/dist/domain/entities/Metric.d.ts.map +1 -0
  64. package/dist/domain/entities/Metric.js +36 -0
  65. package/dist/domain/entities/Metric.js.map +1 -0
  66. package/dist/domain/entities/Rule.d.ts +41 -0
  67. package/dist/domain/entities/Rule.d.ts.map +1 -0
  68. package/dist/domain/entities/Rule.js +15 -0
  69. package/dist/domain/entities/Rule.js.map +1 -0
  70. package/dist/domain/entities/Score.d.ts +62 -0
  71. package/dist/domain/entities/Score.d.ts.map +1 -0
  72. package/dist/domain/entities/Score.js +40 -0
  73. package/dist/domain/entities/Score.js.map +1 -0
  74. package/dist/domain/index.d.ts +12 -0
  75. package/dist/domain/index.d.ts.map +1 -0
  76. package/dist/domain/index.js +14 -0
  77. package/dist/domain/index.js.map +1 -0
  78. package/dist/domain/rules/CircularDependencyRule.d.ts +13 -0
  79. package/dist/domain/rules/CircularDependencyRule.d.ts.map +1 -0
  80. package/dist/domain/rules/CircularDependencyRule.js +47 -0
  81. package/dist/domain/rules/CircularDependencyRule.js.map +1 -0
  82. package/dist/domain/rules/ComplexityRule.d.ts +15 -0
  83. package/dist/domain/rules/ComplexityRule.d.ts.map +1 -0
  84. package/dist/domain/rules/ComplexityRule.js +63 -0
  85. package/dist/domain/rules/ComplexityRule.js.map +1 -0
  86. package/dist/domain/rules/DuplicationRule.d.ts +15 -0
  87. package/dist/domain/rules/DuplicationRule.d.ts.map +1 -0
  88. package/dist/domain/rules/DuplicationRule.js +51 -0
  89. package/dist/domain/rules/DuplicationRule.js.map +1 -0
  90. package/dist/domain/rules/SizeRule.d.ts +16 -0
  91. package/dist/domain/rules/SizeRule.d.ts.map +1 -0
  92. package/dist/domain/rules/SizeRule.js +70 -0
  93. package/dist/domain/rules/SizeRule.js.map +1 -0
  94. package/dist/domain/rules/TypeSafetyRule.d.ts +13 -0
  95. package/dist/domain/rules/TypeSafetyRule.d.ts.map +1 -0
  96. package/dist/domain/rules/TypeSafetyRule.js +45 -0
  97. package/dist/domain/rules/TypeSafetyRule.js.map +1 -0
  98. package/dist/index.d.ts +2 -0
  99. package/dist/index.d.ts.map +1 -0
  100. package/dist/index.js +2 -0
  101. package/dist/index.js.map +1 -0
  102. package/dist/shared/types.d.ts +16 -0
  103. package/dist/shared/types.d.ts.map +1 -0
  104. package/dist/shared/types.js +5 -0
  105. package/dist/shared/types.js.map +1 -0
  106. package/package.json +47 -0
  107. package/src/adapters/input/FileSystemReader.ts +51 -0
  108. package/src/adapters/input/TypeScriptParser.ts +367 -0
  109. package/src/adapters/output/JsonExporter.ts +48 -0
  110. package/src/adapters/output/TerminalReporter.ts +88 -0
  111. package/src/application/config/AnalysisConfig.ts +50 -0
  112. package/src/application/ports/IFileReader.ts +36 -0
  113. package/src/application/ports/IParser.ts +40 -0
  114. package/src/application/ports/IReporter.ts +26 -0
  115. package/src/application/services/AnalysisService.ts +199 -0
  116. package/src/application/services/DependencyAnalyzer.ts +158 -0
  117. package/src/application/services/DuplicationDetector.ts +207 -0
  118. package/src/cli/commands/analyze.ts +76 -0
  119. package/src/cli/index.ts +81 -0
  120. package/src/domain/entities/Finding.ts +79 -0
  121. package/src/domain/entities/Metric.ts +70 -0
  122. package/src/domain/entities/Rule.ts +49 -0
  123. package/src/domain/entities/Score.ts +94 -0
  124. package/src/domain/index.ts +15 -0
  125. package/src/domain/rules/CircularDependencyRule.ts +65 -0
  126. package/src/domain/rules/ComplexityRule.ts +88 -0
  127. package/src/domain/rules/DuplicationRule.ts +70 -0
  128. package/src/domain/rules/SizeRule.ts +98 -0
  129. package/src/domain/rules/TypeSafetyRule.ts +63 -0
  130. package/src/index.ts +0 -0
  131. package/src/shared/types.ts +18 -0
  132. package/tests/application/index.test.ts +12 -0
  133. package/tests/domain/index.test.ts +14 -0
  134. package/tests/e2e/index.test.ts +13 -0
  135. package/tsconfig.json +31 -0
@@ -0,0 +1,305 @@
1
+ /**
2
+ * Input Adapter: TypeScript/JavaScript Parser
3
+ * Implements IParser using TypeScript Compiler API for AST-based analysis
4
+ */
5
+ import * as ts from 'typescript';
6
+ import { MetricBuilder } from '../../domain/entities/Metric.js';
7
+ /**
8
+ * Helper class to extract metrics from AST nodes
9
+ */
10
+ class MetricExtractor {
11
+ constructor(sourceFile, filePath) {
12
+ this.sourceFile = sourceFile;
13
+ this.filePath = filePath;
14
+ this.metrics = [];
15
+ }
16
+ /**
17
+ * Extract all metrics from the source file
18
+ */
19
+ extract() {
20
+ this.metrics = [];
21
+ // File-level metrics
22
+ this.extractFileMetrics();
23
+ // Function-level metrics
24
+ this.visit(this.sourceFile);
25
+ return this.metrics;
26
+ }
27
+ /**
28
+ * Extract file-level metrics
29
+ */
30
+ extractFileMetrics() {
31
+ const lines = this.sourceFile.getLineStarts();
32
+ const lineCount = lines.length;
33
+ // File length metric
34
+ this.metrics.push(new MetricBuilder()
35
+ .withName('file-length')
36
+ .withValue(lineCount)
37
+ .withFilePath(this.filePath)
38
+ .build());
39
+ // Count TODO/FIXME comments
40
+ const text = this.sourceFile.getFullText();
41
+ const todoCount = (text.match(/\/\/\s*TODO/gi) || []).length +
42
+ (text.match(/\/\*[\s\S]*?TODO[\s\S]*?\*\//gi) || []).length;
43
+ const fixmeCount = (text.match(/\/\/\s*FIXME/gi) || []).length +
44
+ (text.match(/\/\*[\s\S]*?FIXME[\s\S]*?\*\//gi) || []).length;
45
+ if (todoCount > 0) {
46
+ this.metrics.push(new MetricBuilder()
47
+ .withName('todo-comments')
48
+ .withValue(todoCount)
49
+ .withFilePath(this.filePath)
50
+ .build());
51
+ }
52
+ if (fixmeCount > 0) {
53
+ this.metrics.push(new MetricBuilder()
54
+ .withName('fixme-comments')
55
+ .withValue(fixmeCount)
56
+ .withFilePath(this.filePath)
57
+ .build());
58
+ }
59
+ }
60
+ /**
61
+ * Visit AST nodes recursively
62
+ */
63
+ visit(node) {
64
+ // Check if this is a function node
65
+ if (this.isFunctionNode(node)) {
66
+ this.extractFunctionMetrics(node);
67
+ }
68
+ // Recurse to children
69
+ ts.forEachChild(node, (child) => this.visit(child));
70
+ }
71
+ /**
72
+ * Check if node is a function-like declaration
73
+ */
74
+ isFunctionNode(node) {
75
+ return ts.isFunctionDeclaration(node) ||
76
+ ts.isMethodDeclaration(node) ||
77
+ ts.isArrowFunction(node) ||
78
+ ts.isFunctionExpression(node) ||
79
+ ts.isConstructorDeclaration(node);
80
+ }
81
+ /**
82
+ * Extract metrics from a function node
83
+ */
84
+ extractFunctionMetrics(node) {
85
+ const functionName = this.getFunctionName(node);
86
+ const location = this.getLocation(node);
87
+ // Function length
88
+ const startLine = this.sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
89
+ const endLine = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line + 1;
90
+ const functionLength = endLine - startLine + 1;
91
+ this.metrics.push(new MetricBuilder()
92
+ .withName('function-length')
93
+ .withValue(functionLength)
94
+ .withFilePath(this.filePath)
95
+ .withContext(functionName)
96
+ .withLocation(location)
97
+ .build());
98
+ // Parameter count
99
+ const paramCount = node.parameters.length;
100
+ if (paramCount > 0) {
101
+ this.metrics.push(new MetricBuilder()
102
+ .withName('parameter-count')
103
+ .withValue(paramCount)
104
+ .withFilePath(this.filePath)
105
+ .withContext(functionName)
106
+ .withLocation(location)
107
+ .build());
108
+ }
109
+ // Cyclomatic complexity
110
+ const complexity = this.calculateComplexity(node);
111
+ this.metrics.push(new MetricBuilder()
112
+ .withName('cyclomatic-complexity')
113
+ .withValue(complexity)
114
+ .withFilePath(this.filePath)
115
+ .withContext(functionName)
116
+ .withLocation(location)
117
+ .build());
118
+ // Nesting depth
119
+ const maxDepth = this.calculateNestingDepth(node);
120
+ if (maxDepth > 0) {
121
+ this.metrics.push(new MetricBuilder()
122
+ .withName('nesting-depth')
123
+ .withValue(maxDepth)
124
+ .withFilePath(this.filePath)
125
+ .withContext(functionName)
126
+ .withLocation(location)
127
+ .build());
128
+ }
129
+ // Count 'any' usage in function signature
130
+ const anyCount = this.countAnyUsage(node);
131
+ if (anyCount > 0) {
132
+ this.metrics.push(new MetricBuilder()
133
+ .withName('any-usage')
134
+ .withValue(anyCount)
135
+ .withFilePath(this.filePath)
136
+ .withContext(functionName)
137
+ .withLocation(location)
138
+ .build());
139
+ }
140
+ }
141
+ /**
142
+ * Calculate cyclomatic complexity
143
+ * Formula: Number of decision points + 1
144
+ */
145
+ calculateComplexity(node) {
146
+ let complexity = 1; // Base complexity
147
+ const countDecisionPoints = (n) => {
148
+ if (MetricExtractor.COMPLEXITY_KINDS.has(n.kind)) {
149
+ complexity++;
150
+ }
151
+ else if (ts.isBinaryExpression(n)) {
152
+ // Logical operators && and ||
153
+ const op = n.operatorToken.kind;
154
+ if (op === ts.SyntaxKind.AmpersandAmpersandToken ||
155
+ op === ts.SyntaxKind.BarBarToken) {
156
+ complexity++;
157
+ }
158
+ }
159
+ ts.forEachChild(n, countDecisionPoints);
160
+ };
161
+ countDecisionPoints(node);
162
+ return complexity;
163
+ }
164
+ /**
165
+ * Calculate maximum nesting depth
166
+ */
167
+ calculateNestingDepth(node) {
168
+ let maxDepth = 0;
169
+ const traverse = (n, depth) => {
170
+ let currentDepth = depth;
171
+ // Increment depth for nesting constructs using the static registry
172
+ if (MetricExtractor.NESTING_KINDS.has(n.kind)) {
173
+ currentDepth++;
174
+ maxDepth = Math.max(maxDepth, currentDepth);
175
+ }
176
+ ts.forEachChild(n, (child) => traverse(child, currentDepth));
177
+ };
178
+ traverse(node, 0);
179
+ return maxDepth;
180
+ }
181
+ /**
182
+ * Count 'any' type usage in function signature
183
+ */
184
+ countAnyUsage(node) {
185
+ let count = 0;
186
+ // Check parameters
187
+ for (const param of node.parameters) {
188
+ if (param.type && this.isAnyType(param.type)) {
189
+ count++;
190
+ }
191
+ }
192
+ // Check return type
193
+ if (node.type && this.isAnyType(node.type)) {
194
+ count++;
195
+ }
196
+ return count;
197
+ }
198
+ /**
199
+ * Check if a type node represents 'any'
200
+ */
201
+ isAnyType(typeNode) {
202
+ return typeNode.kind === ts.SyntaxKind.AnyKeyword;
203
+ }
204
+ /**
205
+ * Get function name for context
206
+ */
207
+ getFunctionName(node) {
208
+ if (ts.isFunctionDeclaration(node) && node.name) {
209
+ return node.name.getText();
210
+ }
211
+ else if (ts.isMethodDeclaration(node) && node.name) {
212
+ return node.name.getText();
213
+ }
214
+ else if (ts.isConstructorDeclaration(node)) {
215
+ return 'constructor';
216
+ }
217
+ return 'anonymous function';
218
+ }
219
+ /**
220
+ * Get source location from node
221
+ */
222
+ getLocation(node) {
223
+ const start = this.sourceFile.getLineAndCharacterOfPosition(node.getStart());
224
+ const end = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd());
225
+ return {
226
+ startLine: start.line + 1,
227
+ endLine: end.line + 1,
228
+ startColumn: start.character,
229
+ endColumn: end.character,
230
+ };
231
+ }
232
+ }
233
+ /**
234
+ * Node types that contribute to cyclomatic complexity
235
+ */
236
+ MetricExtractor.COMPLEXITY_KINDS = new Set([
237
+ ts.SyntaxKind.IfStatement,
238
+ ts.SyntaxKind.ForStatement,
239
+ ts.SyntaxKind.ForInStatement,
240
+ ts.SyntaxKind.ForOfStatement,
241
+ ts.SyntaxKind.WhileStatement,
242
+ ts.SyntaxKind.DoStatement,
243
+ ts.SyntaxKind.CaseClause,
244
+ ts.SyntaxKind.ConditionalExpression,
245
+ ts.SyntaxKind.CatchClause,
246
+ ]);
247
+ /**
248
+ * Node types that contribute to nesting depth
249
+ */
250
+ MetricExtractor.NESTING_KINDS = new Set([
251
+ ts.SyntaxKind.Block,
252
+ ts.SyntaxKind.IfStatement,
253
+ ts.SyntaxKind.ForStatement,
254
+ ts.SyntaxKind.ForInStatement,
255
+ ts.SyntaxKind.ForOfStatement,
256
+ ts.SyntaxKind.WhileStatement,
257
+ ts.SyntaxKind.DoStatement,
258
+ ts.SyntaxKind.SwitchStatement,
259
+ ts.SyntaxKind.TryStatement,
260
+ ]);
261
+ /**
262
+ * TypeScript Parser using native TypeScript Compiler API
263
+ */
264
+ export class TypeScriptParser {
265
+ supports(filePath) {
266
+ return filePath.endsWith('.ts') ||
267
+ filePath.endsWith('.tsx') ||
268
+ filePath.endsWith('.js') ||
269
+ filePath.endsWith('.jsx');
270
+ }
271
+ async parse(filePath, content) {
272
+ try {
273
+ // Create source file from content
274
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, // setParentNodes
275
+ this.getScriptKind(filePath));
276
+ // Extract metrics using AST traversal
277
+ const extractor = new MetricExtractor(sourceFile, filePath);
278
+ const metrics = extractor.extract();
279
+ return {
280
+ metrics,
281
+ success: true,
282
+ };
283
+ }
284
+ catch (error) {
285
+ return {
286
+ metrics: [],
287
+ success: false,
288
+ error: error instanceof Error ? error.message : 'Unknown parsing error',
289
+ };
290
+ }
291
+ }
292
+ /**
293
+ * Determine script kind from file extension
294
+ */
295
+ getScriptKind(filePath) {
296
+ if (filePath.endsWith('.tsx'))
297
+ return ts.ScriptKind.TSX;
298
+ if (filePath.endsWith('.jsx'))
299
+ return ts.ScriptKind.JSX;
300
+ if (filePath.endsWith('.ts'))
301
+ return ts.ScriptKind.TS;
302
+ return ts.ScriptKind.JS;
303
+ }
304
+ }
305
+ //# sourceMappingURL=TypeScriptParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TypeScriptParser.js","sourceRoot":"","sources":["../../../src/adapters/input/TypeScriptParser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Output Adapter: JSON Exporter
3
+ * Implements IReporter for JSON file output
4
+ */
5
+ import type { IReporter, AnalysisReport } from '../../application/ports/IReporter.js';
6
+ export declare class JsonExporter implements IReporter {
7
+ private readonly outputPath;
8
+ constructor(outputPath?: string);
9
+ generate(report: AnalysisReport): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=JsonExporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonExporter.d.ts","sourceRoot":"","sources":["../../../src/adapters/output/JsonExporter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAEtF,qBAAa,YAAa,YAAW,SAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,GAAE,MAAkC;IAErE,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAoCtD"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Output Adapter: JSON Exporter
3
+ * Implements IReporter for JSON file output
4
+ */
5
+ import { writeFile } from 'node:fs/promises';
6
+ export class JsonExporter {
7
+ constructor(outputPath = './tech-debt-report.json') {
8
+ this.outputPath = outputPath;
9
+ }
10
+ async generate(report) {
11
+ const jsonReport = {
12
+ version: '1.0.0',
13
+ generatedAt: report.metadata.timestamp.toISOString(),
14
+ score: {
15
+ overall: report.score.overall,
16
+ categories: report.score.categories.map(cat => ({
17
+ name: cat.name,
18
+ score: cat.score,
19
+ weight: cat.weight,
20
+ description: cat.description,
21
+ })),
22
+ },
23
+ findings: report.findings.map(finding => ({
24
+ ruleId: finding.ruleId,
25
+ severity: finding.severity,
26
+ message: finding.message,
27
+ filePath: finding.filePath,
28
+ location: finding.location ? {
29
+ startLine: finding.location.startLine,
30
+ endLine: finding.location.endLine,
31
+ startColumn: finding.location.startColumn,
32
+ endColumn: finding.location.endColumn,
33
+ } : undefined,
34
+ suggestion: finding.suggestion,
35
+ })),
36
+ metadata: {
37
+ filesAnalyzed: report.metadata.filesAnalyzed,
38
+ durationMs: report.metadata.duration,
39
+ timestamp: report.metadata.timestamp.toISOString(),
40
+ },
41
+ };
42
+ await writeFile(this.outputPath, JSON.stringify(jsonReport, null, 2), 'utf-8');
43
+ console.log(`💾 JSON report saved to: ${this.outputPath}`);
44
+ }
45
+ }
46
+ //# sourceMappingURL=JsonExporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonExporter.js","sourceRoot":"","sources":["../../../src/adapters/output/JsonExporter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG7C,MAAM,OAAO,YAAY;IACvB,YAA6B,aAAqB,yBAAyB;QAA9C,eAAU,GAAV,UAAU,CAAoC;IAAG,CAAC;IAE/E,KAAK,CAAC,QAAQ,CAAC,MAAsB;QACnC,MAAM,UAAU,GAAG;YACjB,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE;YACpD,KAAK,EAAE;gBACL,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO;gBAC7B,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAC9C,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,KAAK,EAAE,GAAG,CAAC,KAAK;oBAChB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,WAAW,EAAE,GAAG,CAAC,WAAW;iBAC7B,CAAC,CAAC;aACJ;YACD,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBACxC,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAC3B,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS;oBACrC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,OAAO;oBACjC,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,WAAW;oBACzC,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS;iBACtC,CAAC,CAAC,CAAC,SAAS;gBACb,UAAU,EAAE,OAAO,CAAC,UAAU;aAC/B,CAAC,CAAC;YACH,QAAQ,EAAE;gBACR,aAAa,EAAE,MAAM,CAAC,QAAQ,CAAC,aAAa;gBAC5C,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ;gBACpC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE;aACnD;SACF,CAAC;QAEF,MAAM,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC/E,OAAO,CAAC,GAAG,CAAC,4BAA4B,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IAC7D,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Output Adapter: Terminal Reporter
3
+ * Implements IReporter for console output
4
+ */
5
+ import type { IReporter, AnalysisReport } from '../../application/ports/IReporter.js';
6
+ export declare class TerminalReporter implements IReporter {
7
+ generate(report: AnalysisReport): Promise<void>;
8
+ private createBar;
9
+ private getScoreColor;
10
+ private reset;
11
+ private getScoreLabel;
12
+ }
13
+ //# sourceMappingURL=TerminalReporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TerminalReporter.d.ts","sourceRoot":"","sources":["../../../src/adapters/output/TerminalReporter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAEtF,qBAAa,gBAAiB,YAAW,SAAS;IAC1C,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAuDrD,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,aAAa;CAOtB"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Output Adapter: Terminal Reporter
3
+ * Implements IReporter for console output
4
+ */
5
+ export class TerminalReporter {
6
+ async generate(report) {
7
+ console.log('\n');
8
+ console.log('═'.repeat(60));
9
+ console.log(' TECHNICAL DEBT SCORE REPORT');
10
+ console.log('═'.repeat(60));
11
+ console.log('\n');
12
+ // Overall Score
13
+ const scoreColor = this.getScoreColor(report.score.overall);
14
+ console.log(`📊 Overall Score: ${scoreColor}${report.score.overall.toFixed(1)}/100${this.reset()}`);
15
+ console.log(this.getScoreLabel(report.score.overall));
16
+ console.log('\n');
17
+ // Category Breakdown
18
+ console.log('📈 Category Breakdown:');
19
+ console.log('─'.repeat(60));
20
+ for (const category of report.score.categories) {
21
+ const bar = this.createBar(category.score);
22
+ const weight = (category.weight * 100).toFixed(0);
23
+ console.log(` ${category.name.padEnd(20)} ${bar} ${category.score.toFixed(1)} (${weight}%)`);
24
+ }
25
+ console.log('\n');
26
+ // Summary Statistics
27
+ console.log('📋 Analysis Summary:');
28
+ console.log('─'.repeat(60));
29
+ console.log(` Files Analyzed: ${report.metadata.filesAnalyzed}`);
30
+ console.log(` Total Findings: ${report.findings.length}`);
31
+ console.log(` Duration: ${(report.metadata.duration / 1000).toFixed(2)}s`);
32
+ console.log(` Timestamp: ${report.metadata.timestamp.toISOString()}`);
33
+ console.log('\n');
34
+ // Top Issues
35
+ if (report.findings.length > 0) {
36
+ console.log('⚠️ Top Issues:');
37
+ console.log('─'.repeat(60));
38
+ const topFindings = report.findings
39
+ .sort((a, b) => {
40
+ const severityOrder = { high: 0, medium: 1, low: 2 };
41
+ return severityOrder[a.severity] - severityOrder[b.severity];
42
+ })
43
+ .slice(0, 10);
44
+ for (const finding of topFindings) {
45
+ const icon = finding.severity === 'high' ? '🔴' : finding.severity === 'medium' ? '🟡' : '🟢';
46
+ console.log(` ${icon} ${finding.message}`);
47
+ console.log(` ${finding.filePath}${finding.location ? `:${finding.location.startLine}` : ''}`);
48
+ }
49
+ console.log('\n');
50
+ }
51
+ console.log('═'.repeat(60));
52
+ console.log('\n');
53
+ }
54
+ createBar(score, length = 20) {
55
+ const filled = Math.round((score / 100) * length);
56
+ const empty = length - filled;
57
+ return `[${'█'.repeat(filled)}${'░'.repeat(empty)}]`;
58
+ }
59
+ getScoreColor(score) {
60
+ // ANSI color codes (placeholder - could use chalk library)
61
+ if (score >= 80)
62
+ return '\x1b[32m'; // Green
63
+ if (score >= 60)
64
+ return '\x1b[33m'; // Yellow
65
+ return '\x1b[31m'; // Red
66
+ }
67
+ reset() {
68
+ return '\x1b[0m';
69
+ }
70
+ getScoreLabel(score) {
71
+ if (score >= 90)
72
+ return ' ✨ Excellent - Very low technical debt';
73
+ if (score >= 80)
74
+ return ' ✅ Good - Manageable technical debt';
75
+ if (score >= 60)
76
+ return ' ⚠️ Fair - Moderate technical debt';
77
+ if (score >= 40)
78
+ return ' ❗ Poor - High technical debt';
79
+ return ' 🚨 Critical - Very high technical debt';
80
+ }
81
+ }
82
+ //# sourceMappingURL=TerminalReporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TerminalReporter.js","sourceRoot":"","sources":["../../../src/adapters/output/TerminalReporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Application Configuration
3
+ * Configuration for running code analysis
4
+ */
5
+ export interface AnalysisConfig {
6
+ /**
7
+ * Root directory to analyze
8
+ */
9
+ rootPath: string;
10
+ /**
11
+ * File patterns to include (glob patterns)
12
+ * Default: ['src/**\/*.ts', 'src/**\/*.js']
13
+ */
14
+ patterns: string[];
15
+ /**
16
+ * Patterns to ignore
17
+ * Default: ['node_modules', 'dist', 'build', 'coverage', '.git']
18
+ */
19
+ ignore: string[];
20
+ /**
21
+ * Category weights for score calculation
22
+ * Should sum to 1.0
23
+ */
24
+ weights?: {
25
+ complexity: number;
26
+ size: number;
27
+ typeSafety: number;
28
+ codeQuality: number;
29
+ structure: number;
30
+ };
31
+ }
32
+ /**
33
+ * Default configuration values
34
+ */
35
+ export declare const DEFAULT_CONFIG: Omit<AnalysisConfig, 'rootPath'>;
36
+ //# sourceMappingURL=AnalysisConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalysisConfig.d.ts","sourceRoot":"","sources":["../../../src/application/config/AnalysisConfig.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;IAEnB;;;OAGG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE;QACR,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,CAU3D,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Application Configuration
3
+ * Configuration for running code analysis
4
+ */
5
+ /**
6
+ * Default configuration values
7
+ */
8
+ export const DEFAULT_CONFIG = {
9
+ patterns: ['src/**/*.ts', 'src/**/*.js'],
10
+ ignore: ['node_modules', 'dist', 'build', 'coverage', '.git'],
11
+ weights: {
12
+ complexity: 0.30,
13
+ size: 0.25,
14
+ typeSafety: 0.20,
15
+ codeQuality: 0.15,
16
+ structure: 0.10,
17
+ },
18
+ };
19
+ //# sourceMappingURL=AnalysisConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalysisConfig.js","sourceRoot":"","sources":["../../../src/application/config/AnalysisConfig.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiCH;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAqC;IAC9D,QAAQ,EAAE,CAAC,aAAa,EAAE,aAAa,CAAC;IACxC,MAAM,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC;IAC7D,OAAO,EAAE;QACP,UAAU,EAAE,IAAI;QAChB,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,IAAI;QAChB,WAAW,EAAE,IAAI;QACjB,SAAS,EAAE,IAAI;KAChB;CACF,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Application Port: File Reader Interface
3
+ * Input adapter interface for reading files from the filesystem
4
+ */
5
+ import type { FileMetadata } from '../../shared/types.js';
6
+ export interface FileReadResult {
7
+ content: string;
8
+ metadata: FileMetadata;
9
+ }
10
+ export interface IFileReader {
11
+ /**
12
+ * Scan a directory and return matching file paths
13
+ *
14
+ * @param rootPath - Root directory to scan
15
+ * @param patterns - Glob patterns to match (e.g., ['src/**\/*.ts'])
16
+ * @param ignore - Patterns to ignore (e.g., ['node_modules', 'dist'])
17
+ */
18
+ scan(rootPath: string, patterns: string[], ignore: string[]): Promise<string[]>;
19
+ /**
20
+ * Read a single file and return its content
21
+ *
22
+ * @param filePath - Absolute path to the file
23
+ */
24
+ read(filePath: string): Promise<FileReadResult>;
25
+ /**
26
+ * Read multiple files in batch
27
+ *
28
+ * @param filePaths - Array of absolute file paths
29
+ */
30
+ readBatch(filePaths: string[]): Promise<FileReadResult[]>;
31
+ }
32
+ //# sourceMappingURL=IFileReader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IFileReader.d.ts","sourceRoot":"","sources":["../../../src/application/ports/IFileReader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;;;OAMG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEhF;;;;OAIG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEhD;;;;OAIG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;CAC3D"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Application Port: File Reader Interface
3
+ * Input adapter interface for reading files from the filesystem
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=IFileReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IFileReader.js","sourceRoot":"","sources":["../../../src/application/ports/IFileReader.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Application Port: Parser Interface
3
+ * Input adapter interface for parsing source code into AST and extracting metrics
4
+ */
5
+ import type { Metric } from '../../domain/entities/Metric.js';
6
+ export interface ParseResult {
7
+ /**
8
+ * Array of metrics extracted from the source code
9
+ */
10
+ metrics: Metric[];
11
+ /**
12
+ * Indicates if parsing was successful
13
+ */
14
+ success: boolean;
15
+ /**
16
+ * Error message if parsing failed
17
+ */
18
+ error?: string;
19
+ }
20
+ export interface IParser {
21
+ /**
22
+ * Parse source code and extract metrics
23
+ *
24
+ * @param filePath - Path to the file being parsed
25
+ * @param content - Source code content
26
+ */
27
+ parse(filePath: string, content: string): Promise<ParseResult>;
28
+ /**
29
+ * Check if this parser supports a given file
30
+ *
31
+ * @param filePath - Path to check
32
+ */
33
+ supports(filePath: string): boolean;
34
+ }
35
+ //# sourceMappingURL=IParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IParser.d.ts","sourceRoot":"","sources":["../../../src/application/ports/IParser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAE9D,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAE/D;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CACrC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Application Port: Parser Interface
3
+ * Input adapter interface for parsing source code into AST and extracting metrics
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=IParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IParser.js","sourceRoot":"","sources":["../../../src/application/ports/IParser.ts"],"names":[],"mappings":"AAAA;;;GAGG"}