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.
- package/DEVELOPMENT.md +147 -0
- package/LICENSE +21 -0
- package/README.md +200 -0
- package/SETUP_COMPLETE.md +188 -0
- package/TECHNICAL_DESIGN.md +563 -0
- package/dist/adapters/input/FileSystemReader.d.ts +11 -0
- package/dist/adapters/input/FileSystemReader.d.ts.map +1 -0
- package/dist/adapters/input/FileSystemReader.js +41 -0
- package/dist/adapters/input/FileSystemReader.js.map +1 -0
- package/dist/adapters/input/TypeScriptParser.d.ts +17 -0
- package/dist/adapters/input/TypeScriptParser.d.ts.map +1 -0
- package/dist/adapters/input/TypeScriptParser.js +305 -0
- package/dist/adapters/input/TypeScriptParser.js.map +1 -0
- package/dist/adapters/output/JsonExporter.d.ts +11 -0
- package/dist/adapters/output/JsonExporter.d.ts.map +1 -0
- package/dist/adapters/output/JsonExporter.js +46 -0
- package/dist/adapters/output/JsonExporter.js.map +1 -0
- package/dist/adapters/output/TerminalReporter.d.ts +13 -0
- package/dist/adapters/output/TerminalReporter.d.ts.map +1 -0
- package/dist/adapters/output/TerminalReporter.js +82 -0
- package/dist/adapters/output/TerminalReporter.js.map +1 -0
- package/dist/application/config/AnalysisConfig.d.ts +36 -0
- package/dist/application/config/AnalysisConfig.d.ts.map +1 -0
- package/dist/application/config/AnalysisConfig.js +19 -0
- package/dist/application/config/AnalysisConfig.js.map +1 -0
- package/dist/application/ports/IFileReader.d.ts +32 -0
- package/dist/application/ports/IFileReader.d.ts.map +1 -0
- package/dist/application/ports/IFileReader.js +6 -0
- package/dist/application/ports/IFileReader.js.map +1 -0
- package/dist/application/ports/IParser.d.ts +35 -0
- package/dist/application/ports/IParser.d.ts.map +1 -0
- package/dist/application/ports/IParser.js +6 -0
- package/dist/application/ports/IParser.js.map +1 -0
- package/dist/application/ports/IReporter.d.ts +24 -0
- package/dist/application/ports/IReporter.d.ts.map +1 -0
- package/dist/application/ports/IReporter.js +6 -0
- package/dist/application/ports/IReporter.js.map +1 -0
- package/dist/application/services/AnalysisService.d.ts +31 -0
- package/dist/application/services/AnalysisService.d.ts.map +1 -0
- package/dist/application/services/AnalysisService.js +161 -0
- package/dist/application/services/AnalysisService.js.map +1 -0
- package/dist/application/services/DependencyAnalyzer.d.ts +29 -0
- package/dist/application/services/DependencyAnalyzer.d.ts.map +1 -0
- package/dist/application/services/DependencyAnalyzer.js +128 -0
- package/dist/application/services/DependencyAnalyzer.js.map +1 -0
- package/dist/application/services/DuplicationDetector.d.ts +46 -0
- package/dist/application/services/DuplicationDetector.d.ts.map +1 -0
- package/dist/application/services/DuplicationDetector.js +165 -0
- package/dist/application/services/DuplicationDetector.js.map +1 -0
- package/dist/cli/commands/analyze.d.ts +2 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/analyze.js +58 -0
- package/dist/cli/commands/analyze.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +76 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/domain/entities/Finding.d.ts +42 -0
- package/dist/domain/entities/Finding.d.ts.map +1 -0
- package/dist/domain/entities/Finding.js +40 -0
- package/dist/domain/entities/Finding.js.map +1 -0
- package/dist/domain/entities/Metric.d.ts +38 -0
- package/dist/domain/entities/Metric.d.ts.map +1 -0
- package/dist/domain/entities/Metric.js +36 -0
- package/dist/domain/entities/Metric.js.map +1 -0
- package/dist/domain/entities/Rule.d.ts +41 -0
- package/dist/domain/entities/Rule.d.ts.map +1 -0
- package/dist/domain/entities/Rule.js +15 -0
- package/dist/domain/entities/Rule.js.map +1 -0
- package/dist/domain/entities/Score.d.ts +62 -0
- package/dist/domain/entities/Score.d.ts.map +1 -0
- package/dist/domain/entities/Score.js +40 -0
- package/dist/domain/entities/Score.js.map +1 -0
- package/dist/domain/index.d.ts +12 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +14 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/domain/rules/CircularDependencyRule.d.ts +13 -0
- package/dist/domain/rules/CircularDependencyRule.d.ts.map +1 -0
- package/dist/domain/rules/CircularDependencyRule.js +47 -0
- package/dist/domain/rules/CircularDependencyRule.js.map +1 -0
- package/dist/domain/rules/ComplexityRule.d.ts +15 -0
- package/dist/domain/rules/ComplexityRule.d.ts.map +1 -0
- package/dist/domain/rules/ComplexityRule.js +63 -0
- package/dist/domain/rules/ComplexityRule.js.map +1 -0
- package/dist/domain/rules/DuplicationRule.d.ts +15 -0
- package/dist/domain/rules/DuplicationRule.d.ts.map +1 -0
- package/dist/domain/rules/DuplicationRule.js +51 -0
- package/dist/domain/rules/DuplicationRule.js.map +1 -0
- package/dist/domain/rules/SizeRule.d.ts +16 -0
- package/dist/domain/rules/SizeRule.d.ts.map +1 -0
- package/dist/domain/rules/SizeRule.js +70 -0
- package/dist/domain/rules/SizeRule.js.map +1 -0
- package/dist/domain/rules/TypeSafetyRule.d.ts +13 -0
- package/dist/domain/rules/TypeSafetyRule.d.ts.map +1 -0
- package/dist/domain/rules/TypeSafetyRule.js +45 -0
- package/dist/domain/rules/TypeSafetyRule.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/shared/types.d.ts +16 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +5 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +47 -0
- package/src/adapters/input/FileSystemReader.ts +51 -0
- package/src/adapters/input/TypeScriptParser.ts +367 -0
- package/src/adapters/output/JsonExporter.ts +48 -0
- package/src/adapters/output/TerminalReporter.ts +88 -0
- package/src/application/config/AnalysisConfig.ts +50 -0
- package/src/application/ports/IFileReader.ts +36 -0
- package/src/application/ports/IParser.ts +40 -0
- package/src/application/ports/IReporter.ts +26 -0
- package/src/application/services/AnalysisService.ts +199 -0
- package/src/application/services/DependencyAnalyzer.ts +158 -0
- package/src/application/services/DuplicationDetector.ts +207 -0
- package/src/cli/commands/analyze.ts +76 -0
- package/src/cli/index.ts +81 -0
- package/src/domain/entities/Finding.ts +79 -0
- package/src/domain/entities/Metric.ts +70 -0
- package/src/domain/entities/Rule.ts +49 -0
- package/src/domain/entities/Score.ts +94 -0
- package/src/domain/index.ts +15 -0
- package/src/domain/rules/CircularDependencyRule.ts +65 -0
- package/src/domain/rules/ComplexityRule.ts +88 -0
- package/src/domain/rules/DuplicationRule.ts +70 -0
- package/src/domain/rules/SizeRule.ts +98 -0
- package/src/domain/rules/TypeSafetyRule.ts +63 -0
- package/src/index.ts +0 -0
- package/src/shared/types.ts +18 -0
- package/tests/application/index.test.ts +12 -0
- package/tests/domain/index.test.ts +14 -0
- package/tests/e2e/index.test.ts +13 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Port: Reporter Interface
|
|
3
|
+
* Output adapter interface for reporting analysis results
|
|
4
|
+
*/
|
|
5
|
+
import type { Score } from '../../domain/entities/Score.js';
|
|
6
|
+
import type { Finding } from '../../domain/entities/Finding.js';
|
|
7
|
+
export interface AnalysisReport {
|
|
8
|
+
score: Score;
|
|
9
|
+
findings: Finding[];
|
|
10
|
+
metadata: {
|
|
11
|
+
filesAnalyzed: number;
|
|
12
|
+
duration: number;
|
|
13
|
+
timestamp: Date;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface IReporter {
|
|
17
|
+
/**
|
|
18
|
+
* Generate and output a report
|
|
19
|
+
*
|
|
20
|
+
* @param report - The analysis report data
|
|
21
|
+
*/
|
|
22
|
+
generate(report: AnalysisReport): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=IReporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IReporter.d.ts","sourceRoot":"","sources":["../../../src/application/ports/IReporter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAEhE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE;QACR,aAAa,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,IAAI,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IReporter.js","sourceRoot":"","sources":["../../../src/application/ports/IReporter.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Service: Analysis Service
|
|
3
|
+
* Orchestrates the entire code analysis workflow
|
|
4
|
+
*/
|
|
5
|
+
import type { IFileReader } from '../ports/IFileReader.js';
|
|
6
|
+
import type { IParser } from '../ports/IParser.js';
|
|
7
|
+
import type { IReporter, AnalysisReport } from '../ports/IReporter.js';
|
|
8
|
+
import type { AnalysisConfig } from '../config/AnalysisConfig.js';
|
|
9
|
+
import type { Rule } from '../../domain/entities/Rule.js';
|
|
10
|
+
export declare class AnalysisService {
|
|
11
|
+
private readonly fileReader;
|
|
12
|
+
private readonly parser;
|
|
13
|
+
private readonly rules;
|
|
14
|
+
private readonly reporter;
|
|
15
|
+
constructor(fileReader: IFileReader, parser: IParser, rules: Rule[], reporter: IReporter);
|
|
16
|
+
/**
|
|
17
|
+
* Run the complete analysis workflow
|
|
18
|
+
*/
|
|
19
|
+
analyze(config: AnalysisConfig): Promise<AnalysisReport>;
|
|
20
|
+
/**
|
|
21
|
+
* Analyze dependencies and code duplication
|
|
22
|
+
*/
|
|
23
|
+
private analyzeAdvancedMetrics;
|
|
24
|
+
private getCategoryWeight;
|
|
25
|
+
/**
|
|
26
|
+
* Normalize weights so they sum to 1.0
|
|
27
|
+
* This handles cases where not all categories are active
|
|
28
|
+
*/
|
|
29
|
+
private normalizeWeights;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=AnalysisService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalysisService.d.ts","sourceRoot":"","sources":["../../../src/application/services/AnalysisService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AAM1D,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAHR,UAAU,EAAE,WAAW,EACvB,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,IAAI,EAAE,EACb,QAAQ,EAAE,SAAS;IAGtC;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;IA8F9D;;OAEG;YACW,sBAAsB;IA4BpC,OAAO,CAAC,iBAAiB;IAyBzB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;CAkBzB"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Service: Analysis Service
|
|
3
|
+
* Orchestrates the entire code analysis workflow
|
|
4
|
+
*/
|
|
5
|
+
import { ScoreCalculator } from '../../domain/entities/Score.js';
|
|
6
|
+
export class AnalysisService {
|
|
7
|
+
constructor(fileReader, parser, rules, reporter) {
|
|
8
|
+
this.fileReader = fileReader;
|
|
9
|
+
this.parser = parser;
|
|
10
|
+
this.rules = rules;
|
|
11
|
+
this.reporter = reporter;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Run the complete analysis workflow
|
|
15
|
+
*/
|
|
16
|
+
async analyze(config) {
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
// 1. Scan for files
|
|
19
|
+
console.log('📁 Scanning files...');
|
|
20
|
+
const filePaths = await this.fileReader.scan(config.rootPath, config.patterns, config.ignore);
|
|
21
|
+
console.log(` Found ${filePaths.length} files`);
|
|
22
|
+
// 2. Read and parse files
|
|
23
|
+
console.log('🔍 Parsing files...');
|
|
24
|
+
const allMetrics = [];
|
|
25
|
+
const fileContents = new Map();
|
|
26
|
+
for (const filePath of filePaths) {
|
|
27
|
+
const fileResult = await this.fileReader.read(filePath);
|
|
28
|
+
fileContents.set(filePath, fileResult.content);
|
|
29
|
+
if (this.parser.supports(filePath)) {
|
|
30
|
+
const parseResult = await this.parser.parse(filePath, fileResult.content);
|
|
31
|
+
if (parseResult.success) {
|
|
32
|
+
allMetrics.push(...parseResult.metrics);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.warn(` ⚠️ Failed to parse ${filePath}: ${parseResult.error}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
console.log(` Extracted ${allMetrics.length} metrics`);
|
|
40
|
+
// 3. Analyze dependencies and duplication
|
|
41
|
+
console.log('🔗 Analyzing dependencies and duplication...');
|
|
42
|
+
const additionalMetrics = await this.analyzeAdvancedMetrics(fileContents);
|
|
43
|
+
allMetrics.push(...additionalMetrics);
|
|
44
|
+
console.log(` Added ${additionalMetrics.length} advanced metrics`);
|
|
45
|
+
// 4. Apply rules and collect findings
|
|
46
|
+
console.log('📊 Applying rules...');
|
|
47
|
+
const allFindings = [];
|
|
48
|
+
const rawCategoryScores = [];
|
|
49
|
+
for (const rule of this.rules) {
|
|
50
|
+
const findings = rule.evaluate(allMetrics);
|
|
51
|
+
allFindings.push(...findings);
|
|
52
|
+
const score = rule.calculateScore(findings);
|
|
53
|
+
rawCategoryScores.push({
|
|
54
|
+
name: rule.name,
|
|
55
|
+
score,
|
|
56
|
+
weight: this.getCategoryWeight(rule.id, config),
|
|
57
|
+
description: rule.description,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
console.log(` Generated ${allFindings.length} findings`);
|
|
61
|
+
// Normalize weights to sum to 1.0 (in case not all categories are active)
|
|
62
|
+
const categoryScores = this.normalizeWeights(rawCategoryScores);
|
|
63
|
+
// 5. Calculate overall score
|
|
64
|
+
console.log('🎯 Calculating score...');
|
|
65
|
+
const overallScore = ScoreCalculator.calculateOverall(categoryScores);
|
|
66
|
+
const finalScore = {
|
|
67
|
+
overall: overallScore,
|
|
68
|
+
categories: categoryScores,
|
|
69
|
+
timestamp: new Date(),
|
|
70
|
+
metadata: {
|
|
71
|
+
filesAnalyzed: filePaths.length,
|
|
72
|
+
totalMetrics: allMetrics.length,
|
|
73
|
+
totalFindings: allFindings.length,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
// 6. Prepare report
|
|
77
|
+
const duration = Date.now() - startTime;
|
|
78
|
+
const report = {
|
|
79
|
+
score: finalScore,
|
|
80
|
+
findings: allFindings,
|
|
81
|
+
metadata: {
|
|
82
|
+
filesAnalyzed: filePaths.length,
|
|
83
|
+
duration,
|
|
84
|
+
timestamp: new Date(),
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
// 7. Generate output
|
|
88
|
+
console.log('📋 Generating report...');
|
|
89
|
+
await this.reporter.generate(report);
|
|
90
|
+
return report;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Analyze dependencies and code duplication
|
|
94
|
+
*/
|
|
95
|
+
async analyzeAdvancedMetrics(fileContents) {
|
|
96
|
+
const { DependencyAnalyzer } = await import('./DependencyAnalyzer.js');
|
|
97
|
+
const { DuplicationDetector } = await import('./DuplicationDetector.js');
|
|
98
|
+
const depAnalyzer = new DependencyAnalyzer();
|
|
99
|
+
const dupDetector = new DuplicationDetector();
|
|
100
|
+
const metrics = [];
|
|
101
|
+
// Analyze all files
|
|
102
|
+
for (const [filePath, content] of fileContents.entries()) {
|
|
103
|
+
if (filePath.endsWith('.ts') || filePath.endsWith('.tsx') ||
|
|
104
|
+
filePath.endsWith('.js') || filePath.endsWith('.jsx')) {
|
|
105
|
+
depAnalyzer.analyzeDependencies(filePath, content);
|
|
106
|
+
dupDetector.analyzeFile(filePath, content);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Detect circular dependencies
|
|
110
|
+
const circularDeps = depAnalyzer.detectCircularDependencies();
|
|
111
|
+
metrics.push(...circularDeps);
|
|
112
|
+
// Detect code duplication
|
|
113
|
+
const duplicates = dupDetector.detectDuplicates();
|
|
114
|
+
metrics.push(...duplicates);
|
|
115
|
+
return metrics;
|
|
116
|
+
}
|
|
117
|
+
getCategoryWeight(ruleId, config) {
|
|
118
|
+
const weights = config.weights ?? {
|
|
119
|
+
complexity: 0.30,
|
|
120
|
+
size: 0.25,
|
|
121
|
+
typeSafety: 0.20,
|
|
122
|
+
codeQuality: 0.15,
|
|
123
|
+
structure: 0.10,
|
|
124
|
+
};
|
|
125
|
+
switch (ruleId) {
|
|
126
|
+
case 'complexity':
|
|
127
|
+
return weights.complexity;
|
|
128
|
+
case 'size':
|
|
129
|
+
return weights.size;
|
|
130
|
+
case 'type-safety':
|
|
131
|
+
return weights.typeSafety;
|
|
132
|
+
case 'duplication':
|
|
133
|
+
return weights.codeQuality;
|
|
134
|
+
case 'circular-dependency':
|
|
135
|
+
return weights.structure;
|
|
136
|
+
default:
|
|
137
|
+
return 0.05; // Default weight for unknown categories
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Normalize weights so they sum to 1.0
|
|
142
|
+
* This handles cases where not all categories are active
|
|
143
|
+
*/
|
|
144
|
+
normalizeWeights(categories) {
|
|
145
|
+
const totalWeight = categories.reduce((sum, cat) => sum + cat.weight, 0);
|
|
146
|
+
if (totalWeight === 0) {
|
|
147
|
+
// If all weights are 0, distribute evenly
|
|
148
|
+
const evenWeight = 1.0 / categories.length;
|
|
149
|
+
return categories.map(cat => ({
|
|
150
|
+
...cat,
|
|
151
|
+
weight: evenWeight,
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
// Normalize proportionally
|
|
155
|
+
return categories.map(cat => ({
|
|
156
|
+
...cat,
|
|
157
|
+
weight: cat.weight / totalWeight,
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=AnalysisService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalysisService.js","sourceRoot":"","sources":["../../../src/application/services/AnalysisService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Service: Dependency Analyzer
|
|
3
|
+
* Analyzes import/require statements to detect circular dependencies
|
|
4
|
+
*/
|
|
5
|
+
import type { Metric } from '../../domain/entities/Metric.js';
|
|
6
|
+
export declare class DependencyAnalyzer {
|
|
7
|
+
private dependencyGraph;
|
|
8
|
+
/**
|
|
9
|
+
* Analyze files for import statements and build dependency graph
|
|
10
|
+
*/
|
|
11
|
+
analyzeDependencies(filePath: string, content: string): void;
|
|
12
|
+
/**
|
|
13
|
+
* Detect circular dependencies using DFS
|
|
14
|
+
*/
|
|
15
|
+
detectCircularDependencies(): Metric[];
|
|
16
|
+
/**
|
|
17
|
+
* Resolve relative import to absolute path
|
|
18
|
+
*/
|
|
19
|
+
private resolveImportPath;
|
|
20
|
+
/**
|
|
21
|
+
* Get file name from path for display
|
|
22
|
+
*/
|
|
23
|
+
private getFileName;
|
|
24
|
+
/**
|
|
25
|
+
* Clear the dependency graph (useful for new analysis)
|
|
26
|
+
*/
|
|
27
|
+
clear(): void;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=DependencyAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DependencyAnalyzer.d.ts","sourceRoot":"","sources":["../../../src/application/services/DependencyAnalyzer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAQ9D,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,eAAe,CAA0C;IAEjE;;OAEG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAgC5D;;OAEG;IACH,0BAA0B,IAAI,MAAM,EAAE;IA0DtC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA0BzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Service: Dependency Analyzer
|
|
3
|
+
* Analyzes import/require statements to detect circular dependencies
|
|
4
|
+
*/
|
|
5
|
+
import * as ts from 'typescript';
|
|
6
|
+
import { resolve, dirname, join } from 'node:path';
|
|
7
|
+
import { MetricBuilder } from '../../domain/entities/Metric.js';
|
|
8
|
+
export class DependencyAnalyzer {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.dependencyGraph = new Map();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Analyze files for import statements and build dependency graph
|
|
14
|
+
*/
|
|
15
|
+
analyzeDependencies(filePath, content) {
|
|
16
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
17
|
+
const imports = [];
|
|
18
|
+
// Extract import statements
|
|
19
|
+
const visit = (node) => {
|
|
20
|
+
if (ts.isImportDeclaration(node)) {
|
|
21
|
+
const moduleSpecifier = node.moduleSpecifier;
|
|
22
|
+
if (ts.isStringLiteral(moduleSpecifier)) {
|
|
23
|
+
const importPath = this.resolveImportPath(filePath, moduleSpecifier.text);
|
|
24
|
+
if (importPath) {
|
|
25
|
+
imports.push(importPath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
ts.forEachChild(node, visit);
|
|
30
|
+
};
|
|
31
|
+
visit(sourceFile);
|
|
32
|
+
this.dependencyGraph.set(filePath, {
|
|
33
|
+
filePath,
|
|
34
|
+
imports,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Detect circular dependencies using DFS
|
|
39
|
+
*/
|
|
40
|
+
detectCircularDependencies() {
|
|
41
|
+
const metrics = [];
|
|
42
|
+
const visited = new Set();
|
|
43
|
+
const recursionStack = new Set();
|
|
44
|
+
const cycles = new Set(); // Track unique cycles
|
|
45
|
+
const dfs = (filePath, path) => {
|
|
46
|
+
if (cycles.has(filePath))
|
|
47
|
+
return; // Already found this cycle
|
|
48
|
+
visited.add(filePath);
|
|
49
|
+
recursionStack.add(filePath);
|
|
50
|
+
const node = this.dependencyGraph.get(filePath);
|
|
51
|
+
if (!node) {
|
|
52
|
+
recursionStack.delete(filePath);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
for (const importPath of node.imports) {
|
|
56
|
+
if (!visited.has(importPath)) {
|
|
57
|
+
dfs(importPath, [...path, filePath]);
|
|
58
|
+
}
|
|
59
|
+
else if (recursionStack.has(importPath)) {
|
|
60
|
+
// Found a cycle!
|
|
61
|
+
const cycleStart = path.indexOf(importPath);
|
|
62
|
+
if (cycleStart !== -1) {
|
|
63
|
+
const cycle = [...path.slice(cycleStart), importPath];
|
|
64
|
+
const cycleKey = [...cycle].sort().join('->');
|
|
65
|
+
if (!cycles.has(cycleKey)) {
|
|
66
|
+
cycles.add(cycleKey);
|
|
67
|
+
// Create metric for this cycle
|
|
68
|
+
metrics.push(new MetricBuilder()
|
|
69
|
+
.withName('circular-dependency')
|
|
70
|
+
.withValue(cycle.length)
|
|
71
|
+
.withFilePath(filePath)
|
|
72
|
+
.withContext(cycle.map(p => this.getFileName(p)).join(' → '))
|
|
73
|
+
.build());
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
recursionStack.delete(filePath);
|
|
79
|
+
};
|
|
80
|
+
// Check all nodes for cycles
|
|
81
|
+
for (const filePath of this.dependencyGraph.keys()) {
|
|
82
|
+
if (!visited.has(filePath)) {
|
|
83
|
+
dfs(filePath, []);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return metrics;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolve relative import to absolute path
|
|
90
|
+
*/
|
|
91
|
+
resolveImportPath(fromFile, importSpecifier) {
|
|
92
|
+
// Skip node_modules and external packages
|
|
93
|
+
if (!importSpecifier.startsWith('.')) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const dir = dirname(fromFile);
|
|
98
|
+
let resolvedPath = resolve(dir, importSpecifier);
|
|
99
|
+
// Try adding extensions if file doesn't exist
|
|
100
|
+
const extensions = ['.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.js'];
|
|
101
|
+
for (const ext of extensions) {
|
|
102
|
+
const pathWithExt = resolvedPath + ext;
|
|
103
|
+
// We can't check if file exists in this context, so just normalize
|
|
104
|
+
if (ext.startsWith('/')) {
|
|
105
|
+
return resolvedPath + ext;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return resolvedPath + '.ts'; // Default to .ts
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get file name from path for display
|
|
116
|
+
*/
|
|
117
|
+
getFileName(filePath) {
|
|
118
|
+
const parts = filePath.split('/');
|
|
119
|
+
return parts[parts.length - 1] ?? filePath;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Clear the dependency graph (useful for new analysis)
|
|
123
|
+
*/
|
|
124
|
+
clear() {
|
|
125
|
+
this.dependencyGraph.clear();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=DependencyAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DependencyAnalyzer.js","sourceRoot":"","sources":["../../../src/application/services/DependencyAnalyzer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAOhE,MAAM,OAAO,kBAAkB;IAA/B;QACU,oBAAe,GAAgC,IAAI,GAAG,EAAE,CAAC;IA6InE,CAAC;IA3IC;;OAEG;IACH,mBAAmB,CAAC,QAAgB,EAAE,OAAe;QACnD,MAAM,UAAU,GAAG,EAAE,CAAC,gBAAgB,CACpC,QAAQ,EACR,OAAO,EACP,EAAE,CAAC,YAAY,CAAC,MAAM,EACtB,IAAI,CACL,CAAC;QAEF,MAAM,OAAO,GAAa,EAAE,CAAC;QAE7B,4BAA4B;QAC5B,MAAM,KAAK,GAAG,CAAC,IAAa,EAAQ,EAAE;YACpC,IAAI,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC;gBAC7C,IAAI,EAAE,CAAC,eAAe,CAAC,eAAe,CAAC,EAAE,CAAC;oBACxC,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC;oBAC1E,IAAI,UAAU,EAAE,CAAC;wBACf,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBAC3B,CAAC;gBACH,CAAC;YACH,CAAC;YACD,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC,CAAC;QAEF,KAAK,CAAC,UAAU,CAAC,CAAC;QAElB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE;YACjC,QAAQ;YACR,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,0BAA0B;QACxB,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;QAClC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC,CAAC,sBAAsB;QAExD,MAAM,GAAG,GAAG,CAAC,QAAgB,EAAE,IAAc,EAAQ,EAAE;YACrD,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAAE,OAAO,CAAC,2BAA2B;YAE7D,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACtB,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAE7B,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAChD,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAChC,OAAO;YACT,CAAC;YAED,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC7B,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;gBACvC,CAAC;qBAAM,IAAI,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC1C,iBAAiB;oBACjB,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;oBAC5C,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;wBACtB,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC;wBACtD,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAE9C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;4BAC1B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;4BAErB,+BAA+B;4BAC/B,OAAO,CAAC,IAAI,CACV,IAAI,aAAa,EAAE;iCAChB,QAAQ,CAAC,qBAAqB,CAAC;iCAC/B,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;iCACvB,YAAY,CAAC,QAAQ,CAAC;iCACtB,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;iCAC5D,KAAK,EAAE,CACX,CAAC;wBACJ,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAED,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClC,CAAC,CAAC;QAEF,6BAA6B;QAC7B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC;YACnD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC3B,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACK,iBAAiB,CAAC,QAAgB,EAAE,eAAuB;QACjE,0CAA0C;QAC1C,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC9B,IAAI,YAAY,GAAG,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;YAEjD,8CAA8C;YAC9C,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;YAC5E,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;gBAC7B,MAAM,WAAW,GAAG,YAAY,GAAG,GAAG,CAAC;gBACvC,mEAAmE;gBACnE,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACxB,OAAO,YAAY,GAAG,GAAG,CAAC;gBAC5B,CAAC;YACH,CAAC;YAED,OAAO,YAAY,GAAG,KAAK,CAAC,CAAC,iBAAiB;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,QAAgB;QAClC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAClC,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,QAAQ,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Service: Code Duplication Detector
|
|
3
|
+
* Detects duplicate code blocks using token-based similarity
|
|
4
|
+
*/
|
|
5
|
+
import type { Metric } from '../../domain/entities/Metric.js';
|
|
6
|
+
export declare class DuplicationDetector {
|
|
7
|
+
private codeBlocks;
|
|
8
|
+
private readonly MIN_BLOCK_SIZE;
|
|
9
|
+
/**
|
|
10
|
+
* Analyze file for code blocks
|
|
11
|
+
*/
|
|
12
|
+
analyzeFile(filePath: string, content: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Detect duplicates across all analyzed files
|
|
15
|
+
*/
|
|
16
|
+
detectDuplicates(): Metric[];
|
|
17
|
+
/**
|
|
18
|
+
* Extract code block from function node
|
|
19
|
+
*/
|
|
20
|
+
private extractCodeBlock;
|
|
21
|
+
/**
|
|
22
|
+
* Simple tokenization (normalize whitespace)
|
|
23
|
+
*/
|
|
24
|
+
private tokenize;
|
|
25
|
+
/**
|
|
26
|
+
* Calculate similarity between two token strings
|
|
27
|
+
*/
|
|
28
|
+
private calculateSimilarity;
|
|
29
|
+
/**
|
|
30
|
+
* Calculate Levenshtein distance
|
|
31
|
+
*/
|
|
32
|
+
private levenshteinDistance;
|
|
33
|
+
/**
|
|
34
|
+
* Check if node is a function
|
|
35
|
+
*/
|
|
36
|
+
private isFunctionNode;
|
|
37
|
+
/**
|
|
38
|
+
* Get function name for context
|
|
39
|
+
*/
|
|
40
|
+
private getFunctionName;
|
|
41
|
+
/**
|
|
42
|
+
* Clear stored blocks
|
|
43
|
+
*/
|
|
44
|
+
clear(): void;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=DuplicationDetector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DuplicationDetector.d.ts","sourceRoot":"","sources":["../../../src/application/services/DuplicationDetector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAW9D,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAM;IAErC;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAsBpD;;OAEG;IACH,gBAAgB,IAAI,MAAM,EAAE;IA+C5B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAqBxB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAQhB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAc3B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA2B3B;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application Service: Code Duplication Detector
|
|
3
|
+
* Detects duplicate code blocks using token-based similarity
|
|
4
|
+
*/
|
|
5
|
+
import * as ts from 'typescript';
|
|
6
|
+
import { MetricBuilder } from '../../domain/entities/Metric.js';
|
|
7
|
+
export class DuplicationDetector {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.codeBlocks = [];
|
|
10
|
+
this.MIN_BLOCK_SIZE = 50; // Minimum token count
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Analyze file for code blocks
|
|
14
|
+
*/
|
|
15
|
+
analyzeFile(filePath, content) {
|
|
16
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
17
|
+
// Extract function bodies as code blocks
|
|
18
|
+
const visit = (node) => {
|
|
19
|
+
if (this.isFunctionNode(node)) {
|
|
20
|
+
const block = this.extractCodeBlock(sourceFile, filePath, node);
|
|
21
|
+
if (block && block.tokens.length >= this.MIN_BLOCK_SIZE) {
|
|
22
|
+
this.codeBlocks.push(block);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
ts.forEachChild(node, visit);
|
|
26
|
+
};
|
|
27
|
+
visit(sourceFile);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Detect duplicates across all analyzed files
|
|
31
|
+
*/
|
|
32
|
+
detectDuplicates() {
|
|
33
|
+
const metrics = [];
|
|
34
|
+
const seen = new Set();
|
|
35
|
+
for (let i = 0; i < this.codeBlocks.length; i++) {
|
|
36
|
+
if (seen.has(i))
|
|
37
|
+
continue;
|
|
38
|
+
const block1 = this.codeBlocks[i];
|
|
39
|
+
if (!block1)
|
|
40
|
+
continue;
|
|
41
|
+
let duplicateCount = 0;
|
|
42
|
+
for (let j = i + 1; j < this.codeBlocks.length; j++) {
|
|
43
|
+
if (seen.has(j))
|
|
44
|
+
continue;
|
|
45
|
+
const block2 = this.codeBlocks[j];
|
|
46
|
+
if (!block2)
|
|
47
|
+
continue;
|
|
48
|
+
const similarity = this.calculateSimilarity(block1.tokens, block2.tokens);
|
|
49
|
+
if (similarity >= 0.85) { // 85% similarity threshold
|
|
50
|
+
duplicateCount++;
|
|
51
|
+
seen.add(j);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (duplicateCount > 0) {
|
|
55
|
+
metrics.push(new MetricBuilder()
|
|
56
|
+
.withName('code-duplication')
|
|
57
|
+
.withValue(duplicateCount)
|
|
58
|
+
.withFilePath(block1.filePath)
|
|
59
|
+
.withContext(block1.functionName || 'code block')
|
|
60
|
+
.withLocation({
|
|
61
|
+
startLine: block1.startLine,
|
|
62
|
+
endLine: block1.endLine,
|
|
63
|
+
startColumn: 0,
|
|
64
|
+
endColumn: 0,
|
|
65
|
+
})
|
|
66
|
+
.build());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return metrics;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Extract code block from function node
|
|
73
|
+
*/
|
|
74
|
+
extractCodeBlock(sourceFile, filePath, node) {
|
|
75
|
+
const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
76
|
+
const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
|
|
77
|
+
// Tokenize the code (simple whitespace normalization)
|
|
78
|
+
const text = node.getText(sourceFile);
|
|
79
|
+
const tokens = this.tokenize(text);
|
|
80
|
+
return {
|
|
81
|
+
filePath,
|
|
82
|
+
tokens,
|
|
83
|
+
startLine: start.line + 1,
|
|
84
|
+
endLine: end.line + 1,
|
|
85
|
+
functionName: this.getFunctionName(node),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Simple tokenization (normalize whitespace)
|
|
90
|
+
*/
|
|
91
|
+
tokenize(code) {
|
|
92
|
+
return code
|
|
93
|
+
.replace(/\s+/g, ' ') // Normalize whitespace
|
|
94
|
+
.replace(/\/\*[\s\S]*?\*\//g, '') // Remove block comments
|
|
95
|
+
.replace(/\/\/.*/g, '') // Remove line comments
|
|
96
|
+
.trim();
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Calculate similarity between two token strings
|
|
100
|
+
*/
|
|
101
|
+
calculateSimilarity(tokens1, tokens2) {
|
|
102
|
+
if (tokens1 === tokens2)
|
|
103
|
+
return 1.0;
|
|
104
|
+
// Use Levenshtein distance for similarity
|
|
105
|
+
const len1 = tokens1.length;
|
|
106
|
+
const len2 = tokens2.length;
|
|
107
|
+
const maxLen = Math.max(len1, len2);
|
|
108
|
+
if (maxLen === 0)
|
|
109
|
+
return 1.0;
|
|
110
|
+
const distance = this.levenshteinDistance(tokens1, tokens2);
|
|
111
|
+
return 1 - distance / maxLen;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Calculate Levenshtein distance
|
|
115
|
+
*/
|
|
116
|
+
levenshteinDistance(str1, str2) {
|
|
117
|
+
const len1 = str1.length;
|
|
118
|
+
const len2 = str2.length;
|
|
119
|
+
const matrix = [];
|
|
120
|
+
for (let i = 0; i <= len1; i++) {
|
|
121
|
+
matrix[i] = [i];
|
|
122
|
+
}
|
|
123
|
+
for (let j = 0; j <= len2; j++) {
|
|
124
|
+
matrix[0][j] = j;
|
|
125
|
+
}
|
|
126
|
+
for (let i = 1; i <= len1; i++) {
|
|
127
|
+
for (let j = 1; j <= len2; j++) {
|
|
128
|
+
const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
|
|
129
|
+
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, // deletion
|
|
130
|
+
matrix[i][j - 1] + 1, // insertion
|
|
131
|
+
matrix[i - 1][j - 1] + cost // substitution
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return matrix[len1][len2];
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Check if node is a function
|
|
139
|
+
*/
|
|
140
|
+
isFunctionNode(node) {
|
|
141
|
+
return ts.isFunctionDeclaration(node) ||
|
|
142
|
+
ts.isMethodDeclaration(node) ||
|
|
143
|
+
ts.isArrowFunction(node) ||
|
|
144
|
+
ts.isFunctionExpression(node);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get function name for context
|
|
148
|
+
*/
|
|
149
|
+
getFunctionName(node) {
|
|
150
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
151
|
+
return node.name.getText();
|
|
152
|
+
}
|
|
153
|
+
else if (ts.isMethodDeclaration(node) && node.name) {
|
|
154
|
+
return node.name.getText();
|
|
155
|
+
}
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Clear stored blocks
|
|
160
|
+
*/
|
|
161
|
+
clear() {
|
|
162
|
+
this.codeBlocks = [];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=DuplicationDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DuplicationDetector.js","sourceRoot":"","sources":["../../../src/application/services/DuplicationDetector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/analyze.ts"],"names":[],"mappings":"AAyBA,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD7F"}
|