vibecodingmachine-core 2026.2.20-438 → 2026.2.26-1739
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 +240 -0
- package/package.json +10 -2
- package/src/agents/Agent.js +300 -0
- package/src/agents/AgentAdditionService.js +311 -0
- package/src/agents/AgentCheckService.js +690 -0
- package/src/agents/AgentInstallationService.js +140 -0
- package/src/agents/AgentSetupService.js +467 -0
- package/src/agents/AgentStatus.js +183 -0
- package/src/agents/AgentVerificationService.js +634 -0
- package/src/agents/ConfigurationSchemaValidator.js +543 -0
- package/src/agents/EnvironmentConfigurationManager.js +602 -0
- package/src/agents/InstallationErrorHandler.js +372 -0
- package/src/agents/InstallationLog.js +363 -0
- package/src/agents/InstallationMethod.js +510 -0
- package/src/agents/InstallationOrchestrator.js +352 -0
- package/src/agents/InstallationProgressReporter.js +372 -0
- package/src/agents/InstallationRetryManager.js +322 -0
- package/src/agents/InstallationType.js +254 -0
- package/src/agents/OperationTypes.js +310 -0
- package/src/agents/PerformanceMetricsCollector.js +493 -0
- package/src/agents/SecurityValidationService.js +534 -0
- package/src/agents/VerificationTest.js +354 -0
- package/src/agents/VerificationType.js +226 -0
- package/src/agents/WindowsPermissionHandler.js +518 -0
- package/src/agents/config/AgentConfigManager.js +393 -0
- package/src/agents/config/AgentDefaultsRegistry.js +373 -0
- package/src/agents/config/ConfigValidator.js +281 -0
- package/src/agents/discovery/AgentDiscoveryService.js +707 -0
- package/src/agents/logging/AgentLogger.js +511 -0
- package/src/agents/status/AgentStatusManager.js +481 -0
- package/src/agents/storage/FileManager.js +454 -0
- package/src/agents/verification/AgentCommunicationTester.js +474 -0
- package/src/agents/verification/BaseVerifier.js +430 -0
- package/src/agents/verification/CommandVerifier.js +480 -0
- package/src/agents/verification/FileOperationVerifier.js +453 -0
- package/src/agents/verification/ResultAnalyzer.js +707 -0
- package/src/agents/verification/TestRequirementManager.js +495 -0
- package/src/agents/verification/VerificationRunner.js +433 -0
- package/src/agents/windows/BaseWindowsInstaller.js +441 -0
- package/src/agents/windows/ChocolateyInstaller.js +509 -0
- package/src/agents/windows/DirectInstaller.js +443 -0
- package/src/agents/windows/InstallerFactory.js +391 -0
- package/src/agents/windows/NpmInstaller.js +505 -0
- package/src/agents/windows/PowerShellInstaller.js +458 -0
- package/src/agents/windows/WinGetInstaller.js +390 -0
- package/src/analysis/analysis-reporter.js +132 -0
- package/src/analysis/boundary-detector.js +712 -0
- package/src/analysis/categorizer.js +340 -0
- package/src/analysis/codebase-scanner.js +384 -0
- package/src/analysis/line-counter.js +513 -0
- package/src/analysis/priority-calculator.js +679 -0
- package/src/analysis/report/analysis-report.js +250 -0
- package/src/analysis/report/package-analyzer.js +278 -0
- package/src/analysis/report/recommendation-generator.js +382 -0
- package/src/analysis/report/statistics-generator.js +515 -0
- package/src/analysis/reports/analysis-report-model.js +101 -0
- package/src/analysis/reports/recommendation-generator.js +283 -0
- package/src/analysis/reports/report-generators.js +191 -0
- package/src/analysis/reports/statistics-calculator.js +231 -0
- package/src/analysis/reports/trend-analyzer.js +219 -0
- package/src/analysis/strategy-generator.js +814 -0
- package/src/auto-mode/AutoModeBusinessLogic.js +836 -0
- package/src/config/refactoring-config.js +307 -0
- package/src/health-tracking/json-storage.js +38 -2
- package/src/ide-integration/applescript-manager-core.js +233 -0
- package/src/ide-integration/applescript-manager.cjs +357 -28
- package/src/ide-integration/applescript-manager.js +89 -3599
- package/src/ide-integration/cdp-manager.js +306 -0
- package/src/ide-integration/claude-code-cli-manager.cjs +1 -1
- package/src/ide-integration/continuation-handler.js +337 -0
- package/src/ide-integration/ide-status-checker.js +292 -0
- package/src/ide-integration/macos-ide-manager.js +627 -0
- package/src/ide-integration/macos-text-sender.js +528 -0
- package/src/ide-integration/response-reader.js +548 -0
- package/src/ide-integration/windows-automation-manager.js +121 -0
- package/src/ide-integration/windows-ide-manager.js +373 -0
- package/src/index.cjs +25 -3
- package/src/index.js +15 -1
- package/src/llm/direct-llm-manager.cjs +90 -2
- package/src/models/compliance-report.js +538 -0
- package/src/models/file-analysis.js +681 -0
- package/src/models/refactoring-plan.js +770 -0
- package/src/monitoring/alert-system.js +834 -0
- package/src/monitoring/compliance-progress-tracker.js +437 -0
- package/src/monitoring/continuous-scan-notifications.js +661 -0
- package/src/monitoring/continuous-scanner.js +279 -0
- package/src/monitoring/file-monitor/file-analyzer.js +262 -0
- package/src/monitoring/file-monitor/file-monitor.js +237 -0
- package/src/monitoring/file-monitor/watcher.js +194 -0
- package/src/monitoring/file-monitor.js +17 -0
- package/src/monitoring/notification-manager.js +437 -0
- package/src/monitoring/scanner-core.js +368 -0
- package/src/monitoring/scanner-events.js +214 -0
- package/src/monitoring/violation-notification-system.js +515 -0
- package/src/refactoring/boundaries/cohesion-analyzer.js +316 -0
- package/src/refactoring/boundaries/extraction-result.js +285 -0
- package/src/refactoring/boundaries/extraction-strategies.js +392 -0
- package/src/refactoring/boundaries/module-boundary.js +209 -0
- package/src/refactoring/boundary/boundary-detector.js +741 -0
- package/src/refactoring/boundary/boundary-types.js +405 -0
- package/src/refactoring/boundary/extraction-strategies.js +554 -0
- package/src/refactoring/boundary-extraction-result.js +77 -0
- package/src/refactoring/boundary-extraction-strategies.js +330 -0
- package/src/refactoring/boundary-extractor.js +384 -0
- package/src/refactoring/boundary-types.js +46 -0
- package/src/refactoring/circular/circular-dependency.js +88 -0
- package/src/refactoring/circular/cycle-detection.js +147 -0
- package/src/refactoring/circular/dependency-node.js +82 -0
- package/src/refactoring/circular/dependency-result.js +107 -0
- package/src/refactoring/circular/dependency-types.js +58 -0
- package/src/refactoring/circular/graph-builder.js +213 -0
- package/src/refactoring/circular/resolution-strategy.js +72 -0
- package/src/refactoring/circular/strategy-generator.js +229 -0
- package/src/refactoring/circular-dependency-resolver-original.js +809 -0
- package/src/refactoring/circular-dependency-resolver.js +200 -0
- package/src/refactoring/code-mover.js +761 -0
- package/src/refactoring/file-splitter.js +696 -0
- package/src/refactoring/functionality-validator.js +816 -0
- package/src/refactoring/import-manager.js +774 -0
- package/src/refactoring/module-boundary.js +107 -0
- package/src/refactoring/refactoring-executor.js +672 -0
- package/src/refactoring/refactoring-rollback.js +614 -0
- package/src/refactoring/test-validator.js +631 -0
- package/src/requirement-management/default-requirement-manager.js +321 -0
- package/src/requirement-management/requirement-file-parser.js +159 -0
- package/src/requirement-management/requirement-sequencer.js +221 -0
- package/src/rui/commands/AgentCommandParser.js +600 -0
- package/src/rui/commands/AgentCommands.js +487 -0
- package/src/rui/commands/AgentResponseFormatter.js +832 -0
- package/src/scripts/verify-full-compliance.js +269 -0
- package/src/sync/sync-engine-core.js +1 -0
- package/src/sync/sync-engine-remote-handlers.js +135 -0
- package/src/task-generation/automated-task-generator.js +351 -0
- package/src/task-generation/prioritizer.js +287 -0
- package/src/task-generation/task-list-updater.js +215 -0
- package/src/task-generation/task-management-integration.js +480 -0
- package/src/task-generation/task-manager-integration.js +270 -0
- package/src/task-generation/violation-task-generator.js +474 -0
- package/src/task-management/continuous-scan-integration.js +342 -0
- package/src/timeout-management/index.js +12 -3
- package/src/timeout-management/response-time-tracker.js +167 -0
- package/src/timeout-management/timeout-calculator.js +159 -0
- package/src/timeout-management/timeout-config-manager.js +172 -0
- package/src/utils/ast-analyzer.js +417 -0
- package/src/utils/current-requirement-manager.js +276 -0
- package/src/utils/current-requirement-operations.js +472 -0
- package/src/utils/dependency-mapper.js +456 -0
- package/src/utils/download-with-progress.js +4 -2
- package/src/utils/electron-update-checker.js +4 -1
- package/src/utils/file-size-analyzer.js +272 -0
- package/src/utils/import-updater.js +280 -0
- package/src/utils/refactoring-tools.js +512 -0
- package/src/utils/report-generator.js +569 -0
- package/src/utils/reports/report-analysis.js +218 -0
- package/src/utils/reports/report-types.js +55 -0
- package/src/utils/reports/summary-generators.js +102 -0
- package/src/utils/requirement-file-management.js +157 -0
- package/src/utils/requirement-helpers/requirement-file-ops.js +392 -0
- package/src/utils/requirement-helpers/requirement-mover.js +414 -0
- package/src/utils/requirement-helpers/requirement-parser.js +326 -0
- package/src/utils/requirement-helpers/requirement-status.js +320 -0
- package/src/utils/requirement-helpers-new.js +55 -0
- package/src/utils/requirement-helpers-refactored.js +367 -0
- package/src/utils/requirement-helpers.js +291 -1191
- package/src/utils/requirement-movement-operations.js +450 -0
- package/src/utils/requirement-movement.js +312 -0
- package/src/utils/requirement-parsing-helpers.js +56 -0
- package/src/utils/requirement-statistics.js +200 -0
- package/src/utils/requirement-text-utils.js +58 -0
- package/src/utils/rollback/rollback-handlers.js +125 -0
- package/src/utils/rollback/rollback-operation.js +63 -0
- package/src/utils/rollback/rollback-recorder.js +166 -0
- package/src/utils/rollback/rollback-state-manager.js +175 -0
- package/src/utils/rollback/rollback-types.js +33 -0
- package/src/utils/rollback/rollback-utils.js +110 -0
- package/src/utils/rollback-manager-original.js +569 -0
- package/src/utils/rollback-manager.js +202 -0
- package/src/utils/smoke-test-cli.js +362 -0
- package/src/utils/smoke-test-gui.js +351 -0
- package/src/utils/smoke-test-orchestrator.js +321 -0
- package/src/utils/smoke-test-runner.js +60 -0
- package/src/utils/smoke-test-web.js +347 -0
- package/src/utils/specification-helpers.js +39 -13
- package/src/utils/specification-migration.js +97 -0
- package/src/utils/test-runner.js +579 -0
- package/src/utils/validation-framework.js +518 -0
- package/src/validation/compliance-analyzer.js +197 -0
- package/src/validation/compliance-report-generator.js +343 -0
- package/src/validation/compliance-reporter.js +711 -0
- package/src/validation/compliance-rules.js +127 -0
- package/src/validation/constitution-validator-new.js +196 -0
- package/src/validation/constitution-validator.js +17 -0
- package/src/validation/file-validators.js +170 -0
- package/src/validation/line-limit/file-analyzer.js +201 -0
- package/src/validation/line-limit/line-limit-validator.js +208 -0
- package/src/validation/line-limit/validation-result.js +144 -0
- package/src/validation/line-limit-core.js +225 -0
- package/src/validation/line-limit-reporter.js +134 -0
- package/src/validation/line-limit-result.js +125 -0
- package/src/validation/line-limit-validator.js +41 -0
- package/src/validation/metrics-calculator.js +660 -0
- package/src/sync/sync-engine-backup.js +0 -559
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Categorizer
|
|
3
|
+
*
|
|
4
|
+
* Categorizes files based on size, complexity, and refactoring priority.
|
|
5
|
+
* Provides consistent categorization across the analysis pipeline.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const RefactoringConfig = require('../config/refactoring-config');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* File size categories
|
|
12
|
+
*/
|
|
13
|
+
const SIZE_CATEGORIES = {
|
|
14
|
+
SMALL: 'SMALL',
|
|
15
|
+
MEDIUM: 'MEDIUM',
|
|
16
|
+
LARGE: 'LARGE',
|
|
17
|
+
XLARGE: 'XLARGE'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Priority categories
|
|
22
|
+
*/
|
|
23
|
+
const PRIORITY_CATEGORIES = {
|
|
24
|
+
LOW: 'LOW',
|
|
25
|
+
MEDIUM: 'MEDIUM',
|
|
26
|
+
HIGH: 'HIGH',
|
|
27
|
+
CRITICAL: 'CRITICAL'
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Complexity categories
|
|
32
|
+
*/
|
|
33
|
+
const COMPLEXITY_CATEGORIES = {
|
|
34
|
+
SIMPLE: 'SIMPLE',
|
|
35
|
+
MODERATE: 'MODERATE',
|
|
36
|
+
COMPLEX: 'COMPLEX',
|
|
37
|
+
VERY_COMPLEX: 'VERY_COMPLEX'
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* File categorizer class
|
|
42
|
+
*/
|
|
43
|
+
class FileCategorizer {
|
|
44
|
+
constructor(config = RefactoringConfig) {
|
|
45
|
+
this.config = config;
|
|
46
|
+
this.limits = config.limits;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Categorize file by size
|
|
51
|
+
*/
|
|
52
|
+
categorizeBySize(lineCount) {
|
|
53
|
+
if (lineCount <= this.limits.smallFileMax) {
|
|
54
|
+
return SIZE_CATEGORIES.SMALL;
|
|
55
|
+
} else if (lineCount <= this.limits.mediumFileMax) {
|
|
56
|
+
return SIZE_CATEGORIES.MEDIUM;
|
|
57
|
+
} else if (lineCount <= this.limits.largeFileMax) {
|
|
58
|
+
return SIZE_CATEGORIES.LARGE;
|
|
59
|
+
} else {
|
|
60
|
+
return SIZE_CATEGORIES.XLARGE;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Categorize file by priority
|
|
66
|
+
*/
|
|
67
|
+
categorizeByPriority(fileAnalysis) {
|
|
68
|
+
const { lineCount, complexity, isTestFile, isConfigFile, package: packageName } = fileAnalysis;
|
|
69
|
+
|
|
70
|
+
// Critical priority: files way over the limit
|
|
71
|
+
if (lineCount > this.limits.criticalThreshold) {
|
|
72
|
+
return PRIORITY_CATEGORIES.CRITICAL;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// High priority: files over the limit
|
|
76
|
+
if (lineCount > this.limits.maxFileSize) {
|
|
77
|
+
return PRIORITY_CATEGORIES.HIGH;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Medium priority: files approaching the limit
|
|
81
|
+
if (lineCount > this.limits.warningThreshold) {
|
|
82
|
+
return PRIORITY_CATEGORIES.MEDIUM;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Consider complexity for medium priority
|
|
86
|
+
if (complexity >= COMPLEXITY_CATEGORIES.COMPLEX && lineCount > this.limits.mediumFileMax) {
|
|
87
|
+
return PRIORITY_CATEGORIES.MEDIUM;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Low priority for everything else
|
|
91
|
+
return PRIORITY_CATEGORIES.LOW;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Categorize file by complexity
|
|
96
|
+
*/
|
|
97
|
+
categorizeByComplexity(fileAnalysis) {
|
|
98
|
+
const { cyclomaticComplexity, nestingDepth, functionCount, classCount } = fileAnalysis;
|
|
99
|
+
|
|
100
|
+
// Use multiple factors for complexity assessment
|
|
101
|
+
const complexityScore = this._calculateComplexityScore({
|
|
102
|
+
cyclomaticComplexity,
|
|
103
|
+
nestingDepth,
|
|
104
|
+
functionCount,
|
|
105
|
+
classCount
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (complexityScore >= 80) {
|
|
109
|
+
return COMPLEXITY_CATEGORIES.VERY_COMPLEX;
|
|
110
|
+
} else if (complexityScore >= 60) {
|
|
111
|
+
return COMPLEXITY_CATEGORIES.COMPLEX;
|
|
112
|
+
} else if (complexityScore >= 30) {
|
|
113
|
+
return COMPLEXITY_CATEGORIES.MODERATE;
|
|
114
|
+
} else {
|
|
115
|
+
return COMPLEXITY_CATEGORIES.SIMPLE;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Categorize file by refactoring difficulty
|
|
121
|
+
*/
|
|
122
|
+
categorizeByDifficulty(fileAnalysis) {
|
|
123
|
+
const { lineCount, complexity, hasImports, hasExports, dependencyCount } = fileAnalysis;
|
|
124
|
+
|
|
125
|
+
let difficultyScore = 0;
|
|
126
|
+
|
|
127
|
+
// Size contribution
|
|
128
|
+
if (lineCount > 1000) difficultyScore += 40;
|
|
129
|
+
else if (lineCount > 555) difficultyScore += 30;
|
|
130
|
+
else if (lineCount > 300) difficultyScore += 20;
|
|
131
|
+
else if (lineCount > 100) difficultyScore += 10;
|
|
132
|
+
|
|
133
|
+
// Complexity contribution
|
|
134
|
+
if (complexity === COMPLEXITY_CATEGORIES.VERY_COMPLEX) difficultyScore += 30;
|
|
135
|
+
else if (complexity === COMPLEXITY_CATEGORIES.COMPLEX) difficultyScore += 20;
|
|
136
|
+
else if (complexity === COMPLEXITY_CATEGORIES.MODERATE) difficultyScore += 10;
|
|
137
|
+
|
|
138
|
+
// Dependencies contribution
|
|
139
|
+
if (dependencyCount > 20) difficultyScore += 20;
|
|
140
|
+
else if (dependencyCount > 10) difficultyScore += 10;
|
|
141
|
+
else if (dependencyCount > 5) difficultyScore += 5;
|
|
142
|
+
|
|
143
|
+
// Import/Export complexity
|
|
144
|
+
if (hasImports && hasExports) difficultyScore += 10;
|
|
145
|
+
else if (hasImports || hasExports) difficultyScore += 5;
|
|
146
|
+
|
|
147
|
+
if (difficultyScore >= 70) return 'VERY_DIFFICULT';
|
|
148
|
+
if (difficultyScore >= 50) return 'DIFFICULT';
|
|
149
|
+
if (difficultyScore >= 30) return 'MODERATE';
|
|
150
|
+
return 'EASY';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Get comprehensive categorization for a file
|
|
155
|
+
*/
|
|
156
|
+
categorizeFile(fileAnalysis) {
|
|
157
|
+
const sizeCategory = this.categorizeBySize(fileAnalysis.lineCount);
|
|
158
|
+
const priorityCategory = this.categorizeByPriority(fileAnalysis);
|
|
159
|
+
const complexityCategory = this.categorizeByComplexity(fileAnalysis);
|
|
160
|
+
const difficultyCategory = this.categorizeByDifficulty(fileAnalysis);
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
size: sizeCategory,
|
|
164
|
+
priority: priorityCategory,
|
|
165
|
+
complexity: complexityCategory,
|
|
166
|
+
difficulty: difficultyCategory,
|
|
167
|
+
needsRefactoring: sizeCategory === SIZE_CATEGORIES.LARGE || sizeCategory === SIZE_CATEGORIES.XLARGE,
|
|
168
|
+
urgentRefactoring: sizeCategory === SIZE_CATEGORIES.XLARGE || priorityCategory === PRIORITY_CATEGORIES.CRITICAL,
|
|
169
|
+
recommendedAction: this._getRecommendedAction(sizeCategory, priorityCategory, complexityCategory),
|
|
170
|
+
estimatedEffort: this._estimateEffort(sizeCategory, difficultyCategory)
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Categorize multiple files
|
|
176
|
+
*/
|
|
177
|
+
categorizeFiles(fileAnalyses) {
|
|
178
|
+
const categorizedFiles = [];
|
|
179
|
+
const summary = {
|
|
180
|
+
total: fileAnalyses.length,
|
|
181
|
+
bySize: {},
|
|
182
|
+
byPriority: {},
|
|
183
|
+
byComplexity: {},
|
|
184
|
+
byDifficulty: {},
|
|
185
|
+
needsRefactoring: 0,
|
|
186
|
+
urgentRefactoring: 0
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// Initialize summary counters
|
|
190
|
+
Object.values(SIZE_CATEGORIES).forEach(cat => summary.bySize[cat] = 0);
|
|
191
|
+
Object.values(PRIORITY_CATEGORIES).forEach(cat => summary.byPriority[cat] = 0);
|
|
192
|
+
Object.values(COMPLEXITY_CATEGORIES).forEach(cat => summary.byComplexity[cat] = 0);
|
|
193
|
+
['EASY', 'MODERATE', 'DIFFICULT', 'VERY_DIFFICULT'].forEach(cat => summary.byDifficulty[cat] = 0);
|
|
194
|
+
|
|
195
|
+
for (const fileAnalysis of fileAnalyses) {
|
|
196
|
+
const categorization = this.categorizeFile(fileAnalysis);
|
|
197
|
+
|
|
198
|
+
categorizedFiles.push({
|
|
199
|
+
...fileAnalysis,
|
|
200
|
+
categorization
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Update summary
|
|
204
|
+
summary.bySize[categorization.size]++;
|
|
205
|
+
summary.byPriority[categorization.priority]++;
|
|
206
|
+
summary.byComplexity[categorization.complexity]++;
|
|
207
|
+
summary.byDifficulty[categorization.difficulty]++;
|
|
208
|
+
|
|
209
|
+
if (categorization.needsRefactoring) summary.needsRefactoring++;
|
|
210
|
+
if (categorization.urgentRefactoring) summary.urgentRefactoring++;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
files: categorizedFiles,
|
|
215
|
+
summary
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get category thresholds
|
|
221
|
+
*/
|
|
222
|
+
getCategoryThresholds() {
|
|
223
|
+
return {
|
|
224
|
+
size: {
|
|
225
|
+
[SIZE_CATEGORIES.SMALL]: `≤ ${this.limits.smallFileMax} lines`,
|
|
226
|
+
[SIZE_CATEGORIES.MEDIUM]: `${this.limits.smallFileMax + 1}-${this.limits.mediumFileMax} lines`,
|
|
227
|
+
[SIZE_CATEGORIES.LARGE]: `${this.limits.mediumFileMax + 1}-${this.limits.largeFileMax} lines`,
|
|
228
|
+
[SIZE_CATEGORIES.XLARGE]: `> ${this.limits.largeFileMax} lines`
|
|
229
|
+
},
|
|
230
|
+
priority: {
|
|
231
|
+
[PRIORITY_CATEGORIES.LOW]: 'Well within limits',
|
|
232
|
+
[PRIORITY_CATEGORIES.MEDIUM]: 'Approaching limits',
|
|
233
|
+
[PRIORITY_CATEGORIES.HIGH]: 'Exceeds limits',
|
|
234
|
+
[PRIORITY_CATEGORIES.CRITICAL]: 'Far exceeds limits'
|
|
235
|
+
},
|
|
236
|
+
complexity: {
|
|
237
|
+
[COMPLEXITY_CATEGORIES.SIMPLE]: 'Low complexity',
|
|
238
|
+
[COMPLEXITY_CATEGORIES.MODERATE]: 'Moderate complexity',
|
|
239
|
+
[COMPLEXITY_CATEGORIES.COMPLEX]: 'High complexity',
|
|
240
|
+
[COMPLEXITY_CATEGORIES.VERY_COMPLEX]: 'Very high complexity'
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Calculate complexity score
|
|
247
|
+
*/
|
|
248
|
+
_calculateComplexityScore(metrics) {
|
|
249
|
+
let score = 0;
|
|
250
|
+
|
|
251
|
+
// Cyclomatic complexity contribution (0-40 points)
|
|
252
|
+
if (metrics.cyclomaticComplexity >= 50) score += 40;
|
|
253
|
+
else if (metrics.cyclomaticComplexity >= 20) score += 30;
|
|
254
|
+
else if (metrics.cyclomaticComplexity >= 10) score += 20;
|
|
255
|
+
else if (metrics.cyclomaticComplexity >= 5) score += 10;
|
|
256
|
+
|
|
257
|
+
// Nesting depth contribution (0-30 points)
|
|
258
|
+
if (metrics.nestingDepth >= 8) score += 30;
|
|
259
|
+
else if (metrics.nestingDepth >= 5) score += 20;
|
|
260
|
+
else if (metrics.nestingDepth >= 3) score += 10;
|
|
261
|
+
|
|
262
|
+
// Function count contribution (0-20 points)
|
|
263
|
+
if (metrics.functionCount >= 20) score += 20;
|
|
264
|
+
else if (metrics.functionCount >= 10) score += 15;
|
|
265
|
+
else if (metrics.functionCount >= 5) score += 10;
|
|
266
|
+
else if (metrics.functionCount >= 2) score += 5;
|
|
267
|
+
|
|
268
|
+
// Class count contribution (0-10 points)
|
|
269
|
+
if (metrics.classCount >= 5) score += 10;
|
|
270
|
+
else if (metrics.classCount >= 3) score += 7;
|
|
271
|
+
else if (metrics.classCount >= 2) score += 5;
|
|
272
|
+
else if (metrics.classCount >= 1) score += 3;
|
|
273
|
+
|
|
274
|
+
return Math.min(score, 100);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get recommended action based on categorization
|
|
279
|
+
*/
|
|
280
|
+
_getRecommendedAction(sizeCategory, priorityCategory, complexityCategory) {
|
|
281
|
+
if (sizeCategory === SIZE_CATEGORIES.XLARGE || priorityCategory === PRIORITY_CATEGORIES.CRITICAL) {
|
|
282
|
+
return 'IMMEDIATE_REFACTORING';
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (sizeCategory === SIZE_CATEGORIES.LARGE || priorityCategory === PRIORITY_CATEGORIES.HIGH) {
|
|
286
|
+
return 'SCHEDULE_REFACTORING';
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (priorityCategory === PRIORITY_CATEGORIES.MEDIUM && complexityCategory === COMPLEXITY_CATEGORIES.COMPLEX) {
|
|
290
|
+
return 'PLAN_REFACTORING';
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (complexityCategory === COMPLEXITY_CATEGORIES.VERY_COMPLEX) {
|
|
294
|
+
return 'CONSIDER_REFACTORING';
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return 'MONITOR';
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Estimate refactoring effort
|
|
302
|
+
*/
|
|
303
|
+
_estimateEffort(sizeCategory, difficultyCategory) {
|
|
304
|
+
const effortMatrix = {
|
|
305
|
+
[SIZE_CATEGORIES.SMALL]: {
|
|
306
|
+
'EASY': 'MINIMAL',
|
|
307
|
+
'MODERATE': 'LOW',
|
|
308
|
+
'DIFFICULT': 'MEDIUM',
|
|
309
|
+
'VERY_DIFFICULT': 'HIGH'
|
|
310
|
+
},
|
|
311
|
+
[SIZE_CATEGORIES.MEDIUM]: {
|
|
312
|
+
'EASY': 'LOW',
|
|
313
|
+
'MODERATE': 'MEDIUM',
|
|
314
|
+
'DIFFICULT': 'HIGH',
|
|
315
|
+
'VERY_DIFFICULT': 'VERY_HIGH'
|
|
316
|
+
},
|
|
317
|
+
[SIZE_CATEGORIES.LARGE]: {
|
|
318
|
+
'EASY': 'MEDIUM',
|
|
319
|
+
'MODERATE': 'HIGH',
|
|
320
|
+
'DIFFICULT': 'VERY_HIGH',
|
|
321
|
+
'VERY_DIFFICULT': 'EXTREME'
|
|
322
|
+
},
|
|
323
|
+
[SIZE_CATEGORIES.XLARGE]: {
|
|
324
|
+
'EASY': 'HIGH',
|
|
325
|
+
'MODERATE': 'VERY_HIGH',
|
|
326
|
+
'DIFFICULT': 'EXTREME',
|
|
327
|
+
'VERY_DIFFICULT': 'MAJOR'
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
return effortMatrix[sizeCategory]?.[difficultyCategory] || 'UNKNOWN';
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
module.exports = {
|
|
336
|
+
FileCategorizer,
|
|
337
|
+
SIZE_CATEGORIES,
|
|
338
|
+
PRIORITY_CATEGORIES,
|
|
339
|
+
COMPLEXITY_CATEGORIES
|
|
340
|
+
};
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codebase Scanner
|
|
3
|
+
*
|
|
4
|
+
* Scans the entire codebase to identify files for analysis,
|
|
5
|
+
* excluding third-party libraries and generated files.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const RefactoringConfig = require('../config/refactoring-config');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Scanner result class
|
|
14
|
+
*/
|
|
15
|
+
class ScanResult {
|
|
16
|
+
constructor(filePath, stats) {
|
|
17
|
+
this.path = filePath;
|
|
18
|
+
this.size = stats.size;
|
|
19
|
+
this.modified = stats.mtime;
|
|
20
|
+
this.created = stats.birthtime || stats.ctime;
|
|
21
|
+
this.isDirectory = stats.isDirectory();
|
|
22
|
+
this.extension = path.extname(filePath);
|
|
23
|
+
this.basename = path.basename(filePath);
|
|
24
|
+
this.relativePath = path.relative(process.cwd(), filePath);
|
|
25
|
+
this.package = this.extractPackage();
|
|
26
|
+
this.shouldAnalyze = this.shouldIncludeInAnalysis();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
extractPackage() {
|
|
30
|
+
const match = this.relativePath.match(/packages\/([^\/]+)/);
|
|
31
|
+
return match ? match[1] : 'root';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
shouldIncludeInAnalysis() {
|
|
35
|
+
// Skip directories
|
|
36
|
+
if (this.isDirectory) return false;
|
|
37
|
+
|
|
38
|
+
// Check exclusions
|
|
39
|
+
if (RefactoringConfig.isExcluded(this.path)) return false;
|
|
40
|
+
|
|
41
|
+
// Check file extensions
|
|
42
|
+
const ext = this.extension.toLowerCase();
|
|
43
|
+
const allowedExtensions = ['.js', '.jsx', '.ts', '.tsx', '.md', '.json', '.yml', '.yaml'];
|
|
44
|
+
|
|
45
|
+
return allowedExtensions.includes(ext);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Codebase scanner class
|
|
51
|
+
*/
|
|
52
|
+
class CodebaseScanner {
|
|
53
|
+
constructor(config = RefactoringConfig) {
|
|
54
|
+
this.config = config;
|
|
55
|
+
this.results = [];
|
|
56
|
+
this.stats = {
|
|
57
|
+
totalFiles: 0,
|
|
58
|
+
analyzedFiles: 0,
|
|
59
|
+
excludedFiles: 0,
|
|
60
|
+
directories: 0,
|
|
61
|
+
errors: 0
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Scan the entire codebase
|
|
67
|
+
*/
|
|
68
|
+
async scan(rootPath = process.cwd()) {
|
|
69
|
+
console.log(`Scanning codebase from: ${rootPath}`);
|
|
70
|
+
|
|
71
|
+
this.results = [];
|
|
72
|
+
this.resetStats();
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
await this.scanDirectory(rootPath);
|
|
76
|
+
console.log(`Scan completed: ${this.stats.analyzedFiles} files to analyze, ${this.stats.excludedFiles} excluded`);
|
|
77
|
+
return this.results;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error(`Scan failed: ${error.message}`);
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Scan a single directory recursively
|
|
86
|
+
*/
|
|
87
|
+
async scanDirectory(dirPath) {
|
|
88
|
+
try {
|
|
89
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
90
|
+
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const stats = fs.statSync(fullPath);
|
|
96
|
+
const result = new ScanResult(fullPath, stats);
|
|
97
|
+
|
|
98
|
+
if (entry.isDirectory()) {
|
|
99
|
+
this.stats.directories++;
|
|
100
|
+
|
|
101
|
+
// Skip excluded directories
|
|
102
|
+
if (!this.shouldSkipDirectory(fullPath)) {
|
|
103
|
+
await this.scanDirectory(fullPath);
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
this.stats.totalFiles++;
|
|
107
|
+
|
|
108
|
+
if (result.shouldAnalyze) {
|
|
109
|
+
this.results.push(result);
|
|
110
|
+
this.stats.analyzedFiles++;
|
|
111
|
+
} else {
|
|
112
|
+
this.stats.excludedFiles++;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
this.stats.errors++;
|
|
117
|
+
console.warn(`Error scanning ${fullPath}: ${error.message}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
this.stats.errors++;
|
|
122
|
+
throw new Error(`Failed to scan directory ${dirPath}: ${error.message}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Check if directory should be skipped
|
|
128
|
+
*/
|
|
129
|
+
shouldSkipDirectory(dirPath) {
|
|
130
|
+
const dirName = path.basename(dirPath);
|
|
131
|
+
const relativePath = path.relative(process.cwd(), dirPath);
|
|
132
|
+
|
|
133
|
+
// Skip common excluded directories
|
|
134
|
+
const excludedDirs = [
|
|
135
|
+
'node_modules',
|
|
136
|
+
'.git',
|
|
137
|
+
'dist',
|
|
138
|
+
'build',
|
|
139
|
+
'coverage',
|
|
140
|
+
'.nyc_output',
|
|
141
|
+
'.vscode',
|
|
142
|
+
'.idea',
|
|
143
|
+
'.cursor',
|
|
144
|
+
'.windsurf',
|
|
145
|
+
'vendor',
|
|
146
|
+
'bower_components',
|
|
147
|
+
'.refactoring-backups'
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
// Check if directory name is excluded
|
|
151
|
+
if (excludedDirs.includes(dirName)) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Check if relative path contains excluded directories
|
|
156
|
+
for (const excludedDir of excludedDirs) {
|
|
157
|
+
if (relativePath.includes(path.sep + excludedDir + path.sep) ||
|
|
158
|
+
relativePath.startsWith(excludedDir + path.sep)) {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get files by package
|
|
168
|
+
*/
|
|
169
|
+
getFilesByPackage() {
|
|
170
|
+
const byPackage = {};
|
|
171
|
+
|
|
172
|
+
for (const result of this.results) {
|
|
173
|
+
if (!byPackage[result.package]) {
|
|
174
|
+
byPackage[result.package] = [];
|
|
175
|
+
}
|
|
176
|
+
byPackage[result.package].push(result);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return byPackage;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get files by extension
|
|
184
|
+
*/
|
|
185
|
+
getFilesByExtension() {
|
|
186
|
+
const byExtension = {};
|
|
187
|
+
|
|
188
|
+
for (const result of this.results) {
|
|
189
|
+
if (!byExtension[result.extension]) {
|
|
190
|
+
byExtension[result.extension] = [];
|
|
191
|
+
}
|
|
192
|
+
byExtension[result.extension].push(result);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return byExtension;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get files by size range
|
|
200
|
+
*/
|
|
201
|
+
getFilesBySizeRange() {
|
|
202
|
+
const ranges = {
|
|
203
|
+
small: [], // 0-100 lines (estimated)
|
|
204
|
+
medium: [], // 101-300 lines
|
|
205
|
+
large: [], // 301-555 lines
|
|
206
|
+
xlarge: [] // 556+ lines
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
for (const result of this.results) {
|
|
210
|
+
// Estimate line count from file size (rough approximation)
|
|
211
|
+
const estimatedLines = Math.ceil(result.size / 50); // ~50 chars per line
|
|
212
|
+
|
|
213
|
+
if (estimatedLines <= 100) ranges.small.push(result);
|
|
214
|
+
else if (estimatedLines <= 300) ranges.medium.push(result);
|
|
215
|
+
else if (estimatedLines <= 555) ranges.large.push(result);
|
|
216
|
+
else ranges.xlarge.push(result);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return ranges;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Filter results by criteria
|
|
224
|
+
*/
|
|
225
|
+
filter(criteria = {}) {
|
|
226
|
+
let filtered = [...this.results];
|
|
227
|
+
|
|
228
|
+
if (criteria.package) {
|
|
229
|
+
filtered = filtered.filter(result => result.package === criteria.package);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (criteria.extension) {
|
|
233
|
+
filtered = filtered.filter(result => result.extension === criteria.extension);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (criteria.minSize) {
|
|
237
|
+
filtered = filtered.filter(result => result.size >= criteria.minSize);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (criteria.maxSize) {
|
|
241
|
+
filtered = filtered.filter(result => result.size <= criteria.maxSize);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (criteria.pattern) {
|
|
245
|
+
const regex = new RegExp(criteria.pattern, 'i');
|
|
246
|
+
filtered = filtered.filter(result =>
|
|
247
|
+
regex.test(result.basename) || regex.test(result.relativePath)
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return filtered;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Find recently modified files
|
|
256
|
+
*/
|
|
257
|
+
getRecentlyModified(days = 7) {
|
|
258
|
+
const cutoff = new Date(Date.now() - (days * 24 * 60 * 60 * 1000));
|
|
259
|
+
|
|
260
|
+
return this.results.filter(result => result.modified > cutoff);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Find large files (by size estimation)
|
|
265
|
+
*/
|
|
266
|
+
getLargeFiles(minLines = 556) {
|
|
267
|
+
return this.results.filter(result => {
|
|
268
|
+
const estimatedLines = Math.ceil(result.size / 50);
|
|
269
|
+
return estimatedLines >= minLines;
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Get scan statistics
|
|
275
|
+
*/
|
|
276
|
+
getStatistics() {
|
|
277
|
+
const stats = { ...this.stats };
|
|
278
|
+
|
|
279
|
+
// Calculate additional statistics
|
|
280
|
+
stats.totalSize = this.results.reduce((sum, result) => sum + result.size, 0);
|
|
281
|
+
stats.averageFileSize = stats.analyzedFiles > 0 ? Math.round(stats.totalSize / stats.analyzedFiles) : 0;
|
|
282
|
+
stats.largestFile = this.results.reduce((largest, result) =>
|
|
283
|
+
result.size > (largest?.size || 0) ? result : largest, null
|
|
284
|
+
);
|
|
285
|
+
stats.smallestFile = this.results.reduce((smallest, result) =>
|
|
286
|
+
result.size < (smallest?.size || Infinity) ? result : smallest, null
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
// Package distribution
|
|
290
|
+
stats.packageDistribution = {};
|
|
291
|
+
for (const result of this.results) {
|
|
292
|
+
if (!stats.packageDistribution[result.package]) {
|
|
293
|
+
stats.packageDistribution[result.package] = 0;
|
|
294
|
+
}
|
|
295
|
+
stats.packageDistribution[result.package]++;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Extension distribution
|
|
299
|
+
stats.extensionDistribution = {};
|
|
300
|
+
for (const result of this.results) {
|
|
301
|
+
if (!stats.extensionDistribution[result.extension]) {
|
|
302
|
+
stats.extensionDistribution[result.extension] = 0;
|
|
303
|
+
}
|
|
304
|
+
stats.extensionDistribution[result.extension]++;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return stats;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Export results to JSON
|
|
312
|
+
*/
|
|
313
|
+
exportToJson(filePath) {
|
|
314
|
+
const exportData = {
|
|
315
|
+
metadata: {
|
|
316
|
+
scannedAt: new Date().toISOString(),
|
|
317
|
+
rootPath: process.cwd(),
|
|
318
|
+
config: this.config.reporting || {}
|
|
319
|
+
},
|
|
320
|
+
statistics: this.getStatistics(),
|
|
321
|
+
results: this.results.map(result => ({
|
|
322
|
+
path: result.path,
|
|
323
|
+
relativePath: result.relativePath,
|
|
324
|
+
package: result.package,
|
|
325
|
+
size: result.size,
|
|
326
|
+
extension: result.extension,
|
|
327
|
+
modified: result.modified.toISOString(),
|
|
328
|
+
shouldAnalyze: result.shouldAnalyze
|
|
329
|
+
}))
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
fs.writeFileSync(filePath, JSON.stringify(exportData, null, 2));
|
|
333
|
+
return filePath;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Reset statistics
|
|
338
|
+
*/
|
|
339
|
+
resetStats() {
|
|
340
|
+
this.stats = {
|
|
341
|
+
totalFiles: 0,
|
|
342
|
+
analyzedFiles: 0,
|
|
343
|
+
excludedFiles: 0,
|
|
344
|
+
directories: 0,
|
|
345
|
+
errors: 0
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Validate scan results
|
|
351
|
+
*/
|
|
352
|
+
validate() {
|
|
353
|
+
const issues = [];
|
|
354
|
+
|
|
355
|
+
// Check if we have any results
|
|
356
|
+
if (this.results.length === 0) {
|
|
357
|
+
issues.push('No files found for analysis');
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Check for errors during scanning
|
|
361
|
+
if (this.stats.errors > 0) {
|
|
362
|
+
issues.push(`${this.stats.errors} errors occurred during scanning`);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Check for excluded files ratio
|
|
366
|
+
const exclusionRatio = this.stats.totalFiles > 0 ?
|
|
367
|
+
(this.stats.excludedFiles / this.stats.totalFiles) : 0;
|
|
368
|
+
|
|
369
|
+
if (exclusionRatio > 0.9) {
|
|
370
|
+
issues.push('Very high exclusion ratio - check configuration');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return {
|
|
374
|
+
isValid: issues.length === 0,
|
|
375
|
+
issues,
|
|
376
|
+
stats: this.stats
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
module.exports = {
|
|
382
|
+
CodebaseScanner,
|
|
383
|
+
ScanResult
|
|
384
|
+
};
|