Skip to content

Commit 428f1e9

Browse files
committed
chore: safe copy mechanism
1 parent dca59d6 commit 428f1e9

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

src/generators/legacy-html/index.mjs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
'use strict';
22

3-
import { cp, readFile, rm, writeFile } from 'node:fs/promises';
3+
import { readFile, rm, writeFile, mkdir } from 'node:fs/promises';
44
import { join } from 'node:path';
55

66
import HTMLMinifier from '@minify-html/node';
77

88
import buildContent from './utils/buildContent.mjs';
99
import dropdowns from './utils/buildDropdowns.mjs';
10+
import { safeCopy } from './utils/safeCopy.mjs';
1011
import tableOfContents from './utils/tableOfContents.mjs';
1112
import { groupNodesByModule } from '../../utils/generators.mjs';
1213
import { getRemarkRehype } from '../../utils/remark.mjs';
@@ -169,6 +170,9 @@ export default {
169170
}
170171

171172
if (output) {
173+
// Define the source folder for API docs assets
174+
const srcAssets = join(baseDir, 'assets');
175+
172176
// Define the output folder for API docs assets
173177
const assetsFolder = join(output, 'assets');
174178

@@ -177,13 +181,11 @@ export default {
177181
// If the path does not exists, it will simply ignore and continue
178182
await rm(assetsFolder, { recursive: true, force: true, maxRetries: 10 });
179183

180-
// We copy all the other assets to the output folder at the end of the process
181-
// to ensure that all latest changes on the styles are applied to the output
182-
// Note.: This is not meant to be used for DX/developer purposes.
183-
await cp(join(baseDir, 'assets'), assetsFolder, {
184-
recursive: true,
185-
force: true,
186-
});
184+
// Creates the assets folder if it does not exist
185+
await mkdir(assetsFolder, { recursive: true });
186+
187+
// Copy all files from assets folder to output, skipping unchanged files
188+
await safeCopy(srcAssets, assetsFolder);
187189
}
188190

189191
return generatedValues;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
3+
import { readFile, writeFile, stat } from 'node:fs/promises';
4+
import { join } from 'node:path';
5+
6+
import { glob } from 'glob';
7+
8+
/**
9+
* Safely copies files from source to target directory, skipping files that haven't changed
10+
* based on file stats (size and modification time)
11+
*
12+
* @param {string} srcDir - Source directory path
13+
* @param {string} targetDir - Target directory path
14+
*/
15+
export async function safeCopy(srcDir, targetDir) {
16+
// Get all files in the source folder (no subdirectories expected)
17+
const files = await glob('*', {
18+
cwd: srcDir,
19+
dot: true,
20+
nodir: true,
21+
});
22+
23+
// Copy each file individually
24+
for (const file of files) {
25+
const sourcePath = join(srcDir, file);
26+
27+
const targetPath = join(targetDir, file);
28+
29+
const [sStat, tStat] = await Promise.allSettled([
30+
stat(sourcePath),
31+
stat(targetPath),
32+
]);
33+
34+
const shouldWrite =
35+
// the target file doesn't exist
36+
sStat.status === 'rejected' ||
37+
// file sizes are different
38+
sStat.size !== tStat.size ||
39+
// source got modified / is newer
40+
sStat.mtimeMs > tStat.mtimeMs;
41+
42+
if (shouldWrite) {
43+
const fileContent = await readFile(sourcePath);
44+
45+
await writeFile(targetPath, fileContent);
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)