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,816 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Functionality Preservation Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates that refactoring operations preserve original functionality.
|
|
5
|
+
* Uses multiple validation techniques to ensure behavioral consistency.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { execSync } = require('child_process');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Validation techniques
|
|
14
|
+
*/
|
|
15
|
+
const VALIDATION_TECHNIQUES = {
|
|
16
|
+
STATIC_ANALYSIS: 'static_analysis',
|
|
17
|
+
BEHAVIORAL_COMPARISON: 'behavioral_comparison',
|
|
18
|
+
API_COMPATIBILITY: 'api_compatibility',
|
|
19
|
+
TYPE_CHECKING: 'type_checking',
|
|
20
|
+
RUNTIME_VALIDATION: 'runtime_validation'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Validation severity levels
|
|
25
|
+
*/
|
|
26
|
+
const VALIDATION_SEVERITY = {
|
|
27
|
+
INFO: 'info',
|
|
28
|
+
WARNING: 'warning',
|
|
29
|
+
ERROR: 'error',
|
|
30
|
+
CRITICAL: 'critical'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Functionality validation result class
|
|
35
|
+
*/
|
|
36
|
+
class FunctionalityValidationResult {
|
|
37
|
+
constructor(operationId) {
|
|
38
|
+
this.operationId = operationId;
|
|
39
|
+
this.techniques = new Map();
|
|
40
|
+
this.success = false;
|
|
41
|
+
this.confidence = 0;
|
|
42
|
+
this.issues = [];
|
|
43
|
+
this.metadata = {
|
|
44
|
+
validatedAt: new Date().toISOString(),
|
|
45
|
+
duration: 0,
|
|
46
|
+
environment: process.env.NODE_ENV || 'development'
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
addTechniqueResult(technique, result) {
|
|
51
|
+
this.techniques.set(technique, result);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
addIssue(severity, message, details = null) {
|
|
55
|
+
this.issues.push({
|
|
56
|
+
severity,
|
|
57
|
+
message,
|
|
58
|
+
details,
|
|
59
|
+
timestamp: new Date().toISOString()
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
setSuccess(success) {
|
|
64
|
+
this.success = success;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
setConfidence(confidence) {
|
|
68
|
+
this.confidence = Math.max(0, Math.min(1, confidence));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
calculateOverallSuccess() {
|
|
72
|
+
const techniqueResults = Array.from(this.techniques.values());
|
|
73
|
+
const passedTechniques = techniqueResults.filter(r => r.success).length;
|
|
74
|
+
const totalTechniques = techniqueResults.length;
|
|
75
|
+
|
|
76
|
+
if (totalTechniques === 0) {
|
|
77
|
+
this.setSuccess(false);
|
|
78
|
+
this.setConfidence(0);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const successRate = passedTechniques / totalTechniques;
|
|
83
|
+
this.setSuccess(successRate >= 0.8 && this.issues.filter(i => i.severity === VALIDATION_SEVERITY.ERROR || i.severity === VALIDATION_SEVERITY.CRITICAL).length === 0);
|
|
84
|
+
this.setConfidence(successRate);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
getSummary() {
|
|
88
|
+
this.calculateOverallSuccess();
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
operationId: this.operationId,
|
|
92
|
+
success: this.success,
|
|
93
|
+
confidence: this.confidence,
|
|
94
|
+
techniques: Array.from(this.techniques.entries()).map(([tech, result]) => ({
|
|
95
|
+
technique: tech,
|
|
96
|
+
success: result.success,
|
|
97
|
+
duration: result.duration || 0,
|
|
98
|
+
issues: result.issues || []
|
|
99
|
+
})),
|
|
100
|
+
issues: this.issues,
|
|
101
|
+
issueCount: this.issues.length,
|
|
102
|
+
criticalIssues: this.issues.filter(i => i.severity === VALIDATION_SEVERITY.CRITICAL).length,
|
|
103
|
+
errorIssues: this.issues.filter(i => i.severity === VALIDATION_SEVERITY.ERROR).length
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Technique result class
|
|
110
|
+
*/
|
|
111
|
+
class TechniqueResult {
|
|
112
|
+
constructor(technique) {
|
|
113
|
+
this.technique = technique;
|
|
114
|
+
this.success = false;
|
|
115
|
+
this.duration = 0;
|
|
116
|
+
this.issues = [];
|
|
117
|
+
this.metadata = {
|
|
118
|
+
executedAt: new Date().toISOString(),
|
|
119
|
+
details: {}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
setSuccess(success) {
|
|
124
|
+
this.success = success;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
setDuration(duration) {
|
|
128
|
+
this.duration = duration;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
addIssue(severity, message, details = null) {
|
|
132
|
+
this.issues.push({
|
|
133
|
+
severity,
|
|
134
|
+
message,
|
|
135
|
+
details,
|
|
136
|
+
timestamp: new Date().toISOString()
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
setDetails(details) {
|
|
141
|
+
this.metadata.details = details;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Functionality validator class
|
|
147
|
+
*/
|
|
148
|
+
class FunctionalityValidator {
|
|
149
|
+
constructor(options = {}) {
|
|
150
|
+
this.options = {
|
|
151
|
+
enableStaticAnalysis: true,
|
|
152
|
+
enableBehavioralComparison: true,
|
|
153
|
+
enableAPICompatibility: true,
|
|
154
|
+
enableTypeChecking: true,
|
|
155
|
+
enableRuntimeValidation: true,
|
|
156
|
+
strictMode: false,
|
|
157
|
+
...options
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
this.validationResults = new Map();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Validate functionality preservation for a refactoring operation
|
|
165
|
+
*/
|
|
166
|
+
async validateOperation(operationId, originalPath, modifiedPath, options = {}) {
|
|
167
|
+
const result = new FunctionalityValidationResult(operationId);
|
|
168
|
+
const startTime = Date.now();
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
console.log(`Validating functionality preservation for: ${operationId}`);
|
|
172
|
+
|
|
173
|
+
// Static analysis
|
|
174
|
+
if (this.options.enableStaticAnalysis) {
|
|
175
|
+
await this.validateStaticAnalysis(originalPath, modifiedPath, result);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Behavioral comparison
|
|
179
|
+
if (this.options.enableBehavioralComparison) {
|
|
180
|
+
await this.validateBehavioralComparison(originalPath, modifiedPath, result);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// API compatibility
|
|
184
|
+
if (this.options.enableAPICompatibility) {
|
|
185
|
+
await this.validateAPICompatibility(originalPath, modifiedPath, result);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Type checking
|
|
189
|
+
if (this.options.enableTypeChecking) {
|
|
190
|
+
await this.validateTypeChecking(originalPath, modifiedPath, result);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Runtime validation
|
|
194
|
+
if (this.options.enableRuntimeValidation) {
|
|
195
|
+
await this.validateRuntime(originalPath, modifiedPath, result);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
result.calculateOverallSuccess();
|
|
199
|
+
result.metadata.duration = (Date.now() - startTime) / 1000;
|
|
200
|
+
|
|
201
|
+
console.log(`Validation completed: ${result.success ? 'PASSED' : 'FAILED'} (confidence: ${(result.confidence * 100).toFixed(1)}%)`);
|
|
202
|
+
|
|
203
|
+
} catch (error) {
|
|
204
|
+
result.addIssue(VALIDATION_SEVERITY.ERROR, 'Validation execution failed', error.message);
|
|
205
|
+
result.setSuccess(false);
|
|
206
|
+
result.metadata.duration = (Date.now() - startTime) / 1000;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
this.validationResults.set(operationId, result);
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Perform static analysis validation
|
|
215
|
+
*/
|
|
216
|
+
async validateStaticAnalysis(originalPath, modifiedPath, result) {
|
|
217
|
+
const techniqueResult = new TechniqueResult(VALIDATION_TECHNIQUES.STATIC_ANALYSIS);
|
|
218
|
+
const startTime = Date.now();
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
console.log('Performing static analysis validation...');
|
|
222
|
+
|
|
223
|
+
// Compare AST structures
|
|
224
|
+
const astComparison = await this.compareASTs(originalPath, modifiedPath);
|
|
225
|
+
techniqueResult.setDetails({ astComparison });
|
|
226
|
+
|
|
227
|
+
if (!astComparison.structuralChangesAcceptable) {
|
|
228
|
+
techniqueResult.addIssue(VALIDATION_SEVERITY.WARNING, 'Significant structural changes detected', astComparison);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Check for missing exports
|
|
232
|
+
const exportComparison = await this.compareExports(originalPath, modifiedPath);
|
|
233
|
+
techniqueResult.metadata.details.exportComparison = exportComparison;
|
|
234
|
+
|
|
235
|
+
if (exportComparison.missingExports.length > 0) {
|
|
236
|
+
techniqueResult.addIssue(
|
|
237
|
+
VALIDATION_SEVERITY.ERROR,
|
|
238
|
+
'Missing exports detected',
|
|
239
|
+
{ missing: exportComparison.missingExports }
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Check for breaking changes
|
|
244
|
+
const breakingChanges = await this.detectBreakingChanges(originalPath, modifiedPath);
|
|
245
|
+
techniqueResult.metadata.details.breakingChanges = breakingChanges;
|
|
246
|
+
|
|
247
|
+
if (breakingChanges.length > 0) {
|
|
248
|
+
techniqueResult.addIssue(
|
|
249
|
+
VALIDATION_SEVERITY.ERROR,
|
|
250
|
+
'Breaking changes detected',
|
|
251
|
+
{ changes: breakingChanges }
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
techniqueResult.setSuccess(techniqueResult.issues.filter(i => i.severity === VALIDATION_SEVERITY.ERROR || i.severity === VALIDATION_SEVERITY.CRITICAL).length === 0);
|
|
256
|
+
|
|
257
|
+
} catch (error) {
|
|
258
|
+
techniqueResult.addIssue(VALIDATION_SEVERITY.ERROR, 'Static analysis failed', error.message);
|
|
259
|
+
techniqueResult.setSuccess(false);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
techniqueResult.setDuration((Date.now() - startTime) / 1000);
|
|
263
|
+
result.addTechniqueResult(VALIDATION_TECHNIQUES.STATIC_ANALYSIS, techniqueResult);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Perform behavioral comparison validation
|
|
268
|
+
*/
|
|
269
|
+
async validateBehavioralComparison(originalPath, modifiedPath, result) {
|
|
270
|
+
const techniqueResult = new TechniqueResult(VALIDATION_TECHNIQUES.BEHAVIORAL_COMPARISON);
|
|
271
|
+
const startTime = Date.now();
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
console.log('Performing behavioral comparison...');
|
|
275
|
+
|
|
276
|
+
// Create test scenarios
|
|
277
|
+
const scenarios = await this.generateTestScenarios(originalPath);
|
|
278
|
+
techniqueResult.metadata.details.scenarios = scenarios;
|
|
279
|
+
|
|
280
|
+
// Execute scenarios on both versions
|
|
281
|
+
const originalResults = await this.executeScenarios(originalPath, scenarios);
|
|
282
|
+
const modifiedResults = await this.executeScenarios(modifiedPath, scenarios);
|
|
283
|
+
|
|
284
|
+
// Compare results
|
|
285
|
+
const comparison = this.compareScenarioResults(originalResults, modifiedResults);
|
|
286
|
+
techniqueResult.metadata.details.behavioralComparison = comparison;
|
|
287
|
+
|
|
288
|
+
if (comparison.differences.length > 0) {
|
|
289
|
+
techniqueResult.addIssue(
|
|
290
|
+
VALIDATION_SEVERITY.ERROR,
|
|
291
|
+
'Behavioral differences detected',
|
|
292
|
+
{ differences: comparison.differences }
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
techniqueResult.setSuccess(comparison.differences.length === 0);
|
|
297
|
+
|
|
298
|
+
} catch (error) {
|
|
299
|
+
techniqueResult.addIssue(VALIDATION_SEVERITY.ERROR, 'Behavioral comparison failed', error.message);
|
|
300
|
+
techniqueResult.setSuccess(false);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
techniqueResult.setDuration((Date.now() - startTime) / 1000);
|
|
304
|
+
result.addTechniqueResult(VALIDATION_TECHNIQUES.BEHAVIORAL_COMPARISON, techniqueResult);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Perform API compatibility validation
|
|
309
|
+
*/
|
|
310
|
+
async validateAPICompatibility(originalPath, modifiedPath, result) {
|
|
311
|
+
const techniqueResult = new TechniqueResult(VALIDATION_TECHNIQUES.API_COMPATIBILITY);
|
|
312
|
+
const startTime = Date.now();
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
console.log('Performing API compatibility validation...');
|
|
316
|
+
|
|
317
|
+
// Extract API signatures
|
|
318
|
+
const originalAPI = await this.extractAPI(originalPath);
|
|
319
|
+
const modifiedAPI = await this.extractAPI(modifiedPath);
|
|
320
|
+
|
|
321
|
+
techniqueResult.metadata.details.originalAPI = originalAPI;
|
|
322
|
+
techniqueResult.metadata.details.modifiedAPI = modifiedAPI;
|
|
323
|
+
|
|
324
|
+
// Compare APIs
|
|
325
|
+
const apiComparison = this.compareAPIs(originalAPI, modifiedAPI);
|
|
326
|
+
techniqueResult.metadata.details.apiComparison = apiComparison;
|
|
327
|
+
|
|
328
|
+
if (apiComparison.removedMethods.length > 0) {
|
|
329
|
+
techniqueResult.addIssue(
|
|
330
|
+
VALIDATION_SEVERITY.ERROR,
|
|
331
|
+
'API methods removed',
|
|
332
|
+
{ removed: apiComparison.removedMethods }
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (apiComparison.changedSignatures.length > 0) {
|
|
337
|
+
techniqueResult.addIssue(
|
|
338
|
+
VALIDATION_SEVERITY.WARNING,
|
|
339
|
+
'API signatures changed',
|
|
340
|
+
{ changed: apiComparison.changedSignatures }
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
techniqueResult.setSuccess(apiCompatibilityAcceptable(apiComparison, this.options.strictMode));
|
|
345
|
+
|
|
346
|
+
} catch (error) {
|
|
347
|
+
techniqueResult.addIssue(VALIDATION_SEVERITY.ERROR, 'API compatibility check failed', error.message);
|
|
348
|
+
techniqueResult.setSuccess(false);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
techniqueResult.setDuration((Date.now() - startTime) / 1000);
|
|
352
|
+
result.addTechniqueResult(VALIDATION_TECHNIQUES.API_COMPATIBILITY, techniqueResult);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Perform type checking validation
|
|
357
|
+
*/
|
|
358
|
+
async validateTypeChecking(originalPath, modifiedPath, result) {
|
|
359
|
+
const techniqueResult = new TechniqueResult(VALIDATION_TECHNIQUES.TYPE_CHECKING);
|
|
360
|
+
const startTime = Date.now();
|
|
361
|
+
|
|
362
|
+
try {
|
|
363
|
+
console.log('Performing type checking...');
|
|
364
|
+
|
|
365
|
+
// Run TypeScript compiler if applicable
|
|
366
|
+
const isTypeScript = originalPath.endsWith('.ts') || originalPath.endsWith('.tsx');
|
|
367
|
+
|
|
368
|
+
if (isTypeScript) {
|
|
369
|
+
const originalTypeErrors = await this.runTypeChecker(originalPath);
|
|
370
|
+
const modifiedTypeErrors = await this.runTypeChecker(modifiedPath);
|
|
371
|
+
|
|
372
|
+
techniqueResult.metadata.details.originalTypeErrors = originalTypeErrors;
|
|
373
|
+
techniqueResult.metadata.details.modifiedTypeErrors = modifiedTypeErrors;
|
|
374
|
+
|
|
375
|
+
if (modifiedTypeErrors.length > originalTypeErrors.length) {
|
|
376
|
+
techniqueResult.addIssue(
|
|
377
|
+
VALIDATION_SEVERITY.ERROR,
|
|
378
|
+
'New type errors introduced',
|
|
379
|
+
{ newErrors: modifiedTypeErrors.length - originalTypeErrors.length }
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
techniqueResult.setSuccess(modifiedTypeErrors.length <= originalTypeErrors.length);
|
|
384
|
+
} else {
|
|
385
|
+
// For JavaScript, use JSDoc validation or skip
|
|
386
|
+
techniqueResult.setSuccess(true);
|
|
387
|
+
techniqueResult.addIssue(VALIDATION_SEVERITY.INFO, 'Type checking skipped for JavaScript file');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
} catch (error) {
|
|
391
|
+
techniqueResult.addIssue(VALIDATION_SEVERITY.ERROR, 'Type checking failed', error.message);
|
|
392
|
+
techniqueResult.setSuccess(false);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
techniqueResult.setDuration((Date.now() - startTime) / 1000);
|
|
396
|
+
result.addTechniqueResult(VALIDATION_TECHNIQUES.TYPE_CHECKING, techniqueResult);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Perform runtime validation
|
|
401
|
+
*/
|
|
402
|
+
async validateRuntime(originalPath, modifiedPath, result) {
|
|
403
|
+
const techniqueResult = new TechniqueResult(VALIDATION_TECHNIQUES.RUNTIME_VALIDATION);
|
|
404
|
+
const startTime = Date.now();
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
console.log('Performing runtime validation...');
|
|
408
|
+
|
|
409
|
+
// Load and execute both modules
|
|
410
|
+
const originalModule = await this.loadModule(originalPath);
|
|
411
|
+
const modifiedModule = await this.loadModule(modifiedPath);
|
|
412
|
+
|
|
413
|
+
// Test module interfaces
|
|
414
|
+
const interfaceTest = await this.testModuleInterface(originalModule, modifiedModule);
|
|
415
|
+
techniqueResult.metadata.details.interfaceTest = interfaceTest;
|
|
416
|
+
|
|
417
|
+
if (!interfaceTest.compatible) {
|
|
418
|
+
techniqueResult.addIssue(
|
|
419
|
+
VALIDATION_SEVERITY.ERROR,
|
|
420
|
+
'Module interface incompatibility',
|
|
421
|
+
interfaceTest
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
techniqueResult.setSuccess(interfaceTest.compatible);
|
|
426
|
+
|
|
427
|
+
} catch (error) {
|
|
428
|
+
techniqueResult.addIssue(VALIDATION_SEVERITY.ERROR, 'Runtime validation failed', error.message);
|
|
429
|
+
techniqueResult.setSuccess(false);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
techniqueResult.setDuration((Date.now() - startTime) / 1000);
|
|
433
|
+
result.addTechniqueResult(VALIDATION_TECHNIQUES.RUNTIME_VALIDATION, techniqueResult);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Compare AST structures
|
|
438
|
+
*/
|
|
439
|
+
async compareASTs(originalPath, modifiedPath) {
|
|
440
|
+
// Simplified AST comparison
|
|
441
|
+
const originalContent = fs.readFileSync(originalPath, 'utf8');
|
|
442
|
+
const modifiedContent = fs.readFileSync(modifiedPath, 'utf8');
|
|
443
|
+
|
|
444
|
+
const originalLines = originalContent.split('\n').length;
|
|
445
|
+
const modifiedLines = modifiedContent.split('\n').length;
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
structuralChangesAcceptable: Math.abs(originalLines - modifiedLines) < originalLines * 0.5,
|
|
449
|
+
originalLines,
|
|
450
|
+
modifiedLines,
|
|
451
|
+
lineDifference: modifiedLines - originalLines
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Compare exports
|
|
457
|
+
*/
|
|
458
|
+
async compareExports(originalPath, modifiedPath) {
|
|
459
|
+
const originalExports = await this.extractExports(originalPath);
|
|
460
|
+
const modifiedExports = await this.extractExports(modifiedPath);
|
|
461
|
+
|
|
462
|
+
const missingExports = originalExports.filter(exp => !modifiedExports.includes(exp));
|
|
463
|
+
const newExports = modifiedExports.filter(exp => !originalExports.includes(exp));
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
originalExports,
|
|
467
|
+
modifiedExports,
|
|
468
|
+
missingExports,
|
|
469
|
+
newExports
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Detect breaking changes
|
|
475
|
+
*/
|
|
476
|
+
async detectBreakingChanges(originalPath, modifiedPath) {
|
|
477
|
+
// Simplified breaking change detection
|
|
478
|
+
const changes = [];
|
|
479
|
+
|
|
480
|
+
// Check for removed functions
|
|
481
|
+
const originalFunctions = await this.extractFunctions(originalPath);
|
|
482
|
+
const modifiedFunctions = await this.extractFunctions(modifiedPath);
|
|
483
|
+
|
|
484
|
+
for (const func of originalFunctions) {
|
|
485
|
+
if (!modifiedFunctions.includes(func)) {
|
|
486
|
+
changes.push({
|
|
487
|
+
type: 'removed_function',
|
|
488
|
+
name: func,
|
|
489
|
+
severity: 'breaking'
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return changes;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Generate test scenarios
|
|
499
|
+
*/
|
|
500
|
+
async generateTestScenarios(filePath) {
|
|
501
|
+
// Simplified scenario generation
|
|
502
|
+
return [
|
|
503
|
+
{
|
|
504
|
+
name: 'module_load',
|
|
505
|
+
type: 'load',
|
|
506
|
+
description: 'Test module loading'
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
name: 'export_access',
|
|
510
|
+
type: 'access',
|
|
511
|
+
description: 'Test export access'
|
|
512
|
+
}
|
|
513
|
+
];
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Execute test scenarios
|
|
518
|
+
*/
|
|
519
|
+
async executeScenarios(filePath, scenarios) {
|
|
520
|
+
const results = [];
|
|
521
|
+
|
|
522
|
+
for (const scenario of scenarios) {
|
|
523
|
+
try {
|
|
524
|
+
const result = await this.executeScenario(filePath, scenario);
|
|
525
|
+
results.push(result);
|
|
526
|
+
} catch (error) {
|
|
527
|
+
results.push({
|
|
528
|
+
scenario: scenario.name,
|
|
529
|
+
success: false,
|
|
530
|
+
error: error.message
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return results;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Execute single scenario
|
|
540
|
+
*/
|
|
541
|
+
async executeScenario(filePath, scenario) {
|
|
542
|
+
switch (scenario.type) {
|
|
543
|
+
case 'load':
|
|
544
|
+
const module = await this.loadModule(filePath);
|
|
545
|
+
return { scenario: scenario.name, success: true, result: 'loaded' };
|
|
546
|
+
case 'access':
|
|
547
|
+
const mod = await this.loadModule(filePath);
|
|
548
|
+
return { scenario: scenario.name, success: true, result: Object.keys(mod) };
|
|
549
|
+
default:
|
|
550
|
+
return { scenario: scenario.name, success: false, error: 'Unknown scenario type' };
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Compare scenario results
|
|
556
|
+
*/
|
|
557
|
+
compareScenarioResults(originalResults, modifiedResults) {
|
|
558
|
+
const differences = [];
|
|
559
|
+
|
|
560
|
+
for (let i = 0; i < Math.min(originalResults.length, modifiedResults.length); i++) {
|
|
561
|
+
const original = originalResults[i];
|
|
562
|
+
const modified = modifiedResults[i];
|
|
563
|
+
|
|
564
|
+
if (original.success !== modified.success) {
|
|
565
|
+
differences.push({
|
|
566
|
+
scenario: original.scenario,
|
|
567
|
+
type: 'success_mismatch',
|
|
568
|
+
original: original.success,
|
|
569
|
+
modified: modified.success
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
if (JSON.stringify(original.result) !== JSON.stringify(modified.result)) {
|
|
574
|
+
differences.push({
|
|
575
|
+
scenario: original.scenario,
|
|
576
|
+
type: 'result_mismatch',
|
|
577
|
+
original: original.result,
|
|
578
|
+
modified: modified.result
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return { differences };
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Extract API from file
|
|
588
|
+
*/
|
|
589
|
+
async extractAPI(filePath) {
|
|
590
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
591
|
+
const api = {
|
|
592
|
+
functions: [],
|
|
593
|
+
classes: [],
|
|
594
|
+
exports: [],
|
|
595
|
+
imports: []
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
// Simple extraction using regex
|
|
599
|
+
const functionMatches = content.match(/(?:function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:function|\([^)]*\)\s*=>))/g);
|
|
600
|
+
if (functionMatches) {
|
|
601
|
+
for (const match of functionMatches) {
|
|
602
|
+
const nameMatch = match.match(/(\w+)/);
|
|
603
|
+
if (nameMatch) {
|
|
604
|
+
api.functions.push(nameMatch[1]);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const classMatches = content.match(/class\s+(\w+)/g);
|
|
610
|
+
if (classMatches) {
|
|
611
|
+
for (const match of classMatches) {
|
|
612
|
+
const nameMatch = match.match(/class\s+(\w+)/);
|
|
613
|
+
if (nameMatch) {
|
|
614
|
+
api.classes.push(nameMatch[1]);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
return api;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Compare APIs
|
|
624
|
+
*/
|
|
625
|
+
compareAPIs(originalAPI, modifiedAPI) {
|
|
626
|
+
const removedMethods = originalAPI.functions.filter(f => !modifiedAPI.functions.includes(f));
|
|
627
|
+
const newMethods = modifiedAPI.functions.filter(f => !originalAPI.functions.includes(f));
|
|
628
|
+
const changedSignatures = []; // Simplified - would need signature analysis
|
|
629
|
+
|
|
630
|
+
return {
|
|
631
|
+
removedMethods,
|
|
632
|
+
newMethods,
|
|
633
|
+
changedSignatures
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Check API compatibility acceptability
|
|
639
|
+
*/
|
|
640
|
+
apiCompatibilityAcceptable(comparison, strictMode) {
|
|
641
|
+
if (strictMode) {
|
|
642
|
+
return comparison.removedMethods.length === 0 && comparison.changedSignatures.length === 0;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Allow additions but not removals in non-strict mode
|
|
646
|
+
return comparison.removedMethods.length === 0;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Run type checker
|
|
651
|
+
*/
|
|
652
|
+
async runTypeChecker(filePath) {
|
|
653
|
+
try {
|
|
654
|
+
// Try to run TypeScript compiler
|
|
655
|
+
const result = execSync(`npx tsc --noEmit ${filePath}`, { encoding: 'utf8' });
|
|
656
|
+
return []; // No errors
|
|
657
|
+
} catch (error) {
|
|
658
|
+
// Parse TypeScript errors
|
|
659
|
+
const errorOutput = error.stdout || error.message;
|
|
660
|
+
const errors = errorOutput.split('\n').filter(line => line.trim()).map(line => ({
|
|
661
|
+
line: line,
|
|
662
|
+
message: line
|
|
663
|
+
}));
|
|
664
|
+
return errors;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Load module safely
|
|
670
|
+
*/
|
|
671
|
+
async loadModule(filePath) {
|
|
672
|
+
// Clear require cache to ensure fresh load
|
|
673
|
+
delete require.cache[require.resolve(filePath)];
|
|
674
|
+
return require(filePath);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Test module interface compatibility
|
|
679
|
+
*/
|
|
680
|
+
async testModuleInterface(originalModule, modifiedModule) {
|
|
681
|
+
const originalKeys = new Set(Object.keys(originalModule));
|
|
682
|
+
const modifiedKeys = new Set(Object.keys(modifiedModule));
|
|
683
|
+
|
|
684
|
+
const missingKeys = Array.from(originalKeys).filter(key => !modifiedKeys.has(key));
|
|
685
|
+
const extraKeys = Array.from(modifiedKeys).filter(key => !originalKeys.has(key));
|
|
686
|
+
|
|
687
|
+
return {
|
|
688
|
+
compatible: missingKeys.length === 0,
|
|
689
|
+
missingKeys,
|
|
690
|
+
extraKeys
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Helper methods for extraction
|
|
696
|
+
*/
|
|
697
|
+
async extractExports(filePath) {
|
|
698
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
699
|
+
const exports = [];
|
|
700
|
+
|
|
701
|
+
const exportMatches = content.match(/export\s+(?:default\s+)?(?:function|class|const|let|var)\s+(\w+)/g);
|
|
702
|
+
if (exportMatches) {
|
|
703
|
+
for (const match of exportMatches) {
|
|
704
|
+
const nameMatch = match.match(/\w+/);
|
|
705
|
+
if (nameMatch) {
|
|
706
|
+
exports.push(nameMatch[0]);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
return exports;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
async extractFunctions(filePath) {
|
|
715
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
716
|
+
const functions = [];
|
|
717
|
+
|
|
718
|
+
const functionMatches = content.match(/(?:function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:function|\([^)]*\)\s*=>))/g);
|
|
719
|
+
if (functionMatches) {
|
|
720
|
+
for (const match of functionMatches) {
|
|
721
|
+
const nameMatch = match.match(/(\w+)/);
|
|
722
|
+
if (nameMatch) {
|
|
723
|
+
functions.push(nameMatch[1]);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
return functions;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Get validation summary
|
|
733
|
+
*/
|
|
734
|
+
getValidationSummary() {
|
|
735
|
+
const summary = {
|
|
736
|
+
totalValidations: this.validationResults.size,
|
|
737
|
+
successful: 0,
|
|
738
|
+
failed: 0,
|
|
739
|
+
averageConfidence: 0,
|
|
740
|
+
techniqueUsage: {},
|
|
741
|
+
commonIssues: {}
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
let totalConfidence = 0;
|
|
745
|
+
const techniqueCounts = {};
|
|
746
|
+
const issueCounts = {};
|
|
747
|
+
|
|
748
|
+
for (const result of this.validationResults.values()) {
|
|
749
|
+
if (result.success) {
|
|
750
|
+
summary.successful++;
|
|
751
|
+
} else {
|
|
752
|
+
summary.failed++;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
totalConfidence += result.confidence;
|
|
756
|
+
|
|
757
|
+
// Count technique usage
|
|
758
|
+
for (const [technique, techniqueResult] of result.techniques) {
|
|
759
|
+
techniqueCounts[technique] = (techniqueCounts[technique] || 0) + 1;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// Count issues
|
|
763
|
+
for (const issue of result.issues) {
|
|
764
|
+
const key = `${issue.severity}_${issue.message.substring(0, 50)}`;
|
|
765
|
+
issueCounts[key] = (issueCounts[key] || 0) + 1;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
summary.averageConfidence = summary.totalValidations > 0 ?
|
|
770
|
+
totalConfidence / summary.totalValidations : 0;
|
|
771
|
+
summary.techniqueUsage = techniqueCounts;
|
|
772
|
+
summary.commonIssues = issueCounts;
|
|
773
|
+
|
|
774
|
+
return summary;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Export validation results
|
|
779
|
+
*/
|
|
780
|
+
exportResults(format = 'json') {
|
|
781
|
+
const exportData = {
|
|
782
|
+
metadata: {
|
|
783
|
+
exportedAt: new Date().toISOString(),
|
|
784
|
+
validatorVersion: '1.0.0',
|
|
785
|
+
options: this.options
|
|
786
|
+
},
|
|
787
|
+
summary: this.getValidationSummary(),
|
|
788
|
+
validations: Array.from(this.validationResults.entries()).map(([id, result]) => ({
|
|
789
|
+
operationId: id,
|
|
790
|
+
...result.getSummary()
|
|
791
|
+
}))
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
if (format === 'json') {
|
|
795
|
+
return JSON.stringify(exportData, null, 2);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
return exportData;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function apiCompatibilityAcceptable(comparison, strictMode) {
|
|
803
|
+
if (strictMode) {
|
|
804
|
+
return comparison.removedMethods.length === 0 && comparison.changedSignatures.length === 0;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
return comparison.removedMethods.length === 0;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
module.exports = {
|
|
811
|
+
FunctionalityValidator,
|
|
812
|
+
FunctionalityValidationResult,
|
|
813
|
+
TechniqueResult,
|
|
814
|
+
VALIDATION_TECHNIQUES,
|
|
815
|
+
VALIDATION_SEVERITY
|
|
816
|
+
};
|