Skip to content

feat(fs): file system improvements#672

Open
avivkeller wants to merge 2 commits intomainfrom
feat/fs-improvements
Open

feat(fs): file system improvements#672
avivkeller wants to merge 2 commits intomainfrom
feat/fs-improvements

Conversation

@avivkeller
Copy link
Member

@avivkeller avivkeller commented Mar 13, 2026

This PR introduces some file system improvements to resolve #662. Specifically, it:

  • Makes a recursive writeFile function, allowing us to write files at any depth
  • Removes safeCopy. This function was meant for running doc-kit in parallel, which is not done, nor recommended.
  • Adds new path to the metadata entries, allowing us to "see" where an API actually is.

Note: This slightly changes the output of HTML generators. Instead of relying on a flat index file, they now build the index using page titles to support multiple depths. This means some titles may differ slightly from the index (e.g., VM becomes VM (executing JavaScript)), but file names themselves remain unchanged. The legacy generator does not implement this functionality, so while its output remains identical under this PR, it does not support recursive output.

Test this output with node bin/cli.mjs generate -t web -i "../node/doc/{api,}/*.md" -o "out"

Copilot AI review requested due to automatic review settings March 13, 2026 21:24
@avivkeller avivkeller requested a review from a team as a code owner March 13, 2026 21:24
@vercel
Copy link

vercel bot commented Mar 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
api-docs-tooling Ready Ready Preview Mar 14, 2026 9:44pm

Request Review

@codecov
Copy link

codecov bot commented Mar 13, 2026

Codecov Report

❌ Patch coverage is 52.68817% with 88 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.94%. Comparing base (84f6dac) to head (4295b29).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/generators/ast/generate.mjs 0.00% 21 Missing ⚠️
src/utils/file.mjs 64.28% 15 Missing ⚠️
src/generators/jsx-ast/generate.mjs 0.00% 11 Missing ⚠️
src/generators/web/utils/processing.mjs 0.00% 11 Missing ⚠️
src/generators/legacy-html/generate.mjs 0.00% 5 Missing ⚠️
src/generators/orama-db/generate.mjs 0.00% 4 Missing ⚠️
src/generators/web/generate.mjs 0.00% 4 Missing ⚠️
...rc/generators/legacy-html/utils/buildDropdowns.mjs 0.00% 3 Missing ⚠️
...rators/legacy-html/utils/replaceTemplateValues.mjs 0.00% 3 Missing ⚠️
src/generators/addon-verify/generate.mjs 0.00% 2 Missing ⚠️
... and 6 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #672      +/-   ##
==========================================
- Coverage   74.76%   73.94%   -0.83%     
==========================================
  Files         146      145       -1     
  Lines       13251    13283      +32     
  Branches      960      953       -7     
==========================================
- Hits         9907     9822      -85     
- Misses       3338     3455     +117     
  Partials        6        6              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link

github-actions bot commented Mar 13, 2026

orama-db Generator

File Base Head Diff
orama-db.json 8.04 MB 8.04 MB +1.78 KB (+0.02%)

web Generator

