feat(mod_compiler): add diagnostic interception of fs operations to detect and report unexpected file system changes in previously compiled output directories during compilation

This commit is contained in:
2026-03-05 15:22:04 +00:00
parent 431c82a186
commit dc9a9640df
3 changed files with 69 additions and 1 deletions

View File

@@ -1,5 +1,13 @@
# Changelog # Changelog
## 2026-03-05 - 4.2.0 - feat(mod_compiler)
add diagnostic interception of fs operations to detect and report unexpected file system changes in previously compiled output directories during compilation
- Wraps fs.unlinkSync, fs.rmSync, fs.rmdirSync, fs.renameSync and fs.writeFileSync to record operations targeting other successful output directories during a compile.
- Enabled only when there are previously compiled output dirs and when not running in quiet or JSON mode; original fs methods are restored after compilation.
- Logs up to 30 intercepted operations and prints a summary count if any ops were observed; intercepted calls still perform the original fs action (diagnostic-only).
- No functional change to compilation behavior beyond additional diagnostic reporting.
## 2026-03-05 - 4.1.26 - fix(compiler) ## 2026-03-05 - 4.1.26 - fix(compiler)
fsync output directories after unpack to avoid XFS delayed logging causing corrupt or invisible directory entries during subsequent TypeScript emits fsync output directories after unpack to avoid XFS delayed logging causing corrupt or invisible directory entries during subsequent TypeScript emits

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@git.zone/tsbuild', name: '@git.zone/tsbuild',
version: '4.1.26', version: '4.2.0',
description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.' description: 'A tool for compiling TypeScript files using the latest nightly features, offering flexible APIs and a CLI for streamlined development.'
} }

View File

@@ -380,9 +380,69 @@ export class TsCompiler {
fileCount: absoluteFiles.length, fileCount: absoluteFiles.length,
}; };
// Diagnostic: intercept fs operations during compilation to detect
// any unexpected deletions in previously compiled output directories
const watchedDirs = successfulOutputDirs.filter(d => d !== destDir);
const origUnlink = fs.unlinkSync;
const origRm = fs.rmSync;
const origRmdir = fs.rmdirSync;
const origRename = fs.renameSync;
const origWriteFile = fs.writeFileSync;
let interceptedOps: string[] = [];
if (watchedDirs.length > 0 && !isQuiet && !isJson) {
(fs as any).unlinkSync = (p: string, ...args: any[]) => {
if (watchedDirs.some(d => String(p).startsWith(d + '/'))) {
interceptedOps.push(`unlink: ${p}`);
}
return origUnlink.call(fs, p, ...args);
};
(fs as any).rmSync = (p: string, ...args: any[]) => {
if (watchedDirs.some(d => String(p).startsWith(d + '/'))) {
interceptedOps.push(`rm: ${p}`);
}
return origRm.call(fs, p, ...args);
};
(fs as any).rmdirSync = (p: string, ...args: any[]) => {
if (watchedDirs.some(d => String(p).startsWith(d + '/'))) {
interceptedOps.push(`rmdir: ${p}`);
}
return origRmdir.call(fs, p, ...args);
};
(fs as any).renameSync = (src: string, dest: string, ...args: any[]) => {
if (watchedDirs.some(d => String(src).startsWith(d + '/') || String(dest).startsWith(d + '/'))) {
interceptedOps.push(`rename: ${src}${dest}`);
}
return origRename.call(fs, src, dest, ...args);
};
(fs as any).writeFileSync = (p: string, ...args: any[]) => {
if (watchedDirs.some(d => String(p).startsWith(d + '/'))) {
interceptedOps.push(`write: ${p}`);
}
return origWriteFile.call(fs, p, ...args);
};
}
const result = await this.compileFiles(absoluteFiles, options, taskInfo); const result = await this.compileFiles(absoluteFiles, options, taskInfo);
emittedFiles.push(...result.emittedFiles); emittedFiles.push(...result.emittedFiles);
errorSummaries.push(result.errorSummary); errorSummaries.push(result.errorSummary);
// Restore original fs methods and report any intercepted operations
if (watchedDirs.length > 0 && !isQuiet && !isJson) {
(fs as any).unlinkSync = origUnlink;
(fs as any).rmSync = origRm;
(fs as any).rmdirSync = origRmdir;
(fs as any).renameSync = origRename;
(fs as any).writeFileSync = origWriteFile;
if (interceptedOps.length > 0) {
console.log(` ⚠️ [diag] ${interceptedOps.length} ops on previous output dirs during compilation:`);
for (const op of interceptedOps.slice(0, 30)) {
console.log(` ${op.replace(this.cwd + '/', '')}`);
}
if (interceptedOps.length > 30) {
console.log(` ... and ${interceptedOps.length - 30} more`);
}
}
}
diagSnap('post-compile'); diagSnap('post-compile');
// Diagnostic: log emitted files that went to unexpected directories // Diagnostic: log emitted files that went to unexpected directories