diff --git a/packages/repl-sdk/src/compilers/markdown/heading-id.js b/packages/repl-sdk/src/compilers/markdown/heading-id.js index 4f2647d9e..f679ba029 100644 --- a/packages/repl-sdk/src/compilers/markdown/heading-id.js +++ b/packages/repl-sdk/src/compilers/markdown/heading-id.js @@ -38,7 +38,7 @@ function extractText(children) { * @param {string} value */ function formatDefaultId(value) { - return kebabCase(value.replaceAll(/\\s+/g, ' ').trim()); + return kebabCase(value.replaceAll(/\s+/g, ' ').trim()); } /** diff --git a/packages/repl-sdk/src/compilers/markdown/parse.test.ts b/packages/repl-sdk/src/compilers/markdown/parse.test.ts index 213679e87..ae952b93a 100644 --- a/packages/repl-sdk/src/compilers/markdown/parse.test.ts +++ b/packages/repl-sdk/src/compilers/markdown/parse.test.ts @@ -237,6 +237,24 @@ describe('default features', () => { }); }); +describe('heading ids', () => { + it('collapses runs of whitespace in the heading text', async () => { + const result = await parseMarkdown(`## Hello World `, { ...defaults }); + + // Only the id is normalized; the rendered text keeps the author's spacing. + expect(result.text).toContain('id="hello-world"'); + }); + + it('treats a literal \\s in a heading as text, not as whitespace', async () => { + // The regex in formatDefaultId used to be /\\s+/g -- a literal backslash + // followed by `s`, rather than whitespace -- so `\s` here was replaced with + // a space and the `s` vanished from the id. + const result = await parseMarkdown(`## a \\s b`, { ...defaults }); + + expect(result.text).toContain('id="a-s-b"'); + }); +}); + describe('options', () => { describe('remarkPlugins', () => { it('works', async () => {