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.
Files changed (118) hide show
  1. package/README.md +530 -0
  2. package/dist/analyzers/dead-code.d.ts +95 -0
  3. package/dist/analyzers/dead-code.js +327 -0
  4. package/dist/analyzers/duplication.d.ts +90 -0
  5. package/dist/analyzers/duplication.js +344 -0
  6. package/dist/analyzers/security.d.ts +79 -0
  7. package/dist/analyzers/security.js +484 -0
  8. package/dist/architecture/index.d.ts +35 -0
  9. package/dist/architecture/index.js +249 -0
  10. package/dist/cli/commands/analyzers.d.ts +6 -0
  11. package/dist/cli/commands/analyzers.js +431 -0
  12. package/dist/cli/commands/export.d.ts +6 -0
  13. package/dist/cli/commands/export.js +78 -0
  14. package/dist/cli/commands/index.d.ts +8 -0
  15. package/dist/cli/commands/index.js +8 -0
  16. package/dist/cli/commands/init.d.ts +26 -0
  17. package/dist/cli/commands/init.js +140 -0
  18. package/dist/cli/commands/interactive.d.ts +7 -0
  19. package/dist/cli/commands/interactive.js +522 -0
  20. package/dist/cli/commands/projects.d.ts +6 -0
  21. package/dist/cli/commands/projects.js +249 -0
  22. package/dist/cli/index.d.ts +7 -0
  23. package/dist/cli/index.js +7 -0
  24. package/dist/cli/ui/box.d.ts +17 -0
  25. package/dist/cli/ui/box.js +62 -0
  26. package/dist/cli/ui/colors.d.ts +49 -0
  27. package/dist/cli/ui/colors.js +86 -0
  28. package/dist/cli/ui/index.d.ts +9 -0
  29. package/dist/cli/ui/index.js +9 -0
  30. package/dist/cli/ui/prompt.d.ts +34 -0
  31. package/dist/cli/ui/prompt.js +122 -0
  32. package/dist/cli/ui/spinner.d.ts +29 -0
  33. package/dist/cli/ui/spinner.js +80 -0
  34. package/dist/cli/ui/table.d.ts +33 -0
  35. package/dist/cli/ui/table.js +84 -0
  36. package/dist/cli/utils/config.d.ts +23 -0
  37. package/dist/cli/utils/config.js +73 -0
  38. package/dist/cli/utils/index.d.ts +6 -0
  39. package/dist/cli/utils/index.js +6 -0
  40. package/dist/cli/utils/session.d.ts +27 -0
  41. package/dist/cli/utils/session.js +117 -0
  42. package/dist/cli.d.ts +8 -0
  43. package/dist/cli.js +295 -0
  44. package/dist/code-index/ast-parser.d.ts +16 -0
  45. package/dist/code-index/ast-parser.js +330 -0
  46. package/dist/code-index/dependency-graph.d.ts +16 -0
  47. package/dist/code-index/dependency-graph.js +161 -0
  48. package/dist/code-index/index.d.ts +44 -0
  49. package/dist/code-index/index.js +124 -0
  50. package/dist/code-index/symbol-extractor.d.ts +13 -0
  51. package/dist/code-index/symbol-extractor.js +150 -0
  52. package/dist/export/index.d.ts +92 -0
  53. package/dist/export/index.js +676 -0
  54. package/dist/github/github-service.d.ts +146 -0
  55. package/dist/github/github-service.js +609 -0
  56. package/dist/impact-engine/index.d.ts +25 -0
  57. package/dist/impact-engine/index.js +284 -0
  58. package/dist/index.d.ts +60 -0
  59. package/dist/index.js +149 -0
  60. package/dist/metrics/index.d.ts +136 -0
  61. package/dist/metrics/index.js +525 -0
  62. package/dist/orchestrator/deepseek-optimizer.d.ts +67 -0
  63. package/dist/orchestrator/deepseek-optimizer.js +320 -0
  64. package/dist/orchestrator/index.d.ts +34 -0
  65. package/dist/orchestrator/index.js +305 -0
  66. package/dist/pr-guardian/index.d.ts +143 -0
  67. package/dist/pr-guardian/index.js +553 -0
  68. package/dist/refactoring/index.d.ts +108 -0
  69. package/dist/refactoring/index.js +580 -0
  70. package/dist/rules-engine/index.d.ts +129 -0
  71. package/dist/rules-engine/index.js +482 -0
  72. package/dist/semantic-memory/embedding-service.d.ts +24 -0
  73. package/dist/semantic-memory/embedding-service.js +120 -0
  74. package/dist/semantic-memory/index.d.ts +45 -0
  75. package/dist/semantic-memory/index.js +206 -0
  76. package/dist/semantic-memory/vector-store.d.ts +27 -0
  77. package/dist/semantic-memory/vector-store.js +166 -0
  78. package/dist/server/index.d.ts +28 -0
  79. package/dist/server/index.js +141 -0
  80. package/dist/server/middleware/api-auth.d.ts +43 -0
  81. package/dist/server/middleware/api-auth.js +256 -0
  82. package/dist/server/routes/admin.d.ts +5 -0
  83. package/dist/server/routes/admin.js +123 -0
  84. package/dist/server/routes/api.d.ts +7 -0
  85. package/dist/server/routes/api.js +362 -0
  86. package/dist/server/routes/auth.d.ts +16 -0
  87. package/dist/server/routes/auth.js +191 -0
  88. package/dist/server/routes/developer.d.ts +8 -0
  89. package/dist/server/routes/developer.js +439 -0
  90. package/dist/server/routes/github.d.ts +7 -0
  91. package/dist/server/routes/github.js +495 -0
  92. package/dist/server/routes/upload.d.ts +7 -0
  93. package/dist/server/routes/upload.js +196 -0
  94. package/dist/server/services/api-key-service.d.ts +81 -0
  95. package/dist/server/services/api-key-service.js +281 -0
  96. package/dist/server/services/auth-service.d.ts +40 -0
  97. package/dist/server/services/auth-service.js +315 -0
  98. package/dist/server/services/project-service.d.ts +123 -0
  99. package/dist/server/services/project-service.js +533 -0
  100. package/dist/server/services/token-service.d.ts +107 -0
  101. package/dist/server/services/token-service.js +416 -0
  102. package/dist/server/services/upload-service.d.ts +93 -0
  103. package/dist/server/services/upload-service.js +464 -0
  104. package/dist/types/api.d.ts +188 -0
  105. package/dist/types/api.js +86 -0
  106. package/dist/types/github.d.ts +335 -0
  107. package/dist/types/github.js +5 -0
  108. package/dist/types/index.d.ts +265 -0
  109. package/dist/types/index.js +32 -0
  110. package/dist/types/user.d.ts +69 -0
  111. package/dist/types/user.js +42 -0
  112. package/dist/utils/file-utils.d.ts +20 -0
  113. package/dist/utils/file-utils.js +163 -0
  114. package/dist/utils/logger.d.ts +17 -0
  115. package/dist/utils/logger.js +41 -0
  116. package/dist/watcher/index.d.ts +125 -0
  117. package/dist/watcher/index.js +397 -0
  118. package/package.json +71 -0
