From 428f1e90b2d532548734b8ff69d6e3346ab6463b Mon Sep 17 00:00:00 2001 From: Claudio Wunder Date: Mon, 3 Nov 2025 22:19:07 +0100 Subject: [PATCH 1/3] chore: safe copy mechanism --- src/generators/legacy-html/index.mjs | 18 +++---- src/generators/legacy-html/utils/safeCopy.mjs | 48 +++++++++++++++++++ 2 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 src/generators/legacy-html/utils/safeCopy.mjs diff --git a/src/generators/legacy-html/index.mjs b/src/generators/legacy-html/index.mjs index f8c1e58f..c100967b 100644 --- a/src/generators/legacy-html/index.mjs +++ b/src/generators/legacy-html/index.mjs @@ -1,12 +1,13 @@ 'use strict'; -import { cp, readFile, rm, writeFile } from 'node:fs/promises'; +import { readFile, rm, writeFile, mkdir } from 'node:fs/promises'; import { join } from 'node:path'; import HTMLMinifier from '@minify-html/node'; import buildContent from './utils/buildContent.mjs'; import dropdowns from './utils/buildDropdowns.mjs'; +import { safeCopy } from './utils/safeCopy.mjs'; import tableOfContents from './utils/tableOfContents.mjs'; import { groupNodesByModule } from '../../utils/generators.mjs'; import { getRemarkRehype } from '../../utils/remark.mjs'; @@ -169,6 +170,9 @@ export default { } if (output) { + // Define the source folder for API docs assets + const srcAssets = join(baseDir, 'assets'); + // Define the output folder for API docs assets const assetsFolder = join(output, 'assets'); @@ -177,13 +181,11 @@ export default { // If the path does not exists, it will simply ignore and continue await rm(assetsFolder, { recursive: true, force: true, maxRetries: 10 }); - // We copy all the other assets to the output folder at the end of the process - // to ensure that all latest changes on the styles are applied to the output - // Note.: This is not meant to be used for DX/developer purposes. - await cp(join(baseDir, 'assets'), assetsFolder, { - recursive: true, - force: true, - }); + // Creates the assets folder if it does not exist + await mkdir(assetsFolder, { recursive: true }); + + // Copy all files from assets folder to output, skipping unchanged files + await safeCopy(srcAssets, assetsFolder); } return generatedValues; diff --git a/src/generators/legacy-html/utils/safeCopy.mjs b/src/generators/legacy-html/utils/safeCopy.mjs new file mode 100644 index 00000000..406e0a0a --- /dev/null +++ b/src/generators/legacy-html/utils/safeCopy.mjs @@ -0,0 +1,48 @@ +'use strict'; + +import { readFile, writeFile, stat } from 'node:fs/promises'; +import { join } from 'node:path'; + +import { glob } from 'glob'; + +/** + * Safely copies files from source to target directory, skipping files that haven't changed + * based on file stats (size and modification time) + * + * @param {string} srcDir - Source directory path + * @param {string} targetDir - Target directory path + */ +export async function safeCopy(srcDir, targetDir) { + // Get all files in the source folder (no subdirectories expected) + const files = await glob('*', { + cwd: srcDir, + dot: true, + nodir: true, + }); + + // Copy each file individually + for (const file of files) { + const sourcePath = join(srcDir, file); + + const targetPath = join(targetDir, file); + + const [sStat, tStat] = await Promise.allSettled([ + stat(sourcePath), + stat(targetPath), + ]); + + const shouldWrite = + // the target file doesn't exist + sStat.status === 'rejected' || + // file sizes are different + sStat.size !== tStat.size || + // source got modified / is newer + sStat.mtimeMs > tStat.mtimeMs; + + if (shouldWrite) { + const fileContent = await readFile(sourcePath); + + await writeFile(targetPath, fileContent); + } + } +} From c41fd52f93eb160266c7771075c96e42d0dde954 Mon Sep 17 00:00:00 2001 From: Claudio Wunder Date: Mon, 3 Nov 2025 22:23:12 +0100 Subject: [PATCH 2/3] fix: the code was incorrectly skipping --- src/generators/legacy-html/utils/safeCopy.mjs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/generators/legacy-html/utils/safeCopy.mjs b/src/generators/legacy-html/utils/safeCopy.mjs index 406e0a0a..f78bbd2b 100644 --- a/src/generators/legacy-html/utils/safeCopy.mjs +++ b/src/generators/legacy-html/utils/safeCopy.mjs @@ -13,17 +13,14 @@ import { glob } from 'glob'; * @param {string} targetDir - Target directory path */ export async function safeCopy(srcDir, targetDir) { - // Get all files in the source folder (no subdirectories expected) const files = await glob('*', { cwd: srcDir, dot: true, nodir: true, }); - // Copy each file individually for (const file of files) { const sourcePath = join(srcDir, file); - const targetPath = join(targetDir, file); const [sStat, tStat] = await Promise.allSettled([ @@ -32,17 +29,16 @@ export async function safeCopy(srcDir, targetDir) { ]); const shouldWrite = - // the target file doesn't exist - sStat.status === 'rejected' || - // file sizes are different - sStat.size !== tStat.size || - // source got modified / is newer - sStat.mtimeMs > tStat.mtimeMs; - - if (shouldWrite) { - const fileContent = await readFile(sourcePath); + tStat.status === 'rejected' || + sStat.value.size !== tStat.value.size || + sStat.value.mtimeMs > tStat.value.mtimeMs; - await writeFile(targetPath, fileContent); + if (!shouldWrite) { + continue; } + + const fileContent = await readFile(sourcePath); + + await writeFile(targetPath, fileContent); } } From 52560255064debb24f18679b0dc730d6121befaa Mon Sep 17 00:00:00 2001 From: Claudio Wunder Date: Mon, 3 Nov 2025 22:53:30 +0100 Subject: [PATCH 3/3] chore: use readdir --- src/generators/legacy-html/utils/safeCopy.mjs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/generators/legacy-html/utils/safeCopy.mjs b/src/generators/legacy-html/utils/safeCopy.mjs index f78bbd2b..e96b62ed 100644 --- a/src/generators/legacy-html/utils/safeCopy.mjs +++ b/src/generators/legacy-html/utils/safeCopy.mjs @@ -1,10 +1,8 @@ 'use strict'; -import { readFile, writeFile, stat } from 'node:fs/promises'; +import { readFile, writeFile, stat, readdir } from 'node:fs/promises'; import { join } from 'node:path'; -import { glob } from 'glob'; - /** * Safely copies files from source to target directory, skipping files that haven't changed * based on file stats (size and modification time) @@ -13,11 +11,7 @@ import { glob } from 'glob'; * @param {string} targetDir - Target directory path */ export async function safeCopy(srcDir, targetDir) { - const files = await glob('*', { - cwd: srcDir, - dot: true, - nodir: true, - }); + const files = await readdir(srcDir); for (const file of files) { const sourcePath = join(srcDir, file);