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,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boundary Extraction Strategies
|
|
3
|
+
*
|
|
4
|
+
* Contains methods for extracting different types of boundaries from code.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { BOUNDARY_TYPES } = require('./boundary-types');
|
|
8
|
+
const ModuleBoundary = require('./module-boundary');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Boundary extraction strategies class
|
|
12
|
+
*/
|
|
13
|
+
class BoundaryExtractionStrategies {
|
|
14
|
+
/**
|
|
15
|
+
* Extract function boundaries
|
|
16
|
+
*/
|
|
17
|
+
static async extractFunctionBoundaries(lines, result) {
|
|
18
|
+
for (let i = 0; i < lines.length; i++) {
|
|
19
|
+
const line = lines[i].trim();
|
|
20
|
+
|
|
21
|
+
// Function declarations
|
|
22
|
+
const funcMatch = line.match(/^(?:async\s+)?function\s+(\w+)/);
|
|
23
|
+
if (funcMatch) {
|
|
24
|
+
const boundary = BoundaryExtractionStrategies.findFunctionBoundary(lines, i, funcMatch[1], result.filePath);
|
|
25
|
+
if (boundary) {
|
|
26
|
+
result.addBoundary(boundary);
|
|
27
|
+
}
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Function expressions
|
|
32
|
+
const exprMatch = line.match(/^(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?function/);
|
|
33
|
+
if (exprMatch) {
|
|
34
|
+
const boundary = BoundaryExtractionStrategies.findFunctionBoundary(lines, i, exprMatch[1], result.filePath);
|
|
35
|
+
if (boundary) {
|
|
36
|
+
result.addBoundary(boundary);
|
|
37
|
+
}
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Arrow functions
|
|
42
|
+
const arrowMatch = line.match(/^(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(/);
|
|
43
|
+
if (arrowMatch) {
|
|
44
|
+
const boundary = BoundaryExtractionStrategies.findArrowFunctionBoundary(lines, i, arrowMatch[1], result.filePath);
|
|
45
|
+
if (boundary) {
|
|
46
|
+
result.addBoundary(boundary);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Find function boundary
|
|
54
|
+
*/
|
|
55
|
+
static findFunctionBoundary(lines, startLine, name, filePath) {
|
|
56
|
+
let braceCount = 0;
|
|
57
|
+
let foundBrace = false;
|
|
58
|
+
|
|
59
|
+
for (let i = startLine; i < lines.length; i++) {
|
|
60
|
+
const line = lines[i];
|
|
61
|
+
|
|
62
|
+
for (let j = 0; j < line.length; j++) {
|
|
63
|
+
if (line[j] === '{') {
|
|
64
|
+
braceCount++;
|
|
65
|
+
foundBrace = true;
|
|
66
|
+
} else if (line[j] === '}') {
|
|
67
|
+
braceCount--;
|
|
68
|
+
if (foundBrace && braceCount === 0) {
|
|
69
|
+
const boundary = new ModuleBoundary(
|
|
70
|
+
BOUNDARY_TYPES.FUNCTION,
|
|
71
|
+
name,
|
|
72
|
+
startLine + 1,
|
|
73
|
+
i + 1,
|
|
74
|
+
filePath
|
|
75
|
+
);
|
|
76
|
+
return boundary;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Find arrow function boundary
|
|
87
|
+
*/
|
|
88
|
+
static findArrowFunctionBoundary(lines, startLine, name, filePath) {
|
|
89
|
+
let braceCount = 0;
|
|
90
|
+
let foundBrace = false;
|
|
91
|
+
let foundArrow = false;
|
|
92
|
+
|
|
93
|
+
for (let i = startLine; i < lines.length; i++) {
|
|
94
|
+
const line = lines[i];
|
|
95
|
+
|
|
96
|
+
if (line.includes('=>')) {
|
|
97
|
+
foundArrow = true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (let j = 0; j < line.length; j++) {
|
|
101
|
+
if (line[j] === '{') {
|
|
102
|
+
braceCount++;
|
|
103
|
+
foundBrace = true;
|
|
104
|
+
} else if (line[j] === '}') {
|
|
105
|
+
braceCount--;
|
|
106
|
+
if (foundBrace && foundArrow && braceCount === 0) {
|
|
107
|
+
const boundary = new ModuleBoundary(
|
|
108
|
+
BOUNDARY_TYPES.FUNCTION,
|
|
109
|
+
name,
|
|
110
|
+
startLine + 1,
|
|
111
|
+
i + 1,
|
|
112
|
+
filePath
|
|
113
|
+
);
|
|
114
|
+
return boundary;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Extract class boundaries
|
|
125
|
+
*/
|
|
126
|
+
static async extractClassBoundaries(lines, result) {
|
|
127
|
+
for (let i = 0; i < lines.length; i++) {
|
|
128
|
+
const line = lines[i].trim();
|
|
129
|
+
|
|
130
|
+
const classMatch = line.match(/^class\s+(\w+)/);
|
|
131
|
+
if (classMatch) {
|
|
132
|
+
const boundary = BoundaryExtractionStrategies.findClassBoundary(lines, i, classMatch[1], result.filePath);
|
|
133
|
+
if (boundary) {
|
|
134
|
+
result.addBoundary(boundary);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Find class boundary
|
|
142
|
+
*/
|
|
143
|
+
static findClassBoundary(lines, startLine, name, filePath) {
|
|
144
|
+
let braceCount = 0;
|
|
145
|
+
let foundBrace = false;
|
|
146
|
+
|
|
147
|
+
for (let i = startLine; i < lines.length; i++) {
|
|
148
|
+
const line = lines[i];
|
|
149
|
+
|
|
150
|
+
for (let j = 0; j < line.length; j++) {
|
|
151
|
+
if (line[j] === '{') {
|
|
152
|
+
braceCount++;
|
|
153
|
+
foundBrace = true;
|
|
154
|
+
} else if (line[j] === '}') {
|
|
155
|
+
braceCount--;
|
|
156
|
+
if (foundBrace && braceCount === 0) {
|
|
157
|
+
return new ModuleBoundary(
|
|
158
|
+
BOUNDARY_TYPES.CLASS,
|
|
159
|
+
name,
|
|
160
|
+
startLine + 1,
|
|
161
|
+
i + 1,
|
|
162
|
+
filePath
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Extract object boundaries
|
|
174
|
+
*/
|
|
175
|
+
static async extractObjectBoundaries(lines, result) {
|
|
176
|
+
for (let i = 0; i < lines.length; i++) {
|
|
177
|
+
const line = lines[i].trim();
|
|
178
|
+
|
|
179
|
+
// Object assignments
|
|
180
|
+
const objMatch = line.match(/^(?:const|let|var)\s+(\w+)\s*=\s*\{/);
|
|
181
|
+
if (objMatch) {
|
|
182
|
+
const boundary = BoundaryExtractionStrategies.findObjectBoundary(lines, i, objMatch[1], result.filePath);
|
|
183
|
+
if (boundary) {
|
|
184
|
+
result.addBoundary(boundary);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Find object boundary
|
|
192
|
+
*/
|
|
193
|
+
static findObjectBoundary(lines, startLine, name, filePath) {
|
|
194
|
+
let braceCount = 0;
|
|
195
|
+
let foundBrace = false;
|
|
196
|
+
|
|
197
|
+
for (let i = startLine; i < lines.length; i++) {
|
|
198
|
+
const line = lines[i];
|
|
199
|
+
|
|
200
|
+
for (let j = 0; j < line.length; j++) {
|
|
201
|
+
if (line[j] === '{') {
|
|
202
|
+
braceCount++;
|
|
203
|
+
foundBrace = true;
|
|
204
|
+
} else if (line[j] === '}') {
|
|
205
|
+
braceCount--;
|
|
206
|
+
if (foundBrace && braceCount === 0) {
|
|
207
|
+
const boundary = new ModuleBoundary(
|
|
208
|
+
BOUNDARY_TYPES.OBJECT,
|
|
209
|
+
name,
|
|
210
|
+
startLine + 1,
|
|
211
|
+
i + 1,
|
|
212
|
+
filePath
|
|
213
|
+
);
|
|
214
|
+
return boundary;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Extract utility boundaries
|
|
225
|
+
*/
|
|
226
|
+
static async extractUtilityBoundaries(lines, result) {
|
|
227
|
+
// Look for utility sections marked by comments
|
|
228
|
+
let utilityStart = null;
|
|
229
|
+
let utilityName = null;
|
|
230
|
+
|
|
231
|
+
for (let i = 0; i < lines.length; i++) {
|
|
232
|
+
const line = lines[i].trim();
|
|
233
|
+
|
|
234
|
+
if (line.startsWith('//') && (line.includes('utility') || line.includes('helper'))) {
|
|
235
|
+
if (utilityStart) {
|
|
236
|
+
// Close previous utility section
|
|
237
|
+
const boundary = new ModuleBoundary(
|
|
238
|
+
BOUNDARY_TYPES.UTILITY,
|
|
239
|
+
utilityName || 'utilities',
|
|
240
|
+
utilityStart,
|
|
241
|
+
i,
|
|
242
|
+
result.filePath
|
|
243
|
+
);
|
|
244
|
+
result.addBoundary(boundary);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
utilityStart = i + 1;
|
|
248
|
+
utilityName = line.replace('//', '').trim();
|
|
249
|
+
} else if (line.startsWith('//') && line.includes('end utility')) {
|
|
250
|
+
if (utilityStart) {
|
|
251
|
+
const boundary = new ModuleBoundary(
|
|
252
|
+
BOUNDARY_TYPES.UTILITY,
|
|
253
|
+
utilityName || 'utilities',
|
|
254
|
+
utilityStart,
|
|
255
|
+
i,
|
|
256
|
+
result.filePath
|
|
257
|
+
);
|
|
258
|
+
result.addBoundary(boundary);
|
|
259
|
+
utilityStart = null;
|
|
260
|
+
utilityName = null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Close final utility section
|
|
266
|
+
if (utilityStart) {
|
|
267
|
+
const boundary = new ModuleBoundary(
|
|
268
|
+
BOUNDARY_TYPES.UTILITY,
|
|
269
|
+
utilityName || 'utilities',
|
|
270
|
+
utilityStart,
|
|
271
|
+
lines.length,
|
|
272
|
+
result.filePath
|
|
273
|
+
);
|
|
274
|
+
result.addBoundary(boundary);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Extract constant boundaries
|
|
280
|
+
*/
|
|
281
|
+
static async extractConstantBoundaries(lines, result) {
|
|
282
|
+
// Look for constant blocks
|
|
283
|
+
const constants = [];
|
|
284
|
+
let constStart = null;
|
|
285
|
+
|
|
286
|
+
for (let i = 0; i < lines.length; i++) {
|
|
287
|
+
const line = lines[i].trim();
|
|
288
|
+
|
|
289
|
+
if (line.startsWith('const ') && line.includes('=')) {
|
|
290
|
+
const match = line.match(/^const\s+(\w+)/);
|
|
291
|
+
if (match) {
|
|
292
|
+
constants.push({ name: match[1], line: i + 1 });
|
|
293
|
+
|
|
294
|
+
if (constStart === null) {
|
|
295
|
+
constStart = i + 1;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} else if (constStart !== null && !line.startsWith('const ') && line.trim() !== '') {
|
|
299
|
+
// End of constant block
|
|
300
|
+
if (constants.length >= 3) { // Only extract if there are multiple constants
|
|
301
|
+
const boundary = new ModuleBoundary(
|
|
302
|
+
BOUNDARY_TYPES.CONSTANT,
|
|
303
|
+
'constants',
|
|
304
|
+
constStart,
|
|
305
|
+
i,
|
|
306
|
+
result.filePath
|
|
307
|
+
);
|
|
308
|
+
result.addBoundary(boundary);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
constants.length = 0;
|
|
312
|
+
constStart = null;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Close final constant block
|
|
317
|
+
if (constStart !== null && constants.length >= 3) {
|
|
318
|
+
const boundary = new ModuleBoundary(
|
|
319
|
+
BOUNDARY_TYPES.CONSTANT,
|
|
320
|
+
'constants',
|
|
321
|
+
constStart,
|
|
322
|
+
lines.length,
|
|
323
|
+
result.filePath
|
|
324
|
+
);
|
|
325
|
+
result.addBoundary(boundary);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
module.exports = BoundaryExtractionStrategies;
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module Boundary Extractor
|
|
3
|
+
*
|
|
4
|
+
* Main orchestrator for extracting logical module boundaries from files for refactoring.
|
|
5
|
+
* Identifies cohesive code segments that can be safely extracted.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { ModuleBoundary, BOUNDARY_TYPES, COHESION_LEVELS } = require('./boundaries/module-boundary');
|
|
11
|
+
const {
|
|
12
|
+
FunctionExtractionStrategy,
|
|
13
|
+
ClassExtractionStrategy,
|
|
14
|
+
ObjectExtractionStrategy,
|
|
15
|
+
UtilityExtractionStrategy
|
|
16
|
+
} = require('./boundaries/extraction-strategies');
|
|
17
|
+
const CohesionAnalyzer = require('./boundaries/cohesion-analyzer');
|
|
18
|
+
const BoundaryExtractionResult = require('./boundaries/extraction-result');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Main Boundary Extractor class
|
|
22
|
+
*/
|
|
23
|
+
class BoundaryExtractor {
|
|
24
|
+
constructor(options = {}) {
|
|
25
|
+
this.options = {
|
|
26
|
+
minBoundarySize: options.minBoundarySize || 5,
|
|
27
|
+
maxBoundarySize: options.maxBoundarySize || 200,
|
|
28
|
+
includeStrategies: options.includeStrategies || ['function', 'class', 'object', 'utility'],
|
|
29
|
+
analyzeCohesion: options.analyzeCohesion !== false,
|
|
30
|
+
confidenceThreshold: options.confidenceThreshold || 0.6,
|
|
31
|
+
...options
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
this.strategies = this.initializeStrategies();
|
|
35
|
+
this.cohesionAnalyzer = new CohesionAnalyzer();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Initialize extraction strategies
|
|
40
|
+
*/
|
|
41
|
+
initializeStrategies() {
|
|
42
|
+
const strategyMap = {
|
|
43
|
+
function: new FunctionExtractionStrategy(),
|
|
44
|
+
class: new ClassExtractionStrategy(),
|
|
45
|
+
object: new ObjectExtractionStrategy(),
|
|
46
|
+
utility: new UtilityExtractionStrategy()
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return Object.keys(strategyMap)
|
|
50
|
+
.filter(key => this.options.includeStrategies.includes(key))
|
|
51
|
+
.reduce((acc, key) => {
|
|
52
|
+
acc[key] = strategyMap[key];
|
|
53
|
+
return acc;
|
|
54
|
+
}, {});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Extract boundaries from a file
|
|
59
|
+
*/
|
|
60
|
+
async extractBoundaries(filePath) {
|
|
61
|
+
const startTime = Date.now();
|
|
62
|
+
const result = new BoundaryExtractionResult(filePath);
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
// Read file content
|
|
66
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
67
|
+
const lines = content.split('\n');
|
|
68
|
+
|
|
69
|
+
result.setMetadata('totalLines', lines.length);
|
|
70
|
+
result.setMetadata('processedLines', lines.length);
|
|
71
|
+
|
|
72
|
+
// Extract boundaries using all strategies
|
|
73
|
+
for (const [strategyName, strategy] of Object.entries(this.strategies)) {
|
|
74
|
+
if (strategy.canHandle(content)) {
|
|
75
|
+
try {
|
|
76
|
+
const boundaries = strategy.extract(content, filePath);
|
|
77
|
+
this.addBoundariesToResult(result, boundaries, strategyName);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
result.addError({
|
|
80
|
+
message: `Strategy ${strategyName} failed: ${error.message}`,
|
|
81
|
+
severity: 'warning'
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Analyze cohesion for all boundaries
|
|
88
|
+
if (this.options.analyzeCohesion) {
|
|
89
|
+
await this.analyzeCohesionForBoundaries(result, content);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Filter boundaries by size and confidence
|
|
93
|
+
this.filterBoundaries(result);
|
|
94
|
+
|
|
95
|
+
// Validate results
|
|
96
|
+
const issues = result.validate();
|
|
97
|
+
issues.forEach(issue => {
|
|
98
|
+
if (issue.type === 'overlap') {
|
|
99
|
+
result.addWarning({ message: issue.message, code: 'OVERLAP' });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
} catch (error) {
|
|
104
|
+
result.addError({
|
|
105
|
+
message: `Failed to process file: ${error.message}`,
|
|
106
|
+
severity: 'error'
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
result.setMetadata('extractionTime', Date.now() - startTime);
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Extract boundaries from multiple files
|
|
116
|
+
*/
|
|
117
|
+
async extractBoundariesFromFiles(filePaths) {
|
|
118
|
+
const results = [];
|
|
119
|
+
|
|
120
|
+
for (const filePath of filePaths) {
|
|
121
|
+
try {
|
|
122
|
+
const result = await this.extractBoundaries(filePath);
|
|
123
|
+
results.push(result);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
// Create error result
|
|
126
|
+
const errorResult = new BoundaryExtractionResult(filePath);
|
|
127
|
+
errorResult.addError({
|
|
128
|
+
message: `File processing failed: ${error.message}`,
|
|
129
|
+
severity: 'error'
|
|
130
|
+
});
|
|
131
|
+
results.push(errorResult);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return results;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Add boundaries to result
|
|
140
|
+
*/
|
|
141
|
+
addBoundariesToResult(result, boundaries, strategyName) {
|
|
142
|
+
for (const boundaryData of boundaries) {
|
|
143
|
+
// Apply confidence threshold
|
|
144
|
+
if (boundaryData.confidence < this.options.confidenceThreshold) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const boundary = result.addBoundary(boundaryData);
|
|
149
|
+
|
|
150
|
+
// Add strategy metadata
|
|
151
|
+
boundary.extractionStrategy = strategyName;
|
|
152
|
+
boundary.confidence = boundaryData.confidence;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Analyze cohesion for all boundaries
|
|
158
|
+
*/
|
|
159
|
+
async analyzeCohesionForBoundaries(result, content) {
|
|
160
|
+
for (const boundary of result.boundaries) {
|
|
161
|
+
try {
|
|
162
|
+
// Extract code segment for this boundary
|
|
163
|
+
const lines = content.split('\n');
|
|
164
|
+
const segmentLines = lines.slice(boundary.startLine - 1, boundary.endLine);
|
|
165
|
+
const segmentCode = segmentLines.join('\n');
|
|
166
|
+
|
|
167
|
+
// Analyze cohesion
|
|
168
|
+
const cohesion = this.cohesionAnalyzer.analyzeCohesion(segmentCode, boundary);
|
|
169
|
+
|
|
170
|
+
boundary.setCohesion(cohesion.level);
|
|
171
|
+
boundary.cohesionScore = cohesion.score;
|
|
172
|
+
boundary.cohesionDetails = cohesion.details;
|
|
173
|
+
|
|
174
|
+
} catch (error) {
|
|
175
|
+
result.addWarning({
|
|
176
|
+
message: `Cohesion analysis failed for ${boundary.name}: ${error.message}`,
|
|
177
|
+
line: boundary.startLine
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Filter boundaries based on criteria
|
|
185
|
+
*/
|
|
186
|
+
filterBoundaries(result) {
|
|
187
|
+
result.boundaries = result.boundaries.filter(boundary => {
|
|
188
|
+
// Size filter
|
|
189
|
+
if (boundary.lineCount < this.options.minBoundarySize) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
if (boundary.lineCount > this.options.maxBoundarySize) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Name filter
|
|
197
|
+
if (!boundary.name || boundary.name.trim() === '') {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return true;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get extraction statistics for multiple results
|
|
207
|
+
*/
|
|
208
|
+
getStatistics(results) {
|
|
209
|
+
const stats = {
|
|
210
|
+
totalFiles: results.length,
|
|
211
|
+
totalBoundaries: 0,
|
|
212
|
+
extractableBoundaries: 0,
|
|
213
|
+
highCohesionBoundaries: 0,
|
|
214
|
+
averageCoverage: 0,
|
|
215
|
+
byType: {},
|
|
216
|
+
errors: [],
|
|
217
|
+
warnings: [],
|
|
218
|
+
extractionTime: 0
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
let totalCoverage = 0;
|
|
222
|
+
|
|
223
|
+
for (const result of results) {
|
|
224
|
+
const resultStats = result.getStatistics();
|
|
225
|
+
|
|
226
|
+
stats.totalBoundaries += resultStats.totalBoundaries;
|
|
227
|
+
stats.extractableBoundaries += resultStats.extractableBoundaries;
|
|
228
|
+
stats.highCohesionBoundaries += resultStats.highCohesionBoundaries;
|
|
229
|
+
totalCoverage += resultStats.coverage;
|
|
230
|
+
stats.extractionTime += result.metadata.extractionTime || 0;
|
|
231
|
+
|
|
232
|
+
stats.errors.push(...result.errors);
|
|
233
|
+
stats.warnings.push(...result.warnings);
|
|
234
|
+
|
|
235
|
+
// Count by type
|
|
236
|
+
for (const [type, count] of Object.entries(resultStats.typeDistribution)) {
|
|
237
|
+
stats.byType[type] = (stats.byType[type] || 0) + count;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
stats.averageCoverage = results.length > 0 ? totalCoverage / results.length : 0;
|
|
242
|
+
|
|
243
|
+
return stats;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Get top extraction candidates across all results
|
|
248
|
+
*/
|
|
249
|
+
getTopExtractionCandidates(results, limit = 20) {
|
|
250
|
+
const allCandidates = [];
|
|
251
|
+
|
|
252
|
+
for (const result of results) {
|
|
253
|
+
const candidates = result.getTopExtractionCandidates(limit);
|
|
254
|
+
allCandidates.push(...candidates);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return allCandidates
|
|
258
|
+
.sort((a, b) => b.getExtractionPriority() - a.getExtractionPriority())
|
|
259
|
+
.slice(0, limit);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Generate extraction plan
|
|
264
|
+
*/
|
|
265
|
+
generateExtractionPlan(results, options = {}) {
|
|
266
|
+
const candidates = this.getTopExtractionCandidates(results, options.limit || 50);
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
summary: this.getStatistics(results),
|
|
270
|
+
candidates: candidates.map(boundary => ({
|
|
271
|
+
...boundary.getSummary(),
|
|
272
|
+
extractionPlan: this.generateBoundaryExtractionPlan(boundary)
|
|
273
|
+
})),
|
|
274
|
+
recommendations: this.generateRecommendations(results),
|
|
275
|
+
estimatedEffort: this.estimateExtractionEffort(candidates)
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Generate extraction plan for a single boundary
|
|
281
|
+
*/
|
|
282
|
+
generateBoundaryExtractionPlan(boundary) {
|
|
283
|
+
return {
|
|
284
|
+
targetFile: boundary.getSuggestedFilename(),
|
|
285
|
+
extractionSteps: [
|
|
286
|
+
`Create new file: ${boundary.getSuggestedFilename()}`,
|
|
287
|
+
`Extract lines ${boundary.startLine}-${boundary.endLine}`,
|
|
288
|
+
`Update imports in ${boundary.filePath}`,
|
|
289
|
+
`Add export statement to new file`,
|
|
290
|
+
`Test extraction and functionality`
|
|
291
|
+
],
|
|
292
|
+
complexity: boundary.complexity,
|
|
293
|
+
estimatedTime: this.estimateBoundaryExtractionTime(boundary)
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Generate recommendations
|
|
299
|
+
*/
|
|
300
|
+
generateRecommendations(results) {
|
|
301
|
+
const stats = this.getStatistics(results);
|
|
302
|
+
const recommendations = [];
|
|
303
|
+
|
|
304
|
+
if (stats.extractableBoundaries === 0) {
|
|
305
|
+
recommendations.push('No extractable boundaries found. Consider adjusting extraction criteria.');
|
|
306
|
+
} else if (stats.extractableBoundaries < 5) {
|
|
307
|
+
recommendations.push('Few extractable boundaries found. Code may already be well-modularized.');
|
|
308
|
+
} else {
|
|
309
|
+
recommendations.push(`Found ${stats.extractableBoundaries} extractable boundaries. Prioritize high cohesion boundaries.`);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (stats.averageCoverage < 30) {
|
|
313
|
+
recommendations.push('Low coverage suggests boundaries may be too small. Consider increasing minimum size.');
|
|
314
|
+
} else if (stats.averageCoverage > 80) {
|
|
315
|
+
recommendations.push('High coverage suggests boundaries may be too large. Consider decreasing maximum size.');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (stats.highCohesionBoundaries / stats.extractableBoundaries < 0.5) {
|
|
319
|
+
recommendations.push('Many boundaries have low cohesion. Focus on improving code organization.');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return recommendations;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Estimate extraction effort
|
|
327
|
+
*/
|
|
328
|
+
estimateExtractionEffort(candidates) {
|
|
329
|
+
let totalEffort = 0;
|
|
330
|
+
|
|
331
|
+
for (const boundary of candidates) {
|
|
332
|
+
totalEffort += this.estimateBoundaryExtractionTime(boundary);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return {
|
|
336
|
+
totalHours: totalEffort,
|
|
337
|
+
averageHoursPerBoundary: totalEffort / candidates.length,
|
|
338
|
+
complexityBreakdown: this.getComplexityBreakdown(candidates)
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Estimate extraction time for a boundary
|
|
344
|
+
*/
|
|
345
|
+
estimateBoundaryExtractionTime(boundary) {
|
|
346
|
+
let baseTime = 1; // 1 hour base
|
|
347
|
+
|
|
348
|
+
// Adjust for size
|
|
349
|
+
if (boundary.lineCount > 100) baseTime += 2;
|
|
350
|
+
else if (boundary.lineCount > 50) baseTime += 1;
|
|
351
|
+
|
|
352
|
+
// Adjust for complexity
|
|
353
|
+
if (boundary.complexity > 50) baseTime += 2;
|
|
354
|
+
else if (boundary.complexity > 20) baseTime += 1;
|
|
355
|
+
|
|
356
|
+
// Adjust for dependencies
|
|
357
|
+
baseTime += Math.min(boundary.dependencies.length * 0.5, 2);
|
|
358
|
+
|
|
359
|
+
return baseTime;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Get complexity breakdown
|
|
364
|
+
*/
|
|
365
|
+
getComplexityBreakdown(candidates) {
|
|
366
|
+
const breakdown = { low: 0, medium: 0, high: 0 };
|
|
367
|
+
|
|
368
|
+
for (const boundary of candidates) {
|
|
369
|
+
if (boundary.complexity <= 20) breakdown.low++;
|
|
370
|
+
else if (boundary.complexity <= 50) breakdown.medium++;
|
|
371
|
+
else breakdown.high++;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return breakdown;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
module.exports = {
|
|
379
|
+
BoundaryExtractor,
|
|
380
|
+
ModuleBoundary,
|
|
381
|
+
BoundaryExtractionResult,
|
|
382
|
+
BOUNDARY_TYPES,
|
|
383
|
+
COHESION_LEVELS
|
|
384
|
+
};
|