diff --git a/src/node/markdown/markdown.ts b/src/node/markdown/markdown.ts index fd6bf492..7210c7a5 100644 --- a/src/node/markdown/markdown.ts +++ b/src/node/markdown/markdown.ts @@ -242,7 +242,8 @@ export async function createMarkdownRenderer( .use( linkPlugin, { target: '_blank', rel: 'noreferrer', ...options.externalLinks }, - base + base, + options.anchor?.slugify ?? slugify ) .use(lineNumberPlugin, options.lineNumbers) diff --git a/src/node/markdown/plugins/link.ts b/src/node/markdown/plugins/link.ts index c636db9f..2fe2e1ac 100644 --- a/src/node/markdown/plugins/link.ts +++ b/src/node/markdown/plugins/link.ts @@ -16,7 +16,8 @@ const indexRE = /(^|.*\/)index.md(#?.*)$/i export const linkPlugin = ( md: MarkdownItAsync, externalAttrs: Record, - base: string + base: string, + slugify: (str: string) => string ) => { md.renderer.rules.link_open = ( tokens, @@ -27,9 +28,12 @@ export const linkPlugin = ( ) => { const token = tokens[idx] const hrefIndex = token.attrIndex('href') - const targetIndex = token.attrIndex('target') - const downloadIndex = token.attrIndex('download') - if (hrefIndex >= 0 && targetIndex < 0 && downloadIndex < 0) { + if ( + hrefIndex >= 0 && + token.attrIndex('target') < 0 && + token.attrIndex('download') < 0 && + token.attrGet('class') !== 'header-anchor' // header anchors are already normalized + ) { const hrefAttr = token.attrs![hrefIndex] const url = hrefAttr[1] if (isExternal(url)) { @@ -54,9 +58,7 @@ export const linkPlugin = ( ) { normalizeHref(hrefAttr, env) } else if (url.startsWith('#')) { - hrefAttr[1] = decodeURI(hrefAttr[1]) - .normalize('NFKD') - .replace(/[\u0300-\u036F]/g, '') + hrefAttr[1] = decodeURI(normalizeHash(hrefAttr[1])) } // append base to internal (non-relative) urls @@ -74,7 +76,7 @@ export const linkPlugin = ( const indexMatch = url.match(indexRE) if (indexMatch) { const [, path, hash] = indexMatch - url = path + hash.normalize('NFKD').replace(/[\u0300-\u036F]/g, '') + url = path + normalizeHash(hash) } else { let cleanUrl = url.replace(/[?#].*$/, '') // transform foo.md -> foo[.html] @@ -90,10 +92,7 @@ export const linkPlugin = ( cleanUrl += '.html' } const parsed = new URL(url, 'http://a.com') - url = - cleanUrl + - parsed.search + - parsed.hash.normalize('NFKD').replace(/[\u0300-\u036F]/g, '') + url = cleanUrl + parsed.search + normalizeHash(parsed.hash) } // ensure leading . for relative paths @@ -108,6 +107,10 @@ export const linkPlugin = ( hrefAttr[1] = decodeURI(url) } + function normalizeHash(str: string) { + return str ? encodeURI('#' + slugify(decodeURI(str).slice(1))) : '' + } + function pushLink(link: string, env: MarkdownEnv) { const links = env.links || (env.links = []) links.push(link)