tech-debt-score 0.1.5 → 0.1.6

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 (48) hide show
  1. package/dist/adapters/input/FileSystemReader.d.ts.map +1 -1
  2. package/dist/adapters/input/FileSystemReader.js +4 -5
  3. package/dist/adapters/input/FileSystemReader.js.map +1 -1
  4. package/dist/adapters/output/TerminalReporter.d.ts.map +1 -1
  5. package/dist/adapters/output/TerminalReporter.js +8 -0
  6. package/dist/adapters/output/TerminalReporter.js.map +1 -1
  7. package/dist/application/config/AnalysisConfig.d.ts.map +1 -1
  8. package/dist/application/config/AnalysisConfig.js +10 -2
  9. package/dist/application/config/AnalysisConfig.js.map +1 -1
  10. package/dist/application/services/AnalysisService.d.ts.map +1 -1
  11. package/dist/application/services/AnalysisService.js +29 -11
  12. package/dist/application/services/AnalysisService.js.map +1 -1
  13. package/dist/cli/commands/analyze.d.ts.map +1 -1
  14. package/dist/cli/commands/analyze.js +8 -7
  15. package/dist/cli/commands/analyze.js.map +1 -1
  16. package/package.json +8 -2
  17. package/DEVELOPMENT.md +0 -147
  18. package/SETUP_COMPLETE.md +0 -188
  19. package/TECHNICAL_DESIGN.md +0 -563
  20. package/src/adapters/input/FileSystemReader.ts +0 -47
  21. package/src/adapters/input/TypeScriptParser.ts +0 -367
  22. package/src/adapters/output/JsonExporter.ts +0 -48
  23. package/src/adapters/output/TerminalReporter.ts +0 -94
  24. package/src/application/config/AnalysisConfig.ts +0 -58
  25. package/src/application/ports/IFileReader.ts +0 -36
  26. package/src/application/ports/IParser.ts +0 -40
  27. package/src/application/ports/IReporter.ts +0 -26
  28. package/src/application/services/AnalysisService.ts +0 -218
  29. package/src/application/services/DependencyAnalyzer.ts +0 -158
  30. package/src/application/services/DuplicationDetector.ts +0 -207
  31. package/src/cli/commands/analyze.ts +0 -77
  32. package/src/cli/index.ts +0 -81
  33. package/src/domain/entities/Finding.ts +0 -79
  34. package/src/domain/entities/Metric.ts +0 -70
  35. package/src/domain/entities/Rule.ts +0 -49
  36. package/src/domain/entities/Score.ts +0 -94
  37. package/src/domain/index.ts +0 -15
  38. package/src/domain/rules/CircularDependencyRule.ts +0 -65
  39. package/src/domain/rules/ComplexityRule.ts +0 -88
  40. package/src/domain/rules/DuplicationRule.ts +0 -70
  41. package/src/domain/rules/SizeRule.ts +0 -98
  42. package/src/domain/rules/TypeSafetyRule.ts +0 -63
  43. package/src/index.ts +0 -0
  44. package/src/shared/types.ts +0 -18
  45. package/tests/application/index.test.ts +0 -12
  46. package/tests/domain/index.test.ts +0 -14
  47. package/tests/e2e/index.test.ts +0 -13
  48. package/tsconfig.json +0 -31
