import * as plugins from './mod.plugins.js'; import { FormatContext } from './classes.formatcontext.js'; import type { IPlannedChange } from './interfaces.format.js'; import { Project } from '../classes.project.js'; export abstract class BaseFormatter { protected context: FormatContext; protected project: Project; protected stats: any; // Will be FormatStats from context constructor(context: FormatContext, project: Project) { this.context = context; this.project = project; this.stats = context.getFormatStats(); } abstract get name(): string; abstract analyze(): Promise; abstract applyChange(change: IPlannedChange): Promise; async execute(changes: IPlannedChange[]): Promise { const startTime = this.stats.moduleStartTime(this.name); this.stats.startModule(this.name); try { await this.preExecute(); for (const change of changes) { try { await this.applyChange(change); this.stats.recordFileOperation(this.name, change.type, true); } catch (error) { this.stats.recordFileOperation(this.name, change.type, false); throw error; } } await this.postExecute(); } catch (error) { // Don't rollback here - let the FormatPlanner handle it throw error; } finally { this.stats.endModule(this.name, startTime); } } protected async preExecute(): Promise { // Override in subclasses if needed } protected async postExecute(): Promise { // Override in subclasses if needed } protected async modifyFile(filepath: string, content: string): Promise { // Validate filepath before writing if (!filepath || filepath.trim() === '') { throw new Error(`Invalid empty filepath in modifyFile`); } // Ensure we have a proper path with directory component // If the path has no directory component (e.g., "package.json"), prepend "./" let normalizedPath = filepath; if (!plugins.path.parse(filepath).dir) { normalizedPath = './' + filepath; } await plugins.smartfile.memory.toFs(content, normalizedPath); } protected async createFile(filepath: string, content: string): Promise { await plugins.smartfile.memory.toFs(content, filepath); } protected async deleteFile(filepath: string): Promise { await plugins.smartfile.fs.remove(filepath); } protected async shouldProcessFile(filepath: string): Promise { return true; } }