@girardelli/architect 1.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 (66) hide show
  1. package/CONTRIBUTING.md +140 -0
  2. package/LICENSE +21 -0
  3. package/PROJECT_STRUCTURE.txt +168 -0
  4. package/README.md +269 -0
  5. package/dist/analyzer.d.ts +17 -0
  6. package/dist/analyzer.d.ts.map +1 -0
  7. package/dist/analyzer.js +254 -0
  8. package/dist/analyzer.js.map +1 -0
  9. package/dist/anti-patterns.d.ts +17 -0
  10. package/dist/anti-patterns.d.ts.map +1 -0
  11. package/dist/anti-patterns.js +211 -0
  12. package/dist/anti-patterns.js.map +1 -0
  13. package/dist/cli.d.ts +15 -0
  14. package/dist/cli.d.ts.map +1 -0
  15. package/dist/cli.js +164 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/config.d.ts +6 -0
  18. package/dist/config.d.ts.map +1 -0
  19. package/dist/config.js +73 -0
  20. package/dist/config.js.map +1 -0
  21. package/dist/diagram.d.ts +9 -0
  22. package/dist/diagram.d.ts.map +1 -0
  23. package/dist/diagram.js +116 -0
  24. package/dist/diagram.js.map +1 -0
  25. package/dist/html-reporter.d.ts +23 -0
  26. package/dist/html-reporter.d.ts.map +1 -0
  27. package/dist/html-reporter.js +454 -0
  28. package/dist/html-reporter.js.map +1 -0
  29. package/dist/index.d.ts +48 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +151 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/reporter.d.ts +13 -0
  34. package/dist/reporter.d.ts.map +1 -0
  35. package/dist/reporter.js +135 -0
  36. package/dist/reporter.js.map +1 -0
  37. package/dist/scanner.d.ts +25 -0
  38. package/dist/scanner.d.ts.map +1 -0
  39. package/dist/scanner.js +288 -0
  40. package/dist/scanner.js.map +1 -0
  41. package/dist/scorer.d.ts +15 -0
  42. package/dist/scorer.d.ts.map +1 -0
  43. package/dist/scorer.js +172 -0
  44. package/dist/scorer.js.map +1 -0
  45. package/dist/types.d.ts +106 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +2 -0
  48. package/dist/types.js.map +1 -0
  49. package/examples/sample-report.md +207 -0
  50. package/jest.config.js +18 -0
  51. package/package.json +70 -0
  52. package/src/analyzer.ts +310 -0
  53. package/src/anti-patterns.ts +264 -0
  54. package/src/cli.ts +183 -0
  55. package/src/config.ts +82 -0
  56. package/src/diagram.ts +144 -0
  57. package/src/html-reporter.ts +485 -0
  58. package/src/index.ts +212 -0
  59. package/src/reporter.ts +166 -0
  60. package/src/scanner.ts +298 -0
  61. package/src/scorer.ts +193 -0
  62. package/src/types.ts +114 -0
  63. package/tests/anti-patterns.test.ts +94 -0
  64. package/tests/scanner.test.ts +55 -0
  65. package/tests/scorer.test.ts +80 -0
  66. package/tsconfig.json +24 -0