File Base Head Diff
wasi.html 68.33 KB 68.92 KB +604.00 B (+0.86%)
vm.html 369.57 KB 370.14 KB +588.00 B (+0.16%)
index.html 35.01 KB 35.57 KB +573.00 B (+1.60%)
quic.html 357.00 KB 357.56 KB +571.00 B (+0.16%)
perf_hooks.html 379.00 KB 379.55 KB +564.00 B (+0.15%)
report.html 174.66 KB 175.21 KB +564.00 B (+0.32%)
dgram.html 193.24 KB 193.78 KB +558.00 B (+0.28%)
intl.html 56.96 KB 57.50 KB +558.00 B (+0.96%)
globals.html 227.26 KB 227.81 KB +556.00 B (+0.24%)
tls.html 372.28 KB 372.81 KB +546.00 B (+0.14%)
addons.html 261.10 KB 261.63 KB +542.00 B (+0.20%)
async_context.html 162.33 KB 162.86 KB +542.00 B (+0.33%)
async_hooks.html 158.40 KB 158.93 KB +542.00 B (+0.33%)
buffer.html 904.70 KB 905.23 KB +542.00 B (+0.06%)
cluster.html 194.67 KB 195.20 KB +542.00 B (+0.27%)
console.html 145.74 KB 146.26 KB +542.00 B (+0.36%)
crypto.html 1.03 MB 1.03 MB +542.00 B (+0.05%)
debugger.html 53.07 KB 53.60 KB +542.00 B (+1.00%)
deprecations.html 494.80 KB 495.33 KB +542.00 B (+0.11%)
diagnostics_channel.html 234.20 KB 234.73 KB +542.00 B (+0.23%)
dns.html 295.20 KB 295.73 KB +542.00 B (+0.18%)
documentation.html 36.92 KB 37.45 KB +542.00 B (+1.43%)
domain.html 103.85 KB 104.38 KB +542.00 B (+0.51%)
embedding.html 58.29 KB 58.82 KB +542.00 B (+0.91%)
environment_variables.html 42.79 KB 43.32 KB +542.00 B (+1.24%)
errors.html 456.80 KB 457.33 KB +542.00 B (+0.12%)
esm.html 152.68 KB 153.21 KB +542.00 B (+0.35%)
events.html 454.02 KB 454.55 KB +542.00 B (+0.12%)
fs.html 1.39 MB 1.40 MB +542.00 B (+0.04%)
http.html 735.07 KB 735.60 KB +542.00 B (+0.07%)
http2.html 767.47 KB 768.00 KB +542.00 B (+0.07%)
https.html 149.00 KB 149.53 KB +542.00 B (+0.36%)
inspector.html 170.04 KB 170.57 KB +542.00 B (+0.31%)
module.html 325.48 KB 326.01 KB +542.00 B (+0.16%)
modules.html 176.88 KB 177.41 KB +542.00 B (+0.30%)
net.html 380.69 KB 381.22 KB +542.00 B (+0.14%)
os.html 141.53 KB 142.06 KB +542.00 B (+0.37%)
packages.html 153.11 KB 153.64 KB +542.00 B (+0.35%)
path.html 137.92 KB 138.45 KB +542.00 B (+0.38%)
permissions.html 53.92 KB 54.45 KB +542.00 B (+0.98%)
process.html 672.86 KB 673.39 KB +542.00 B (+0.08%)
punycode.html 62.00 KB 62.53 KB +542.00 B (+0.85%)
readline.html 250.90 KB 251.43 KB +542.00 B (+0.21%)
repl.html 182.05 KB 182.58 KB +542.00 B (+0.29%)
single-executable-applications.html 105.67 KB 106.20 KB +542.00 B (+0.50%)
sqlite.html 267.54 KB 268.07 KB +542.00 B (+0.20%)
stream.html 856.50 KB 857.03 KB +542.00 B (+0.06%)
string_decoder.html 54.33 KB 54.86 KB +542.00 B (+0.97%)
synopsis.html 41.51 KB 42.04 KB +542.00 B (+1.28%)
test.html 738.25 KB 738.78 KB +542.00 B (+0.07%)
timers.html 132.41 KB 132.94 KB +542.00 B (+0.40%)
tracing.html 83.00 KB 83.53 KB +542.00 B (+0.64%)
tty.html 94.08 KB 94.61 KB +542.00 B (+0.56%)
typescript.html 52.28 KB 52.81 KB +542.00 B (+1.01%)
url.html 346.80 KB 347.33 KB +542.00 B (+0.15%)
v8.html 320.09 KB 320.62 KB +542.00 B (+0.17%)
webcrypto.html 529.82 KB 530.34 KB +542.00 B (+0.10%)
webstreams.html 355.66 KB 356.19 KB +542.00 B (+0.15%)
worker_threads.html 363.79 KB 364.32 KB +542.00 B (+0.15%)
zlib.html 289.44 KB 289.96 KB +542.00 B (+0.18%)
querystring.html 62.81 KB 63.34 KB +540.00 B (+0.84%)
child_process.html 381.38 KB 381.90 KB +538.00 B (+0.14%)
cli.html 488.11 KB 488.63 KB +534.00 B (+0.11%)
util.html 690.89 KB 691.41 KB +532.00 B (+0.08%)
assert.html 329.39 KB 329.90 KB +520.00 B (+0.15%)
n-api.html 803.53 KB 804.03 KB +506.00 B (+0.06%)
addons.js 294.48 KB 294.58 KB +104.00 B (+0.03%)
assert.js 457.93 KB 458.03 KB +104.00 B (+0.02%)
async_context.js 189.28 KB 189.39 KB +104.00 B (+0.05%)
async_hooks.js 197.29 KB 197.39 KB +104.00 B (+0.05%)
buffer.js 1.10 MB 1.10 MB +104.00 B (+0.01%)
child_process.js 469.81 KB 469.91 KB +104.00 B (+0.02%)
cli.js 325.41 KB 325.51 KB +104.00 B (+0.03%)
cluster.js 197.88 KB 197.98 KB +104.00 B (+0.05%)
console.js 109.11 KB 109.21 KB +104.00 B (+0.09%)
crypto.js 1.16 MB 1.16 MB +104.00 B (+0.01%)
debugger.js 30.69 KB 30.80 KB +104.00 B (+0.33%)
deprecations.js 313.77 KB 313.87 KB +104.00 B (+0.03%)
dgram.js 174.74 KB 174.84 KB +104.00 B (+0.06%)
diagnostics_channel.js 228.46 KB 228.56 KB +104.00 B (+0.04%)
dns.js 270.57 KB 270.68 KB +104.00 B (+0.04%)
documentation.js 9.74 KB 9.85 KB +104.00 B (+1.04%)
domain.js 91.28 KB 91.38 KB +104.00 B (+0.11%)
embedding.js 37.29 KB 37.40 KB +104.00 B (+0.27%)
environment_variables.js 15.15 KB 15.25 KB +104.00 B (+0.67%)
errors.js 407.90 KB 408.00 KB +104.00 B (+0.02%)
esm.js 137.90 KB 138.00 KB +104.00 B (+0.07%)
events.js 550.91 KB 551.01 KB +104.00 B (+0.02%)
fs.js 1.19 MB 1.19 MB +104.00 B (+0.01%)
globals.js 137.16 KB 137.26 KB +104.00 B (+0.07%)
http.js 692.18 KB 692.29 KB +104.00 B (+0.01%)
http2.js 803.47 KB 803.58 KB +104.00 B (+0.01%)
https.js 162.04 KB 162.14 KB +104.00 B (+0.06%)
index.js 9.69 KB 9.79 KB +104.00 B (+1.05%)
inspector.js 122.38 KB 122.48 KB +104.00 B (+0.08%)
intl.js 37.08 KB 37.18 KB +104.00 B (+0.27%)
module.js 337.77 KB 337.87 KB +104.00 B (+0.03%)
modules.js 151.41 KB 151.51 KB +104.00 B (+0.07%)
n-api.js 721.32 KB 721.42 KB +104.00 B (+0.01%)
net.js 287.37 KB 287.47 KB +104.00 B (+0.04%)
os.js 107.30 KB 107.41 KB +104.00 B (+0.09%)
packages.js 124.76 KB 124.86 KB +104.00 B (+0.08%)
path.js 97.70 KB 97.80 KB +104.00 B (+0.10%)
perf_hooks.js 375.18 KB 375.28 KB +104.00 B (+0.03%)
permissions.js 28.57 KB 28.68 KB +104.00 B (+0.36%)
process.js 717.80 KB 717.90 KB +104.00 B (+0.01%)
punycode.js 28.47 KB 28.57 KB +104.00 B (+0.36%)
querystring.js 31.24 KB 31.34 KB +104.00 B (+0.33%)
quic.js 169.48 KB 169.58 KB +104.00 B (+0.06%)
readline.js 225.61 KB 225.71 KB +104.00 B (+0.05%)
repl.js 211.69 KB 211.79 KB +104.00 B (+0.05%)
report.js 188.55 KB 188.65 KB +104.00 B (+0.05%)
single-executable-applications.js 86.41 KB 86.51 KB +104.00 B (+0.12%)
sqlite.js 235.67 KB 235.77 KB +104.00 B (+0.04%)
stream.js 855.81 KB 855.91 KB +104.00 B (+0.01%)
string_decoder.js 31.49 KB 31.59 KB +104.00 B (+0.32%)
synopsis.js 15.72 KB 15.82 KB +104.00 B (+0.65%)
test.js 865.27 KB 865.37 KB +104.00 B (+0.01%)
timers.js 100.79 KB 100.89 KB +104.00 B (+0.10%)
tls.js 322.11 KB 322.21 KB +104.00 B (+0.03%)
tracing.js 77.51 KB 77.61 KB +104.00 B (+0.13%)
tty.js 49.45 KB 49.55 KB +104.00 B (+0.21%)
typescript.js 25.38 KB 25.48 KB +104.00 B (+0.40%)
url.js 337.22 KB 337.32 KB +104.00 B (+0.03%)
util.js 754.67 KB 754.77 KB +104.00 B (+0.01%)
v8.js 336.01 KB 336.11 KB +104.00 B (+0.03%)
vm.js 443.64 KB 443.74 KB +104.00 B (+0.02%)
wasi.js 42.51 KB 42.61 KB +104.00 B (+0.24%)
webcrypto.js 423.71 KB 423.82 KB +104.00 B (+0.02%)
webstreams.js 285.67 KB 285.77 KB +104.00 B (+0.04%)
worker_threads.js 401.97 KB 402.07 KB +104.00 B (+0.03%)
zlib.js 320.85 KB 320.95 KB +104.00 B (+0.03%)

