From 079de38a668b5b7c20087815a3bfbf526e63cb6a Mon Sep 17 00:00:00 2001 From: Sujal Goel Date: Thu, 9 Apr 2026 11:23:31 +0530 Subject: [PATCH 1/3] fix(metadata): preserve -- prefix in anchor IDs for CLI flags Two regexes in DOC_API_SLUGS_REPLACEMENTS were stripping -- from the start of slugs, turning --permission into permission and breaking existing links. Fixes #757 --- src/generators/metadata/constants.mjs | 4 ++-- .../metadata/utils/__tests__/slugger.test.mjs | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/generators/metadata/constants.mjs b/src/generators/metadata/constants.mjs index e8ac140b..d9cbd2d8 100644 --- a/src/generators/metadata/constants.mjs +++ b/src/generators/metadata/constants.mjs @@ -7,9 +7,9 @@ export const DOC_API_SLUGS_REPLACEMENTS = [ { from: /node.js/i, to: 'nodejs' }, // Replace Node.js { from: /&/, to: '-and-' }, // Replace & { from: /[/,:;\\ ]/g, to: '-' }, // Replace /,:;\. and whitespace - { from: /^-+(?!-*$)/g, to: '' }, // Remove any leading hyphens + { from: /^-(?=[^-])/g, to: '' }, // Remove a single leading hyphen (preserves -- prefix for CLI flags) { from: /(? { assert.strictEqual(slug('-foo', identity), 'foo'); }); - it('removes multiple leading hyphens', () => { - assert.strictEqual(slug('--foo', identity), 'foo'); + it('preserves double leading hyphens (CLI flag prefix)', () => { + assert.strictEqual(slug('--foo', identity), '--foo'); }); it('preserves an all-hyphen string', () => { @@ -80,6 +80,16 @@ describe('slug', () => { }); }); + describe('cli flag anchor preservation', () => { + it('preserves -- prefix for CLI flags', () => { + assert.strictEqual(slug('--permission', identity), '--permission'); + }); + + it('preserves -- prefix for multi-word CLI flags', () => { + assert.strictEqual(slug('--allow-fs-read', identity), '--allow-fs-read'); + }); + }); + describe('integration with github-slugger', () => { it('lowercases and hyphenates a plain title', () => { assert.strictEqual(slug('Hello World'), 'hello-world'); From a15edcab0bb2590590288bf412500abac99e562f Mon Sep 17 00:00:00 2001 From: Sujal Goel Date: Fri, 10 Apr 2026 19:57:58 +0530 Subject: [PATCH 2/3] test(metadata): remove redundant CLI flag slug tests --- .../metadata/utils/__tests__/slugger.test.mjs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/generators/metadata/utils/__tests__/slugger.test.mjs b/src/generators/metadata/utils/__tests__/slugger.test.mjs index a25a37cd..587632a4 100644 --- a/src/generators/metadata/utils/__tests__/slugger.test.mjs +++ b/src/generators/metadata/utils/__tests__/slugger.test.mjs @@ -80,16 +80,6 @@ describe('slug', () => { }); }); - describe('cli flag anchor preservation', () => { - it('preserves -- prefix for CLI flags', () => { - assert.strictEqual(slug('--permission', identity), '--permission'); - }); - - it('preserves -- prefix for multi-word CLI flags', () => { - assert.strictEqual(slug('--allow-fs-read', identity), '--allow-fs-read'); - }); - }); - describe('integration with github-slugger', () => { it('lowercases and hyphenates a plain title', () => { assert.strictEqual(slug('Hello World'), 'hello-world'); From 6d416aaee695c0f1b88246eda06d08c6a593c0a1 Mon Sep 17 00:00:00 2001 From: Sujal Goel Date: Mon, 13 Apr 2026 22:41:44 +0530 Subject: [PATCH 3/3] fix(metadata): rework slug rules to preserve CLI flag anchor prefixes Remove two post-slugger rules that stripped leading hyphens, which caused --permission and similar CLI flag headings to lose their -- prefix. Move & and = replacements to run before github-slugger so they produce proper separators instead of being silently removed. Fixes #757 --- src/generators/metadata/constants.mjs | 7 ++-- .../metadata/utils/__tests__/slugger.test.mjs | 34 +++++++++---------- src/generators/metadata/utils/slugger.mjs | 11 ++++-- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/generators/metadata/constants.mjs b/src/generators/metadata/constants.mjs index d9cbd2d8..88ffcf3e 100644 --- a/src/generators/metadata/constants.mjs +++ b/src/generators/metadata/constants.mjs @@ -5,11 +5,10 @@ export const IGNORE_STABILITY_STEMS = ['documentation']; // These are string replacements specific to Node.js API docs for anchor IDs export const DOC_API_SLUGS_REPLACEMENTS = [ { from: /node.js/i, to: 'nodejs' }, // Replace Node.js - { from: /&/, to: '-and-' }, // Replace & - { from: /[/,:;\\ ]/g, to: '-' }, // Replace /,:;\. and whitespace - { from: /^-(?=[^-])/g, to: '' }, // Remove a single leading hyphen (preserves -- prefix for CLI flags) + { from: /&/g, to: '-and-', pre: true }, // Replace & before slugging (slugger removes it without a separator) + { from: /=/g, to: '-', pre: true }, // Replace = before slugging (slugger removes it without a separator) + { from: /[/,:;\\ ]/g, to: '-' }, // Replace /,:;\ and whitespace { from: /(? { it('replaces semicolons with hyphens', () => { assert.strictEqual(slug('foo;bar', identity), 'foo-bar'); }); - }); - - describe('leading hyphen removal', () => { - it('removes a single leading hyphen', () => { - assert.strictEqual(slug('-foo', identity), 'foo'); - }); - it('preserves double leading hyphens (CLI flag prefix)', () => { - assert.strictEqual(slug('--foo', identity), '--foo'); - }); - - it('preserves an all-hyphen string', () => { - assert.strictEqual(slug('---', identity), '---'); + it('replaces equals signs with hyphens', () => { + assert.strictEqual(slug('foo=bar', identity), 'foo-bar'); }); }); @@ -70,13 +60,23 @@ describe('slug', () => { }); }); - describe('consecutive hyphen replacement', () => { - it('replaces from start of string up to and including double-hyphen with a single hyphen', () => { - assert.strictEqual(slug('foo--bar', identity), '-bar'); + describe('cli flag anchors', () => { + it('preserves -- prefix for CLI flags', () => { + assert.strictEqual(slug('--permission', identity), '--permission'); + }); + + it('preserves -x, --long-form mixed flag headings', () => { + assert.strictEqual( + slug('-p---print-script', identity), + '-p---print-script' + ); }); - it('does not fire on an all-hyphen string', () => { - assert.strictEqual(slug('---', identity), '---'); + it('handles = in flag values', () => { + assert.strictEqual( + slug('-c-condition---conditions=condition', identity), + '-c-condition---conditions-condition' + ); }); }); diff --git a/src/generators/metadata/utils/slugger.mjs b/src/generators/metadata/utils/slugger.mjs index 40c7ec7c..63577287 100644 --- a/src/generators/metadata/utils/slugger.mjs +++ b/src/generators/metadata/utils/slugger.mjs @@ -30,10 +30,15 @@ const createNodeSlugger = () => { * @param {string} title * @param {typeof defaultSlugFn} slugFn */ -export const slug = (title, slugFn = defaultSlugFn) => - DOC_API_SLUGS_REPLACEMENTS.reduce( +export const slug = (title, slugFn = defaultSlugFn) => { + const preTitle = DOC_API_SLUGS_REPLACEMENTS.filter(r => r.pre).reduce( + (s, { from, to }) => s.replace(from, to), + title + ); + return DOC_API_SLUGS_REPLACEMENTS.filter(r => !r.pre).reduce( (piece, { from, to }) => piece.replace(from, to), - slugFn(title) + slugFn(preTitle) ); +}; export default createNodeSlugger;