@sun-asterisk/sunlint 1.3.34 → 1.3.35

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 (90) hide show
  1. package/core/architecture-integration.js +16 -7
  2. package/core/auto-performance-manager.js +1 -1
  3. package/core/cli-action-handler.js +92 -2
  4. package/core/cli-program.js +96 -138
  5. package/core/file-targeting-service.js +62 -4
  6. package/core/git-utils.js +19 -12
  7. package/core/github-annotate-service.js +326 -11
  8. package/core/html-report-generator.js +326 -731
  9. package/core/impact-integration.js +433 -0
  10. package/core/output-service.js +293 -21
  11. package/core/scoring-service.js +3 -2
  12. package/engines/arch-detect/core/analyzer.js +413 -0
  13. package/engines/arch-detect/core/index.js +22 -0
  14. package/engines/arch-detect/engine/hybrid-detector.js +176 -0
  15. package/engines/arch-detect/engine/index.js +24 -0
  16. package/engines/arch-detect/engine/rule-executor.js +228 -0
  17. package/engines/arch-detect/engine/score-calculator.js +214 -0
  18. package/engines/arch-detect/engine/violation-detector.js +616 -0
  19. package/engines/arch-detect/index.js +50 -0
  20. package/engines/arch-detect/rules/base-rule.js +187 -0
  21. package/engines/arch-detect/rules/index.js +35 -0
  22. package/engines/arch-detect/rules/layered/index.js +28 -0
  23. package/engines/arch-detect/rules/layered/l001-presentation-layer.js +237 -0
  24. package/engines/arch-detect/rules/layered/l002-business-layer.js +215 -0
  25. package/engines/arch-detect/rules/layered/l003-data-layer.js +229 -0
  26. package/engines/arch-detect/rules/layered/l004-model-layer.js +204 -0
  27. package/engines/arch-detect/rules/layered/l005-layer-separation.js +215 -0
  28. package/engines/arch-detect/rules/layered/l006-dependency-direction.js +221 -0
  29. package/engines/arch-detect/rules/layered/layered-rules-collection.js +445 -0
  30. package/engines/arch-detect/rules/modular/index.js +27 -0
  31. package/engines/arch-detect/rules/modular/m001-feature-modules.js +238 -0
  32. package/engines/arch-detect/rules/modular/m002-core-module.js +169 -0
  33. package/engines/arch-detect/rules/modular/m003-module-declaration.js +186 -0
  34. package/engines/arch-detect/rules/modular/m004-public-api.js +171 -0
  35. package/engines/arch-detect/rules/modular/m005-no-deep-imports.js +220 -0
  36. package/engines/arch-detect/rules/modular/modular-rules-collection.js +357 -0
  37. package/engines/arch-detect/rules/presentation/index.js +27 -0
  38. package/engines/arch-detect/rules/presentation/pr001-view-layer.js +221 -0
  39. package/engines/arch-detect/rules/presentation/pr002-presentation-logic.js +192 -0
  40. package/engines/arch-detect/rules/presentation/pr004-data-binding.js +187 -0
  41. package/engines/arch-detect/rules/presentation/pr006-router-layer.js +185 -0
  42. package/engines/arch-detect/rules/presentation/pr007-interactor-layer.js +181 -0
  43. package/engines/arch-detect/rules/presentation/presentation-rules-collection.js +507 -0
  44. package/engines/arch-detect/rules/project-scanner/index.js +31 -0
  45. package/engines/arch-detect/rules/project-scanner/ps001-project-root.js +213 -0
  46. package/engines/arch-detect/rules/project-scanner/ps002-language-detection.js +192 -0
  47. package/engines/arch-detect/rules/project-scanner/ps003-framework-detection.js +339 -0
  48. package/engines/arch-detect/rules/project-scanner/ps004-build-system.js +171 -0
  49. package/engines/arch-detect/rules/project-scanner/ps005-source-directory.js +163 -0
  50. package/engines/arch-detect/rules/project-scanner/ps006-test-directory.js +184 -0
  51. package/engines/arch-detect/rules/project-scanner/ps007-documentation.js +149 -0
  52. package/engines/arch-detect/rules/project-scanner/ps008-cicd-detection.js +163 -0
  53. package/engines/arch-detect/rules/project-scanner/ps009-code-quality.js +152 -0
  54. package/engines/arch-detect/rules/project-scanner/ps010-statistics.js +180 -0
  55. package/engines/arch-detect/rules/rule-registry.js +111 -0
  56. package/engines/arch-detect/types/context.types.js +60 -0
  57. package/engines/arch-detect/types/enums.js +161 -0
  58. package/engines/arch-detect/types/index.js +25 -0
  59. package/engines/arch-detect/types/result.types.js +7 -0
  60. package/engines/arch-detect/types/rule.types.js +7 -0
  61. package/engines/arch-detect/utils/file-scanner.js +411 -0
  62. package/engines/arch-detect/utils/index.js +23 -0
  63. package/engines/arch-detect/utils/pattern-matcher.js +328 -0
  64. package/engines/impact/cli.js +106 -0
  65. package/engines/impact/config/default-config.js +54 -0
  66. package/engines/impact/core/change-detector.js +258 -0
  67. package/engines/impact/core/detectors/database-detector.js +1317 -0
  68. package/engines/impact/core/detectors/endpoint-detector.js +55 -0
  69. package/engines/impact/core/impact-analyzer.js +124 -0
  70. package/engines/impact/core/report-generator.js +462 -0
  71. package/engines/impact/core/utils/ast-parser.js +241 -0
  72. package/engines/impact/core/utils/dependency-graph.js +159 -0
  73. package/engines/impact/core/utils/file-utils.js +116 -0
  74. package/engines/impact/core/utils/git-utils.js +203 -0
  75. package/engines/impact/core/utils/logger.js +13 -0
  76. package/engines/impact/core/utils/method-call-graph.js +1192 -0
  77. package/engines/impact/index.js +135 -0
  78. package/engines/impact/package.json +29 -0
  79. package/package.json +18 -43
  80. package/scripts/build-release.sh +0 -0
  81. package/scripts/copy-impact-analyzer.js +135 -0
  82. package/scripts/install.sh +0 -0
  83. package/scripts/manual-release.sh +0 -0
  84. package/scripts/pre-release-test.sh +0 -0
  85. package/scripts/prepare-release.sh +0 -0
  86. package/scripts/quick-performance-test.js +0 -0
  87. package/scripts/setup-github-registry.sh +0 -0
  88. package/scripts/trigger-release.sh +0 -0
  89. package/scripts/verify-install.sh +0 -0
  90. package/templates/combined-report.html +1418 -0
