feat(format): Enhance format module with rollback, diff reporting, and improved parallel execution
This commit is contained in:
144
ts/mod_format/classes.changecache.ts
Normal file
144
ts/mod_format/classes.changecache.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import * as plugins from './mod.plugins.js';
|
||||
import * as paths from '../paths.js';
|
||||
|
||||
export interface IFileCache {
|
||||
path: string;
|
||||
checksum: string;
|
||||
modified: number;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export interface ICacheManifest {
|
||||
version: string;
|
||||
lastFormat: number;
|
||||
files: IFileCache[];
|
||||
}
|
||||
|
||||
export class ChangeCache {
|
||||
private cacheDir: string;
|
||||
private manifestPath: string;
|
||||
private cacheVersion = '1.0.0';
|
||||
|
||||
constructor() {
|
||||
this.cacheDir = plugins.path.join(paths.cwd, '.nogit', 'gitzone-cache');
|
||||
this.manifestPath = plugins.path.join(this.cacheDir, 'manifest.json');
|
||||
}
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
await plugins.smartfile.fs.ensureDir(this.cacheDir);
|
||||
}
|
||||
|
||||
async getManifest(): Promise<ICacheManifest> {
|
||||
const exists = await plugins.smartfile.fs.fileExists(this.manifestPath);
|
||||
if (!exists) {
|
||||
return {
|
||||
version: this.cacheVersion,
|
||||
lastFormat: 0,
|
||||
files: []
|
||||
};
|
||||
}
|
||||
|
||||
const content = await plugins.smartfile.fs.toStringSync(this.manifestPath);
|
||||
return JSON.parse(content);
|
||||
}
|
||||
|
||||
async saveManifest(manifest: ICacheManifest): Promise<void> {
|
||||
await plugins.smartfile.memory.toFs(JSON.stringify(manifest, null, 2), this.manifestPath);
|
||||
}
|
||||
|
||||
async hasFileChanged(filePath: string): Promise<boolean> {
|
||||
const absolutePath = plugins.path.isAbsolute(filePath)
|
||||
? filePath
|
||||
: plugins.path.join(paths.cwd, filePath);
|
||||
|
||||
// Check if file exists
|
||||
const exists = await plugins.smartfile.fs.fileExists(absolutePath);
|
||||
if (!exists) {
|
||||
return true; // File doesn't exist, so it's "changed" (will be created)
|
||||
}
|
||||
|
||||
// Get current file stats
|
||||
const stats = await plugins.smartfile.fs.stat(absolutePath);
|
||||
const content = await plugins.smartfile.fs.toStringSync(absolutePath);
|
||||
const currentChecksum = this.calculateChecksum(content);
|
||||
|
||||
// Get cached info
|
||||
const manifest = await this.getManifest();
|
||||
const cachedFile = manifest.files.find(f => f.path === filePath);
|
||||
|
||||
if (!cachedFile) {
|
||||
return true; // Not in cache, so it's changed
|
||||
}
|
||||
|
||||
// Compare checksums
|
||||
return cachedFile.checksum !== currentChecksum ||
|
||||
cachedFile.size !== stats.size ||
|
||||
cachedFile.modified !== stats.mtimeMs;
|
||||
}
|
||||
|
||||
async updateFileCache(filePath: string): Promise<void> {
|
||||
const absolutePath = plugins.path.isAbsolute(filePath)
|
||||
? filePath
|
||||
: plugins.path.join(paths.cwd, filePath);
|
||||
|
||||
// Get current file stats
|
||||
const stats = await plugins.smartfile.fs.stat(absolutePath);
|
||||
const content = await plugins.smartfile.fs.toStringSync(absolutePath);
|
||||
const checksum = this.calculateChecksum(content);
|
||||
|
||||
// Update manifest
|
||||
const manifest = await this.getManifest();
|
||||
const existingIndex = manifest.files.findIndex(f => f.path === filePath);
|
||||
|
||||
const cacheEntry: IFileCache = {
|
||||
path: filePath,
|
||||
checksum,
|
||||
modified: stats.mtimeMs,
|
||||
size: stats.size
|
||||
};
|
||||
|
||||
if (existingIndex !== -1) {
|
||||
manifest.files[existingIndex] = cacheEntry;
|
||||
} else {
|
||||
manifest.files.push(cacheEntry);
|
||||
}
|
||||
|
||||
manifest.lastFormat = Date.now();
|
||||
await this.saveManifest(manifest);
|
||||
}
|
||||
|
||||
async getChangedFiles(filePaths: string[]): Promise<string[]> {
|
||||
const changedFiles: string[] = [];
|
||||
|
||||
for (const filePath of filePaths) {
|
||||
if (await this.hasFileChanged(filePath)) {
|
||||
changedFiles.push(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
return changedFiles;
|
||||
}
|
||||
|
||||
async clean(): Promise<void> {
|
||||
const manifest = await this.getManifest();
|
||||
const validFiles: IFileCache[] = [];
|
||||
|
||||
// Remove entries for files that no longer exist
|
||||
for (const file of manifest.files) {
|
||||
const absolutePath = plugins.path.isAbsolute(file.path)
|
||||
? file.path
|
||||
: plugins.path.join(paths.cwd, file.path);
|
||||
|
||||
if (await plugins.smartfile.fs.fileExists(absolutePath)) {
|
||||
validFiles.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
manifest.files = validFiles;
|
||||
await this.saveManifest(manifest);
|
||||
}
|
||||
|
||||
private calculateChecksum(content: string | Buffer): string {
|
||||
return plugins.crypto.createHash('sha256').update(content).digest('hex');
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user