@@ -1,367 +0,0 @@
1
- /**
2
- * Input Adapter: TypeScript/JavaScript Parser
3
- * Implements IParser using TypeScript Compiler API for AST-based analysis
4
- */
5
-
6
- import * as ts from 'typescript';
7
- import type { IParser, ParseResult } from '../../application/ports/IParser.js';
8
- import type { Metric } from '../../domain/entities/Metric.js';
9
- import { MetricBuilder } from '../../domain/entities/Metric.js';
10
- import type { SourceLocation } from '../../shared/types.js';
11
-
12
- /**
13
- * Helper class to extract metrics from AST nodes
14
- */
15
- class MetricExtractor {
16
- private metrics: Metric[] = [];
17
-
18
- constructor(
19
- private sourceFile: ts.SourceFile,
20
- private filePath: string
21
- ) {}
22
-
23
- /**
24
- * Node types that contribute to cyclomatic complexity
25
- */
26
- private static readonly COMPLEXITY_KINDS = new Set<ts.SyntaxKind>([
27
- ts.SyntaxKind.IfStatement,
28
- ts.SyntaxKind.ForStatement,
29
- ts.SyntaxKind.ForInStatement,
30
- ts.SyntaxKind.ForOfStatement,
31
- ts.SyntaxKind.WhileStatement,
32
- ts.SyntaxKind.DoStatement,
33
- ts.SyntaxKind.CaseClause,
34
- ts.SyntaxKind.ConditionalExpression,
35
- ts.SyntaxKind.CatchClause,
36
- ]);
37
-
38
- /**
39
- * Node types that contribute to nesting depth
40
- */
41
- private static readonly NESTING_KINDS = new Set<ts.SyntaxKind>([
42
- ts.SyntaxKind.Block,
43
- ts.SyntaxKind.IfStatement,
44
- ts.SyntaxKind.ForStatement,
45
- ts.SyntaxKind.ForInStatement,
46
- ts.SyntaxKind.ForOfStatement,
47
- ts.SyntaxKind.WhileStatement,
48
- ts.SyntaxKind.DoStatement,
49
- ts.SyntaxKind.SwitchStatement,
50
- ts.SyntaxKind.TryStatement,
51
- ]);
52
-
53
- /**
54
- * Extract all metrics from the source file
55
- */
56
- extract(): Metric[] {
57
- this.metrics = [];
58
-
59
- // File-level metrics
60
- this.extractFileMetrics();
61
-
62
- // Function-level metrics
63
- this.visit(this.sourceFile);
64
-
65
- return this.metrics;
66
- }
67
-
68
- /**
69
- * Extract file-level metrics
70
- */
71
- private extractFileMetrics(): void {
72
- const lines = this.sourceFile.getLineStarts();
73
- const lineCount = lines.length;
74
-
75
- // File length metric
76
- this.metrics.push(
77
- new MetricBuilder()
78
- .withName('file-length')
79
- .withValue(lineCount)
80
- .withFilePath(this.filePath)
81
- .build()
82
- );
83
-
84
- // Count TODO/FIXME comments
85
- const text = this.sourceFile.getFullText();
86
- const todoCount = (text.match(/\/\/\s*TODO/gi) || []).length +
87
- (text.match(/\/\*[\s\S]*?TODO[\s\S]*?\*\//gi) || []).length;
88
- const fixmeCount = (text.match(/\/\/\s*FIXME/gi) || []).length +
89
- (text.match(/\/\*[\s\S]*?FIXME[\s\S]*?\*\//gi) || []).length;
90
-
91
- if (todoCount > 0) {
92
- this.metrics.push(
93
- new MetricBuilder()
94
- .withName('todo-comments')
95
- .withValue(todoCount)
96
- .withFilePath(this.filePath)
97
- .build()
98
- );
99
- }
100
-
101
- if (fixmeCount > 0) {
102
- this.metrics.push(
103
- new MetricBuilder()
104
- .withName('fixme-comments')
105
- .withValue(fixmeCount)
106
- .withFilePath(this.filePath)
107
- .build()
108
- );
109
- }
110
- }
111
-
112
- /**
113
- * Visit AST nodes recursively
114
- */
115
- private visit(node: ts.Node): void {
116
- // Check if this is a function node
117
- if (this.isFunctionNode(node)) {
118
- this.extractFunctionMetrics(node as ts.FunctionLikeDeclaration);
119
- }
120
-
121
- // Recurse to children
122
- ts.forEachChild(node, (child) => this.visit(child));
123
- }
124
-
125
- /**
126
- * Check if node is a function-like declaration
127
- */
128
- private isFunctionNode(node: ts.Node): boolean {
129
- return ts.isFunctionDeclaration(node) ||
130
- ts.isMethodDeclaration(node) ||
131
- ts.isArrowFunction(node) ||
132
- ts.isFunctionExpression(node) ||
133
- ts.isConstructorDeclaration(node);
134
- }
135
-
136
- /**
137
- * Extract metrics from a function node
138
- */
139
- private extractFunctionMetrics(node: ts.FunctionLikeDeclaration): void {
140
- const functionName = this.getFunctionName(node);
141
- const location = this.getLocation(node);
142
-
143
- // Function length
144
- const startLine = this.sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
145
- const endLine = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line + 1;
146
- const functionLength = endLine - startLine + 1;
147
-
148
- this.metrics.push(
149
- new MetricBuilder()
150
- .withName('function-length')
151
- .withValue(functionLength)
152
- .withFilePath(this.filePath)
153
- .withContext(functionName)
154
- .withLocation(location)
155
- .build()
156
- );
157
-
158
- // Parameter count
159
- const paramCount = node.parameters.length;
160
- if (paramCount > 0) {
161
- this.metrics.push(
162
- new MetricBuilder()
163
- .withName('parameter-count')
164
- .withValue(paramCount)
165
- .withFilePath(this.filePath)
166
- .withContext(functionName)
167
- .withLocation(location)
168
- .build()
169
- );
170
- }
171
-
172
- // Cyclomatic complexity
173
- const complexity = this.calculateComplexity(node);
174
- this.metrics.push(
175
- new MetricBuilder()
176
- .withName('cyclomatic-complexity')
177
- .withValue(complexity)
178
- .withFilePath(this.filePath)
179
- .withContext(functionName)
180
- .withLocation(location)
181
- .build()
182
- );
183
-
184
- // Nesting depth
185
- const maxDepth = this.calculateNestingDepth(node);
186
- if (maxDepth > 0) {
187
- this.metrics.push(
188
- new MetricBuilder()
189
- .withName('nesting-depth')
190
- .withValue(maxDepth)
191
- .withFilePath(this.filePath)
192
- .withContext(functionName)
193
- .withLocation(location)
194
- .build()
195
- );
196
- }
197
-
198
- // Count 'any' usage in function signature
199
- const anyCount = this.countAnyUsage(node);
200
- if (anyCount > 0) {
201
- this.metrics.push(
202
- new MetricBuilder()
203
- .withName('any-usage')
204
- .withValue(anyCount)
205
- .withFilePath(this.filePath)
206
- .withContext(functionName)
207
- .withLocation(location)
208
- .build()
209
- );
210
- }
211
- }
212
-
213
- /**
214
- * Calculate cyclomatic complexity
215
- * Formula: Number of decision points + 1
216
- */
217
- private calculateComplexity(node: ts.Node): number {
218
- let complexity = 1; // Base complexity
219
-
220
- const countDecisionPoints = (n: ts.Node): void => {
221
- if (MetricExtractor.COMPLEXITY_KINDS.has(n.kind)) {
222
- complexity++;
223
- } else if (ts.isBinaryExpression(n)) {
224
- // Logical operators && and ||
225
- const op = n.operatorToken.kind;
226
- if (op === ts.SyntaxKind.AmpersandAmpersandToken ||
227
- op === ts.SyntaxKind.BarBarToken) {
228
- complexity++;
229
- }
230
- }
231
-
232
- ts.forEachChild(n, countDecisionPoints);
233
- };
234
-
235
- countDecisionPoints(node);
236
- return complexity;
237
- }
238
-
239
- /**
240
- * Calculate maximum nesting depth
241
- */
242
- private calculateNestingDepth(node: ts.Node): number {
243
- let maxDepth = 0;
244
-
245
- const traverse = (n: ts.Node, depth: number): void => {
246
- let currentDepth = depth;
247
-
248
- // Increment depth for nesting constructs using the static registry
249
- if (MetricExtractor.NESTING_KINDS.has(n.kind)) {
250
- currentDepth++;
251
- maxDepth = Math.max(maxDepth, currentDepth);
252
- }
253
-
254
- ts.forEachChild(n, (child) => traverse(child, currentDepth));
255
- };
256
-
257
- traverse(node, 0);
258
- return maxDepth;
259
- }
260
-
261
- /**
262
- * Count 'any' type usage in function signature
263
- */
264
- private countAnyUsage(node: ts.FunctionLikeDeclaration): number {
265
- let count = 0;
266
-
267
- // Check parameters
268
- for (const param of node.parameters) {
269
- if (param.type && this.isAnyType(param.type)) {
270
- count++;
271
- }
272
- }
273
-
274
- // Check return type
275
- if (node.type && this.isAnyType(node.type)) {
276
- count++;
277
- }
278
-
279
- return count;
280
- }
281
-
282
- /**
283
- * Check if a type node represents 'any'
284
- */
285
- private isAnyType(typeNode: ts.TypeNode): boolean {
286
- return typeNode.kind === ts.SyntaxKind.AnyKeyword;
287
- }
288
-
289
- /**
290
- * Get function name for context
291
- */
292
- private getFunctionName(node: ts.FunctionLikeDeclaration): string {
293
- if (ts.isFunctionDeclaration(node) && node.name) {
294
- return node.name.getText();
295
- } else if (ts.isMethodDeclaration(node) && node.name) {
296
- return node.name.getText();
297
- } else if (ts.isConstructorDeclaration(node)) {
298
- return 'constructor';
299
- }
300
- return 'anonymous function';
301
- }
302
-
303
- /**
304
- * Get source location from node
305
- */
306
- private getLocation(node: ts.Node): SourceLocation {
307
- const start = this.sourceFile.getLineAndCharacterOfPosition(node.getStart());
308
- const end = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd());
309
-
310
- return {
311
- startLine: start.line + 1,
312
- endLine: end.line + 1,
313
- startColumn: start.character,
314
- endColumn: end.character,
315
- };
316
- }
317
- }
318
-
319
- /**
320
- * TypeScript Parser using native TypeScript Compiler API
321
- */
322
- export class TypeScriptParser implements IParser {
323
- supports(filePath: string): boolean {
324
- return filePath.endsWith('.ts') ||
325
- filePath.endsWith('.tsx') ||
326
- filePath.endsWith('.js') ||
327
- filePath.endsWith('.jsx');
328
- }
329
-
330
- async parse(filePath: string, content: string): Promise<ParseResult> {
331
- try {
332
- // Create source file from content
333
- const sourceFile = ts.createSourceFile(
334
- filePath,
335
- content,
336
- ts.ScriptTarget.Latest,
337
- true, // setParentNodes
338
- this.getScriptKind(filePath)
339
- );
340
-
341
- // Extract metrics using AST traversal
342
- const extractor = new MetricExtractor(sourceFile, filePath);
343
- const metrics = extractor.extract();
344
-
345
- return {
346
- metrics,
347
- success: true,
348
- };
349
- } catch (error) {
350
- return {
351
- metrics: [],
352
- success: false,
353
- error: error instanceof Error ? error.message : 'Unknown parsing error',
354
- };
355
- }
356
- }
357
-
358
- /**
359
- * Determine script kind from file extension
360
- */
361
- private getScriptKind(filePath: string): ts.ScriptKind {
362
- if (filePath.endsWith('.tsx')) return ts.ScriptKind.TSX;
363
- if (filePath.endsWith('.jsx')) return ts.ScriptKind.JSX;
364
- if (filePath.endsWith('.ts')) return ts.ScriptKind.TS;
365
- return ts.ScriptKind.JS;
366
- }
367
- }
@@ -1,48 +0,0 @@
1
- /**
2
- * Output Adapter: JSON Exporter
3
- * Implements IReporter for JSON file output
4
- */
5
-
6
- import { writeFile } from 'node:fs/promises';
7
- import type { IReporter, AnalysisReport } from '../../application/ports/IReporter.js';
8
-
9
- export class JsonExporter implements IReporter {
10
- constructor(private readonly outputPath: string = './tech-debt-report.json') {}
11
-
12
- async generate(report: AnalysisReport): Promise<void> {
13
- const jsonReport = {
14
- version: '1.0.0',
15
- generatedAt: report.metadata.timestamp.toISOString(),
16
- score: {
17
- overall: report.score.overall,
18
- categories: report.score.categories.map(cat => ({
19
- name: cat.name,
20
- score: cat.score,
21
- weight: cat.weight,
22
- description: cat.description,
23
- })),
24
- },
25
- findings: report.findings.map(finding => ({
26
- ruleId: finding.ruleId,
27
- severity: finding.severity,
28
- message: finding.message,
29
- filePath: finding.filePath,
30
- location: finding.location ? {
31
- startLine: finding.location.startLine,
32
- endLine: finding.location.endLine,
33
- startColumn: finding.location.startColumn,
34
- endColumn: finding.location.endColumn,
35
- } : undefined,
36
- suggestion: finding.suggestion,
37
- })),
38
- metadata: {
39
- filesAnalyzed: report.metadata.filesAnalyzed,
40
- durationMs: report.metadata.duration,
41
- timestamp: report.metadata.timestamp.toISOString(),
42
- },
43
- };
44
-
45
- await writeFile(this.outputPath, JSON.stringify(jsonReport, null, 2), 'utf-8');
46
- console.log(`💾 JSON report saved to: ${this.outputPath}`);
47
- }
48
- }
@@ -1,94 +0,0 @@
1
- /**
2
- * Output Adapter: Terminal Reporter
3
- * Implements IReporter for console output
4
- */
5
-
6
- import type { IReporter, AnalysisReport } from '../../application/ports/IReporter.js';
7
-
8
- export class TerminalReporter implements IReporter {
9
- async generate(report: AnalysisReport): Promise<void> {
10
- console.log('\n');
11
- console.log('═'.repeat(60));
12
- console.log(' TECHNICAL DEBT SCORE REPORT');
13
- console.log('═'.repeat(60));
14
- console.log('\n');
15
-
16
- // Overall Score
17
- const scoreColor = this.getScoreColor(report.score.overall);
18
- console.log(`📊 Overall Score: ${scoreColor}${report.score.overall.toFixed(1)}/100${this.reset()}`);
19
- console.log(this.getScoreLabel(report.score.overall));
20
- console.log('\n');
21
-
22
- // Category Breakdown
23
- console.log('📈 Category Breakdown:');
24
- console.log('─'.repeat(60));
25
- for (const category of report.score.categories) {
26
- const bar = this.createBar(category.score);
27
- const weight = (category.weight * 100).toFixed(0);
28
- console.log(` ${category.name.padEnd(20)} ${bar} ${category.score.toFixed(1)} (${weight}%)`);
29
- }
30
- console.log('\n');
31
-
32
- // Summary Statistics
33
- console.log('📋 Analysis Summary:');
34
- console.log('─'.repeat(60));
35
- console.log(` Files Analyzed: ${report.metadata.filesAnalyzed}`);
36
- console.log(` Total Findings: ${report.findings.length}`);
37
- console.log(` Duration: ${(report.metadata.duration / 1000).toFixed(2)}s`);
38
- console.log(` Timestamp: ${report.metadata.timestamp.toISOString()}`);
39
- console.log('\n');
40
-
41
- // Top Issues
42
- if (report.findings.length > 0) {
43
- console.log('⚠️ Top Issues:');
44
- console.log('─'.repeat(60));
45
- const topFindings = report.findings
46
- .sort((a, b) => {
47
- const severityOrder = { high: 0, medium: 1, low: 2 };
48
- return severityOrder[a.severity] - severityOrder[b.severity];
49
- })
50
- .slice(0, 10);
51
-
52
- for (const finding of topFindings) {
53
- const icon = finding.severity === 'high' ? '🔴' : finding.severity === 'medium' ? '🟡' : '🟢';
54
- console.log(` ${icon} ${finding.message}`);
55
- console.log(` ${finding.filePath}${finding.location ? `:${finding.location.startLine}` : ''}`);
56
- }
57
- console.log('\n');
58
- } else if (report.metadata.filesAnalyzed > 0) {
59
- console.log('✨ No issues found! Your codebase looks clean.');
60
- console.log('\n');
61
- } else {
62
- console.log('❓ No files were analyzed. Check your configuration or directory.');
63
- console.log('\n');
64
- }
65
-
66
- console.log('═'.repeat(60));
67
- console.log('\n');
68
- }
69
-
70
- private createBar(score: number, length = 20): string {
71
- const filled = Math.round((score / 100) * length);
72
- const empty = length - filled;
73
- return `[${'█'.repeat(filled)}${'░'.repeat(empty)}]`;
74
- }
75
-
76
- private getScoreColor(score: number): string {
77
- // ANSI color codes (placeholder - could use chalk library)
78
- if (score >= 80) return '\x1b[32m'; // Green
79
- if (score >= 60) return '\x1b[33m'; // Yellow
80
- return '\x1b[31m'; // Red
81
- }
82
-
83
- private reset(): string {
84
- return '\x1b[0m';
85
- }
86
-
87
- private getScoreLabel(score: number): string {
88
- if (score >= 90) return ' ✨ Excellent - Very low technical debt';
89
- if (score >= 80) return ' ✅ Good - Manageable technical debt';
90
- if (score >= 60) return ' ⚠️ Fair - Moderate technical debt';
91
- if (score >= 40) return ' ❗ Poor - High technical debt';
92
- return ' 🚨 Critical - Very high technical debt';
93
- }
94
- }
@@ -1,58 +0,0 @@
1
- /**
2
- * Application Configuration
3
- * Configuration for running code analysis
4
- */
5
-
6
- export interface AnalysisConfig {
7
- /**
8
- * Root directory to analyze
9
- */
10
- rootPath: string;
11
-
12
- /**
13
- * File patterns to include (glob patterns)
14
- * Default: ['src/**\/*.ts', 'src/**\/*.js']
15
- */
16
- patterns: string[];
17
-
18
- /**
19
- * Patterns to ignore
20
- * Default: ['node_modules', 'dist', 'build', 'coverage', '.git']
21
- */
22
- ignore: string[];
23
-
24
- /**
25
- * Category weights for score calculation
26
- * Should sum to 1.0
27
- */
28
- weights?: {
29
- complexity: number;
30
- size: number;
31
- typeSafety: number;
32
- codeQuality: number;
33
- structure: number;
34
- };
35
- }
36
-
37
- /**
38
- * Default configuration values
39
- */
40
- export const DEFAULT_CONFIG: Omit<AnalysisConfig, 'rootPath'> = {
41
- patterns: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
42
- ignore: [
43
- '**/node_modules/**',
44
- '**/dist/**',
45
- '**/build/**',
46
- '**/coverage/**',
47
- '**/.git/**',
48
- '**/.next/**',
49
- '**/out/**',
50
- ],
51
- weights: {
52
- complexity: 0.30,
53
- size: 0.25,
54
- typeSafety: 0.20,
55
- codeQuality: 0.15,
56
- structure: 0.10,
57
- },
58
- };
@@ -1,36 +0,0 @@
1
- /**
2
- * Application Port: File Reader Interface
3
- * Input adapter interface for reading files from the filesystem
4
- */
5
-
6
- import type { FileMetadata } from '../../shared/types.js';
7
-
8
- export interface FileReadResult {
9
- content: string;
10
- metadata: FileMetadata;
11
- }
12
-
13
- export interface IFileReader {
14
- /**
15
- * Scan a directory and return matching file paths
16
- *
17
- * @param rootPath - Root directory to scan
18
- * @param patterns - Glob patterns to match (e.g., ['src/**\/*.ts'])
19
- * @param ignore - Patterns to ignore (e.g., ['node_modules', 'dist'])
20
- */
21
- scan(rootPath: string, patterns: string[], ignore: string[]): Promise<string[]>;
22
-
23
- /**
24
- * Read a single file and return its content
25
- *
26
- * @param filePath - Absolute path to the file
27
- */
28
- read(filePath: string): Promise<FileReadResult>;
29
-
30
- /**
31
- * Read multiple files in batch
32
- *
33
- * @param filePaths - Array of absolute file paths
34
- */
35
- readBatch(filePaths: string[]): Promise<FileReadResult[]>;
36
- }
@@ -1,40 +0,0 @@
1
- /**
2
- * Application Port: Parser Interface
3
- * Input adapter interface for parsing source code into AST and extracting metrics
4
- */
5
-
6
- import type { Metric } from '../../domain/entities/Metric.js';
7
-
8
- export interface ParseResult {
9
- /**
10
- * Array of metrics extracted from the source code
11
- */
12
- metrics: Metric[];
13
-
14
- /**
15
- * Indicates if parsing was successful
16
- */
17
- success: boolean;
18
-
19
- /**
20
- * Error message if parsing failed
21
- */
22
- error?: string;
23
- }
24
-
25
- export interface IParser {
26
- /**
27
- * Parse source code and extract metrics
28
- *
29
- * @param filePath - Path to the file being parsed
30
- * @param content - Source code content
31
- */
32
- parse(filePath: string, content: string): Promise<ParseResult>;
33
-
34
- /**
35
- * Check if this parser supports a given file
36
- *
37
- * @param filePath - Path to check
38
- */
39
- supports(filePath: string): boolean;
40
- }
@@ -1,26 +0,0 @@
1
- /**
2
- * Application Port: Reporter Interface
3
- * Output adapter interface for reporting analysis results
4
- */
5
-
6
- import type { Score } from '../../domain/entities/Score.js';
7
- import type { Finding } from '../../domain/entities/Finding.js';
8
-
9
- export interface AnalysisReport {
10
- score: Score;
11
- findings: Finding[];
12
- metadata: {
13
- filesAnalyzed: number;
14
- duration: number;
15
- timestamp: Date;
16
- };
17
- }
18
-
19
- export interface IReporter {
20
- /**
21
- * Generate and output a report
22
- *
23
- * @param report - The analysis report data
24
- */
25
- generate(report: AnalysisReport): Promise<void>;
26
- }