@@ -0,0 +1,413 @@
1
+ "use strict";
2
+ /**
3
+ * Architecture Analyzer
4
+ * Core orchestrator cho việc phân tích kiến trúc project
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.ArchitectureAnalyzer = void 0;
41
+ const path = __importStar(require("node:path"));
42
+ const hybrid_detector_1 = require("../engine/hybrid-detector");
43
+ const rule_executor_1 = require("../engine/rule-executor");
44
+ const violation_detector_1 = require("../engine/violation-detector");
45
+ const rule_registry_1 = require("../rules/rule-registry");
46
+ const types_1 = require("../types");
47
+ const enums_1 = require("../types/enums");
48
+ const file_scanner_1 = require("../utils/file-scanner");
49
+ // Import all rules to register them
50
+ require("../rules/project-scanner");
51
+ require("../rules/layered");
52
+ require("../rules/modular");
53
+ require("../rules/presentation");
54
+ class ArchitectureAnalyzer {
55
+ constructor(options = {}) {
56
+ this.ruleExecutor = new rule_executor_1.RuleExecutor();
57
+ this.hybridDetector = new hybrid_detector_1.HybridDetector();
58
+ this.violationDetector = new violation_detector_1.ViolationDetector();
59
+ // Merge options với default config
60
+ this.config = {
61
+ ...types_1.DEFAULT_CONFIG,
62
+ scanner: {
63
+ ...types_1.DEFAULT_CONFIG.scanner,
64
+ respectGitignore: options.respectGitignore ?? types_1.DEFAULT_CONFIG.scanner.respectGitignore,
65
+ },
66
+ analyzer: {
67
+ ...types_1.DEFAULT_CONFIG.analyzer,
68
+ patterns: options.patterns || types_1.DEFAULT_CONFIG.analyzer.patterns,
69
+ },
70
+ };
71
+ }
72
+ /**
73
+ * Analyze một project
74
+ */
75
+ async analyze(projectPath) {
76
+ const startTime = Date.now();
77
+ const absolutePath = path.resolve(projectPath);
78
+ console.log(`\n🔍 Analyzing project: ${absolutePath}\n`);
79
+ // Step 1: Scan project
80
+ console.log('📁 Scanning project structure...');
81
+ const scanner = new file_scanner_1.FileScanner({
82
+ ...this.config.scanner,
83
+ projectPath: absolutePath,
84
+ });
85
+ const scanResult = await scanner.scan();
86
+ // Collect all directories
87
+ const directories = this.collectDirectories(scanResult.tree);
88
+ // Step 2: Build project context
89
+ const context = {
90
+ projectPath: absolutePath,
91
+ files: scanResult.files,
92
+ directories,
93
+ directoryTree: scanResult.tree,
94
+ config: this.config,
95
+ cache: new Map(),
96
+ projectInfo: {
97
+ projectRoot: absolutePath,
98
+ },
99
+ helpers: {
100
+ readFile: async (filePath) => file_scanner_1.FileScanner.readFileContent(filePath),
101
+ fileExists: (filePath) => file_scanner_1.FileScanner.fileExists(filePath),
102
+ findFiles: (pattern) => file_scanner_1.FileScanner.findFilesByPattern(scanResult.files, pattern),
103
+ findFolders: (pattern) => file_scanner_1.FileScanner.findFoldersByPattern(scanResult.tree, pattern),
104
+ searchInFiles: async (pattern, files) => file_scanner_1.FileScanner.searchInFiles(pattern, files || scanResult.files),
105
+ getExtension: (filePath) => filePath.split('.').pop() || '',
106
+ getLanguage: (filePath) => file_scanner_1.FileScanner.getLanguageFromPath(filePath),
107
+ },
108
+ };
109
+ console.log(` Found ${context.files.length} files in ${directories.length} directories\n`);
110
+ // Step 3: Execute all pattern rules
111
+ console.log('🔎 Detecting architecture patterns...\n');
112
+ const patternResults = await this.ruleExecutor.executeAll(context);
113
+ // Step 4: Detect hybrid patterns
114
+ const hybridResult = this.hybridDetector.detectHybrid(patternResults);
115
+ // Step 5: Detect violations for primary pattern
116
+ console.log('⚠️ Detecting architecture violations...');
117
+ const primaryPatternResult = patternResults.find((p) => p.pattern === hybridResult.primaryPattern);
118
+ const violationAssessment = primaryPatternResult
119
+ ? this.violationDetector.detectViolations(primaryPatternResult)
120
+ : undefined;
121
+ // Step 6: Generate recommendations
122
+ const recommendations = this.generateRecommendations(patternResults, hybridResult);
123
+ // Step 7: Build final result
124
+ const analysisTime = Date.now() - startTime;
125
+ const result = {
126
+ projectPath: absolutePath,
127
+ timestamp: new Date().toISOString(),
128
+ patterns: patternResults,
129
+ hybridAnalysis: hybridResult,
130
+ primaryPattern: hybridResult.primaryPattern,
131
+ violationAssessment,
132
+ recommendations,
133
+ metadata: {
134
+ totalFiles: context.files.length,
135
+ totalDirectories: directories.length,
136
+ analysisTimeMs: analysisTime,
137
+ rulesExecuted: this.countExecutedRules(patternResults),
138
+ engineVersion: '1.0.0',
139
+ },
140
+ };
141
+ return result;
142
+ }
143
+ /**
144
+ * Collect all directories from tree
145
+ */
146
+ collectDirectories(tree) {
147
+ const dirs = [tree];
148
+ for (const sub of tree.subdirectories) {
149
+ dirs.push(...this.collectDirectories(sub));
150
+ }
151
+ return dirs;
152
+ }
153
+ /**
154
+ * Count total rules executed
155
+ */
156
+ countExecutedRules(results) {
157
+ return results.reduce((sum, r) => sum + r.ruleResults.length, 0);
158
+ }
159
+ /**
160
+ * Generate recommendations based on analysis
161
+ */
162
+ generateRecommendations(patternResults, hybridResult) {
163
+ const recommendations = [];
164
+ // Add hybrid recommendations
165
+ const hybridRecs = this.hybridDetector.getRecommendation(hybridResult);
166
+ recommendations.push(...hybridRecs);
167
+ // Add pattern-specific recommendations
168
+ for (const result of patternResults) {
169
+ if (result.suggestions) {
170
+ recommendations.push(...result.suggestions.slice(0, 3));
171
+ }
172
+ }
173
+ // Remove duplicates
174
+ return [...new Set(recommendations)];
175
+ }
176
+ /**
177
+ * Format result as text
178
+ */
179
+ formatAsText(result) {
180
+ const lines = [];
181
+ lines.push('╔══════════════════════════════════════════════════════════════╗');
182
+ lines.push('║ ARCHITECTURE DETECTION REPORT ║');
183
+ lines.push('╚══════════════════════════════════════════════════════════════╝');
184
+ lines.push('');
185
+ lines.push(`📂 Project: ${result.projectPath}`);
186
+ lines.push(`📅 Analyzed: ${result.timestamp}`);
187
+ lines.push(`⏱️ Analysis time: ${result.metadata.analysisTimeMs}ms`);
188
+ lines.push('');
189
+ // Primary pattern
190
+ lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
191
+ if (result.hybridAnalysis.isHybrid) {
192
+ lines.push(`🏛️ HYBRID ARCHITECTURE: ${result.hybridAnalysis.combination}`);
193
+ lines.push(` Primary: ${result.hybridAnalysis.primaryPattern}`);
194
+ lines.push(` Secondary: ${result.hybridAnalysis.secondaryPatterns.join(', ')}`);
195
+ }
196
+ else {
197
+ lines.push(`🏛️ PRIMARY ARCHITECTURE: ${result.primaryPattern}`);
198
+ }
199
+ lines.push(` Confidence: ${(result.hybridAnalysis.confidence * 100).toFixed(1)}%`);
200
+ lines.push('');
201
+ // Pattern details
202
+ lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
203
+ lines.push('PATTERN DETECTION RESULTS:');
204
+ lines.push('');
205
+ for (const pattern of result.patterns) {
206
+ const scorePercent = (pattern.score.normalizedScore * 100).toFixed(1);
207
+ const bar = this.createProgressBar(pattern.score.normalizedScore, 20);
208
+ const icon = this.getClassificationIcon(pattern.classification);
209
+ lines.push(`${icon} ${pattern.pattern.toString().padEnd(15)} ${bar} ${scorePercent}% (${pattern.classification})`);
210
+ if (pattern.variant) {
211
+ lines.push(` └─ Variant: ${pattern.variant}`);
212
+ }
213
+ }
214
+ lines.push('');
215
+ // Recommendations
216
+ if (result.recommendations.length > 0) {
217
+ lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
218
+ lines.push('💡 RECOMMENDATIONS:');
219
+ lines.push('');
220
+ for (const rec of result.recommendations.slice(0, 5)) {
221
+ lines.push(` • ${rec}`);
222
+ }
223
+ lines.push('');
224
+ }
225
+ // Statistics
226
+ lines.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
227
+ lines.push('📊 STATISTICS:');
228
+ lines.push(` Files analyzed: ${result.metadata.totalFiles}`);
229
+ lines.push(` Directories scanned: ${result.metadata.totalDirectories}`);
230
+ lines.push(` Rules executed: ${result.metadata.rulesExecuted}`);
231
+ lines.push('');
232
+ return lines.join('\n');
233
+ }
234
+ /**
235
+ * Format result as markdown
236
+ */
237
+ formatAsMarkdown(result) {
238
+ const lines = [];
239
+ const projectName = path.basename(result.projectPath);
240
+ const analyzedDate = new Date(result.timestamp).toLocaleString('vi-VN');
241
+ lines.push('# Architecture Detection Report');
242
+ lines.push('');
243
+ lines.push(`| | |`);
244
+ lines.push(`|---|---|`);
245
+ lines.push(`| **Project** | ${projectName} |`);
246
+ lines.push(`| **Analyzed** | ${analyzedDate} |`);
247
+ lines.push(`| **Analysis time** | ${result.metadata.analysisTimeMs}ms |`);
248
+ lines.push('');
249
+ // Primary pattern
250
+ lines.push('## Detected Architecture');
251
+ lines.push('');
252
+ if (result.hybridAnalysis.isHybrid) {
253
+ lines.push(`**Hybrid Architecture:** ${result.hybridAnalysis.combination}`);
254
+ lines.push(`- Primary: ${result.hybridAnalysis.primaryPattern}`);
255
+ lines.push(`- Secondary: ${result.hybridAnalysis.secondaryPatterns.join(', ')}`);
256
+ }
257
+ else {
258
+ lines.push(`**Primary Architecture:** ${result.primaryPattern}`);
259
+ }
260
+ lines.push(`**Confidence:** ${(result.hybridAnalysis.confidence * 100).toFixed(1)}%`);
261
+ lines.push('');
262
+ // Pattern details table
263
+ lines.push('## Pattern Detection Results');
264
+ lines.push('');
265
+ lines.push('| Pattern | Score | Classification | Confidence |');
266
+ lines.push('|---------|-------|----------------|------------|');
267
+ for (const pattern of result.patterns) {
268
+ const scorePercent = (pattern.score.normalizedScore * 100).toFixed(1);
269
+ const confPercent = (pattern.confidence * 100).toFixed(1);
270
+ lines.push(`| ${pattern.pattern} | ${scorePercent}% | ${pattern.classification} | ${confPercent}% |`);
271
+ }
272
+ lines.push('');
273
+ // Recommendations
274
+ if (result.recommendations.length > 0) {
275
+ lines.push('## Recommendations');
276
+ lines.push('');
277
+ for (const rec of result.recommendations) {
278
+ lines.push(`- ${rec}`);
279
+ }
280
+ lines.push('');
281
+ }
282
+ // Violation Assessment
283
+ if (result.violationAssessment && result.violationAssessment.violations.length > 0) {
284
+ const va = result.violationAssessment;
285
+ lines.push('## Architecture Health Assessment');
286
+ lines.push('');
287
+ lines.push(`**Health Score:** ${this.violationDetector.getHealthIcon(va.healthScore)} ${va.healthScore.toFixed(0)}/100`);
288
+ lines.push('');
289
+ lines.push(`**Assessment:** ${va.overallAssessment}`);
290
+ lines.push('');
291
+ // Violation summary
292
+ lines.push('### Violation Summary');
293
+ lines.push('');
294
+ lines.push('| Impact | Count |');
295
+ lines.push('|--------|-------|');
296
+ if (va.summary.critical > 0)
297
+ lines.push(`| 🔴 Critical | ${va.summary.critical} |`);
298
+ if (va.summary.high > 0)
299
+ lines.push(`| 🟠 High | ${va.summary.high} |`);
300
+ if (va.summary.medium > 0)
301
+ lines.push(`| 🟡 Medium | ${va.summary.medium} |`);
302
+ if (va.summary.low > 0)
303
+ lines.push(`| 🟢 Low | ${va.summary.low} |`);
304
+ lines.push(`| **Total** | **${va.summary.total}** |`);
305
+ lines.push('');
306
+ // Violation details
307
+ lines.push('### Violation Details');
308
+ lines.push('');
309
+ for (const violation of va.violations) {
310
+ const icon = this.violationDetector.getImpactIcon(violation.impact);
311
+ lines.push(`#### ${icon} ${violation.ruleName}`);
312
+ lines.push('');
313
+ lines.push(`| Attribute | Value |`);
314
+ lines.push(`|-----------|-------|`);
315
+ lines.push(`| **Impact Level** | ${violation.impact} |`);
316
+ lines.push(`| **Score** | ${violation.description.match(/\d+%/)?.[0] || 'N/A'} |`);
317
+ lines.push(`| **Type** | ${violation.type} |`);
318
+ lines.push('');
319
+ lines.push(`**Problem:** ${violation.impactReason}`);
320
+ lines.push('');
321
+ // Affected Files - SPECIFIC to this project
322
+ if (violation.affectedFiles && violation.affectedFiles.length > 0) {
323
+ lines.push('**📁 Affected Files trong project này:**');
324
+ lines.push('```');
325
+ for (const file of violation.affectedFiles) {
326
+ lines.push(file);
327
+ }
328
+ lines.push('```');
329
+ lines.push('');
330
+ }
331
+ // Examples found - SPECIFIC to this project
332
+ if (violation.examples && violation.examples.length > 0) {
333
+ lines.push('**📍 Ví dụ cụ thể tìm thấy:**');
334
+ lines.push('```');
335
+ for (const example of violation.examples) {
336
+ lines.push(example);
337
+ }
338
+ lines.push('```');
339
+ lines.push('');
340
+ }
341
+ lines.push('**⚠️ Hậu quả nếu không fix:**');
342
+ for (const consequence of violation.consequences) {
343
+ lines.push(`- ${consequence}`);
344
+ }
345
+ lines.push('');
346
+ lines.push(`**✅ Cách fix:** ${violation.suggestedFix}`);
347
+ lines.push('');
348
+ lines.push('---');
349
+ lines.push('');
350
+ }
351
+ }
352
+ else {
353
+ lines.push('## Architecture Health Assessment');
354
+ lines.push('');
355
+ lines.push('💚 **Health Score:** 100/100');
356
+ lines.push('');
357
+ lines.push('**No violations detected.** The architecture follows best practices.');
358
+ lines.push('');
359
+ }
360
+ // Statistics
361
+ lines.push('## Statistics');
362
+ lines.push('');
363
+ lines.push(`- Files analyzed: ${result.metadata.totalFiles}`);
364
+ lines.push(`- Directories scanned: ${result.metadata.totalDirectories}`);
365
+ lines.push(`- Rules executed: ${result.metadata.rulesExecuted}`);
366
+ lines.push('');
367
+ return lines.join('\n');
368
+ }
369
+ /**
370
+ * Create progress bar
371
+ */
372
+ createProgressBar(value, width) {
373
+ const filled = Math.round(value * width);
374
+ const empty = width - filled;
375
+ return '█'.repeat(filled) + '░'.repeat(empty);
376
+ }
377
+ /**
378
+ * Get icon for classification
379
+ */
380
+ getClassificationIcon(classification) {
381
+ switch (classification) {
382
+ case enums_1.PatternClassification.STRONG_MATCH:
383
+ return '✅';
384
+ case enums_1.PatternClassification.DETECTED:
385
+ return '🟢';
386
+ case enums_1.PatternClassification.POSSIBLE:
387
+ return '🟡';
388
+ case enums_1.PatternClassification.WEAK_SIGNAL:
389
+ return '🟠';
390
+ default:
391
+ return '⚪';
392
+ }
393
+ }
394
+ /**
395
+ * Get registered rules count
396
+ */
397
+ getRegisteredRulesCount() {
398
+ return rule_registry_1.ruleRegistry.getAllRules().length;
399
+ }
400
+ /**
401
+ * List all registered rules
402
+ */
403
+ listRegisteredRules() {
404
+ return rule_registry_1.ruleRegistry.getAllRules().map((rule) => ({
405
+ id: rule.id,
406
+ name: rule.name,
407
+ pattern: rule.applicableTo,
408
+ }));
409
+ }
410
+ }
411
+ exports.ArchitectureAnalyzer = ArchitectureAnalyzer;
412
+ exports.default = ArchitectureAnalyzer;
413
+ //# sourceMappingURL=analyzer.js.map
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ /**
3
+ * Core Index
4
+ * Export core components
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ __exportStar(require("./analyzer"), exports);
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ /**
3
+ * Hybrid Detector
4
+ * Phát hiện hybrid patterns (kết hợp nhiều patterns)
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.HybridDetector = void 0;
8
+ const enums_1 = require("../types/enums");
9
+ /**
10
+ * Common hybrid combinations
11
+ */
12
+ const HYBRID_COMBINATIONS = [
13
+ {
14
+ combination: 'LAYERED+MODULAR',
15
+ patterns: [enums_1.PatternType.LAYERED, enums_1.PatternType.MODULAR],
16
+ description: 'Layered architecture with modular organization (e.g., NestJS, Angular)',
17
+ },
18
+ {
19
+ combination: 'MODULAR+MVVM',
20
+ patterns: [enums_1.PatternType.MODULAR, enums_1.PatternType.MVVM],
21
+ description: 'Feature modules with MVVM pattern per module',
22
+ },
23
+ {
24
+ combination: 'LAYERED+MVVM',
25
+ patterns: [enums_1.PatternType.LAYERED, enums_1.PatternType.MVVM],
26
+ description: 'Layered architecture with MVVM presentation (e.g., Android apps)',
27
+ },
28
+ {
29
+ combination: 'MODULAR+VIPER',
30
+ patterns: [enums_1.PatternType.MODULAR, enums_1.PatternType.VIPER],
31
+ description: 'Feature modules with VIPER pattern per module (iOS)',
32
+ },
33
+ ];
34
+ class HybridDetector {
35
+ /**
36
+ * Detect hybrid patterns từ multiple pattern results
37
+ */
38
+ detectHybrid(results) {
39
+ // Get detected patterns (above threshold)
40
+ const detectedPatterns = results.filter((r) => r.classification === enums_1.PatternClassification.STRONG_MATCH ||
41
+ r.classification === enums_1.PatternClassification.DETECTED);
42
+ if (detectedPatterns.length <= 1) {
43
+ // Not a hybrid
44
+ const primary = this.getPrimaryPattern(results);
45
+ return {
46
+ isHybrid: false,
47
+ primaryPattern: primary?.pattern || enums_1.PatternType.LAYERED,
48
+ secondaryPatterns: [],
49
+ combination: primary?.pattern.toString() || 'UNKNOWN',
50
+ analysis: primary
51
+ ? `Single pattern detected: ${primary.pattern} with ${(primary.score.normalizedScore * 100).toFixed(1)}% match`
52
+ : 'No clear pattern detected',
53
+ confidence: primary?.confidence || 0,
54
+ };
55
+ }
56
+ // Sort by score
57
+ const sorted = [...detectedPatterns].sort((a, b) => b.score.normalizedScore - a.score.normalizedScore);
58
+ const primary = sorted[0];
59
+ const secondary = sorted.slice(1);
60
+ // Check for known hybrid combinations
61
+ const detectedTypes = sorted.map((r) => r.pattern);
62
+ const matchedCombination = this.findMatchingCombination(detectedTypes);
63
+ // Build combination string
64
+ const combinationStr = sorted.map((r) => r.pattern).join('+');
65
+ // Calculate hybrid confidence
66
+ const confidence = this.calculateHybridConfidence(sorted);
67
+ // Generate analysis
68
+ const analysis = this.generateAnalysis(sorted, matchedCombination);
69
+ return {
70
+ isHybrid: true,
71
+ primaryPattern: primary.pattern,
72
+ secondaryPatterns: secondary.map((r) => r.pattern),
73
+ combination: matchedCombination?.combination || combinationStr,
74
+ analysis,
75
+ confidence,
76
+ };
77
+ }
78
+ /**
79
+ * Get primary pattern from results
80
+ */
81
+ getPrimaryPattern(results) {
82
+ if (results.length === 0)
83
+ return null;
84
+ // Sort by score and return highest
85
+ const sorted = [...results].sort((a, b) => b.score.normalizedScore - a.score.normalizedScore);
86
+ // Only return if above weak signal threshold
87
+ if (sorted[0].score.normalizedScore >= 0.2) {
88
+ return sorted[0];
89
+ }
90
+ return null;
91
+ }
92
+ /**
93
+ * Find matching known hybrid combination
94
+ */
95
+ findMatchingCombination(patterns) {
96
+ for (const combo of HYBRID_COMBINATIONS) {
97
+ const matched = combo.patterns.every((p) => patterns.includes(p));
98
+ if (matched) {
99
+ return combo;
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+ /**
105
+ * Calculate hybrid confidence
106
+ */
107
+ calculateHybridConfidence(sortedResults) {
108
+ if (sortedResults.length < 2)
109
+ return 0;
110
+ // Base confidence from pattern scores
111
+ let confidence = sortedResults.reduce((sum, r) => sum + r.confidence, 0) / sortedResults.length;
112
+ // Boost if patterns complement each other
113
+ const primary = sortedResults[0].pattern;
114
+ const secondary = sortedResults[1].pattern;
115
+ // Layered + Modular is a common and valid combination
116
+ if ((primary === enums_1.PatternType.LAYERED && secondary === enums_1.PatternType.MODULAR) ||
117
+ (primary === enums_1.PatternType.MODULAR && secondary === enums_1.PatternType.LAYERED)) {
118
+ confidence += 0.1;
119
+ }
120
+ // Presentation + Layered is common in client apps
121
+ if ((primary === enums_1.PatternType.MVVM || primary === enums_1.PatternType.VIPER) &&
122
+ secondary === enums_1.PatternType.LAYERED) {
123
+ confidence += 0.1;
124
+ }
125
+ return Math.min(confidence, 1);
126
+ }
127
+ /**
128
+ * Generate analysis text
129
+ */
130
+ generateAnalysis(sortedResults, matchedCombination) {
131
+ const parts = [];
132
+ if (matchedCombination) {
133
+ parts.push(matchedCombination.description);
134
+ }
135
+ parts.push('Detected patterns:');
136
+ for (const result of sortedResults) {
137
+ const scorePercent = (result.score.normalizedScore * 100).toFixed(1);
138
+ parts.push(`- ${result.pattern}: ${scorePercent}% (${result.classification})`);
139
+ }
140
+ // Add primary pattern analysis
141
+ const primary = sortedResults[0];
142
+ parts.push(`\nPrimary architecture: ${primary.pattern}`);
143
+ if (primary.variant) {
144
+ parts.push(`Variant: ${primary.variant}`);
145
+ }
146
+ return parts.join('\n');
147
+ }
148
+ /**
149
+ * Get recommendation for hybrid architecture
150
+ */
151
+ getRecommendation(hybridResult) {
152
+ const recommendations = [];
153
+ if (!hybridResult.isHybrid) {
154
+ recommendations.push('Consider if a hybrid approach might better suit your needs');
155
+ return recommendations;
156
+ }
157
+ // Recommendations based on combination
158
+ if (hybridResult.combination.includes('LAYERED') &&
159
+ hybridResult.combination.includes('MODULAR')) {
160
+ recommendations.push('Ensure module boundaries are respected to maintain modularity');
161
+ recommendations.push('Consider using barrel files (index.ts) for module public APIs');
162
+ }
163
+ if (hybridResult.combination.includes('MVVM')) {
164
+ recommendations.push('Ensure ViewModels do not depend on View implementations');
165
+ recommendations.push('Use data binding consistently across the application');
166
+ }
167
+ if (hybridResult.combination.includes('VIPER')) {
168
+ recommendations.push('Ensure each VIPER module has all 5 components');
169
+ recommendations.push('Router should be the only component handling navigation');
170
+ }
171
+ return recommendations;
172
+ }
173
+ }
174
+ exports.HybridDetector = HybridDetector;
175
+ exports.default = HybridDetector;
176
+ //# sourceMappingURL=hybrid-detector.js.map
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * Engine Index
4
+ * Export tất cả engine components
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ __exportStar(require("./hybrid-detector"), exports);
22
+ __exportStar(require("./rule-executor"), exports);
23
+ __exportStar(require("./score-calculator"), exports);
24
+ //# sourceMappingURL=index.js.map