|
|
|
|
@@ -330,26 +330,25 @@ export class TsCompiler {
|
|
|
|
|
console.log('');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Collect unpack tasks to perform AFTER all compilations complete.
|
|
|
|
|
// This prevents filesystem metadata corruption on XFS where heavy write
|
|
|
|
|
// activity during subsequent compilations can make freshly-renamed entries
|
|
|
|
|
// in previously-unpacked directories invisible or lost.
|
|
|
|
|
const pendingUnpacks: Array<{ pattern: string; destDir: string }> = [];
|
|
|
|
|
// Phase 1: Resolve glob patterns and clean ALL output directories upfront.
|
|
|
|
|
// This ensures no rm/rmSync activity overlaps with TypeScript compilation,
|
|
|
|
|
// preventing XFS metadata corruption from concurrent metadata operations.
|
|
|
|
|
interface IResolvedTask {
|
|
|
|
|
pattern: string;
|
|
|
|
|
destPath: string;
|
|
|
|
|
destDir: string;
|
|
|
|
|
absoluteFiles: string[];
|
|
|
|
|
}
|
|
|
|
|
const resolvedTasks: IResolvedTask[] = [];
|
|
|
|
|
|
|
|
|
|
for (const pattern of Object.keys(globPatterns)) {
|
|
|
|
|
const destPath = globPatterns[pattern];
|
|
|
|
|
if (!pattern || !destPath) continue;
|
|
|
|
|
|
|
|
|
|
// Get files matching the glob pattern
|
|
|
|
|
const files = await FsHelpers.listFilesWithGlob(this.cwd, pattern);
|
|
|
|
|
|
|
|
|
|
// Transform to absolute paths
|
|
|
|
|
const absoluteFiles = smartpath.transform.toAbsolute(files, this.cwd) as string[];
|
|
|
|
|
|
|
|
|
|
// Get destination directory as absolute path
|
|
|
|
|
const destDir = smartpath.transform.toAbsolute(destPath, this.cwd) as string;
|
|
|
|
|
|
|
|
|
|
// Clear the destination directory before compilation if it exists
|
|
|
|
|
if (await FsHelpers.directoryExists(destDir)) {
|
|
|
|
|
if (!isQuiet && !isJson) {
|
|
|
|
|
console.log(`🧹 Clearing output directory: ${destPath}`);
|
|
|
|
|
@@ -357,10 +356,16 @@ export class TsCompiler {
|
|
|
|
|
await FsHelpers.removeDirectory(destDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update compiler options with the output directory
|
|
|
|
|
resolvedTasks.push({ pattern, destPath, destDir, absoluteFiles });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Phase 2: Compile all tasks. No filesystem cleanup happens during this phase.
|
|
|
|
|
const pendingUnpacks: Array<{ pattern: string; destDir: string }> = [];
|
|
|
|
|
|
|
|
|
|
for (const task of resolvedTasks) {
|
|
|
|
|
const options: CompilerOptions = {
|
|
|
|
|
...customOptions,
|
|
|
|
|
outDir: destDir,
|
|
|
|
|
outDir: task.destDir,
|
|
|
|
|
listEmittedFiles: true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -368,23 +373,22 @@ export class TsCompiler {
|
|
|
|
|
const taskInfo: ITaskInfo = {
|
|
|
|
|
taskNumber: currentTask,
|
|
|
|
|
totalTasks,
|
|
|
|
|
sourcePattern: pattern,
|
|
|
|
|
destDir: destPath,
|
|
|
|
|
fileCount: absoluteFiles.length,
|
|
|
|
|
sourcePattern: task.pattern,
|
|
|
|
|
destDir: task.destPath,
|
|
|
|
|
fileCount: task.absoluteFiles.length,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const result = await this.compileFiles(absoluteFiles, options, taskInfo);
|
|
|
|
|
const result = await this.compileFiles(task.absoluteFiles, options, taskInfo);
|
|
|
|
|
emittedFiles.push(...result.emittedFiles);
|
|
|
|
|
errorSummaries.push(result.errorSummary);
|
|
|
|
|
|
|
|
|
|
// Queue unpack for after all compilations (don't modify output dirs between compilations)
|
|
|
|
|
if (result.errorSummary.totalErrors === 0) {
|
|
|
|
|
pendingUnpacks.push({ pattern, destDir });
|
|
|
|
|
successfulOutputDirs.push(destDir);
|
|
|
|
|
pendingUnpacks.push({ pattern: task.pattern, destDir: task.destDir });
|
|
|
|
|
successfulOutputDirs.push(task.destDir);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Perform all unpacks after all compilations are done.
|
|
|
|
|
// Phase 3: Perform all unpacks after all compilations are done.
|
|
|
|
|
// This ensures no output directory is modified while subsequent compilations
|
|
|
|
|
// are performing heavy filesystem writes to sibling directories.
|
|
|
|
|
for (const { pattern, destDir } of pendingUnpacks) {
|
|
|
|
|
|