@@ -0,0 +1,676 @@
1
+ /**
2
+ * Export/Import System
3
+ *
4
+ * Форматы экспорта:
5
+ * - JSON (полный)
6
+ * - HTML отчёт
7
+ * - Markdown отчёт
8
+ * - PDF (через HTML)
9
+ * - CSV (метрики)
10
+ * - GraphML (граф зависимостей)
11
+ */
12
+ import { Logger } from '../utils/logger.js';
13
+ const translations = {
14
+ en: {
15
+ reportTitle: 'Architecture Analysis Report',
16
+ generatedOn: 'Generated on',
17
+ projectOverview: 'Project Overview',
18
+ totalFiles: 'Total Files',
19
+ totalSymbols: 'Total Symbols',
20
+ dependencies: 'Dependencies',
21
+ circularDeps: 'Circular Dependencies',
22
+ metricsSection: 'Code Metrics',
23
+ totalLOC: 'Total Lines of Code',
24
+ avgComplexity: 'Average Complexity',
25
+ maintainabilityIndex: 'Maintainability Index',
26
+ hotspots: 'Hotspots',
27
+ rulesSection: 'Architecture Rules',
28
+ rulesPassed: 'Rules Passed',
29
+ violations: 'Violations',
30
+ securitySection: 'Security Analysis',
31
+ vulnerabilities: 'Vulnerabilities',
32
+ critical: 'Critical',
33
+ high: 'High',
34
+ medium: 'Medium',
35
+ low: 'Low',
36
+ hardcodedSecrets: 'Hardcoded Secrets',
37
+ deadCodeSection: 'Dead Code',
38
+ unusedExports: 'Unused Exports',
39
+ unusedVariables: 'Unused Variables',
40
+ unreachableCode: 'Unreachable Code',
41
+ duplicationSection: 'Code Duplication',
42
+ totalClones: 'Total Clones',
43
+ duplicationPercentage: 'Duplication Percentage',
44
+ estimatedRefactorTime: 'Estimated Refactor Time',
45
+ hours: 'hours',
46
+ file: 'File',
47
+ line: 'Line',
48
+ type: 'Type',
49
+ severity: 'Severity',
50
+ message: 'Message',
51
+ recommendation: 'Recommendation'
52
+ },
53
+ ru: {
54
+ reportTitle: 'Отчёт об анализе архитектуры',
55
+ generatedOn: 'Сформирован',
56
+ projectOverview: 'Обзор проекта',
57
+ totalFiles: 'Всего файлов',
58
+ totalSymbols: 'Всего символов',
59
+ dependencies: 'Зависимостей',
60
+ circularDeps: 'Циклических зависимостей',
61
+ metricsSection: 'Метрики кода',
62
+ totalLOC: 'Всего строк кода',
63
+ avgComplexity: 'Средняя сложность',
64
+ maintainabilityIndex: 'Индекс поддерживаемости',
65
+ hotspots: 'Проблемные места',
66
+ rulesSection: 'Правила архитектуры',
67
+ rulesPassed: 'Правил выполнено',
68
+ violations: 'Нарушений',
69
+ securitySection: 'Анализ безопасности',
70
+ vulnerabilities: 'Уязвимостей',
71
+ critical: 'Критических',
72
+ high: 'Высоких',
73
+ medium: 'Средних',
74
+ low: 'Низких',
75
+ hardcodedSecrets: 'Захардкоженных секретов',
76
+ deadCodeSection: 'Мёртвый код',
77
+ unusedExports: 'Неиспользуемых экспортов',
78
+ unusedVariables: 'Неиспользуемых переменных',
79
+ unreachableCode: 'Недостижимый код',
80
+ duplicationSection: 'Дублирование кода',
81
+ totalClones: 'Всего клонов',
82
+ duplicationPercentage: 'Процент дублирования',
83
+ estimatedRefactorTime: 'Время на рефакторинг',
84
+ hours: 'часов',
85
+ file: 'Файл',
86
+ line: 'Строка',
87
+ type: 'Тип',
88
+ severity: 'Серьёзность',
89
+ message: 'Сообщение',
90
+ recommendation: 'Рекомендация'
91
+ }
92
+ };
93
+ export class ExportManager {
94
+ version = '1.0.0';
95
+ /**
96
+ * Экспорт данных в указанный формат
97
+ */
98
+ async export(data, options) {
99
+ Logger.progress(`Exporting to ${options.format}...`);
100
+ let result;
101
+ switch (options.format) {
102
+ case 'json':
103
+ result = this.exportJSON(data, options);
104
+ break;
105
+ case 'html':
106
+ result = this.exportHTML(data, options);
107
+ break;
108
+ case 'markdown':
109
+ result = this.exportMarkdown(data, options);
110
+ break;
111
+ case 'csv':
112
+ result = this.exportCSV(data);
113
+ break;
114
+ case 'graphml':
115
+ result = this.exportGraphML(data);
116
+ break;
117
+ default:
118
+ throw new Error(`Unsupported export format: ${options.format}`);
119
+ }
120
+ Logger.success(`Export completed (${result.length} bytes)`);
121
+ return result;
122
+ }
123
+ /**
124
+ * Импорт данных из JSON
125
+ */
126
+ async import(jsonString) {
127
+ Logger.progress('Importing data...');
128
+ try {
129
+ const parsed = JSON.parse(jsonString);
130
+ // Валидация
131
+ const errors = [];
132
+ if (!parsed.projectName) {
133
+ errors.push('Missing projectName');
134
+ }
135
+ if (!parsed.exportDate) {
136
+ errors.push('Missing exportDate');
137
+ }
138
+ // Восстанавливаем Map из объектов
139
+ if (parsed.symbols && typeof parsed.symbols === 'object') {
140
+ parsed.symbols = new Map(Object.entries(parsed.symbols));
141
+ }
142
+ if (errors.length > 0) {
143
+ return { success: false, errors };
144
+ }
145
+ Logger.success('Import completed');
146
+ return { success: true, data: parsed };
147
+ }
148
+ catch (error) {
149
+ return {
150
+ success: false,
151
+ errors: [`Parse error: ${error instanceof Error ? error.message : 'Unknown error'}`]
152
+ };
153
+ }
154
+ }
155
+ /**
156
+ * Экспорт в JSON
157
+ */
158
+ exportJSON(data, options) {
159
+ const exportObj = {
160
+ projectName: data.projectName,
161
+ exportDate: data.exportDate,
162
+ version: this.version
163
+ };
164
+ if (options.includeGraph && data.graph) {
165
+ exportObj.graph = {
166
+ nodes: data.graph.nodes,
167
+ edges: Object.fromEntries(data.graph.edges)
168
+ };
169
+ }
170
+ if (options.includeSymbols && data.symbols) {
171
+ exportObj.symbols = Object.fromEntries(data.symbols);
172
+ }
173
+ if (options.includeMetrics && data.metrics) {
174
+ exportObj.metrics = data.metrics;
175
+ }
176
+ if (options.includeRules && data.rules) {
177
+ exportObj.rules = data.rules;
178
+ }
179
+ if (options.includeDeadCode && data.deadCode) {
180
+ exportObj.deadCode = data.deadCode;
181
+ }
182
+ if (options.includeDuplication && data.duplication) {
183
+ exportObj.duplication = data.duplication;
184
+ }
185
+ if (options.includeSecurity && data.security) {
186
+ exportObj.security = data.security;
187
+ }
188
+ return JSON.stringify(exportObj, null, 2);
189
+ }
190
+ /**
191
+ * Экспорт в HTML
192
+ */
193
+ exportHTML(data, options) {
194
+ const t = translations[options.language || 'en'];
195
+ let html = `<!DOCTYPE html>
196
+ <html lang="${options.language || 'en'}">
197
+ <head>
198
+ <meta charset="UTF-8">
199
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
200
+ <title>${t.reportTitle} - ${data.projectName}</title>
201
+ <style>
202
+ :root {
203
+ --bg: #0a0a0f;
204
+ --card-bg: #12121a;
205
+ --border: #1e1e2e;
206
+ --text: #e4e4e7;
207
+ --text-muted: #71717a;
208
+ --primary: #8b5cf6;
209
+ --success: #22c55e;
210
+ --warning: #f59e0b;
211
+ --error: #ef4444;
212
+ }
213
+ * { margin: 0; padding: 0; box-sizing: border-box; }
214
+ body {
215
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
216
+ background: var(--bg);
217
+ color: var(--text);
218
+ line-height: 1.6;
219
+ padding: 2rem;
220
+ }
221
+ .container { max-width: 1200px; margin: 0 auto; }
222
+ h1 { color: var(--primary); margin-bottom: 0.5rem; }
223
+ h2 { color: var(--text); margin: 2rem 0 1rem; border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; }
224
+ .meta { color: var(--text-muted); margin-bottom: 2rem; }
225
+ .card {
226
+ background: var(--card-bg);
227
+ border: 1px solid var(--border);
228
+ border-radius: 8px;
229
+ padding: 1.5rem;
230
+ margin-bottom: 1rem;
231
+ }
232
+ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; }
233
+ .stat { text-align: center; }
234
+ .stat-value { font-size: 2rem; font-weight: bold; color: var(--primary); }
235
+ .stat-label { color: var(--text-muted); font-size: 0.875rem; }
236
+ table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
237
+ th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid var(--border); }
238
+ th { color: var(--text-muted); font-weight: 500; }
239
+ .badge {
240
+ display: inline-block;
241
+ padding: 0.25rem 0.5rem;
242
+ border-radius: 4px;
243
+ font-size: 0.75rem;
244
+ font-weight: 500;
245
+ }
246
+ .badge-critical { background: var(--error); color: white; }
247
+ .badge-high { background: #dc2626; color: white; }
248
+ .badge-medium { background: var(--warning); color: black; }
249
+ .badge-low { background: var(--success); color: white; }
250
+ .progress { height: 8px; background: var(--border); border-radius: 4px; overflow: hidden; }
251
+ .progress-bar { height: 100%; background: var(--primary); }
252
+ </style>
253
+ </head>
254
+ <body>
255
+ <div class="container">
256
+ <h1>${t.reportTitle}</h1>
257
+ <p class="meta">${data.projectName} | ${t.generatedOn}: ${new Date(data.exportDate).toLocaleString()}</p>
258
+ `;
259
+ // Project Overview
260
+ if (data.graph) {
261
+ const totalDeps = Array.from(data.graph.edges.values()).reduce((sum, e) => sum + e.length, 0);
262
+ html += `
263
+ <h2>${t.projectOverview}</h2>
264
+ <div class="card">
265
+ <div class="grid">
266
+ <div class="stat">
267
+ <div class="stat-value">${data.graph.nodes.size}</div>
268
+ <div class="stat-label">${t.totalFiles}</div>
269
+ </div>
270
+ <div class="stat">
271
+ <div class="stat-value">${data.symbols?.size || 0}</div>
272
+ <div class="stat-label">${t.totalSymbols}</div>
273
+ </div>
274
+ <div class="stat">
275
+ <div class="stat-value">${totalDeps}</div>
276
+ <div class="stat-label">${t.dependencies}</div>
277
+ </div>
278
+ <div class="stat">
279
+ <div class="stat-value">0</div>
280
+ <div class="stat-label">${t.circularDeps}</div>
281
+ </div>
282
+ </div>
283
+ </div>
284
+ `;
285
+ }
286
+ // Metrics
287
+ if (data.metrics) {
288
+ html += `
289
+ <h2>${t.metricsSection}</h2>
290
+ <div class="card">
291
+ <div class="grid">
292
+ <div class="stat">
293
+ <div class="stat-value">${data.metrics.summary.totalLOC.toLocaleString()}</div>
294
+ <div class="stat-label">${t.totalLOC}</div>
295
+ </div>
296
+ <div class="stat">
297
+ <div class="stat-value">${data.metrics.summary.avgComplexity.toFixed(1)}</div>
298
+ <div class="stat-label">${t.avgComplexity}</div>
299
+ </div>
300
+ <div class="stat">
301
+ <div class="stat-value">${data.metrics.summary.avgMaintainability.toFixed(0)}</div>
302
+ <div class="stat-label">${t.maintainabilityIndex}</div>
303
+ </div>
304
+ </div>
305
+ </div>
306
+ `;
307
+ if (data.metrics.hotspots.length > 0) {
308
+ html += `
309
+ <h3>${t.hotspots}</h3>
310
+ <div class="card">
311
+ <table>
312
+ <thead><tr><th>${t.file}</th><th>Score</th></tr></thead>
313
+ <tbody>
314
+ ${data.metrics.hotspots.slice(0, 10).map(h => `
315
+ <tr><td>${h.filePath}</td><td>${h.score.toFixed(0)}</td></tr>
316
+ `).join('')}
317
+ </tbody>
318
+ </table>
319
+ </div>
320
+ `;
321
+ }
322
+ }
323
+ // Security
324
+ if (data.security) {
325
+ html += `
326
+ <h2>${t.securitySection}</h2>
327
+ <div class="card">
328
+ <div class="grid">
329
+ <div class="stat">
330
+ <div class="stat-value" style="color: var(--error)">${data.security.summary.critical}</div>
331
+ <div class="stat-label">${t.critical}</div>
332
+ </div>
333
+ <div class="stat">
334
+ <div class="stat-value" style="color: #dc2626">${data.security.summary.high}</div>
335
+ <div class="stat-label">${t.high}</div>
336
+ </div>
337
+ <div class="stat">
338
+ <div class="stat-value" style="color: var(--warning)">${data.security.summary.medium}</div>
339
+ <div class="stat-label">${t.medium}</div>
340
+ </div>
341
+ <div class="stat">
342
+ <div class="stat-value" style="color: var(--success)">${data.security.summary.low}</div>
343
+ <div class="stat-label">${t.low}</div>
344
+ </div>
345
+ </div>
346
+ </div>
347
+ `;
348
+ if (data.security.vulnerabilities.length > 0) {
349
+ html += `
350
+ <div class="card">
351
+ <table>
352
+ <thead><tr><th>${t.file}</th><th>${t.line}</th><th>${t.type}</th><th>${t.severity}</th></tr></thead>
353
+ <tbody>
354
+ ${data.security.vulnerabilities.slice(0, 20).map(v => `
355
+ <tr>
356
+ <td>${v.file}</td>
357
+ <td>${v.line}</td>
358
+ <td>${v.type}</td>
359
+ <td><span class="badge badge-${v.severity}">${v.severity}</span></td>
360
+ </tr>
361
+ `).join('')}
362
+ </tbody>
363
+ </table>
364
+ </div>
365
+ `;
366
+ }
367
+ }
368
+ // Rules
369
+ if (data.rules) {
370
+ html += `
371
+ <h2>${t.rulesSection}</h2>
372
+ <div class="card">
373
+ <div class="grid">
374
+ <div class="stat">
375
+ <div class="stat-value" style="color: var(--success)">${data.rules.passed}</div>
376
+ <div class="stat-label">${t.rulesPassed}</div>
377
+ </div>
378
+ <div class="stat">
379
+ <div class="stat-value" style="color: var(--error)">${data.rules.violations.length}</div>
380
+ <div class="stat-label">${t.violations}</div>
381
+ </div>
382
+ </div>
383
+ </div>
384
+ `;
385
+ }
386
+ // Dead Code
387
+ if (data.deadCode) {
388
+ html += `
389
+ <h2>${t.deadCodeSection}</h2>
390
+ <div class="card">
391
+ <div class="grid">
392
+ <div class="stat">
393
+ <div class="stat-value">${data.deadCode.summary.unusedExportsCount}</div>
394
+ <div class="stat-label">${t.unusedExports}</div>
395
+ </div>
396
+ <div class="stat">
397
+ <div class="stat-value">${data.deadCode.summary.unusedVariablesCount}</div>
398
+ <div class="stat-label">${t.unusedVariables}</div>
399
+ </div>
400
+ <div class="stat">
401
+ <div class="stat-value">${data.deadCode.summary.unreachableCodeLines}</div>
402
+ <div class="stat-label">${t.unreachableCode}</div>
403
+ </div>
404
+ </div>
405
+ </div>
406
+ `;
407
+ }
408
+ // Duplication
409
+ if (data.duplication) {
410
+ html += `
411
+ <h2>${t.duplicationSection}</h2>
412
+ <div class="card">
413
+ <div class="grid">
414
+ <div class="stat">
415
+ <div class="stat-value">${data.duplication.summary.totalClones}</div>
416
+ <div class="stat-label">${t.totalClones}</div>
417
+ </div>
418
+ <div class="stat">
419
+ <div class="stat-value">${data.duplication.summary.duplicationPercentage}%</div>
420
+ <div class="stat-label">${t.duplicationPercentage}</div>
421
+ </div>
422
+ <div class="stat">
423
+ <div class="stat-value">${data.duplication.summary.estimatedRefactorHours}</div>
424
+ <div class="stat-label">${t.estimatedRefactorTime} (${t.hours})</div>
425
+ </div>
426
+ </div>
427
+ </div>
428
+ `;
429
+ }
430
+ html += `
431
+ </div>
432
+ </body>
433
+ </html>`;
434
+ return html;
435
+ }
436
+ /**
437
+ * Экспорт в Markdown
438
+ */
439
+ exportMarkdown(data, options) {
440
+ const t = translations[options.language || 'en'];
441
+ let md = `# ${t.reportTitle}
442
+
443
+ **${data.projectName}**
444
+ ${t.generatedOn}: ${new Date(data.exportDate).toLocaleString()}
445
+
446
+ ---
447
+
448
+ `;
449
+ // Overview
450
+ if (data.graph) {
451
+ const totalDeps = Array.from(data.graph.edges.values()).reduce((sum, e) => sum + e.length, 0);
452
+ md += `## ${t.projectOverview}
453
+
454
+ | Metric | Value |
455
+ |--------|-------|
456
+ | ${t.totalFiles} | ${data.graph.nodes.size} |
457
+ | ${t.totalSymbols} | ${data.symbols?.size || 0} |
458
+ | ${t.dependencies} | ${totalDeps} |
459
+ | ${t.circularDeps} | 0 |
460
+
461
+ `;
462
+ }
463
+ // Metrics
464
+ if (data.metrics) {
465
+ md += `## ${t.metricsSection}
466
+
467
+ | Metric | Value |
468
+ |--------|-------|
469
+ | ${t.totalLOC} | ${data.metrics.summary.totalLOC.toLocaleString()} |
470
+ | ${t.avgComplexity} | ${data.metrics.summary.avgComplexity.toFixed(1)} |
471
+ | ${t.maintainabilityIndex} | ${data.metrics.summary.avgMaintainability.toFixed(0)} |
472
+
473
+ `;
474
+ if (data.metrics.hotspots.length > 0) {
475
+ md += `### ${t.hotspots}
476
+
477
+ | ${t.file} | Score |
478
+ |------|-------|
479
+ ${data.metrics.hotspots.slice(0, 10).map(h => `| ${h.filePath} | ${h.score.toFixed(0)} |`).join('\n')}
480
+
481
+ `;
482
+ }
483
+ }
484
+ // Security
485
+ if (data.security) {
486
+ md += `## ${t.securitySection}
487
+
488
+ | ${t.severity} | Count |
489
+ |----------|-------|
490
+ | ${t.critical} | ${data.security.summary.critical} |
491
+ | ${t.high} | ${data.security.summary.high} |
492
+ | ${t.medium} | ${data.security.summary.medium} |
493
+ | ${t.low} | ${data.security.summary.low} |
494
+
495
+ `;
496
+ if (data.security.vulnerabilities.length > 0) {
497
+ md += `### ${t.vulnerabilities}
498
+
499
+ | ${t.file} | ${t.line} | ${t.type} | ${t.severity} |
500
+ |------|------|------|----------|
501
+ ${data.security.vulnerabilities.slice(0, 20).map(v => `| ${v.file} | ${v.line} | ${v.type} | ${v.severity} |`).join('\n')}
502
+
503
+ `;
504
+ }
505
+ }
506
+ // Rules
507
+ if (data.rules) {
508
+ md += `## ${t.rulesSection}
509
+
510
+ - ${t.rulesPassed}: ${data.rules.passed}
511
+ - ${t.violations}: ${data.rules.violations.length}
512
+
513
+ `;
514
+ }
515
+ // Dead Code
516
+ if (data.deadCode) {
517
+ md += `## ${t.deadCodeSection}
518
+
519
+ | ${t.type} | Count |
520
+ |------|-------|
521
+ | ${t.unusedExports} | ${data.deadCode.summary.unusedExportsCount} |
522
+ | ${t.unusedVariables} | ${data.deadCode.summary.unusedVariablesCount} |
523
+ | ${t.unreachableCode} | ${data.deadCode.summary.unreachableCodeLines} |
524
+
525
+ `;
526
+ }
527
+ // Duplication
528
+ if (data.duplication) {
529
+ md += `## ${t.duplicationSection}
530
+
531
+ | Metric | Value |
532
+ |--------|-------|
533
+ | ${t.totalClones} | ${data.duplication.summary.totalClones} |
534
+ | ${t.duplicationPercentage} | ${data.duplication.summary.duplicationPercentage}% |
535
+ | ${t.estimatedRefactorTime} | ${data.duplication.summary.estimatedRefactorHours} ${t.hours} |
536
+
537
+ `;
538
+ }
539
+ return md;
540
+ }
541
+ /**
542
+ * Экспорт метрик в CSV
543
+ */
544
+ exportCSV(data) {
545
+ const rows = [];
546
+ // Header
547
+ rows.push('File,LOC,SLOC,Comments,Complexity,Cognitive,Maintainability,Afferent,Efferent,Instability');
548
+ // Data
549
+ if (data.metrics?.files) {
550
+ for (const fileMetrics of data.metrics.files) {
551
+ rows.push([
552
+ `"${fileMetrics.filePath}"`,
553
+ fileMetrics.loc.total,
554
+ fileMetrics.loc.code,
555
+ fileMetrics.loc.comments,
556
+ fileMetrics.complexity.cyclomatic,
557
+ fileMetrics.complexity.cognitive,
558
+ fileMetrics.maintainability.toFixed(2),
559
+ fileMetrics.coupling.afferentCoupling,
560
+ fileMetrics.coupling.efferentCoupling,
561
+ fileMetrics.coupling.instability.toFixed(2)
562
+ ].join(','));
563
+ }
564
+ }
565
+ return rows.join('\n');
566
+ }
567
+ /**
568
+ * Экспорт графа в GraphML
569
+ */
570
+ exportGraphML(data) {
571
+ if (!data.graph) {
572
+ return '<?xml version="1.0" encoding="UTF-8"?><graphml/>';
573
+ }
574
+ let graphml = `<?xml version="1.0" encoding="UTF-8"?>
575
+ <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
576
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
577
+ xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
578
+ http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
579
+
580
+ <key id="d0" for="node" attr.name="label" attr.type="string"/>
581
+ <key id="d1" for="node" attr.name="type" attr.type="string"/>
582
+ <key id="d2" for="edge" attr.name="type" attr.type="string"/>
583
+
584
+ <graph id="G" edgedefault="directed">
585
+ `;
586
+ // Nodes
587
+ for (const [nodeId, node] of data.graph.nodes) {
588
+ const id = this.sanitizeId(nodeId);
589
+ const label = node.filePath.split(/[/\\]/).pop() || node.filePath;
590
+ graphml += ` <node id="${id}">
591
+ <data key="d0">${this.escapeXml(label)}</data>
592
+ <data key="d1">${node.type}</data>
593
+ </node>
594
+ `;
595
+ }
596
+ // Edges
597
+ let edgeId = 0;
598
+ for (const [source, edges] of data.graph.edges) {
599
+ for (const edge of edges) {
600
+ const sourceId = this.sanitizeId(source);
601
+ const targetId = this.sanitizeId(edge.to);
602
+ graphml += ` <edge id="e${edgeId++}" source="${sourceId}" target="${targetId}">
603
+ <data key="d2">${edge.type}</data>
604
+ </edge>
605
+ `;
606
+ }
607
+ }
608
+ graphml += ` </graph>
609
+ </graphml>`;
610
+ return graphml;
611
+ }
612
+ /**
613
+ * Санитизация ID для GraphML
614
+ */
615
+ sanitizeId(str) {
616
+ return str.replace(/[^a-zA-Z0-9_]/g, '_');
617
+ }
618
+ /**
619
+ * Экранирование XML
620
+ */
621
+ escapeXml(str) {
622
+ return str
623
+ .replace(/&/g, '&amp;')
624
+ .replace(/</g, '&lt;')
625
+ .replace(/>/g, '&gt;')
626
+ .replace(/"/g, '&quot;')
627
+ .replace(/'/g, '&apos;');
628
+ }
629
+ }
630
+ /**
631
+ * Быстрые функции экспорта
632
+ */
633
+ export async function exportToJSON(data) {
634
+ const manager = new ExportManager();
635
+ return manager.export(data, {
636
+ format: 'json',
637
+ includeGraph: true,
638
+ includeSymbols: true,
639
+ includeMetrics: true,
640
+ includeRules: true,
641
+ includeDeadCode: true,
642
+ includeDuplication: true,
643
+ includeSecurity: true
644
+ });
645
+ }
646
+ export async function exportToHTML(data, language = 'en') {
647
+ const manager = new ExportManager();
648
+ return manager.export(data, {
649
+ format: 'html',
650
+ includeGraph: true,
651
+ includeMetrics: true,
652
+ includeRules: true,
653
+ includeDeadCode: true,
654
+ includeDuplication: true,
655
+ includeSecurity: true,
656
+ language
657
+ });
658
+ }
659
+ export async function exportToMarkdown(data, language = 'en') {
660
+ const manager = new ExportManager();
661
+ return manager.export(data, {
662
+ format: 'markdown',
663
+ includeGraph: true,
664
+ includeMetrics: true,
665
+ includeRules: true,
666
+ includeDeadCode: true,
667
+ includeDuplication: true,
668
+ includeSecurity: true,
669
+ language
670
+ });
671
+ }
672
+ export async function importFromJSON(jsonString) {
673
+ const manager = new ExportManager();
674
+ return manager.import(jsonString);
675
+ }
676
+ //# sourceMappingURL=index.js.map