archicore 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/README.md +530 -0
- package/dist/analyzers/dead-code.d.ts +95 -0
- package/dist/analyzers/dead-code.js +327 -0
- package/dist/analyzers/duplication.d.ts +90 -0
- package/dist/analyzers/duplication.js +344 -0
- package/dist/analyzers/security.d.ts +79 -0
- package/dist/analyzers/security.js +484 -0
- package/dist/architecture/index.d.ts +35 -0
- package/dist/architecture/index.js +249 -0
- package/dist/cli/commands/analyzers.d.ts +6 -0
- package/dist/cli/commands/analyzers.js +431 -0
- package/dist/cli/commands/export.d.ts +6 -0
- package/dist/cli/commands/export.js +78 -0
- package/dist/cli/commands/index.d.ts +8 -0
- package/dist/cli/commands/index.js +8 -0
- package/dist/cli/commands/init.d.ts +26 -0
- package/dist/cli/commands/init.js +140 -0
- package/dist/cli/commands/interactive.d.ts +7 -0
- package/dist/cli/commands/interactive.js +522 -0
- package/dist/cli/commands/projects.d.ts +6 -0
- package/dist/cli/commands/projects.js +249 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.js +7 -0
- package/dist/cli/ui/box.d.ts +17 -0
- package/dist/cli/ui/box.js +62 -0
- package/dist/cli/ui/colors.d.ts +49 -0
- package/dist/cli/ui/colors.js +86 -0
- package/dist/cli/ui/index.d.ts +9 -0
- package/dist/cli/ui/index.js +9 -0
- package/dist/cli/ui/prompt.d.ts +34 -0
- package/dist/cli/ui/prompt.js +122 -0
- package/dist/cli/ui/spinner.d.ts +29 -0
- package/dist/cli/ui/spinner.js +80 -0
- package/dist/cli/ui/table.d.ts +33 -0
- package/dist/cli/ui/table.js +84 -0
- package/dist/cli/utils/config.d.ts +23 -0
- package/dist/cli/utils/config.js +73 -0
- package/dist/cli/utils/index.d.ts +6 -0
- package/dist/cli/utils/index.js +6 -0
- package/dist/cli/utils/session.d.ts +27 -0
- package/dist/cli/utils/session.js +117 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +295 -0
- package/dist/code-index/ast-parser.d.ts +16 -0
- package/dist/code-index/ast-parser.js +330 -0
- package/dist/code-index/dependency-graph.d.ts +16 -0
- package/dist/code-index/dependency-graph.js +161 -0
- package/dist/code-index/index.d.ts +44 -0
- package/dist/code-index/index.js +124 -0
- package/dist/code-index/symbol-extractor.d.ts +13 -0
- package/dist/code-index/symbol-extractor.js +150 -0
- package/dist/export/index.d.ts +92 -0
- package/dist/export/index.js +676 -0
- package/dist/github/github-service.d.ts +146 -0
- package/dist/github/github-service.js +609 -0
- package/dist/impact-engine/index.d.ts +25 -0
- package/dist/impact-engine/index.js +284 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +149 -0
- package/dist/metrics/index.d.ts +136 -0
- package/dist/metrics/index.js +525 -0
- package/dist/orchestrator/deepseek-optimizer.d.ts +67 -0
- package/dist/orchestrator/deepseek-optimizer.js +320 -0
- package/dist/orchestrator/index.d.ts +34 -0
- package/dist/orchestrator/index.js +305 -0
- package/dist/pr-guardian/index.d.ts +143 -0
- package/dist/pr-guardian/index.js +553 -0
- package/dist/refactoring/index.d.ts +108 -0
- package/dist/refactoring/index.js +580 -0
- package/dist/rules-engine/index.d.ts +129 -0
- package/dist/rules-engine/index.js +482 -0
- package/dist/semantic-memory/embedding-service.d.ts +24 -0
- package/dist/semantic-memory/embedding-service.js +120 -0
- package/dist/semantic-memory/index.d.ts +45 -0
- package/dist/semantic-memory/index.js +206 -0
- package/dist/semantic-memory/vector-store.d.ts +27 -0
- package/dist/semantic-memory/vector-store.js +166 -0
- package/dist/server/index.d.ts +28 -0
- package/dist/server/index.js +141 -0
- package/dist/server/middleware/api-auth.d.ts +43 -0
- package/dist/server/middleware/api-auth.js +256 -0
- package/dist/server/routes/admin.d.ts +5 -0
- package/dist/server/routes/admin.js +123 -0
- package/dist/server/routes/api.d.ts +7 -0
- package/dist/server/routes/api.js +362 -0
- package/dist/server/routes/auth.d.ts +16 -0
- package/dist/server/routes/auth.js +191 -0
- package/dist/server/routes/developer.d.ts +8 -0
- package/dist/server/routes/developer.js +439 -0
- package/dist/server/routes/github.d.ts +7 -0
- package/dist/server/routes/github.js +495 -0
- package/dist/server/routes/upload.d.ts +7 -0
- package/dist/server/routes/upload.js +196 -0
- package/dist/server/services/api-key-service.d.ts +81 -0
- package/dist/server/services/api-key-service.js +281 -0
- package/dist/server/services/auth-service.d.ts +40 -0
- package/dist/server/services/auth-service.js +315 -0
- package/dist/server/services/project-service.d.ts +123 -0
- package/dist/server/services/project-service.js +533 -0
- package/dist/server/services/token-service.d.ts +107 -0
- package/dist/server/services/token-service.js +416 -0
- package/dist/server/services/upload-service.d.ts +93 -0
- package/dist/server/services/upload-service.js +464 -0
- package/dist/types/api.d.ts +188 -0
- package/dist/types/api.js +86 -0
- package/dist/types/github.d.ts +335 -0
- package/dist/types/github.js +5 -0
- package/dist/types/index.d.ts +265 -0
- package/dist/types/index.js +32 -0
- package/dist/types/user.d.ts +69 -0
- package/dist/types/user.js +42 -0
- package/dist/utils/file-utils.d.ts +20 -0
- package/dist/utils/file-utils.js +163 -0
- package/dist/utils/logger.d.ts +17 -0
- package/dist/utils/logger.js +41 -0
- package/dist/watcher/index.d.ts +125 -0
- package/dist/watcher/index.js +397 -0
- package/package.json +71 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dead Code Detector
|
|
3
|
+
*
|
|
4
|
+
* Обнаружение неиспользуемого кода:
|
|
5
|
+
* - Неиспользуемые экспорты
|
|
6
|
+
* - Неиспользуемые переменные
|
|
7
|
+
* - Unreachable code
|
|
8
|
+
* - Пустые функции/классы
|
|
9
|
+
* - Закомментированный код
|
|
10
|
+
*/
|
|
11
|
+
import { SymbolKind } from '../types/index.js';
|
|
12
|
+
import { Logger } from '../utils/logger.js';
|
|
13
|
+
export class DeadCodeDetector {
|
|
14
|
+
/**
|
|
15
|
+
* Анализ мёртвого кода
|
|
16
|
+
*/
|
|
17
|
+
async analyze(graph, symbols, fileContents) {
|
|
18
|
+
Logger.progress('Analyzing dead code...');
|
|
19
|
+
const unusedExports = this.findUnusedExports(graph, symbols);
|
|
20
|
+
const unusedVariables = this.findUnusedVariables(symbols, fileContents);
|
|
21
|
+
const unreachableCode = this.findUnreachableCode(fileContents);
|
|
22
|
+
const emptyBlocks = this.findEmptyBlocks(fileContents);
|
|
23
|
+
const commentedCode = this.findCommentedCode(fileContents);
|
|
24
|
+
const summary = this.calculateSummary(unusedExports, unusedVariables, unreachableCode, emptyBlocks, commentedCode);
|
|
25
|
+
Logger.success(`Dead code analysis complete: ${summary.totalIssues} issues found`);
|
|
26
|
+
return {
|
|
27
|
+
unusedExports,
|
|
28
|
+
unusedVariables,
|
|
29
|
+
unreachableCode,
|
|
30
|
+
emptyBlocks,
|
|
31
|
+
commentedCode,
|
|
32
|
+
summary
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Поиск неиспользуемых экспортов
|
|
37
|
+
*/
|
|
38
|
+
findUnusedExports(graph, symbols) {
|
|
39
|
+
const unusedExports = [];
|
|
40
|
+
const usedSymbols = new Set();
|
|
41
|
+
// Собираем все используемые символы из графа зависимостей
|
|
42
|
+
for (const [, edges] of graph.edges) {
|
|
43
|
+
for (const edge of edges) {
|
|
44
|
+
usedSymbols.add(edge.to);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Проверяем все экспортируемые символы
|
|
48
|
+
for (const [, symbol] of symbols) {
|
|
49
|
+
if (symbol.exports) {
|
|
50
|
+
// Проверяем, используется ли символ
|
|
51
|
+
const isUsed = usedSymbols.has(symbol.name) ||
|
|
52
|
+
usedSymbols.has(`${symbol.location.filePath}:${symbol.name}`);
|
|
53
|
+
// Пропускаем entry points (index.ts, main.ts и т.д.)
|
|
54
|
+
const isEntryPoint = symbol.location.filePath.match(/(index|main|app)\.(ts|js|tsx|jsx)$/);
|
|
55
|
+
if (!isUsed && !isEntryPoint) {
|
|
56
|
+
unusedExports.push({
|
|
57
|
+
name: symbol.name,
|
|
58
|
+
type: symbol.kind,
|
|
59
|
+
file: symbol.location.filePath,
|
|
60
|
+
line: symbol.location.startLine,
|
|
61
|
+
suggestion: this.getSuggestionForUnusedExport(symbol)
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return unusedExports;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Поиск неиспользуемых переменных
|
|
70
|
+
*/
|
|
71
|
+
findUnusedVariables(_symbols, fileContents) {
|
|
72
|
+
const unusedVariables = [];
|
|
73
|
+
for (const [filePath, content] of fileContents) {
|
|
74
|
+
// Ищем объявления переменных
|
|
75
|
+
const varPatterns = [
|
|
76
|
+
/(?:const|let|var)\s+(\w+)\s*[=:]/g, // const x = ...
|
|
77
|
+
/(?:const|let|var)\s+\{\s*([^}]+)\s*\}/g, // const { x, y } = ...
|
|
78
|
+
/function\s+(\w+)\s*\(/g, // function foo()
|
|
79
|
+
/(\w+)\s*:\s*(?:string|number|boolean|any)/g // params with types
|
|
80
|
+
];
|
|
81
|
+
const declaredVars = new Map();
|
|
82
|
+
for (const pattern of varPatterns) {
|
|
83
|
+
let match;
|
|
84
|
+
const lines = content.split('\n');
|
|
85
|
+
for (let i = 0; i < lines.length; i++) {
|
|
86
|
+
pattern.lastIndex = 0;
|
|
87
|
+
while ((match = pattern.exec(lines[i])) !== null) {
|
|
88
|
+
const varName = match[1];
|
|
89
|
+
// Пропускаем _ префикс (намеренно неиспользуемые)
|
|
90
|
+
if (varName && !varName.startsWith('_')) {
|
|
91
|
+
declaredVars.set(varName, i + 1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Проверяем использование
|
|
97
|
+
for (const [varName, line] of declaredVars) {
|
|
98
|
+
// Создаём regex для поиска использований (не объявлений)
|
|
99
|
+
const usagePattern = new RegExp(`(?<!(?:const|let|var|function)\\s+)\\b${varName}\\b`, 'g');
|
|
100
|
+
const usages = content.match(usagePattern);
|
|
101
|
+
// Если только одно вхождение (само объявление), то переменная не используется
|
|
102
|
+
if (!usages || usages.length <= 1) {
|
|
103
|
+
unusedVariables.push({
|
|
104
|
+
name: varName,
|
|
105
|
+
file: filePath,
|
|
106
|
+
line,
|
|
107
|
+
scope: 'local'
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return unusedVariables.slice(0, 100); // Ограничиваем вывод
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Поиск недостижимого кода
|
|
116
|
+
*/
|
|
117
|
+
findUnreachableCode(fileContents) {
|
|
118
|
+
const unreachable = [];
|
|
119
|
+
for (const [filePath, content] of fileContents) {
|
|
120
|
+
const lines = content.split('\n');
|
|
121
|
+
let inUnreachable = false;
|
|
122
|
+
let unreachableStart = 0;
|
|
123
|
+
let braceCount = 0;
|
|
124
|
+
for (let i = 0; i < lines.length; i++) {
|
|
125
|
+
const line = lines[i].trim();
|
|
126
|
+
// Отслеживаем блоки
|
|
127
|
+
braceCount += (line.match(/{/g) || []).length;
|
|
128
|
+
braceCount -= (line.match(/}/g) || []).length;
|
|
129
|
+
// Код после return/throw/break/continue в том же блоке
|
|
130
|
+
if (line.match(/^(return|throw|break|continue)\b/) && !line.endsWith('{')) {
|
|
131
|
+
inUnreachable = true;
|
|
132
|
+
unreachableStart = i + 2;
|
|
133
|
+
}
|
|
134
|
+
// Конец блока сбрасывает unreachable
|
|
135
|
+
if (inUnreachable && line === '}') {
|
|
136
|
+
if (unreachableStart < i) {
|
|
137
|
+
unreachable.push({
|
|
138
|
+
file: filePath,
|
|
139
|
+
startLine: unreachableStart,
|
|
140
|
+
endLine: i,
|
|
141
|
+
reason: 'Code after return/throw/break statement'
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
inUnreachable = false;
|
|
145
|
+
}
|
|
146
|
+
// Условия, которые всегда false
|
|
147
|
+
if (line.match(/if\s*\(\s*false\s*\)/)) {
|
|
148
|
+
unreachable.push({
|
|
149
|
+
file: filePath,
|
|
150
|
+
startLine: i + 1,
|
|
151
|
+
endLine: i + 1,
|
|
152
|
+
reason: 'Condition is always false'
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
// while(false)
|
|
156
|
+
if (line.match(/while\s*\(\s*false\s*\)/)) {
|
|
157
|
+
unreachable.push({
|
|
158
|
+
file: filePath,
|
|
159
|
+
startLine: i + 1,
|
|
160
|
+
endLine: i + 1,
|
|
161
|
+
reason: 'Loop condition is always false'
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return unreachable;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Поиск пустых блоков
|
|
170
|
+
*/
|
|
171
|
+
findEmptyBlocks(fileContents) {
|
|
172
|
+
const emptyBlocks = [];
|
|
173
|
+
for (const [filePath, content] of fileContents) {
|
|
174
|
+
const lines = content.split('\n');
|
|
175
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
176
|
+
const line = lines[i].trim();
|
|
177
|
+
const nextLine = lines[i + 1]?.trim() || '';
|
|
178
|
+
// Пустая функция
|
|
179
|
+
const funcMatch = line.match(/(?:function\s+(\w+)|(\w+)\s*=\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>))\s*\{\s*$/);
|
|
180
|
+
if (funcMatch && nextLine === '}') {
|
|
181
|
+
emptyBlocks.push({
|
|
182
|
+
type: 'function',
|
|
183
|
+
name: funcMatch[1] || funcMatch[2],
|
|
184
|
+
file: filePath,
|
|
185
|
+
line: i + 1
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
// Пустой класс
|
|
189
|
+
if (line.match(/class\s+\w+.*\{\s*$/) && nextLine === '}') {
|
|
190
|
+
const classMatch = line.match(/class\s+(\w+)/);
|
|
191
|
+
emptyBlocks.push({
|
|
192
|
+
type: 'class',
|
|
193
|
+
name: classMatch?.[1],
|
|
194
|
+
file: filePath,
|
|
195
|
+
line: i + 1
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
// Пустой catch
|
|
199
|
+
if (line.match(/catch\s*\([^)]*\)\s*\{\s*$/) && nextLine === '}') {
|
|
200
|
+
emptyBlocks.push({
|
|
201
|
+
type: 'catch',
|
|
202
|
+
file: filePath,
|
|
203
|
+
line: i + 1
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
// Пустой if/else
|
|
207
|
+
if (line.match(/(?:if|else)\s*(?:\([^)]*\))?\s*\{\s*$/) && nextLine === '}') {
|
|
208
|
+
emptyBlocks.push({
|
|
209
|
+
type: 'if',
|
|
210
|
+
file: filePath,
|
|
211
|
+
line: i + 1
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
// Пустой цикл
|
|
215
|
+
if (line.match(/(?:for|while)\s*\([^)]*\)\s*\{\s*$/) && nextLine === '}') {
|
|
216
|
+
emptyBlocks.push({
|
|
217
|
+
type: 'loop',
|
|
218
|
+
file: filePath,
|
|
219
|
+
line: i + 1
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return emptyBlocks;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Поиск закомментированного кода
|
|
228
|
+
*/
|
|
229
|
+
findCommentedCode(fileContents) {
|
|
230
|
+
const commentedCode = [];
|
|
231
|
+
// Паттерны кода (упрощённо)
|
|
232
|
+
const codePatterns = [
|
|
233
|
+
/^\s*\/\/\s*(const|let|var|function|class|if|for|while|return|import|export)\b/,
|
|
234
|
+
/^\s*\/\/\s*\w+\s*\([^)]*\)\s*[{;]?\s*$/,
|
|
235
|
+
/^\s*\/\/\s*\w+\.\w+\s*\(/,
|
|
236
|
+
/^\s*\/\*[\s\S]*?(const|let|var|function|class|if|for|while|return)[\s\S]*?\*\//
|
|
237
|
+
];
|
|
238
|
+
for (const [filePath, content] of fileContents) {
|
|
239
|
+
const lines = content.split('\n');
|
|
240
|
+
let commentStart = -1;
|
|
241
|
+
let commentLines = [];
|
|
242
|
+
for (let i = 0; i < lines.length; i++) {
|
|
243
|
+
const line = lines[i];
|
|
244
|
+
const isCommentedCode = codePatterns.some(p => p.test(line));
|
|
245
|
+
if (isCommentedCode) {
|
|
246
|
+
if (commentStart === -1) {
|
|
247
|
+
commentStart = i + 1;
|
|
248
|
+
}
|
|
249
|
+
commentLines.push(line.replace(/^\s*\/\/\s?/, '').trim());
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
// Конец блока закомментированного кода
|
|
253
|
+
if (commentStart !== -1 && commentLines.length >= 3) {
|
|
254
|
+
commentedCode.push({
|
|
255
|
+
file: filePath,
|
|
256
|
+
startLine: commentStart,
|
|
257
|
+
endLine: i,
|
|
258
|
+
linesCount: commentLines.length,
|
|
259
|
+
preview: commentLines.slice(0, 2).join('\n').substring(0, 100) + '...'
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
commentStart = -1;
|
|
263
|
+
commentLines = [];
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Проверяем конец файла
|
|
267
|
+
if (commentStart !== -1 && commentLines.length >= 3) {
|
|
268
|
+
commentedCode.push({
|
|
269
|
+
file: filePath,
|
|
270
|
+
startLine: commentStart,
|
|
271
|
+
endLine: lines.length,
|
|
272
|
+
linesCount: commentLines.length,
|
|
273
|
+
preview: commentLines.slice(0, 2).join('\n').substring(0, 100) + '...'
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return commentedCode;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Подсказка для неиспользуемого экспорта
|
|
281
|
+
*/
|
|
282
|
+
getSuggestionForUnusedExport(symbol) {
|
|
283
|
+
switch (symbol.kind) {
|
|
284
|
+
case SymbolKind.Function:
|
|
285
|
+
return 'Удалите функцию или используйте её';
|
|
286
|
+
case SymbolKind.Class:
|
|
287
|
+
return 'Удалите класс или создайте экземпляр';
|
|
288
|
+
case SymbolKind.Interface:
|
|
289
|
+
return 'Удалите интерфейс или реализуйте его';
|
|
290
|
+
case SymbolKind.Type:
|
|
291
|
+
return 'Удалите тип или используйте в аннотациях';
|
|
292
|
+
case SymbolKind.Variable:
|
|
293
|
+
case SymbolKind.Constant:
|
|
294
|
+
return 'Удалите переменную или используйте её';
|
|
295
|
+
default:
|
|
296
|
+
return 'Рассмотрите удаление неиспользуемого экспорта';
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Сводка
|
|
301
|
+
*/
|
|
302
|
+
calculateSummary(unusedExports, unusedVariables, unreachableCode, emptyBlocks, commentedCode) {
|
|
303
|
+
const unreachableLines = unreachableCode.reduce((sum, u) => sum + (u.endLine - u.startLine + 1), 0);
|
|
304
|
+
const commentedLines = commentedCode.reduce((sum, c) => sum + c.linesCount, 0);
|
|
305
|
+
const totalIssues = unusedExports.length +
|
|
306
|
+
unusedVariables.length +
|
|
307
|
+
unreachableCode.length +
|
|
308
|
+
emptyBlocks.length +
|
|
309
|
+
commentedCode.length;
|
|
310
|
+
// Оценка времени на очистку (примерно)
|
|
311
|
+
const estimatedCleanupHours = unusedExports.length * 0.05 +
|
|
312
|
+
unusedVariables.length * 0.02 +
|
|
313
|
+
unreachableCode.length * 0.1 +
|
|
314
|
+
emptyBlocks.length * 0.02 +
|
|
315
|
+
commentedCode.length * 0.03;
|
|
316
|
+
return {
|
|
317
|
+
totalIssues,
|
|
318
|
+
unusedExportsCount: unusedExports.length,
|
|
319
|
+
unusedVariablesCount: unusedVariables.length,
|
|
320
|
+
unreachableCodeLines: unreachableLines,
|
|
321
|
+
emptyBlocksCount: emptyBlocks.length,
|
|
322
|
+
commentedCodeLines: commentedLines,
|
|
323
|
+
estimatedCleanupHours: Math.round(estimatedCleanupHours * 10) / 10
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
//# sourceMappingURL=dead-code.js.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Duplication Detector
|
|
3
|
+
*
|
|
4
|
+
* Оптимизированное обнаружение дублирования кода:
|
|
5
|
+
* - Использует хеширование строк (Rabin-Karp подход)
|
|
6
|
+
* - Ограничивает размер анализа для больших проектов
|
|
7
|
+
* - Не хранит весь код в памяти
|
|
8
|
+
*/
|
|
9
|
+
export interface DuplicationResult {
|
|
10
|
+
clones: CodeClone[];
|
|
11
|
+
summary: DuplicationSummary;
|
|
12
|
+
}
|
|
13
|
+
export interface CodeClone {
|
|
14
|
+
id: string;
|
|
15
|
+
type: 'exact' | 'similar' | 'structural';
|
|
16
|
+
instances: CloneInstance[];
|
|
17
|
+
linesCount: number;
|
|
18
|
+
similarity: number;
|
|
19
|
+
suggestion: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CloneInstance {
|
|
22
|
+
file: string;
|
|
23
|
+
startLine: number;
|
|
24
|
+
endLine: number;
|
|
25
|
+
code: string;
|
|
26
|
+
}
|
|
27
|
+
export interface DuplicationSummary {
|
|
28
|
+
totalClones: number;
|
|
29
|
+
totalDuplicatedLines: number;
|
|
30
|
+
duplicationPercentage: number;
|
|
31
|
+
filesAffected: number;
|
|
32
|
+
estimatedRefactorHours: number;
|
|
33
|
+
}
|
|
34
|
+
export declare class DuplicationDetector {
|
|
35
|
+
private readonly MIN_LINES;
|
|
36
|
+
private readonly WINDOW_SIZES;
|
|
37
|
+
private readonly MAX_CLONES;
|
|
38
|
+
private readonly MAX_FILES;
|
|
39
|
+
private readonly MAX_LINES_PER_FILE;
|
|
40
|
+
/**
|
|
41
|
+
* Анализ дублирования
|
|
42
|
+
*/
|
|
43
|
+
analyze(fileContents: Map<string, string>): Promise<DuplicationResult>;
|
|
44
|
+
/**
|
|
45
|
+
* Ограничение файлов для анализа
|
|
46
|
+
*/
|
|
47
|
+
private limitFiles;
|
|
48
|
+
/**
|
|
49
|
+
* Быстрый алгоритм для больших проектов
|
|
50
|
+
* Использует только хеширование строк
|
|
51
|
+
*/
|
|
52
|
+
private findClonesQuick;
|
|
53
|
+
/**
|
|
54
|
+
* Обычный алгоритм для средних проектов
|
|
55
|
+
*/
|
|
56
|
+
private findClonesNormal;
|
|
57
|
+
/**
|
|
58
|
+
* Расширение блока вниз пока строки совпадают
|
|
59
|
+
*/
|
|
60
|
+
private expandBlock;
|
|
61
|
+
/**
|
|
62
|
+
* Получить блок кода по номерам строк
|
|
63
|
+
*/
|
|
64
|
+
private getCodeBlock;
|
|
65
|
+
/**
|
|
66
|
+
* Нормализация одной строки
|
|
67
|
+
*/
|
|
68
|
+
private normalizeLine;
|
|
69
|
+
/**
|
|
70
|
+
* Нормализация блока строк
|
|
71
|
+
*/
|
|
72
|
+
private normalizeBlock;
|
|
73
|
+
/**
|
|
74
|
+
* Быстрое хеширование
|
|
75
|
+
*/
|
|
76
|
+
private quickHash;
|
|
77
|
+
/**
|
|
78
|
+
* Фильтрация перекрывающихся блоков
|
|
79
|
+
*/
|
|
80
|
+
private filterOverlapping;
|
|
81
|
+
/**
|
|
82
|
+
* Удаление дубликатов клонов (перекрывающихся)
|
|
83
|
+
*/
|
|
84
|
+
private deduplicateClones;
|
|
85
|
+
/**
|
|
86
|
+
* Подсчёт статистики
|
|
87
|
+
*/
|
|
88
|
+
private calculateSummary;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=duplication.d.ts.map
|