@avivkeller avivkeller marked this pull request as draft March 13, 2026 21:26
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR is a WIP attempt to preserve input directory structure in generated outputs (issue #662) by introducing recursive file writes, updating metadata to carry path/base, and removing legacy parallel-safe copy logic.

Changes:

  • Add src/utils/file.mjs with writeFile that creates parent directories (mkdir -p) and a withExt helper.
  • Extend metadata entries with path/base, update many generators to write/read using these fields, and adjust URL/link building accordingly.
  • Remove safeCopy (and its tests) and update asset-copying logic.

Reviewed changes

Copilot reviewed 30 out of 33 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/utils/generators.mjs Switch URL-building helpers to use entry.path and rename api param to path in version URL helper.
src/utils/file.mjs New shared FS helpers: extension replacement and recursive writeFile.
src/generators/web/utils/processing.mjs Update per-page result identity from api to path, and change entrypoint naming to use base.
src/generators/web/generate.mjs Use recursive writeFile; write HTML using ${path}.html.
src/generators/sitemap/generate.mjs Use recursive writeFile helper for output.
src/generators/orama-db/generate.mjs Use recursive writeFile; update search href to use entry.path; use join() for output filename.
src/generators/metadata/utils/parse.mjs Change metadata parsing to accept { path, tree } and add path to produced entries; compute api via slugging.
src/generators/metadata/utils/tests/parse.test.mjs Partially update tests for new parseApiDoc input shape.
src/generators/metadata/types.d.ts Add required path/base fields to MetadataEntry.
src/generators/man-page/generate.mjs Use recursive writeFile helper for output.
src/generators/llms-txt/utils/tests/buildApiDocLink.test.mjs Update test fixtures to use path instead of api for link building.
src/generators/llms-txt/generate.mjs Use recursive writeFile helper for output.
src/generators/legacy-json/utils/buildSection.mjs Include path on root module and update source to reference ${head.path}.md.
src/generators/legacy-json/generate.mjs Use recursive writeFile; write JSON sections using ${path}.json.
src/generators/legacy-json-all/generate.mjs Use recursive writeFile; add note about config.index compatibility.
src/generators/legacy-html/utils/tableOfContents.mjs Update navigation/ToC links to use path for hrefs (keep api for CSS class).
src/generators/legacy-html/utils/replaceTemplateValues.mjs Use base for __FILENAME__, and path for GitHub/edit + version links.
src/generators/legacy-html/utils/buildExtraContent.mjs Update stability overview links to use path.
src/generators/legacy-html/utils/buildDropdowns.mjs Update version URL builder to use path.
src/generators/legacy-html/utils/safeCopy.mjs Removed.
src/generators/legacy-html/utils/tests/safeCopy.test.mjs Removed.
src/generators/legacy-html/types.d.ts Extend template values to include path and base.
src/generators/legacy-html/generate.mjs Use recursive writeFile; replace safeCopy with cp; write ${template.path}.html.
src/generators/legacy-html-all/generate.mjs Use recursive writeFile; ensure entries passed into ToC include the new fields.
src/generators/jsx-ast/utils/buildBarProps.mjs Use base for “View as” and path for edit/version/sidebar links.
src/generators/jsx-ast/utils/tests/buildBarProps.test.mjs Update some fixtures for base/path.
src/generators/jsx-ast/generate.mjs Build sidebar doc pages using ${node.path}.html and drop config.index usage.
src/generators/json-simple/generate.mjs Use recursive writeFile helper for output.
src/generators/ast/generate.mjs Preserve relative directory structure by computing path/base using glob-parent + relative() and removing vfile.
src/generators/api-links/generate.mjs Use recursive writeFile helper for output.
src/generators/addon-verify/generate.mjs Use recursive writeFile helper for output.
package.json Bump version to 1.1.0; add glob-parent; remove vfile.
package-lock.json Lockfile updates for version bump and dependency changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@ovflowd
Copy link
Member

ovflowd commented Mar 14, 2026

I'm unsure what your Note is actually trying to say?

Will file output differ to what we see in node core?

@ovflowd
Copy link
Member

ovflowd commented Mar 14, 2026

And how different it is? If this changes the file names even if 1% it is a block. People rely on those links and file names being evergreen and never changing.

@avivkeller
Copy link
Member Author

To clarify: I can absolutely revert all the legacy changes, so that only the web generator would support files at multiple depths. The file names themselves don't change, but their titles do shift slightly.

The reason is that this PR uses page titles to build the index, since index.md is a flat file and we need to work across multiple depths. Some titles differ slightly from the index, for example, VM is actually titled VM (executing JavaScript).

@ovflowd
Copy link
Member

ovflowd commented Mar 14, 2026

Can you provide actual examples of before and after?

@ovflowd
Copy link
Member

ovflowd commented Mar 14, 2026

My 2 cents:

  • This should work in a way that you can specify file name formatting then at the very least, or so that the generator (ie: legacy-html and web) decide that path and name of the files.
    • This means legacy-html keeps telling whatever fs() functions you have to keep creating the same file names
    • And the web generator allows you to it by a depth basis.
    • But this MUST be configurable, because even once we switch to web generator in nodejs/node the links to the files and their # hashes MUST be the same. That is a NON negotiable.

@avivkeller
Copy link
Member Author

  • This should work in a way that you can specify file name formatting then at the very least, or so that the generator (ie: legacy-html and web) decide that path and name of the files.

Generators can still decide the path of the files they want to export, for instance, orama will always export to orama-db.json.

  • This means legacy-html keeps telling whatever fs() functions you have to keep creating the same file names

legacy-html, and every other generator, are generated the exact same file names, those have not changed.

  • But this MUST be configurable, because even once we switch to web generator in nodejs/node the links to the files and their # hashes MUST be the same. That is a NON negotiable.

This doesn't affect anchors, or any root level files. It only affects the file names of files at a non-root depth (by outputting them at that same depth)


The reason why the comparator is reporting changes is because, without ordering from an index file, the sidebar is in a slightly different order:
image

If needed, I can revert that part of the legacy generator.

@avivkeller
Copy link
Member Author

Actually, I'll revert that on the legacy generator, this should be a new generator only feature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Preserve Directory Structure

3 participants