fix(format): Improve concurrency control in cache and rollback management with mutex locking and refine formatting details
This commit is contained in:
@@ -7,21 +7,16 @@ export class PrettierFormatter extends BaseFormatter {
|
||||
get name(): string {
|
||||
return 'prettier';
|
||||
}
|
||||
|
||||
|
||||
async analyze(): Promise<IPlannedChange[]> {
|
||||
const changes: IPlannedChange[] = [];
|
||||
|
||||
|
||||
// Define directories to format (TypeScript directories by default)
|
||||
const includeDirs = [
|
||||
'ts',
|
||||
'ts_*',
|
||||
'test',
|
||||
'tests'
|
||||
];
|
||||
|
||||
const includeDirs = ['ts', 'ts_*', 'test', 'tests'];
|
||||
|
||||
// File extensions to format
|
||||
const extensions = '{ts,tsx,js,jsx,json,md,css,scss,html,xml,yaml,yml}';
|
||||
|
||||
|
||||
// Also format root-level config files
|
||||
const rootConfigFiles = [
|
||||
'package.json',
|
||||
@@ -36,33 +31,36 @@ export class PrettierFormatter extends BaseFormatter {
|
||||
'CHANGELOG.md',
|
||||
'license',
|
||||
'LICENSE',
|
||||
'*.md'
|
||||
'*.md',
|
||||
];
|
||||
|
||||
|
||||
// Collect all files to format
|
||||
const allFiles: string[] = [];
|
||||
|
||||
|
||||
// Add files from TypeScript directories
|
||||
for (const dir of includeDirs) {
|
||||
const globPattern = `${dir}/**/*.${extensions}`;
|
||||
const dirFiles = await plugins.smartfile.fs.listFileTree('.', globPattern);
|
||||
const dirFiles = await plugins.smartfile.fs.listFileTree(
|
||||
'.',
|
||||
globPattern,
|
||||
);
|
||||
allFiles.push(...dirFiles);
|
||||
}
|
||||
|
||||
|
||||
// Add root config files
|
||||
for (const pattern of rootConfigFiles) {
|
||||
const rootFiles = await plugins.smartfile.fs.listFileTree('.', pattern);
|
||||
// Only include files at root level (no slashes in path)
|
||||
const rootLevelFiles = rootFiles.filter(f => !f.includes('/'));
|
||||
const rootLevelFiles = rootFiles.filter((f) => !f.includes('/'));
|
||||
allFiles.push(...rootLevelFiles);
|
||||
}
|
||||
|
||||
|
||||
// Remove duplicates
|
||||
const uniqueFiles = [...new Set(allFiles)];
|
||||
|
||||
|
||||
// Get all files that match the pattern
|
||||
const files = uniqueFiles;
|
||||
|
||||
|
||||
// Ensure we only process actual files (not directories)
|
||||
const validFiles: string[] = [];
|
||||
for (const file of files) {
|
||||
@@ -76,48 +74,52 @@ export class PrettierFormatter extends BaseFormatter {
|
||||
logVerbose(`Skipping ${file} - cannot access: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check which files need formatting
|
||||
for (const file of validFiles) {
|
||||
// Skip files that haven't changed
|
||||
if (!await this.shouldProcessFile(file)) {
|
||||
if (!(await this.shouldProcessFile(file))) {
|
||||
logVerbose(`Skipping ${file} - no changes detected`);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
changes.push({
|
||||
type: 'modify',
|
||||
path: file,
|
||||
module: this.name,
|
||||
description: 'Format with Prettier'
|
||||
description: 'Format with Prettier',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
logger.log('info', `Found ${changes.length} files to format with Prettier`);
|
||||
return changes;
|
||||
}
|
||||
|
||||
|
||||
async execute(changes: IPlannedChange[]): Promise<void> {
|
||||
const startTime = this.stats.moduleStartTime(this.name);
|
||||
this.stats.startModule(this.name);
|
||||
|
||||
|
||||
try {
|
||||
await this.preExecute();
|
||||
|
||||
|
||||
// Batch process files
|
||||
const batchSize = 10; // Process 10 files at a time
|
||||
const batches: IPlannedChange[][] = [];
|
||||
|
||||
|
||||
for (let i = 0; i < changes.length; i += batchSize) {
|
||||
batches.push(changes.slice(i, i + batchSize));
|
||||
}
|
||||
|
||||
logVerbose(`Processing ${changes.length} files in ${batches.length} batches`);
|
||||
|
||||
|
||||
logVerbose(
|
||||
`Processing ${changes.length} files in ${batches.length} batches`,
|
||||
);
|
||||
|
||||
for (let i = 0; i < batches.length; i++) {
|
||||
const batch = batches[i];
|
||||
logVerbose(`Processing batch ${i + 1}/${batches.length} (${batch.length} files)`);
|
||||
|
||||
logVerbose(
|
||||
`Processing batch ${i + 1}/${batches.length} (${batch.length} files)`,
|
||||
);
|
||||
|
||||
// Process batch in parallel
|
||||
const promises = batch.map(async (change) => {
|
||||
try {
|
||||
@@ -125,44 +127,45 @@ export class PrettierFormatter extends BaseFormatter {
|
||||
this.stats.recordFileOperation(this.name, change.type, true);
|
||||
} catch (error) {
|
||||
this.stats.recordFileOperation(this.name, change.type, false);
|
||||
logger.log('error', `Failed to format ${change.path}: ${error.message}`);
|
||||
logger.log(
|
||||
'error',
|
||||
`Failed to format ${change.path}: ${error.message}`,
|
||||
);
|
||||
// Don't throw - continue with other files
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
|
||||
await this.postExecute();
|
||||
} catch (error) {
|
||||
await this.context.rollbackOperation();
|
||||
// Rollback removed - no longer tracking operations
|
||||
throw error;
|
||||
} finally {
|
||||
this.stats.endModule(this.name, startTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async applyChange(change: IPlannedChange): Promise<void> {
|
||||
if (change.type !== 'modify') return;
|
||||
|
||||
|
||||
try {
|
||||
// Read current content
|
||||
const content = plugins.smartfile.fs.toStringSync(change.path);
|
||||
|
||||
|
||||
// Format with prettier
|
||||
const prettier = await import('prettier');
|
||||
const formatted = await prettier.format(content, {
|
||||
filepath: change.path,
|
||||
...(await this.getPrettierConfig())
|
||||
...(await this.getPrettierConfig()),
|
||||
});
|
||||
|
||||
|
||||
// Only write if content actually changed
|
||||
if (formatted !== content) {
|
||||
await this.modifyFile(change.path, formatted);
|
||||
logVerbose(`Formatted ${change.path}`);
|
||||
} else {
|
||||
// Still update cache even if content didn't change
|
||||
await this.cache.updateFileCache(change.path);
|
||||
logVerbose(`No formatting changes for ${change.path}`);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -170,7 +173,7 @@ export class PrettierFormatter extends BaseFormatter {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async getPrettierConfig(): Promise<any> {
|
||||
// Try to load prettier config from the project
|
||||
const prettierConfig = new plugins.npmextra.Npmextra();
|
||||
@@ -181,7 +184,7 @@ export class PrettierFormatter extends BaseFormatter {
|
||||
printWidth: 80,
|
||||
tabWidth: 2,
|
||||
semi: true,
|
||||
arrowParens: 'always'
|
||||
arrowParens: 'always',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user