diff options
author | 2022-06-10 05:31:36 +0200 | |
---|---|---|
committer | 2022-06-09 22:31:36 -0500 | |
commit | 76fb01cff1002f2a37e93869378802156c4eca7c (patch) | |
tree | c20534f1f3ca5ecdc8d38ed3c4bda96710a3338a /packages/markdown/remark/src | |
parent | 0e5bb2949be4479b36cad66b8d4dd471aef595e5 (diff) | |
download | astro-76fb01cff1002f2a37e93869378802156c4eca7c.tar.gz astro-76fb01cff1002f2a37e93869378802156c4eca7c.tar.zst astro-76fb01cff1002f2a37e93869378802156c4eca7c.zip |
Fix autolinking of URLs inside links in Markdown (#3564)
Diffstat (limited to 'packages/markdown/remark/src')
-rw-r--r-- | packages/markdown/remark/src/index.ts | 9 | ||||
-rw-r--r-- | packages/markdown/remark/src/rehype-jsx.ts | 46 |
2 files changed, 36 insertions, 19 deletions
diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts index 917976d5e..a11419474 100644 --- a/packages/markdown/remark/src/index.ts +++ b/packages/markdown/remark/src/index.ts @@ -99,14 +99,13 @@ export async function renderMarkdown( parser .use(isMDX ? [rehypeJsx, rehypeExpressions] : [rehypeRaw]) .use(rehypeEscape) - .use(rehypeIslands); + .use(rehypeIslands) + .use([rehypeCollectHeaders]) + .use(rehypeStringify, { allowDangerousHtml: true }) let result: string; try { - const vfile = await parser - .use([rehypeCollectHeaders]) - .use(rehypeStringify, { allowDangerousHtml: true }) - .process(input); + const vfile = await parser.process(input); result = vfile.toString(); } catch (err) { // Ensure that the error message contains the input filename diff --git a/packages/markdown/remark/src/rehype-jsx.ts b/packages/markdown/remark/src/rehype-jsx.ts index daeb4d56a..06783ba85 100644 --- a/packages/markdown/remark/src/rehype-jsx.ts +++ b/packages/markdown/remark/src/rehype-jsx.ts @@ -1,15 +1,14 @@ +import type { RehypePlugin } from './types.js'; import { visit } from 'unist-util-visit'; const MDX_ELEMENTS = ['mdxJsxFlowElement', 'mdxJsxTextElement']; -export default function rehypeJsx(): any { - return function (node: any): any { - visit(node, 'element', (child: any) => { - child.tagName = `${child.tagName}`; - }); - visit(node, MDX_ELEMENTS, (child: any, index: number | null, parent: any) => { + +export default function rehypeJsx(): ReturnType<RehypePlugin> { + return function (tree) { + visit(tree, MDX_ELEMENTS, (node: any, index: number | null, parent: any) => { if (index === null || !Boolean(parent)) return; - const attrs = child.attributes.reduce((acc: any[], entry: any) => { + const attrs = node.attributes.reduce((acc: any[], entry: any) => { let attr = entry.value; if (attr && typeof attr === 'object') { attr = `{${attr.value}}`; @@ -26,23 +25,42 @@ export default function rehypeJsx(): any { return acc + ` ${entry.name}${attr ? '=' : ''}${attr}`; }, ''); - if (child.children.length === 0) { - child.type = 'raw'; - child.value = `<${child.name}${attrs} />`; + if (node.children.length === 0) { + node.type = 'raw'; + node.value = `<${node.name}${attrs} />`; return; } - // Replace the current child node with its children + // If the current node is a JSX <a> element, remove autolinks from its children + // to prevent Markdown code like `<a href="/">**Go to www.example.com now!**</a>` + // from creating a nested link to `www.example.com` + if (node.name === 'a') { + visit(node, 'element', (el, elIndex, elParent) => { + const isAutolink = ( + el.tagName === 'a' && + el.children.length === 1 && + el.children[0].type === 'text' && + el.children[0].value.match(/^(https?:\/\/|www\.)/i) + ); + + // If we found an autolink, remove it by replacing it with its text-only child + if (isAutolink) { + elParent.children.splice(elIndex, 1, el.children[0]); + } + }); + } + + // Replace the current node with its children // wrapped by raw opening and closing tags const openingTag = { type: 'raw', - value: `\n<${child.name}${attrs}>`, + value: `\n<${node.name}${attrs}>`, }; const closingTag = { type: 'raw', - value: `</${child.name}>\n`, + value: `</${node.name}>\n`, }; - parent.children.splice(index, 1, openingTag, ...child.children, closingTag); + parent.children.splice(index, 1, openingTag, ...node.children, closingTag); }); }; } |