From 2f11d9a4ba957645c3c37854d8237be1f15515c1 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli-ai-agent <268630448+NullVoxPopuli-ai-agent@users.noreply.github.com> Date: Sat, 15 Aug 2026 17:19:28 -0400 Subject: [PATCH 1/2] fix(repl-sdk): make {#custom-id} heading suffix actually set the id Previously the suffix only suppressed the auto-generated id: the custom id was never assigned and the literal {#custom-id} stayed in the rendered heading text, despite kolay documenting the feature as working. Now the suffix becomes the heading id and is stripped from the text. Co-Authored-By: Claude Fable 5 --- .../repl-sdk/src/compilers/markdown/heading-id.js | 10 ++++++++++ .../repl-sdk/src/compilers/markdown/parse.test.ts | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/packages/repl-sdk/src/compilers/markdown/heading-id.js b/packages/repl-sdk/src/compilers/markdown/heading-id.js index f679ba029..4dba7ad25 100644 --- a/packages/repl-sdk/src/compilers/markdown/heading-id.js +++ b/packages/repl-sdk/src/compilers/markdown/heading-id.js @@ -65,6 +65,16 @@ export function headingId(options = { defaults: false }) { const matched = string.match(/ {#([^]+?)}$/); if (matched) { + const remaining = string.slice(0, -matched[0].length); + + if (remaining) { + lastChild.value = remaining; + } else { + node.children.pop(); + } + + setNodeId(node, matched[1]); + return; } } diff --git a/packages/repl-sdk/src/compilers/markdown/parse.test.ts b/packages/repl-sdk/src/compilers/markdown/parse.test.ts index ae952b93a..87815ba62 100644 --- a/packages/repl-sdk/src/compilers/markdown/parse.test.ts +++ b/packages/repl-sdk/src/compilers/markdown/parse.test.ts @@ -253,6 +253,20 @@ describe('heading ids', () => { expect(result.text).toContain('id="a-s-b"'); }); + + it('uses a {#custom-id} suffix as the id and strips it from the text', async () => { + const result = await parseMarkdown(`## A very long heading {#short-id}`, { ...defaults }); + + expect(result.text).toBe('

A very long heading

'); + }); + + it('supports {#custom-id} on a heading ending in formatting', async () => { + const result = await parseMarkdown(`## Use \`parseMarkdown\` here {#parse}`, { + ...defaults, + }); + + expect(result.text).toBe('

Use parseMarkdown here

'); + }); }); describe('options', () => { From 9fa3c0ffd4dd55232fe00c5fc307163c1c9a265a Mon Sep 17 00:00:00 2001 From: NullVoxPopuli-ai-agent <268630448+NullVoxPopuli-ai-agent@users.noreply.github.com> Date: Sat, 15 Aug 2026 18:05:04 -0400 Subject: [PATCH 2/2] fix types: guard indexed regex-match access Co-Authored-By: Claude Fable 5 --- packages/repl-sdk/src/compilers/markdown/heading-id.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/repl-sdk/src/compilers/markdown/heading-id.js b/packages/repl-sdk/src/compilers/markdown/heading-id.js index 4dba7ad25..c60f4d14e 100644 --- a/packages/repl-sdk/src/compilers/markdown/heading-id.js +++ b/packages/repl-sdk/src/compilers/markdown/heading-id.js @@ -63,9 +63,11 @@ export function headingId(options = { defaults: false }) { if (lastChild && lastChild.type === 'text') { const string = lastChild.value.replace(/ +$/, ''); const matched = string.match(/ {#([^]+?)}$/); + const suffix = matched?.[0]; + const customId = matched?.[1]; - if (matched) { - const remaining = string.slice(0, -matched[0].length); + if (suffix && customId) { + const remaining = string.slice(0, -suffix.length); if (remaining) { lastChild.value = remaining; @@ -73,7 +75,7 @@ export function headingId(options = { defaults: false }) { node.children.pop(); } - setNodeId(node, matched[1]); + setNodeId(node, customId); return; }