@invisiblecities/sidequest-cqo
Version:
Configuration-agnostic TypeScript and ESLint orchestrator with real-time watch mode, SQLite persistence, and intelligent terminal detection
152 lines • 4.6 kB
JavaScript
/**
* @fileoverview Base audit engine abstract class
*
* Provides the common interface and utilities that all audit engines must implement.
* Handles error recovery, timing, and standardized result formatting.
*/
/**
* Abstract base class for all audit engines
*
* Each engine is responsible for:
* - Analyzing code for specific types of violations
* - Handling errors gracefully without breaking the orchestrator
* - Providing consistent violation format
* - Implementing timeout and cancellation support
*/
export class BaseAuditEngine {
engineName;
source;
config;
abortController;
constructor(engineName, source, config) {
this.engineName = engineName;
this.source = source;
this.config = config;
}
/**
* Execute the audit engine analysis
*
* @param targetPath - Directory or file to analyze
* @param options - Engine-specific options
* @returns Promise resolving to engine results
*/
async execute(targetPath, options = {}) {
const startTime = Date.now();
this.abortController = new AbortController();
try {
// Set up timeout if configured
let timeoutId;
if (this.config.timeout) {
timeoutId = setTimeout(() => {
this.abortController?.abort();
}, this.config.timeout);
}
// Execute the actual analysis
const violations = await this.analyze(targetPath, options);
// Clear timeout if analysis completed
if (timeoutId) {
clearTimeout(timeoutId);
}
const executionTime = Date.now() - startTime;
return {
engineName: this.engineName,
violations,
executionTime,
success: true,
metadata: {
targetPath,
violationsFound: violations.length,
config: this.config,
},
};
}
catch (error) {
const executionTime = Date.now() - startTime;
const errorMessage = error instanceof Error ? error.message : String(error);
// Log the error but don't throw if allowFailure is true
console.warn(`[${this.engineName}] Analysis failed: ${errorMessage}`);
if (!this.config.allowFailure) {
throw error;
}
return {
engineName: this.engineName,
violations: [],
executionTime,
success: false,
error: errorMessage,
metadata: {
targetPath,
failureRecovery: true,
},
};
}
finally {
this.abortController = undefined;
}
}
/**
* Check if the engine can be aborted
*/
get canAbort() {
return this.abortController !== undefined;
}
/**
* Abort the current analysis
*/
abort() {
this.abortController?.abort();
}
/**
* Helper method to create standardized violations
*/
createViolation(file, line, code, category, severity, rule, message, column) {
const violation = {
file,
line,
code: code.trim(),
category,
severity,
source: this.source,
};
if (column !== undefined) {
violation.column = column;
}
if (rule !== undefined) {
violation.rule = rule;
}
if (message !== undefined) {
violation.message = message;
}
const fixSuggestion = this.generateFixSuggestion?.(category, rule, code);
if (fixSuggestion !== undefined) {
violation.fixSuggestion = fixSuggestion;
}
return violation;
}
/**
* Update engine configuration
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
}
/**
* Get current engine configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Get engine metadata
*/
getMetadata() {
return {
name: this.engineName,
source: this.source,
enabled: this.config.enabled,
priority: this.config.priority,
allowFailure: this.config.allowFailure,
timeout: this.config.timeout,
};
}
}
//# sourceMappingURL=base-engine.js.map