diff options
author | 2023-01-09 10:23:21 +0100 | |
---|---|---|
committer | 2023-01-09 10:23:21 +0100 | |
commit | 16107b6a10514ef1b563e585ec9add4b14f42b94 (patch) | |
tree | 7aeedf42016e63b81f58dd24050cc83eae7a3dd8 /packages/markdown/remark/src | |
parent | 54076a41ebf5da421370a130b97a6406f094042e (diff) | |
download | astro-16107b6a10514ef1b563e585ec9add4b14f42b94.tar.gz astro-16107b6a10514ef1b563e585ec9add4b14f42b94.tar.zst astro-16107b6a10514ef1b563e585ec9add4b14f42b94.zip |
Remove Astro-flavored Markdown from `@astrojs/markdown-remark` (#5785)
Diffstat (limited to 'packages/markdown/remark/src')
-rw-r--r-- | packages/markdown/remark/src/index.ts | 29 | ||||
-rw-r--r-- | packages/markdown/remark/src/mdast-util-mdxish.ts | 12 | ||||
-rw-r--r-- | packages/markdown/remark/src/mdxjs.ts | 27 | ||||
-rw-r--r-- | packages/markdown/remark/src/rehype-collect-headings.ts | 21 | ||||
-rw-r--r-- | packages/markdown/remark/src/rehype-escape.ts | 22 | ||||
-rw-r--r-- | packages/markdown/remark/src/rehype-expressions.ts | 18 | ||||
-rw-r--r-- | packages/markdown/remark/src/rehype-islands.ts | 43 | ||||
-rw-r--r-- | packages/markdown/remark/src/rehype-jsx.ts | 65 | ||||
-rw-r--r-- | packages/markdown/remark/src/remark-escape.ts | 15 | ||||
-rw-r--r-- | packages/markdown/remark/src/remark-mark-and-unravel.ts | 72 | ||||
-rw-r--r-- | packages/markdown/remark/src/remark-mdxish.ts | 61 | ||||
-rw-r--r-- | packages/markdown/remark/src/remark-unwrap.ts | 44 | ||||
-rw-r--r-- | packages/markdown/remark/src/types.ts | 1 |
13 files changed, 6 insertions, 424 deletions
diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts index 24cffa287..91680f3fd 100644 --- a/packages/markdown/remark/src/index.ts +++ b/packages/markdown/remark/src/index.ts @@ -8,18 +8,10 @@ import type { import { toRemarkInitializeAstroData } from './frontmatter-injection.js'; import { loadPlugins } from './load-plugins.js'; import { rehypeHeadingIds } from './rehype-collect-headings.js'; -import rehypeEscape from './rehype-escape.js'; -import rehypeExpressions from './rehype-expressions.js'; -import rehypeIslands from './rehype-islands.js'; -import rehypeJsx from './rehype-jsx.js'; import toRemarkContentRelImageError from './remark-content-rel-image-error.js'; -import remarkEscape from './remark-escape.js'; -import remarkMarkAndUnravel from './remark-mark-and-unravel.js'; -import remarkMdxish from './remark-mdxish.js'; import remarkPrism from './remark-prism.js'; import scopedStyles from './remark-scoped-styles.js'; import remarkShiki from './remark-shiki.js'; -import remarkUnwrap from './remark-unwrap.js'; import rehypeRaw from 'rehype-raw'; import rehypeStringify from 'rehype-stringify'; @@ -61,7 +53,6 @@ export async function renderMarkdown( remarkRehype = markdownConfigDefaults.remarkRehype, gfm = markdownConfigDefaults.gfm, smartypants = markdownConfigDefaults.smartypants, - isAstroFlavoredMd = false, isExperimentalContentCollections = false, contentDir, frontmatter: userFrontmatter = {}, @@ -72,7 +63,7 @@ export async function renderMarkdown( let parser = unified() .use(markdown) .use(toRemarkInitializeAstroData({ userFrontmatter })) - .use(isAstroFlavoredMd ? [remarkMdxish, remarkMarkAndUnravel, remarkUnwrap, remarkEscape] : []); + .use([]); if (gfm) { parser.use(remarkGfm); @@ -109,15 +100,7 @@ export async function renderMarkdown( markdownToHtml as any, { allowDangerousHtml: true, - passThrough: isAstroFlavoredMd - ? [ - 'raw', - 'mdxFlowExpression', - 'mdxJsxFlowElement', - 'mdxJsxTextElement', - 'mdxTextExpression', - ] - : [], + passThrough: [], ...remarkRehype, }, ], @@ -127,13 +110,7 @@ export async function renderMarkdown( parser.use([[plugin, pluginOpts]]); }); - parser - .use( - isAstroFlavoredMd - ? [rehypeJsx, rehypeExpressions, rehypeEscape, rehypeIslands, rehypeHeadingIds] - : [rehypeHeadingIds, rehypeRaw] - ) - .use(rehypeStringify, { allowDangerousHtml: true }); + parser.use([rehypeHeadingIds, rehypeRaw]).use(rehypeStringify, { allowDangerousHtml: true }); let vfile: MarkdownVFile; try { diff --git a/packages/markdown/remark/src/mdast-util-mdxish.ts b/packages/markdown/remark/src/mdast-util-mdxish.ts deleted file mode 100644 index 10b19f5be..000000000 --- a/packages/markdown/remark/src/mdast-util-mdxish.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { mdxExpressionFromMarkdown, mdxExpressionToMarkdown } from 'mdast-util-mdx-expression'; -import { mdxJsxFromMarkdown, mdxJsxToMarkdown } from 'mdast-util-mdx-jsx'; - -export function mdxFromMarkdown(): any { - return [mdxExpressionFromMarkdown, mdxJsxFromMarkdown]; -} - -export function mdxToMarkdown(): any { - return { - extensions: [mdxExpressionToMarkdown, mdxJsxToMarkdown], - }; -} diff --git a/packages/markdown/remark/src/mdxjs.ts b/packages/markdown/remark/src/mdxjs.ts deleted file mode 100644 index c3a9849ea..000000000 --- a/packages/markdown/remark/src/mdxjs.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Note: The code in this file is based on `micromark-extension-mdxjs` -// and was adapted to use our fork `@astrojs/micromark-extension-mdx-jsx` -// instead of `micromark-extension-mdx-jsx` to allow some extended syntax. -// See `@astrojs/micromark-extension-mdx-jsx` on NPM for more details. -// Also, support for ESM imports & exports in Markdown content was removed. - -import { mdxJsx } from '@astrojs/micromark-extension-mdx-jsx'; -import { Parser } from 'acorn'; -import acornJsx from 'acorn-jsx'; -import type { Options } from 'micromark-extension-mdx-expression'; -import { mdxExpression } from 'micromark-extension-mdx-expression'; -import { mdxMd } from 'micromark-extension-mdx-md'; -import { combineExtensions } from 'micromark-util-combine-extensions'; -import type { Extension } from 'micromark-util-types'; - -export function mdxjs(options: Options): Extension { - const settings: any = Object.assign( - { - acorn: Parser.extend(acornJsx()), - acornOptions: { ecmaVersion: 2020, sourceType: 'module' }, - addResult: true, - }, - options - ); - - return combineExtensions([mdxExpression(settings), mdxJsx(settings), mdxMd]); -} diff --git a/packages/markdown/remark/src/rehype-collect-headings.ts b/packages/markdown/remark/src/rehype-collect-headings.ts index 03a3c6a23..142f796d6 100644 --- a/packages/markdown/remark/src/rehype-collect-headings.ts +++ b/packages/markdown/remark/src/rehype-collect-headings.ts @@ -21,7 +21,6 @@ export function rehypeHeadingIds(): ReturnType<RehypePlugin> { const depth = Number.parseInt(level); let text = ''; - let isJSX = false; visit(node, (child, __, parent) => { if (child.type === 'element' || parent == null) { return; @@ -36,31 +35,17 @@ export function rehypeHeadingIds(): ReturnType<RehypePlugin> { text += child.value; } else { text += child.value.replace(/\{/g, '${'); - isJSX = isJSX || child.value.includes('{'); } } }); node.properties = node.properties || {}; if (typeof node.properties.id !== 'string') { - if (isJSX) { - // HACK: serialized JSX from internal plugins, ignore these for slug - const raw = toHtml(node.children, { allowDangerousHtml: true }) - .replace(/\n(<)/g, '<') - .replace(/(>)\n/g, '>'); - // HACK: for ids that have JSX content, use $$slug helper to generate slug at runtime - node.properties.id = `$$slug(\`${text}\`)`; - (node as any).type = 'raw'; - ( - node as any - ).value = `<${node.tagName} id={${node.properties.id}}>${raw}</${node.tagName}>`; - } else { - let slug = slugger.slug(text); + let slug = slugger.slug(text); - if (slug.endsWith('-')) slug = slug.slice(0, -1); + if (slug.endsWith('-')) slug = slug.slice(0, -1); - node.properties.id = slug; - } + node.properties.id = slug; } headings.push({ depth, slug: node.properties.id, text }); diff --git a/packages/markdown/remark/src/rehype-escape.ts b/packages/markdown/remark/src/rehype-escape.ts deleted file mode 100644 index a4cc32cf7..000000000 --- a/packages/markdown/remark/src/rehype-escape.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { SKIP, visit } from 'unist-util-visit'; - -export function escapeEntities(value: string): string { - return value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); -} - -export default function rehypeEscape(): any { - return function (node: any): any { - return visit(node, 'element', (el) => { - if (el.tagName === 'code' || el.tagName === 'pre') { - el.properties['is:raw'] = true; - // Visit all raw children and escape HTML tags to prevent Markdown code - // like "This is a `<script>` tag" from actually opening a script tag - visit(el, 'raw', (raw) => { - raw.value = escapeEntities(raw.value); - }); - // Do not visit children to prevent double escaping - return SKIP; - } - }); - }; -} diff --git a/packages/markdown/remark/src/rehype-expressions.ts b/packages/markdown/remark/src/rehype-expressions.ts deleted file mode 100644 index f06f242e2..000000000 --- a/packages/markdown/remark/src/rehype-expressions.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { map } from 'unist-util-map'; - -export default function rehypeExpressions(): any { - return function (node: any): any { - return map(node, (child) => { - if (child.type === 'text') { - return { ...child, type: 'raw' }; - } - if (child.type === 'mdxTextExpression') { - return { type: 'raw', value: `{${(child as any).value}}` }; - } - if (child.type === 'mdxFlowExpression') { - return { type: 'raw', value: `{${(child as any).value}}` }; - } - return child; - }); - }; -} diff --git a/packages/markdown/remark/src/rehype-islands.ts b/packages/markdown/remark/src/rehype-islands.ts deleted file mode 100644 index a8b78848d..000000000 --- a/packages/markdown/remark/src/rehype-islands.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { SKIP, visit as _visit } from 'unist-util-visit'; - -// This is a workaround. -// It fixes a compatibility issue between different, incompatible ASTs given by plugins to Unist -const visit = _visit as ( - node: any, - type: string, - callback?: (node: any, index: number, parent: any) => any -) => any; - -// This fixes some confusing bugs coming from somewhere inside of our Markdown pipeline. -// `unist`/`remark`/`rehype` (not sure) often generate malformed HTML inside of <astro-island> -// For hydration to work properly, frameworks need the DOM to be the exact same on server/client. -// This reverts some "helpful corrections" that are applied to our perfectly valid HTML! -export default function rehypeIslands(): any { - return function (node: any): any { - return visit(node, 'element', (el) => { - // Bugs only happen inside of <astro-island> islands - if (el.tagName == 'astro-island') { - visit(el, 'text', (child, index, parent) => { - if (child.type === 'text') { - // Sometimes comments can be trapped as text, which causes them to be escaped - // This casts them back to real HTML comments - if (parent && child.value.indexOf('<!--') > -1 && index != null) { - parent.children.splice(index, 1, { - ...child, - type: 'comment', - value: child.value.replace('<!--', '').replace('-->', '').trim(), - }); - return [SKIP, index]; - } - // For some reason `rehype` likes to inject extra linebreaks, - // but React and Vue throw hydration errors when they see these! - // This removes any extra linebreaks, which is fine because - // framework compilers don't preserve them anyway - child.value = child.value.replace(/\n+/g, ''); - return child; - } - }); - } - }); - }; -} diff --git a/packages/markdown/remark/src/rehype-jsx.ts b/packages/markdown/remark/src/rehype-jsx.ts deleted file mode 100644 index 7082997e2..000000000 --- a/packages/markdown/remark/src/rehype-jsx.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { visit } from 'unist-util-visit'; -import type { RehypePlugin } from './types.js'; - -const MDX_ELEMENTS = ['mdxJsxFlowElement', 'mdxJsxTextElement']; - -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 = node.attributes.reduce((acc: any[], entry: any) => { - let attr = entry.value; - if (attr && typeof attr === 'object') { - attr = `{${attr.value}}`; - } else if (attr && entry.type === 'mdxJsxExpressionAttribute') { - attr = `{${attr}}`; - } else if (attr === null) { - attr = ''; - } else if (typeof attr === 'string') { - attr = `"${attr}"`; - } - if (!entry.name) { - return acc + ` ${attr}`; - } - return acc + ` ${entry.name}${attr ? '=' : ''}${attr}`; - }, ''); - - if (node.children.length === 0) { - node.type = 'raw'; - node.value = `<${node.name}${attrs} />`; - return; - } - - // 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: `<${node.name}${attrs}>`, - }; - const closingTag = { - type: 'raw', - value: `</${node.name}>`, - }; - parent.children.splice(index, 1, openingTag, ...node.children, closingTag); - }); - }; -} diff --git a/packages/markdown/remark/src/remark-escape.ts b/packages/markdown/remark/src/remark-escape.ts deleted file mode 100644 index 84cdf2efa..000000000 --- a/packages/markdown/remark/src/remark-escape.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Literal } from 'unist'; -import { visit } from 'unist-util-visit'; - -// In code blocks, this removes the JS comment wrapper added to -// HTML comments by vite-plugin-markdown-legacy. -export default function remarkEscape() { - return (tree: any) => { - visit(tree, 'code', removeCommentWrapper); - visit(tree, 'inlineCode', removeCommentWrapper); - }; - - function removeCommentWrapper(node: Literal<string>) { - node.value = node.value.replace(/{\/\*<!--/gs, '<!--').replace(/-->\*\/}/gs, '-->'); - } -} diff --git a/packages/markdown/remark/src/remark-mark-and-unravel.ts b/packages/markdown/remark/src/remark-mark-and-unravel.ts deleted file mode 100644 index 294d4211d..000000000 --- a/packages/markdown/remark/src/remark-mark-and-unravel.ts +++ /dev/null @@ -1,72 +0,0 @@ -// https://github.com/mdx-js/mdx/blob/main/packages/mdx/lib/plugin/remark-mark-and-unravel.js -/** - * @typedef {import('mdast').Root} Root - * @typedef {import('mdast').Content} Content - * @typedef {Root|Content} Node - * @typedef {Extract<Node, import('unist').Parent>} Parent - * - * @typedef {import('remark-mdx')} DoNotTouchAsThisImportItIncludesMdxInTree - */ - -import { visit } from 'unist-util-visit'; - -/** - * A tiny plugin that unravels `<p><h1>x</h1></p>` but also - * `<p><Component /></p>` (so it has no knowledge of “HTML”). - * It also marks JSX as being explicitly JSX, so when a user passes a `h1` - * component, it is used for `# heading` but not for `<h1>heading</h1>`. - * - * @type {import('unified').Plugin<Array<void>, Root>} - */ -export default function remarkMarkAndUnravel() { - return (tree: any) => { - visit(tree, (node, index, parent_) => { - const parent = /** @type {Parent} */ parent_; - let offset = -1; - let all = true; - /** @type {boolean|undefined} */ - let oneOrMore; - - if (parent && typeof index === 'number' && node.type === 'paragraph') { - const children = node.children; - - while (++offset < children.length) { - const child = children[offset]; - - if (child.type === 'mdxJsxTextElement' || child.type === 'mdxTextExpression') { - oneOrMore = true; - } else if (child.type === 'text' && /^[\t\r\n ]+$/.test(String(child.value))) { - // Empty. - } else { - all = false; - break; - } - } - - if (all && oneOrMore) { - offset = -1; - - while (++offset < children.length) { - const child = children[offset]; - - if (child.type === 'mdxJsxTextElement') { - child.type = 'mdxJsxFlowElement'; - } - - if (child.type === 'mdxTextExpression') { - child.type = 'mdxFlowExpression'; - } - } - - parent.children.splice(index, 1, ...children); - return index; - } - } - - if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') { - const data = node.data || (node.data = {}); - data._mdxExplicitJsx = true; - } - }); - }; -} diff --git a/packages/markdown/remark/src/remark-mdxish.ts b/packages/markdown/remark/src/remark-mdxish.ts deleted file mode 100644 index 0f70f87b3..000000000 --- a/packages/markdown/remark/src/remark-mdxish.ts +++ /dev/null @@ -1,61 +0,0 @@ -import type * as fromMarkdown from 'mdast-util-from-markdown'; -import type { Tag } from 'mdast-util-mdx-jsx'; -import { mdxFromMarkdown, mdxToMarkdown } from './mdast-util-mdxish.js'; -import { mdxjs } from './mdxjs.js'; - -// Prepare markdown extensions once to prevent performance issues -const extMdxJs = mdxjs({}); -const extMdxFromMarkdown = makeFromMarkdownLessStrict(mdxFromMarkdown()); -const extMdxToMarkdown = mdxToMarkdown(); - -export default function remarkMdxish(this: any) { - const data = this.data(); - - add('micromarkExtensions', extMdxJs); - add('fromMarkdownExtensions', extMdxFromMarkdown); - add('toMarkdownExtensions', extMdxToMarkdown); - - function add(field: string, value: unknown) { - const list = data[field] ? data[field] : (data[field] = []); - list.push(value); - } -} - -function makeFromMarkdownLessStrict(extensions: fromMarkdown.Extension[]) { - extensions.forEach((extension) => { - // Fix exit handlers that are too strict - ['mdxJsxFlowTag', 'mdxJsxTextTag'].forEach((exitHandler) => { - if (!extension.exit || !extension.exit[exitHandler]) return; - extension.exit[exitHandler] = chainHandlers(fixSelfClosing, extension.exit[exitHandler]); - }); - }); - - return extensions; -} - -const selfClosingTags = new Set([ - 'area', - 'base', - 'br', - 'col', - 'embed', - 'hr', - 'img', - 'input', - 'link', - 'meta', - 'source', - 'track', - 'wbr', -]); - -function fixSelfClosing(this: fromMarkdown.CompileContext) { - const tag = this.getData('mdxJsxTag') as Tag; - if (tag.name && selfClosingTags.has(tag.name)) tag.selfClosing = true; -} - -function chainHandlers(...handlers: fromMarkdown.Handle[]) { - return function handlerChain(this: fromMarkdown.CompileContext, token: fromMarkdown.Token) { - handlers.forEach((handler) => handler.call(this, token)); - }; -} diff --git a/packages/markdown/remark/src/remark-unwrap.ts b/packages/markdown/remark/src/remark-unwrap.ts deleted file mode 100644 index 399bd6cd6..000000000 --- a/packages/markdown/remark/src/remark-unwrap.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { SKIP, visit as _visit } from 'unist-util-visit'; - -// This is a workaround. -// It fixes a compatibility issue between different, incompatible ASTs given by plugins to Unist -const visit = _visit as ( - node: any, - type: string, - callback?: (node: any, index: number, parent: any) => any -) => any; - -// Remove the wrapping paragraph for <astro-island> islands -export default function remarkUnwrap() { - const astroRootNodes = new Set(); - let insideAstroRoot = false; - - return (tree: any) => { - // reset state - insideAstroRoot = false; - astroRootNodes.clear(); - - visit(tree, 'html', (node) => { - if (node.value.indexOf('<astro-island') > -1 && !insideAstroRoot) { - insideAstroRoot = true; - } - if (node.value.indexOf('</astro-island') > -1 && insideAstroRoot) { - insideAstroRoot = false; - } - astroRootNodes.add(node); - }); - - visit(tree, 'paragraph', (node, index, parent) => { - if (parent && typeof index === 'number' && containsAstroRootNode(node)) { - parent.children.splice(index, 1, ...node.children); - return [SKIP, index]; - } - }); - }; - - function containsAstroRootNode(node: any) { - return node.children - .map((child: any) => astroRootNodes.has(child)) - .reduce((all: boolean, v: boolean) => (all ? all : v), false); - } -} diff --git a/packages/markdown/remark/src/types.ts b/packages/markdown/remark/src/types.ts index d5133aaf0..40b2ac841 100644 --- a/packages/markdown/remark/src/types.ts +++ b/packages/markdown/remark/src/types.ts @@ -58,7 +58,6 @@ export interface MarkdownRenderingOptions extends AstroMarkdownOptions { $?: { scopedClassName: string | null; }; - isAstroFlavoredMd?: boolean; /** Used to prevent relative image imports from `src/content/` */ isExperimentalContentCollections?: boolean; /** Used to prevent relative image imports from `src/content/` */ |