Skip to content

Commit a89e54c

Browse files
committed
fix: improve anchors parsing in readmes
1 parent 5cb6bc6 commit a89e54c

File tree

2 files changed

+15
-2
lines changed

2 files changed

+15
-2
lines changed

app/pages/package/[[org]]/[name].vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,6 @@ const showSkeleton = shallowRef(false)
548548
:latest-version="latestVersion"
549549
:provenance-data="provenanceData"
550550
:provenance-status="provenanceStatus"
551-
:class="$style.areaHeader"
552551
page="main"
553552
:version-url-pattern="versionUrlPattern"
554553
/>

server/utils/readme.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,11 +549,23 @@ export async function renderReadmeHtml(
549549
toc.push({ text: plainText, id, depth })
550550
}
551551

552+
// The browser doesn't support anchors within anchors and automatically extracts them from each other,
553+
// causing a hydration error. To prevent this from happening in such cases, we use the anchor separately
554+
if (htmlAnchorRe.test(displayHtml)) {
555+
return `<h${semanticLevel} id="${id}" data-level="${depth}"${preservedAttrs}>${displayHtml}<a href="#${id}"></a></h${semanticLevel}>\n`
556+
}
557+
552558
return `<h${semanticLevel} id="${id}" data-level="${depth}"${preservedAttrs}><a href="#${id}">${displayHtml}</a></h${semanticLevel}>\n`
553559
}
554560

555561
renderer.heading = function ({ tokens, depth }: Tokens.Heading) {
556-
const displayHtml = this.parser.parseInline(tokens)
562+
const anchorTokenRegex = /^<a(\s.+)?\/?>$/
563+
const isAnchorHeading =
564+
anchorTokenRegex.test(tokens[0]?.raw ?? '') && tokens[tokens.length - 1]?.raw === '</a>'
565+
566+
// for anchor headings, we will ignore user-added id and add our own
567+
const tokensWithoutAnchor = isAnchorHeading ? tokens.slice(1, -1) : tokens
568+
const displayHtml = this.parser.parseInline(tokensWithoutAnchor)
557569
const plainText = getHeadingPlainText(displayHtml)
558570
const slugSource = getHeadingSlugSource(displayHtml)
559571
return processHeading(depth, displayHtml, plainText, slugSource)
@@ -643,6 +655,8 @@ ${html}
643655

644656
const { resolvedHref, extraAttrs } = processLink(href, plainText || title || '')
645657

658+
if (!resolvedHref) return text
659+
646660
return `<a href="${resolvedHref}"${titleAttr}${extraAttrs}>${text}</a>`
647661
}
648662

0 commit comments

Comments
 (0)