Skip to content

Commit a4d07f7

Browse files
committed
refactor: add user content prefixing for IDs
1 parent ccfcb88 commit a4d07f7

1 file changed

Lines changed: 14 additions & 5 deletions

File tree

server/utils/readme.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,16 @@ const reservedPathsNpmJs = [
266266

267267
const npmJsHosts = new Set(['www.npmjs.com', 'npmjs.com', 'www.npmjs.org', 'npmjs.org'])
268268

269+
const USER_CONTENT_PREFIX = 'user-content-'
270+
271+
function withUserContentPrefix(value: string): string {
272+
return value.startsWith(USER_CONTENT_PREFIX) ? value : `${USER_CONTENT_PREFIX}${value}`
273+
}
274+
275+
function toUserContentHash(value: string): string {
276+
return `#${withUserContentPrefix(value)}`
277+
}
278+
269279
const isNpmJsUrlThatCanBeRedirected = (url: URL) => {
270280
if (!npmJsHosts.has(url.host)) {
271281
return false
@@ -292,8 +302,7 @@ function resolveUrl(url: string, packageName: string, repoInfo?: RepositoryInfo)
292302
if (url.startsWith('#')) {
293303
// Prefix anchor links to match heading IDs (avoids collision with page IDs)
294304
// Idempotent: don't double-prefix if already prefixed
295-
if (url.startsWith('#user-content-')) return url
296-
return `#user-content-${url.slice(1)}`
305+
return toUserContentHash(url.slice(1))
297306
}
298307
// Absolute paths (e.g. /package/foo from a previous npmjs redirect) are already resolved
299308
if (url.startsWith('/')) return url
@@ -385,8 +394,8 @@ function resolveImageUrl(url: string, packageName: string, repoInfo?: Repository
385394

386395
// Helper to prefix id attributes with 'user-content-'
387396
function prefixId(tagName: string, attribs: sanitizeHtml.Attributes) {
388-
if (attribs.id && !attribs.id.startsWith('user-content-')) {
389-
attribs.id = `user-content-${attribs.id}`
397+
if (attribs.id) {
398+
attribs.id = withUserContentPrefix(attribs.id)
390399
}
391400
return { tagName, attribs }
392401
}
@@ -437,7 +446,7 @@ export async function renderReadmeHtml(
437446
const count = usedSlugs.get(slug) ?? 0
438447
usedSlugs.set(slug, count + 1)
439448
const uniqueSlug = count === 0 ? slug : `${slug}-${count}`
440-
const id = `user-content-${uniqueSlug}`
449+
const id = withUserContentPrefix(uniqueSlug)
441450

442451
if (plainText) {
443452
toc.push({ text: plainText, id, depth })

0 commit comments

Comments
 (0)