Skip to content
Merged
7 changes: 1 addition & 6 deletions src/generators/legacy-html/index.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

import { readFile, rm, writeFile, mkdir } from 'node:fs/promises';
import { readFile, writeFile, mkdir } from 'node:fs/promises';
import { join } from 'node:path';

import HTMLMinifier from '@minify-html/node';
Expand Down Expand Up @@ -176,11 +176,6 @@ export default {
// Define the output folder for API docs assets
const assetsFolder = join(output, 'assets');

// Removes the current assets directory to copy the new assets
// and prevent stale assets from existing in the output directory
// If the path does not exists, it will simply ignore and continue
await rm(assetsFolder, { recursive: true, force: true, maxRetries: 10 });

// Creates the assets folder if it does not exist
await mkdir(assetsFolder, { recursive: true });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,6 @@ describe('safeCopy', () => {
it('should handle empty source directory', async () => {
// Don't create any files in source
await safeCopy(srcDir, targetDir);

// Verify no error occurred and target is still empty
const files = await readFile(targetDir).catch(() => []);
assert.ok(Array.isArray(files) || files === undefined);
});

it('should copy files with same size but different content when mtime is newer', async () => {
Expand Down
33 changes: 15 additions & 18 deletions src/generators/legacy-html/utils/safeCopy.mjs
Original file line number Diff line number Diff line change
@@ -1,38 +1,35 @@
'use strict';

import { readFile, writeFile, stat, readdir } from 'node:fs/promises';
import { statSync, constants } from 'node:fs';
import { copyFile, readdir } from 'node:fs/promises';
import { join } from 'node:path';

/**
* Safely copies files from source to target directory, skipping files that haven't changed
* based on file stats (size and modification time)
* Copies files from source to target directory, skipping files that haven't changed.
* Uses synchronous stat checks for simplicity and copyFile for atomic operations.
*
* @param {string} srcDir - Source directory path
* @param {string} targetDir - Target directory path
*/
export async function safeCopy(srcDir, targetDir) {
const files = await readdir(srcDir);

for (const file of files) {
const promises = files.map(file => {
const sourcePath = join(srcDir, file);
const targetPath = join(targetDir, file);

const [sStat, tStat] = await Promise.allSettled([
stat(sourcePath),
stat(targetPath),
]);
const tStat = statSync(targetPath, { throwIfNoEntry: false });

const shouldWrite =
tStat.status === 'rejected' ||
sStat.value.size !== tStat.value.size ||
sStat.value.mtimeMs > tStat.value.mtimeMs;

if (!shouldWrite) {
continue;
if (tStat === undefined) {
return copyFile(sourcePath, targetPath, constants.COPYFILE_FICLONE);
}

const fileContent = await readFile(sourcePath);
const sStat = statSync(sourcePath);

if (sStat.size !== tStat.size || sStat.mtimeMs > tStat.mtimeMs) {
return copyFile(sourcePath, targetPath, constants.COPYFILE_FICLONE);
}
});

await writeFile(targetPath, fileContent);
}
await Promise.all(promises);
}
Loading