Skip to content

fix: preserve underscores in slug generation for anchor link compatibility#733

Open
devprakash93 wants to merge 2 commits intonodejs:mainfrom
devprakash93:fix/preserve-underscores-in-slugs
Open

fix: preserve underscores in slug generation for anchor link compatibility#733
devprakash93 wants to merge 2 commits intonodejs:mainfrom
devprakash93:fix/preserve-underscores-in-slugs

Conversation

@devprakash93
Copy link
Copy Markdown

Fix broken anchor links for Node.js API identifiers containing underscores (e.g. __dirname, __filename).

Problem

The _ character was incorrectly included in DOC_API_SLUGS_REPLACEMENTS, causing underscores to be replaced during slug generation:

__dirname → --dirname → dirname ❌

This resulted in mismatched anchor IDs (dirname) and broken links (#__dirname).

Solution

Remove _ from the replacement character class so underscores are preserved during slug generation.

Result:

__dirname → __dirname ✅
__filename → __filename ✅

Changes

  • Removed _ from the slug replacement regex in DOC_API_SLUGS_REPLACEMENTS
  • Updated existing slugger tests
  • Added new test cases for underscore handling:
    • __dirname
    • __filename
    • child_process
    • mixed cases like foo_bar:baz

Validation

All slug tests pass:

node --test src/generators/metadata/utils/tests/slugger.test.mjs

tests 32 | pass 32 | fail 0

Key checks:

  • slug('__dirname') → '__dirname'
  • slug('__filename') → '__filename'
  • slug('foo/bar') → 'foo-bar'
  • slug('foo:bar') → 'foo-bar'

Impact

Ensures anchor IDs remain consistent with source markdown and fixes broken links for all identifiers containing underscores.

…ility

- Remove underscore (_) from the special-character replacement regex in
  DOC_API_SLUGS_REPLACEMENTS so that names like __dirname and __filename
  keep their underscores in generated IDs.

Previously: __dirname → --dirname → dirname (broken anchor #__dirname)
Now:        __dirname → __dirname  (matches anchor #__dirname correctly)

- Update slugger tests to reflect new behavior
- Add new 'underscore preservation' test suite covering:
    - __dirname
    - __filename
    - child_process (internal underscores)
    - mixed underscore + other special chars

Fixes: broken anchor links for identifiers with leading/internal underscores
@devprakash93 devprakash93 requested a review from a team as a code owner March 30, 2026 19:02
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 30, 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 30, 2026 7:33pm

Request Review

Comment on lines 28 to 30
it('preserves underscores (does not replace with hyphens)', () => {
assert.strictEqual(slug('foo_bar', identity), 'foo_bar');
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This breaks existing behavior, are we 100% sure no existing links break post this PR

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The fix was originally targeted at __dirname / __filename where the old behavior caused a two-step destruction: __dirname → --dirname → dirname (leading hyphens stripped), making the anchor completely unreachable.
However, you're correct that removing _ from the replacement entirely is too broad — names like child_process previously generated the slug child-process, and if existing documentation already links to #child-process, those links would silently break after this change.I'd like to propose a more targeted fix instead of removing _ from the replacement globally, we could handle the specific case where leading underscores get converted to leading hyphens and then stripped. For example, only preserve underscores that are at the start of the identifier.
I'll update the PR with a narrower approach and verify against existing cross-references in the docs before pushing. Thanks for the review!

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.42%. Comparing base (27de0e7) to head (0d8152e).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #733      +/-   ##
==========================================
+ Coverage   76.37%   76.42%   +0.04%     
==========================================
  Files         155      155              
  Lines       13766    13792      +26     
  Branches     1093     1100       +7     
==========================================
+ Hits        10514    10540      +26     
  Misses       3247     3247              
  Partials        5        5              

☔ 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.

Comment on lines +49 to +65
describe('underscore preservation (anchor link compatibility)', () => {
it('preserves leading underscores so __dirname slug matches #__dirname anchor', () => {
assert.strictEqual(slug('__dirname', identity), '__dirname');
});

it('preserves leading underscores so __filename slug matches #__filename anchor', () => {
assert.strictEqual(slug('__filename', identity), '__filename');
});

it('preserves underscores within names', () => {
assert.strictEqual(slug('child_process', identity), 'child_process');
});

it('preserves mixed underscores and other characters', () => {
assert.strictEqual(slug('foo_bar:baz', identity), 'foo_bar-baz');
});
});
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These are redundant tests

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

You're right, those tests are redundant in their current form especially child_process and foo_bar:baz which just duplicate behavior already covered by the existing test suite.
As part of the narrower fix I mentioned in the previous comment (targeting only leading underscores rather than all underscores), I'll clean up these tests too. The updated test suite will:
Remove the redundant child_process and foo_bar:baz cases
Keep only the meaningful new cases: __dirname and __filename with clear assertions that their generated slugs match their markdown anchors
Restore the original child_process → child-process behavior and test
I'll push an updated commit shortly. Appreciate the thorough review!

{ from: /node.js/i, to: 'nodejs' }, // Replace Node.js
{ from: /&/, to: '-and-' }, // Replace &
{ from: /[/_,:;\\ ]/g, to: '-' }, // Replace /_,:;\. and whitespace
{ from: /[/,:;\\ ]/g, to: '-' }, // Replace /,:;\ and whitespace (underscores are preserved)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
{ from: /[/,:;\\ ]/g, to: '-' }, // Replace /,:;\ and whitespace (underscores are preserved)
{ from: /[/,:;\\ ]/g, to: '-' }, // Replace /,:;\ and whitespace.

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.

Some anchor links aren't working

2 participants