@@ -0,0 +1,454 @@
1
+ /**
2
+ * Gera relatórios HTML visuais premium a partir de AnalysisReport
3
+ */
4
+ export class HtmlReportGenerator {
5
+ generateHtml(report) {
6
+ const grouped = this.groupAntiPatterns(report.antiPatterns);
7
+ const sugGrouped = this.groupSuggestions(report.suggestions);
8
+ return `<!DOCTYPE html>
9
+ <html lang="en">
10
+ <head>
11
+ <meta charset="UTF-8">
12
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
13
+ <title>Architect Report — ${this.escapeHtml(report.projectInfo.name)}</title>
14
+ ${this.getStyles()}
15
+ <script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"><\/script>
16
+ </head>
17
+ <body>
18
+ ${this.renderHeader(report)}
19
+ <div class="container">
20
+ ${this.renderScoreHero(report)}
21
+ ${this.renderStats(report)}
22
+ ${this.renderLayers(report)}
23
+ ${this.renderAntiPatterns(report, grouped)}
24
+ ${this.renderDiagram(report)}
25
+ ${this.renderSuggestions(sugGrouped)}
26
+ </div>
27
+ ${this.renderFooter()}
28
+ <script>
29
+ mermaid.initialize({ theme: 'default', startOnLoad: true });
30
+ <\/script>
31
+ </body>
32
+ </html>`;
33
+ }
34
+ scoreColor(score) {
35
+ if (score >= 70)
36
+ return '#22c55e';
37
+ if (score >= 50)
38
+ return '#f59e0b';
39
+ return '#ef4444';
40
+ }
41
+ scoreEmoji(score) {
42
+ if (score >= 70)
43
+ return '✅';
44
+ if (score >= 50)
45
+ return '⚠️';
46
+ return '❌';
47
+ }
48
+ scoreLabel(score) {
49
+ if (score >= 90)
50
+ return 'Excellent';
51
+ if (score >= 70)
52
+ return 'Good';
53
+ if (score >= 50)
54
+ return 'Needs Attention';
55
+ if (score >= 30)
56
+ return 'Poor';
57
+ return 'Critical';
58
+ }
59
+ escapeHtml(text) {
60
+ return text
61
+ .replace(/&/g, '&amp;')
62
+ .replace(/</g, '&lt;')
63
+ .replace(/>/g, '&gt;')
64
+ .replace(/"/g, '&quot;');
65
+ }
66
+ groupAntiPatterns(antiPatterns) {
67
+ const grouped = {};
68
+ for (const p of antiPatterns) {
69
+ if (!grouped[p.name]) {
70
+ grouped[p.name] = { count: 0, severity: p.severity, locations: [], suggestion: p.suggestion };
71
+ }
72
+ grouped[p.name].count++;
73
+ if (grouped[p.name].locations.length < 10) {
74
+ grouped[p.name].locations.push(p.location);
75
+ }
76
+ }
77
+ return grouped;
78
+ }
79
+ groupSuggestions(suggestions) {
80
+ const map = new Map();
81
+ for (const s of suggestions) {
82
+ const key = `${s.title}|${s.priority}`;
83
+ if (!map.has(key)) {
84
+ map.set(key, { ...s, count: 0 });
85
+ }
86
+ map.get(key).count++;
87
+ }
88
+ return Array.from(map.values()).slice(0, 15);
89
+ }
90
+ renderHeader(report) {
91
+ const date = new Date(report.timestamp).toLocaleDateString('en-US', {
92
+ year: 'numeric',
93
+ month: 'long',
94
+ day: 'numeric',
95
+ });
96
+ return `
97
+ <div class="header">
98
+ <h1>🏗️ Architect</h1>
99
+ <p class="subtitle">Architecture Analysis Report</p>
100
+ <div class="meta">
101
+ <span>📂 <strong>${this.escapeHtml(report.projectInfo.name)}</strong></span>
102
+ <span>📁 <strong>${report.projectInfo.totalFiles}</strong> files</span>
103
+ <span>📝 <strong>${report.projectInfo.totalLines.toLocaleString()}</strong> lines</span>
104
+ <span>💻 <strong>${report.projectInfo.primaryLanguages.join(', ')}</strong></span>
105
+ ${report.projectInfo.frameworks.length > 0 ? `<span>🔧 <strong>${report.projectInfo.frameworks.join(', ')}</strong></span>` : ''}
106
+ <span>📅 <strong>${date}</strong></span>
107
+ </div>
108
+ </div>`;
109
+ }
110
+ renderScoreHero(report) {
111
+ const overall = report.score.overall;
112
+ const circumference = 2 * Math.PI * 85;
113
+ const offset = circumference * (1 - overall / 100);
114
+ const breakdownItems = Object.entries(report.score.breakdown)
115
+ .map(([name, score]) => `
116
+ <div class="score-item">
117
+ <div class="name">${name}</div>
118
+ <div class="val" style="color: ${this.scoreColor(score)}">${score} ${this.scoreEmoji(score)}</div>
119
+ <div class="bar-container">
120
+ <div class="bar" style="width: ${score}%; background: ${this.scoreColor(score)}"></div>
121
+ </div>
122
+ </div>`)
123
+ .join('');
124
+ return `
125
+ <div class="score-hero">
126
+ <div class="score-circle">
127
+ <svg viewBox="0 0 200 200" width="180" height="180">
128
+ <circle class="bg" cx="100" cy="100" r="85" />
129
+ <circle class="fg" cx="100" cy="100" r="85"
130
+ stroke="${this.scoreColor(overall)}"
131
+ stroke-dasharray="${circumference}"
132
+ stroke-dashoffset="${offset}" />
133
+ </svg>
134
+ <div class="score-value">
135
+ <div class="number" style="color: ${this.scoreColor(overall)}">${overall}</div>
136
+ <div class="label">/ 100</div>
137
+ <div class="grade">${this.scoreLabel(overall)}</div>
138
+ </div>
139
+ </div>
140
+ <div class="score-breakdown">
141
+ ${breakdownItems}
142
+ </div>
143
+ </div>`;
144
+ }
145
+ renderStats(report) {
146
+ return `
147
+ <div class="stats-grid">
148
+ <div class="stat-card">
149
+ <div class="value">${report.projectInfo.totalFiles}</div>
150
+ <div class="label">Files Scanned</div>
151
+ </div>
152
+ <div class="stat-card">
153
+ <div class="value">${report.projectInfo.totalLines.toLocaleString()}</div>
154
+ <div class="label">Lines of Code</div>
155
+ </div>
156
+ <div class="stat-card">
157
+ <div class="value">${report.antiPatterns.length}</div>
158
+ <div class="label">Anti-Patterns</div>
159
+ </div>
160
+ <div class="stat-card">
161
+ <div class="value">${report.dependencyGraph.edges.length}</div>
162
+ <div class="label">Dependencies</div>
163
+ </div>
164
+ </div>`;
165
+ }
166
+ renderLayers(report) {
167
+ if (report.layers.length === 0)
168
+ return '';
169
+ const layerColors = {
170
+ API: '#ec4899',
171
+ Service: '#3b82f6',
172
+ Data: '#10b981',
173
+ UI: '#f59e0b',
174
+ Infrastructure: '#8b5cf6',
175
+ };
176
+ const cards = report.layers
177
+ .map((l) => {
178
+ const color = layerColors[l.name] || '#64748b';
179
+ return `
180
+ <div class="layer-card" style="--layer-color: ${color}">
181
+ <div class="count" style="color: ${color}">${l.files.length}</div>
182
+ <div class="name">${l.name}</div>
183
+ <div class="desc">${this.escapeHtml(l.description)}</div>
184
+ </div>`;
185
+ })
186
+ .join('');
187
+ return `
188
+ <h2 class="section-title">📐 Architectural Layers</h2>
189
+ <div class="layers-grid">${cards}</div>`;
190
+ }
191
+ renderAntiPatterns(report, grouped) {
192
+ if (report.antiPatterns.length === 0) {
193
+ return `
194
+ <h2 class="section-title">✅ Anti-Patterns</h2>
195
+ <div class="card success-card">
196
+ <p>No significant anti-patterns detected. Excellent architecture!</p>
197
+ </div>`;
198
+ }
199
+ const rows = Object.entries(grouped)
200
+ .sort((a, b) => b[1].count - a[1].count)
201
+ .map(([name, data]) => `
202
+ <tr>
203
+ <td><strong>${this.escapeHtml(name)}</strong></td>
204
+ <td class="count-cell">${data.count}</td>
205
+ <td><span class="severity-badge severity-${data.severity}">${data.severity}</span></td>
206
+ <td><small class="suggestion">${this.escapeHtml(data.suggestion)}</small></td>
207
+ <td><div class="locations">${data.locations
208
+ .slice(0, 5)
209
+ .map((l) => `<code>${this.escapeHtml(l)}</code>`)
210
+ .join(' ')}${data.locations.length > 5 ? ` <em>+${data.count - 5} more</em>` : ''}</div></td>
211
+ </tr>`)
212
+ .join('');
213
+ return `
214
+ <h2 class="section-title">⚠️ Anti-Patterns (${report.antiPatterns.length})</h2>
215
+ <div class="card">
216
+ <table>
217
+ <thead>
218
+ <tr>
219
+ <th>Pattern</th>
220
+ <th>Count</th>
221
+ <th>Severity</th>
222
+ <th>Suggestion</th>
223
+ <th>Locations</th>
224
+ </tr>
225
+ </thead>
226
+ <tbody>${rows}</tbody>
227
+ </table>
228
+ </div>`;
229
+ }
230
+ renderDiagram(report) {
231
+ if (!report.diagram.mermaid)
232
+ return '';
233
+ return `
234
+ <h2 class="section-title">📊 Architecture Diagram</h2>
235
+ <div class="card">
236
+ <div class="mermaid-container">
237
+ <pre class="mermaid">${this.escapeHtml(report.diagram.mermaid)}</pre>
238
+ </div>
239
+ </div>`;
240
+ }
241
+ renderSuggestions(suggestions) {
242
+ if (suggestions.length === 0)
243
+ return '';
244
+ const rows = suggestions
245
+ .map((s, i) => `
246
+ <tr>
247
+ <td>${i + 1}</td>
248
+ <td><span class="severity-badge severity-${s.priority}">${s.priority}</span></td>
249
+ <td>
250
+ <strong>${this.escapeHtml(s.title)}</strong>
251
+ ${s.count > 1 ? `<span class="count-badge">×${s.count}</span>` : ''}
252
+ <br/><small class="suggestion">${this.escapeHtml(s.description)}</small>
253
+ </td>
254
+ <td class="impact">${this.escapeHtml(s.impact)}</td>
255
+ </tr>`)
256
+ .join('');
257
+ return `
258
+ <h2 class="section-title">💡 Refactoring Suggestions</h2>
259
+ <div class="card">
260
+ <table>
261
+ <thead>
262
+ <tr>
263
+ <th>#</th>
264
+ <th>Priority</th>
265
+ <th>Suggestion</th>
266
+ <th>Impact</th>
267
+ </tr>
268
+ </thead>
269
+ <tbody>${rows}</tbody>
270
+ </table>
271
+ </div>`;
272
+ }
273
+ renderFooter() {
274
+ return `
275
+ <div class="footer">
276
+ <p>Generated by <a href="https://github.com/camilogivago/architect">🏗️ Architect</a> — AI-powered architecture analysis</p>
277
+ <p>By <strong>Camilo Girardelli</strong> · <a href="https://girardelli.tech">Girardelli Tecnologia</a></p>
278
+ </div>`;
279
+ }
280
+ getStyles() {
281
+ return `<style>
282
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
283
+
284
+ * { margin: 0; padding: 0; box-sizing: border-box; }
285
+
286
+ body {
287
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
288
+ background: #0f172a;
289
+ color: #e2e8f0;
290
+ line-height: 1.6;
291
+ min-height: 100vh;
292
+ }
293
+
294
+ .container { max-width: 1200px; margin: 0 auto; padding: 2rem; }
295
+
296
+ /* ── Header ── */
297
+ .header {
298
+ text-align: center;
299
+ padding: 3rem 2rem;
300
+ background: linear-gradient(135deg, #1e293b 0%, #0f172a 50%, #1e1b4b 100%);
301
+ border-bottom: 1px solid #334155;
302
+ margin-bottom: 2rem;
303
+ }
304
+ .header h1 {
305
+ font-size: 2.5rem;
306
+ font-weight: 900;
307
+ background: linear-gradient(135deg, #818cf8, #c084fc, #f472b6);
308
+ -webkit-background-clip: text;
309
+ -webkit-text-fill-color: transparent;
310
+ margin-bottom: 0.5rem;
311
+ }
312
+ .header .subtitle { color: #94a3b8; font-size: 1.1rem; font-weight: 300; }
313
+ .header .meta {
314
+ margin-top: 1rem;
315
+ display: flex; justify-content: center; gap: 1rem; flex-wrap: wrap;
316
+ }
317
+ .header .meta span {
318
+ background: #1e293b; padding: 0.4rem 1rem; border-radius: 99px;
319
+ font-size: 0.85rem; color: #94a3b8; border: 1px solid #334155;
320
+ }
321
+ .header .meta span strong { color: #e2e8f0; }
322
+
323
+ /* ── Score Hero ── */
324
+ .score-hero {
325
+ display: flex; align-items: center; justify-content: center; gap: 3rem;
326
+ padding: 2.5rem;
327
+ background: linear-gradient(135deg, #1e293b, #1e1b4b);
328
+ border-radius: 24px; border: 1px solid #334155;
329
+ margin-bottom: 2rem; flex-wrap: wrap;
330
+ }
331
+ .score-circle { position: relative; width: 180px; height: 180px; }
332
+ .score-circle svg { transform: rotate(-90deg); }
333
+ .score-circle circle { fill: none; stroke-width: 10; stroke-linecap: round; }
334
+ .score-circle .bg { stroke: #334155; }
335
+ .score-circle .fg { transition: stroke-dashoffset 1.5s cubic-bezier(0.4, 0, 0.2, 1); }
336
+ .score-value {
337
+ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
338
+ text-align: center;
339
+ }
340
+ .score-value .number { font-size: 3rem; font-weight: 900; line-height: 1; }
341
+ .score-value .label { font-size: 0.85rem; color: #94a3b8; text-transform: uppercase; letter-spacing: 2px; }
342
+ .score-value .grade { font-size: 0.75rem; color: #64748b; margin-top: 4px; text-transform: uppercase; letter-spacing: 1px; }
343
+
344
+ .score-breakdown { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
345
+ .score-item {
346
+ padding: 1rem 1.5rem; background: rgba(255,255,255,0.03);
347
+ border-radius: 12px; border: 1px solid #334155; min-width: 200px;
348
+ }
349
+ .score-item .name { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 1px; color: #94a3b8; margin-bottom: 0.3rem; }
350
+ .score-item .bar-container { background: #1e293b; border-radius: 99px; height: 8px; margin-top: 0.5rem; overflow: hidden; }
351
+ .score-item .bar { height: 100%; border-radius: 99px; transition: width 1.5s cubic-bezier(0.4, 0, 0.2, 1); }
352
+ .score-item .val { font-size: 1.5rem; font-weight: 700; }
353
+
354
+ /* ── Stats Grid ── */
355
+ .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin-bottom: 2rem; }
356
+ .stat-card {
357
+ background: linear-gradient(135deg, #1e293b, #0f172a);
358
+ border: 1px solid #334155; border-radius: 16px; padding: 1.5rem; text-align: center;
359
+ }
360
+ .stat-card .value {
361
+ font-size: 2rem; font-weight: 800;
362
+ background: linear-gradient(135deg, #818cf8, #c084fc);
363
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
364
+ }
365
+ .stat-card .label { font-size: 0.85rem; color: #94a3b8; margin-top: 0.3rem; }
366
+
367
+ /* ── Section Title ── */
368
+ .section-title {
369
+ font-size: 1.4rem; font-weight: 700; margin: 2.5rem 0 1rem;
370
+ display: flex; align-items: center; gap: 0.5rem;
371
+ }
372
+
373
+ /* ── Cards ── */
374
+ .card {
375
+ background: #1e293b; border-radius: 16px; border: 1px solid #334155;
376
+ padding: 1.5rem; margin-bottom: 1rem; overflow-x: auto;
377
+ }
378
+ .success-card { border-color: #22c55e40; color: #22c55e; text-align: center; padding: 2rem; font-size: 1.1rem; }
379
+
380
+ /* ── Layers Grid ── */
381
+ .layers-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; }
382
+ .layer-card {
383
+ background: linear-gradient(135deg, #1e293b, #0f172a);
384
+ border: 1px solid #334155; border-radius: 16px; padding: 1.5rem;
385
+ text-align: center; position: relative; overflow: hidden;
386
+ }
387
+ .layer-card::before {
388
+ content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px;
389
+ background: var(--layer-color, #64748b);
390
+ }
391
+ .layer-card .count { font-size: 2.5rem; font-weight: 900; line-height: 1; }
392
+ .layer-card .name { font-size: 1rem; color: #94a3b8; margin-top: 0.3rem; font-weight: 600; }
393
+ .layer-card .desc { font-size: 0.75rem; color: #475569; margin-top: 0.5rem; }
394
+
395
+ /* ── Tables ── */
396
+ table { width: 100%; border-collapse: collapse; }
397
+ th, td { text-align: left; padding: 0.75rem 1rem; border-bottom: 1px solid #334155; }
398
+ th { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 1px; color: #64748b; font-weight: 600; }
399
+ .count-cell { font-weight: 700; font-size: 1.1rem; }
400
+ .impact { color: #94a3b8; font-size: 0.85rem; }
401
+ .suggestion { color: #64748b; font-size: 0.8rem; }
402
+
403
+ .severity-badge {
404
+ display: inline-block; padding: 0.2rem 0.6rem; border-radius: 99px;
405
+ font-size: 0.72rem; font-weight: 600; letter-spacing: 0.5px;
406
+ }
407
+ .severity-CRITICAL { background: #dc262620; color: #ef4444; border: 1px solid #ef444440; }
408
+ .severity-HIGH { background: #f59e0b20; color: #f59e0b; border: 1px solid #f59e0b40; }
409
+ .severity-MEDIUM { background: #3b82f620; color: #60a5fa; border: 1px solid #60a5fa40; }
410
+ .severity-LOW { background: #22c55e20; color: #22c55e; border: 1px solid #22c55e40; }
411
+
412
+ .count-badge {
413
+ display: inline-block; background: #818cf820; color: #818cf8; padding: 0.1rem 0.4rem;
414
+ border-radius: 99px; font-size: 0.7rem; margin-left: 0.5rem; font-weight: 600;
415
+ }
416
+
417
+ .locations { font-size: 0.75rem; color: #64748b; }
418
+ .locations code { background: #0f172a; padding: 1px 4px; border-radius: 3px; font-size: 0.7rem; }
419
+
420
+ /* ── Mermaid ── */
421
+ .mermaid-container {
422
+ background: #f8fafc; border-radius: 12px; padding: 2rem; text-align: center; color: #0f172a;
423
+ }
424
+
425
+ /* ── Footer ── */
426
+ .footer {
427
+ text-align: center; padding: 2rem; color: #475569; font-size: 0.85rem;
428
+ border-top: 1px solid #1e293b; margin-top: 3rem;
429
+ }
430
+ .footer a { color: #818cf8; text-decoration: none; }
431
+ .footer a:hover { text-decoration: underline; }
432
+
433
+ /* ── Responsive ── */
434
+ @media (max-width: 768px) {
435
+ .score-hero { flex-direction: column; gap: 1.5rem; }
436
+ .score-breakdown { grid-template-columns: 1fr; }
437
+ .header h1 { font-size: 1.8rem; }
438
+ .container { padding: 1rem; }
439
+ }
440
+
441
+ /* ── Print ── */
442
+ @media print {
443
+ body { background: white; color: #1e293b; }
444
+ .header { background: white; border-bottom: 2px solid #e2e8f0; }
445
+ .header h1 { -webkit-text-fill-color: #4f46e5; }
446
+ .card, .stat-card, .score-hero, .layer-card, .score-item {
447
+ background: white; border-color: #e2e8f0;
448
+ }
449
+ .mermaid-container { border: 1px solid #e2e8f0; }
450
+ }
451
+ </style>`;
452
+ }
453
+ }
454
+ //# sourceMappingURL=html-reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-reporter.js","sourceRoot":"","sources":["../src/html-reporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { ProjectScanner } from './scanner.js';
2
+ import { ArchitectureAnalyzer } from './analyzer.js';
3
+ import { AntiPatternDetector } from './anti-patterns.js';
4
+ import { ArchitectureScorer } from './scorer.js';
5
+ import { DiagramGenerator } from './diagram.js';
6
+ import { ReportGenerator } from './reporter.js';
7
+ import { HtmlReportGenerator } from './html-reporter.js';
8
+ import { ConfigLoader } from './config.js';
9
+ import { AnalysisReport } from './types.js';
10
+ export interface ArchitectCommand {
11
+ analyze: (path: string) => Promise<AnalysisReport>;
12
+ diagram: (path: string) => Promise<string>;
13
+ score: (path: string) => Promise<{
14
+ overall: number;
15
+ breakdown: Record<string, number>;
16
+ }>;
17
+ antiPatterns: (path: string) => Promise<Array<{
18
+ name: string;
19
+ severity: string;
20
+ description: string;
21
+ }>>;
22
+ layers: (path: string) => Promise<Array<{
23
+ name: string;
24
+ files: string[];
25
+ }>>;
26
+ }
27
+ declare class Architect implements ArchitectCommand {
28
+ analyze(projectPath: string): Promise<AnalysisReport>;
29
+ private relativizePaths;
30
+ diagram(projectPath: string): Promise<string>;
31
+ score(projectPath: string): Promise<{
32
+ overall: number;
33
+ breakdown: Record<string, number>;
34
+ }>;
35
+ antiPatterns(projectPath: string): Promise<Array<{
36
+ name: string;
37
+ severity: string;
38
+ description: string;
39
+ }>>;
40
+ layers(projectPath: string): Promise<Array<{
41
+ name: string;
42
+ files: string[];
43
+ }>>;
44
+ private generateSuggestions;
45
+ }
46
+ export declare const architect: Architect;
47
+ export { ProjectScanner, ArchitectureAnalyzer, AntiPatternDetector, ArchitectureScorer, DiagramGenerator, ReportGenerator, HtmlReportGenerator, ConfigLoader, };
48
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IACnD,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC,CAAC;IACzF,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACxG,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC,CAAC;CAC7E;AAED,cAAM,SAAU,YAAW,gBAAgB;IACnC,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAgE3D,OAAO,CAAC,eAAe;IA6BjB,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiB7C,KAAK,CACT,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IAQ5D,YAAY,CAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IASpE,MAAM,CACV,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAQpD,OAAO,CAAC,mBAAmB;CAoC5B;AAED,eAAO,MAAM,SAAS,WAAkB,CAAC;AAEzC,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,YAAY,GACb,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,151 @@
1
+ import { ProjectScanner } from './scanner.js';
2
+ import { ArchitectureAnalyzer } from './analyzer.js';
3
+ import { AntiPatternDetector } from './anti-patterns.js';
4
+ import { ArchitectureScorer } from './scorer.js';
5
+ import { DiagramGenerator } from './diagram.js';
6
+ import { ReportGenerator } from './reporter.js';
7
+ import { HtmlReportGenerator } from './html-reporter.js';
8
+ import { ConfigLoader } from './config.js';
9
+ import { relative } from 'path';
10
+ class Architect {
11
+ async analyze(projectPath) {
12
+ const config = ConfigLoader.loadConfig(projectPath);
13
+ const scanner = new ProjectScanner(projectPath, config);
14
+ const projectInfo = scanner.scan();
15
+ if (!projectInfo.fileTree) {
16
+ throw new Error('Failed to scan project');
17
+ }
18
+ const analyzer = new ArchitectureAnalyzer(projectPath);
19
+ const dependencies = new Map();
20
+ for (const [file, imports] of analyzer
21
+ .analyzeDependencies(projectInfo.fileTree)
22
+ .reduce((map, edge) => {
23
+ if (!map.has(edge.from)) {
24
+ map.set(edge.from, new Set());
25
+ }
26
+ map.get(edge.from).add(edge.to);
27
+ return map;
28
+ }, new Map())
29
+ .entries()) {
30
+ dependencies.set(file, imports);
31
+ }
32
+ const edges = analyzer.analyzeDependencies(projectInfo.fileTree);
33
+ const layers = analyzer.detectLayers(projectInfo.fileTree);
34
+ const detector = new AntiPatternDetector(config);
35
+ const antiPatterns = detector.detect(projectInfo.fileTree, dependencies);
36
+ const scorer = new ArchitectureScorer();
37
+ const score = scorer.score(edges, antiPatterns, projectInfo.totalFiles);
38
+ const diagramGenerator = new DiagramGenerator();
39
+ const layerDiagram = diagramGenerator.generateLayerDiagram(layers);
40
+ const suggestions = this.generateSuggestions(antiPatterns, score);
41
+ const report = {
42
+ timestamp: new Date().toISOString(),
43
+ projectInfo,
44
+ score,
45
+ antiPatterns,
46
+ layers,
47
+ dependencyGraph: {
48
+ nodes: Array.from(new Set([...edges.map((e) => e.from), ...edges.map((e) => e.to)])),
49
+ edges,
50
+ },
51
+ suggestions,
52
+ diagram: {
53
+ mermaid: layerDiagram,
54
+ type: 'layer',
55
+ },
56
+ };
57
+ // Normalize paths to be relative to project root
58
+ return this.relativizePaths(report, projectPath);
59
+ }
60
+ relativizePaths(report, basePath) {
61
+ const rel = (p) => {
62
+ if (p.startsWith('/') || p.startsWith('\\')) {
63
+ return relative(basePath, p) || p;
64
+ }
65
+ return p;
66
+ };
67
+ report.antiPatterns = report.antiPatterns.map((p) => ({
68
+ ...p,
69
+ location: rel(p.location),
70
+ affectedFiles: p.affectedFiles?.map(rel),
71
+ }));
72
+ report.layers = report.layers.map((l) => ({
73
+ ...l,
74
+ files: l.files.map(rel),
75
+ }));
76
+ report.dependencyGraph.nodes = report.dependencyGraph.nodes.map(rel);
77
+ report.dependencyGraph.edges = report.dependencyGraph.edges.map((e) => ({
78
+ ...e,
79
+ from: rel(e.from),
80
+ to: rel(e.to),
81
+ }));
82
+ return report;
83
+ }
84
+ async diagram(projectPath) {
85
+ const config = ConfigLoader.loadConfig(projectPath);
86
+ const scanner = new ProjectScanner(projectPath, config);
87
+ const projectInfo = scanner.scan();
88
+ if (!projectInfo.fileTree) {
89
+ throw new Error('Failed to scan project');
90
+ }
91
+ const analyzer = new ArchitectureAnalyzer(projectPath);
92
+ const edges = analyzer.analyzeDependencies(projectInfo.fileTree);
93
+ const layers = analyzer.detectLayers(projectInfo.fileTree);
94
+ const generator = new DiagramGenerator();
95
+ return generator.generateComponentDiagram(edges, layers);
96
+ }
97
+ async score(projectPath) {
98
+ const report = await this.analyze(projectPath);
99
+ return {
100
+ overall: report.score.overall,
101
+ breakdown: report.score.breakdown,
102
+ };
103
+ }
104
+ async antiPatterns(projectPath) {
105
+ const report = await this.analyze(projectPath);
106
+ return report.antiPatterns.map((p) => ({
107
+ name: p.name,
108
+ severity: p.severity,
109
+ description: p.description,
110
+ }));
111
+ }
112
+ async layers(projectPath) {
113
+ const report = await this.analyze(projectPath);
114
+ return report.layers.map((l) => ({
115
+ name: l.name,
116
+ files: l.files,
117
+ }));
118
+ }
119
+ generateSuggestions(antiPatterns, score) {
120
+ const suggestions = [];
121
+ for (const pattern of antiPatterns) {
122
+ const priority = pattern.severity === 'CRITICAL' ? 'CRITICAL' : 'HIGH';
123
+ suggestions.push({
124
+ priority,
125
+ title: pattern.name,
126
+ description: pattern.suggestion,
127
+ impact: `Addressing this ${pattern.name} will improve overall architecture score`,
128
+ });
129
+ }
130
+ if (score.breakdown.coupling < 70) {
131
+ suggestions.push({
132
+ priority: 'HIGH',
133
+ title: 'Reduce Coupling',
134
+ description: 'Use dependency injection and invert control to reduce module interdependencies',
135
+ impact: 'Can improve coupling score by 15-20 points',
136
+ });
137
+ }
138
+ if (score.breakdown.cohesion < 70) {
139
+ suggestions.push({
140
+ priority: 'MEDIUM',
141
+ title: 'Improve Cohesion',
142
+ description: 'Group related functionality closer together; consider extracting utility modules',
143
+ impact: 'Can improve cohesion score by 10-15 points',
144
+ });
145
+ }
146
+ return suggestions;
147
+ }
148
+ }
149
+ export const architect = new Architect();
150
+ export { ProjectScanner, ArchitectureAnalyzer, AntiPatternDetector, ArchitectureScorer, DiagramGenerator, ReportGenerator, HtmlReportGenerator, ConfigLoader, };
151
+ //# sourceMappingURL=index.js.map