File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -272,6 +272,10 @@ function withUserContentPrefix(value: string): string {
272272 return value . startsWith ( USER_CONTENT_PREFIX ) ? value : `${ USER_CONTENT_PREFIX } ${ value } `
273273}
274274
275+ function toUserContentId ( value : string ) : string {
276+ return `${ USER_CONTENT_PREFIX } ${ value } `
277+ }
278+
275279function toUserContentHash ( value : string ) : string {
276280 return `#${ withUserContentPrefix ( value ) } `
277281}
@@ -446,13 +450,13 @@ export async function renderReadmeHtml(
446450 const count = usedSlugs . get ( slug ) ?? 0
447451 usedSlugs . set ( slug , count + 1 )
448452 const uniqueSlug = count === 0 ? slug : `${ slug } -${ count } `
449- const id = withUserContentPrefix ( uniqueSlug )
453+ const id = toUserContentId ( uniqueSlug )
450454
451455 if ( plainText ) {
452456 toc . push ( { text : plainText , id, depth } )
453457 }
454458
455- return `<h${ semanticLevel } id="${ id } " data-level="${ depth } "><a href="#${ uniqueSlug } ">${ plainText } </a></h${ semanticLevel } >\n`
459+ return `<h${ semanticLevel } id="${ id } " data-level="${ depth } "><a href="#${ id } ">${ plainText } </a></h${ semanticLevel } >\n`
456460 }
457461
458462 renderer . heading = function ( { tokens, depth } : Tokens . Heading ) {
Original file line number Diff line number Diff line change @@ -642,6 +642,17 @@ describe('Issue #1323 — single-pass rendering correctness', () => {
642642 expect ( ids ) . toEqual ( [ 'user-content-api' , 'user-content-api-1' , 'user-content-api-2' ] )
643643 } )
644644
645+ it ( 'does not collide when heading text already starts with user-content-' , async ( ) => {
646+ const md = [ '# Title' , '' , '# user-content-title' ] . join ( '\n' )
647+
648+ const result = await renderReadmeHtml ( md , 'test-pkg' )
649+
650+ const ids = Array . from ( result . html . matchAll ( / i d = " ( u s e r - c o n t e n t - [ ^ " ] + ) " / g) , m => m [ 1 ] )
651+ expect ( ids ) . toEqual ( [ 'user-content-title' , 'user-content-user-content-title' ] )
652+ expect ( new Set ( ids ) . size ) . toBe ( ids . length )
653+ expect ( result . toc . map ( t => t . id ) ) . toEqual ( ids )
654+ } )
655+
645656 it ( 'heading semantic levels are sequential even when mixing heading types' , async ( ) => {
646657 // h1 (md) → h3, h3 (html) → should be h4 (max = lastSemantic + 1),
647658 // not jump to h5 or h6 because it was processed in a later pass.
You can’t perform that action at this time.
0 commit comments