Compare commits

...

4 Commits

4 changed files with 66 additions and 2 deletions

View File

@@ -1,5 +1,21 @@
# Changelog # Changelog
## 2026-03-05 - 4.2.1 - fix(compiler)
use TypeScript sys hooks instead of fs monkeypatching to detect writes/deletes in previous output directories
- Replace direct fs.* monkeypatching with interception of typescript.sys.writeFile, typescript.sys.deleteFile and typescript.sys.createDirectory
- Add guards for optional sys.deleteFile before overriding it and preserve original sys methods to restore after compilation
- Update diagnostic messages to reference TypeScript sys ops and add an informational message when no ops are observed
- Reduce surface area of changes by avoiding global fs changes and focusing on TypeScript's sys API for safer interception
## 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

@@ -1,6 +1,6 @@
{ {
"name": "@git.zone/tsbuild", "name": "@git.zone/tsbuild",
"version": "4.1.26", "version": "4.2.1",
"private": false, "private": false,
"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.",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",

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.1',
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,57 @@ export class TsCompiler {
fileCount: absoluteFiles.length, fileCount: absoluteFiles.length,
}; };
// Diagnostic: intercept TypeScript sys operations during compilation to detect
// any unexpected writes/deletes in previously compiled output directories
const watchedDirs = successfulOutputDirs.filter(d => d !== destDir);
let interceptedOps: string[] = [];
const origSysWriteFile = typescript.sys.writeFile;
const origSysDeleteFile = typescript.sys.deleteFile;
const origSysCreateDir = typescript.sys.createDirectory;
if (watchedDirs.length > 0 && !isQuiet && !isJson) {
typescript.sys.writeFile = (p: string, data: string, writeBom?: boolean) => {
if (watchedDirs.some(d => p.startsWith(d + '/'))) {
interceptedOps.push(`sys.writeFile: ${p}`);
}
return origSysWriteFile.call(typescript.sys, p, data, writeBom);
};
if (origSysDeleteFile) {
typescript.sys.deleteFile = (p: string) => {
if (watchedDirs.some(d => p.startsWith(d + '/'))) {
interceptedOps.push(`sys.deleteFile: ${p}`);
}
return origSysDeleteFile!.call(typescript.sys, p);
};
}
typescript.sys.createDirectory = (p: string) => {
if (watchedDirs.some(d => p.startsWith(d + '/'))) {
interceptedOps.push(`sys.createDirectory: ${p}`);
}
return origSysCreateDir.call(typescript.sys, p);
};
}
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 sys methods and report any intercepted operations
if (watchedDirs.length > 0 && !isQuiet && !isJson) {
typescript.sys.writeFile = origSysWriteFile;
typescript.sys.deleteFile = origSysDeleteFile;
typescript.sys.createDirectory = origSysCreateDir;
if (interceptedOps.length > 0) {
console.log(` ⚠️ [diag] ${interceptedOps.length} TypeScript sys ops on previous output dirs:`);
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`);
}
} else {
console.log(` [diag] No TypeScript sys ops on previous output dirs during this compilation`);
}
}
diagSnap('post-compile'); diagSnap('post-compile');
// Diagnostic: log emitted files that went to unexpected directories // Diagnostic: log emitted files that went to unexpected directories