summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/poor-chicken-film.md5
-rw-r--r--packages/astro/src/vite-plugin-markdown/index.ts1
-rw-r--r--packages/markdown/remark/package.json10
-rw-r--r--packages/markdown/remark/src/index.ts29
-rw-r--r--packages/markdown/remark/src/mdast-util-mdxish.ts12
-rw-r--r--packages/markdown/remark/src/mdxjs.ts27
-rw-r--r--packages/markdown/remark/src/rehype-collect-headings.ts21
-rw-r--r--packages/markdown/remark/src/rehype-escape.ts22
-rw-r--r--packages/markdown/remark/src/rehype-expressions.ts18
-rw-r--r--packages/markdown/remark/src/rehype-islands.ts43
-rw-r--r--packages/markdown/remark/src/rehype-jsx.ts65
-rw-r--r--packages/markdown/remark/src/remark-escape.ts15
-rw-r--r--packages/markdown/remark/src/remark-mark-and-unravel.ts72
-rw-r--r--packages/markdown/remark/src/remark-mdxish.ts61
-rw-r--r--packages/markdown/remark/src/remark-unwrap.ts44
-rw-r--r--packages/markdown/remark/src/types.ts1
-rw-r--r--packages/markdown/remark/test/autolinking.test.js72
-rw-r--r--packages/markdown/remark/test/components.test.js78
-rw-r--r--packages/markdown/remark/test/entities.test.js15
-rw-r--r--packages/markdown/remark/test/expressions.test.js125
-rw-r--r--packages/markdown/remark/test/strictness.test.js98
-rw-r--r--pnpm-lock.yaml20
22 files changed, 12 insertions, 842 deletions
diff --git a/.changeset/poor-chicken-film.md b/.changeset/poor-chicken-film.md
new file mode 100644
index 000000000..ecbc3b44c
--- /dev/null
+++ b/.changeset/poor-chicken-film.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/markdown-remark': major
+---
+
+Drop support for legacy Astro-flavored Markdown
diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts
index 10e4cb8c0..34ed3647b 100644
--- a/packages/astro/src/vite-plugin-markdown/index.ts
+++ b/packages/astro/src/vite-plugin-markdown/index.ts
@@ -71,7 +71,6 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
const renderResult = await renderMarkdown(raw.content, {
...settings.config.markdown,
fileURL: new URL(`file://${fileId}`),
- isAstroFlavoredMd: false,
isExperimentalContentCollections: settings.config.experimental.contentCollections,
contentDir: getContentPaths(settings.config).contentDir,
frontmatter: raw.data,
diff --git a/packages/markdown/remark/package.json b/packages/markdown/remark/package.json
index 8e60a06c3..f8d2ec35e 100644
--- a/packages/markdown/remark/package.json
+++ b/packages/markdown/remark/package.json
@@ -25,19 +25,11 @@
"test": "mocha --exit --timeout 20000"
},
"dependencies": {
- "@astrojs/micromark-extension-mdx-jsx": "^1.0.3",
"@astrojs/prism": "^1.0.0",
"acorn": "^8.7.1",
- "acorn-jsx": "^5.3.2",
"github-slugger": "^1.4.0",
"hast-util-to-html": "^8.0.3",
"import-meta-resolve": "^2.1.0",
- "mdast-util-from-markdown": "^1.2.0",
- "mdast-util-mdx-expression": "^1.2.1",
- "mdast-util-mdx-jsx": "^1.2.0",
- "micromark-extension-mdx-expression": "^1.0.3",
- "micromark-extension-mdx-md": "^1.0.0",
- "micromark-util-combine-extensions": "^1.0.0",
"rehype-raw": "^6.1.1",
"rehype-stringify": "^9.0.3",
"remark-gfm": "^3.0.1",
@@ -46,7 +38,6 @@
"remark-smartypants": "^2.0.0",
"shiki": "^0.11.1",
"unified": "^10.1.2",
- "unist-util-map": "^3.1.1",
"unist-util-visit": "^4.1.0",
"vfile": "^5.3.2"
},
@@ -59,7 +50,6 @@
"@types/unist": "^2.0.6",
"astro-scripts": "workspace:*",
"chai": "^4.3.6",
- "micromark-util-types": "^1.0.2",
"mocha": "^9.2.2"
}
}
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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
-}
-
-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/` */
diff --git a/packages/markdown/remark/test/autolinking.test.js b/packages/markdown/remark/test/autolinking.test.js
index c5cd64657..48bf894be 100644
--- a/packages/markdown/remark/test/autolinking.test.js
+++ b/packages/markdown/remark/test/autolinking.test.js
@@ -33,76 +33,4 @@ describe('autolinking', () => {
);
});
});
-
- describe('astro-flavored md', () => {
- const renderAstroMd = (text) => renderMarkdown(text, { isAstroFlavoredMd: true });
-
- it('does not autolink URLs in code blocks', async () => {
- const { code } = await renderAstroMd(
- 'See `https://example.com` or `www.example.com` for more.',
- {}
- );
-
- chai
- .expect(code.trim())
- .to.equal(
- `<p>See <code is:raw>https://example.com</code> or ` +
- `<code is:raw>www.example.com</code> for more.</p>`
- );
- });
-
- it('does not autolink URLs in fenced code blocks', async () => {
- const { code } = await renderAstroMd(
- 'Example:\n```\nGo to https://example.com or www.example.com now.\n```'
- );
-
- chai
- .expect(code)
- .to.contain(`<pre is:raw`)
- .to.contain(`Go to https://example.com or www.example.com now.`);
- });
-
- it('does not autolink URLs starting with a protocol when nested inside links', async () => {
- const { code } = await renderAstroMd(
- `See [http://example.com](http://example.com) or ` +
- `<a test href="https://example.com">https://example.com</a>`
- );
-
- chai
- .expect(code.replace(/\n/g, ''))
- .to.equal(
- `<p>See <a href="http://example.com">http://example.com</a> or ` +
- `<a test href="https://example.com">https://example.com</a></p>`
- );
- });
-
- it('does not autolink URLs starting with "www." when nested inside links', async () => {
- const { code } = await renderAstroMd(
- `See [www.example.com](https://www.example.com) or ` +
- `<a test href="https://www.example.com">www.example.com</a>`
- );
-
- chai
- .expect(code.replace(/\n/g, ''))
- .to.equal(
- `<p>See <a href="https://www.example.com">www.example.com</a> or ` +
- `<a test href="https://www.example.com">www.example.com</a></p>`
- );
- });
-
- it('does not autolink URLs when nested several layers deep inside links', async () => {
- const { code } = await renderAstroMd(
- `<a href="https://www.example.com">**Visit _our www.example.com or ` +
- `http://localhost pages_ for more!**</a>`
- );
-
- chai
- .expect(code.replace(/\n/g, ''))
- .to.equal(
- `<a href="https://www.example.com"><strong>` +
- `Visit <em>our www.example.com or http://localhost pages</em> for more!` +
- `</strong></a>`
- );
- });
- });
});
diff --git a/packages/markdown/remark/test/components.test.js b/packages/markdown/remark/test/components.test.js
deleted file mode 100644
index e60469426..000000000
--- a/packages/markdown/remark/test/components.test.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import { renderMarkdown } from '../dist/index.js';
-import chai from 'chai';
-
-describe('components', () => {
- const renderAstroMd = (text) => renderMarkdown(text, { isAstroFlavoredMd: true });
-
- it('should be able to serialize string', async () => {
- const { code } = await renderAstroMd(`<Component str="cool!" />`);
-
- chai.expect(code).to.equal(`<Component str="cool!" />`);
- });
-
- it('should be able to serialize boolean attribute', async () => {
- const { code } = await renderAstroMd(`<Component bool={true} />`);
-
- chai.expect(code).to.equal(`<Component bool={true} />`);
- });
-
- it('should be able to serialize array', async () => {
- const { code } = await renderAstroMd(`<Component prop={["a", "b", "c"]} />`);
-
- chai.expect(code).to.equal(`<Component prop={["a", "b", "c"]} />`);
- });
-
- it('should be able to serialize object', async () => {
- const { code } = await renderAstroMd(`<Component prop={{ a: 0, b: 1, c: 2 }} />`);
-
- chai.expect(code).to.equal(`<Component prop={{ a: 0, b: 1, c: 2 }} />`);
- });
-
- it('should be able to serialize empty attribute', async () => {
- const { code } = await renderAstroMd(`<Component empty />`);
-
- chai.expect(code).to.equal(`<Component empty />`);
- });
-
- // Notable omission: shorthand attribute
-
- it('should be able to serialize spread attribute', async () => {
- const { code } = await renderAstroMd(`<Component {...spread} />`);
-
- chai.expect(code).to.equal(`<Component {...spread} />`);
- });
-
- it('should allow client:* directives', async () => {
- const { code } = await renderAstroMd(`<Component client:load />`);
-
- chai.expect(code).to.equal(`<Component client:load />`);
- });
-
- it('should normalize children', async () => {
- const { code } = await renderAstroMd(`<Component bool={true}>Hello world!</Component>`);
-
- chai.expect(code).to.equal(`<Component bool={true}>Hello world!</Component>`);
- });
-
- it('should be able to nest components', async () => {
- const { code } = await renderAstroMd(
- `<Component bool={true}><Component>Hello world!</Component></Component>`,
- {}
- );
-
- chai
- .expect(code)
- .to.equal(`<Component bool={true}><Component>Hello world!</Component></Component>`);
- });
-
- it('should allow markdown without many spaces', async () => {
- const { code } = await renderAstroMd(
- `<Component>
-# Hello world!
-</Component>`,
- {}
- );
-
- chai.expect(code).to.equal(`<Component><h1 id="hello-world">Hello world!</h1></Component>`);
- });
-});
diff --git a/packages/markdown/remark/test/entities.test.js b/packages/markdown/remark/test/entities.test.js
index b7d551d72..d35ed3a89 100644
--- a/packages/markdown/remark/test/entities.test.js
+++ b/packages/markdown/remark/test/entities.test.js
@@ -3,21 +3,8 @@ import { expect } from 'chai';
describe('entities', () => {
it('should not unescape entities in regular Markdown', async () => {
- const { code } = await renderMarkdown(`&lt;i&gt;This should NOT be italic&lt;/i&gt;`, {
- isAstroFlavoredMd: false,
- });
+ const { code } = await renderMarkdown(`&lt;i&gt;This should NOT be italic&lt;/i&gt;`, {});
expect(code).to.equal(`<p>&#x3C;i>This should NOT be italic&#x3C;/i></p>`);
});
-
- it('should not escape entities in code blocks twice in Astro-flavored markdown', async () => {
- const { code } = await renderMarkdown(`\`\`\`astro\n<h1>{x && x.name || ''}!</h1>\n\`\`\``, {
- isAstroFlavoredMd: true,
- syntaxHighlight: false,
- });
-
- expect(code).to.equal(
- `<pre is:raw><code class="language-astro">&lt;h1&gt;{x &amp;&amp; x.name || ''}!&lt;/h1&gt;\n</code></pre>`
- );
- });
});
diff --git a/packages/markdown/remark/test/expressions.test.js b/packages/markdown/remark/test/expressions.test.js
deleted file mode 100644
index b2cb1a73d..000000000
--- a/packages/markdown/remark/test/expressions.test.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import { renderMarkdown } from '../dist/index.js';
-import chai from 'chai';
-
-describe('expressions', () => {
- const renderAstroMd = (text, opts) => renderMarkdown(text, { isAstroFlavoredMd: true, ...opts });
-
- it('should be able to serialize bare expression', async () => {
- const { code } = await renderAstroMd(`{a}`, {});
-
- chai.expect(code).to.equal(`{a}`);
- });
-
- it('should be able to serialize expression inside component', async () => {
- const { code } = await renderAstroMd(`<Component>{a}</Component>`, {});
-
- chai.expect(code).to.equal(`<Component>{a}</Component>`);
- });
-
- it('should be able to serialize expression inside markdown', async () => {
- const { code } = await renderAstroMd(`# {frontmatter.title}`, {});
-
- chai
- .expect(code)
- .to.equal(`<h1 id={$$slug(\`\${frontmatter.title}\`)}>{frontmatter.title}</h1>`);
- });
-
- it('should be able to serialize complex expression inside markdown', async () => {
- const { code } = await renderAstroMd(`# Hello {frontmatter.name}`, {});
-
- chai
- .expect(code)
- .to.equal(`<h1 id={$$slug(\`Hello \${frontmatter.name}\`)}>Hello {frontmatter.name}</h1>`);
- });
-
- it('should be able to serialize complex expression with markup inside markdown', async () => {
- const { code } = await renderAstroMd(`# Hello <span>{frontmatter.name}</span>`, {});
-
- chai
- .expect(code)
- .to.equal(
- `<h1 id={$$slug(\`Hello \${frontmatter.name}\`)}>Hello <span>{frontmatter.name}</span></h1>`
- );
- });
-
- it('should be able to avoid evaluating JSX-like expressions in an inline code & generate a slug for id', async () => {
- const { code } = await renderAstroMd(`# \`{frontmatter.title}\``, {});
-
- chai
- .expect(code)
- .to.equal('<h1 id="frontmattertitle"><code is:raw>{frontmatter.title}</code></h1>');
- });
-
- it('should be able to avoid evaluating JSX-like expressions in inline codes', async () => {
- const { code } = await renderAstroMd(`# \`{ foo }\` is a shorthand for \`{ foo: foo }\``, {});
-
- chai
- .expect(code)
- .to.equal(
- '<h1 id="-foo--is-a-shorthand-for--foo-foo"><code is:raw>{ foo }</code> is a shorthand for <code is:raw>{ foo: foo }</code></h1>'
- );
- });
-
- it('should be able to avoid evaluating JSX-like expressions & escape HTML tag characters in inline codes', async () => {
- const { code } = await renderAstroMd(
- `###### \`{}\` is equivalent to \`Record<never, never>\` <small>(at TypeScript v{frontmatter.version})</small>`,
- {}
- );
-
- chai
- .expect(code)
- .to.equal(
- `<h6 id={$$slug(\`{} is equivalent to Record&lt;never, never&gt; (at TypeScript v\${frontmatter.version})\`)}><code is:raw>{}</code> is equivalent to <code is:raw>Record&lt;never, never&gt;</code> <small>(at TypeScript v{frontmatter.version})</small></h6>`
- );
- });
-
- it('should be able to encode ampersand characters in code blocks', async () => {
- const { code } = await renderAstroMd(
- 'The ampersand in `&nbsp;` must be encoded in code blocks.',
- {}
- );
-
- chai
- .expect(code)
- .to.equal(
- '<p>The ampersand in <code is:raw>&amp;nbsp;</code> must be encoded in code blocks.</p>'
- );
- });
-
- it('should be able to encode ampersand characters in fenced code blocks', async () => {
- const { code } = await renderAstroMd(`
- \`\`\`md
- The ampersand in \`&nbsp;\` must be encoded in code blocks.
- \`\`\`
- `);
-
- chai.expect(code).to.match(/^<pre is:raw.*<code>.*The ampersand in `&amp;nbsp;`/);
- });
-
- it('should be able to serialize function expression', async () => {
- const { code } = await renderAstroMd(
- `{frontmatter.list.map(item => <p id={item}>{item}</p>)}`,
- {}
- );
-
- chai.expect(code).to.equal(`{frontmatter.list.map(item => <p id={item}>{item}</p>)}`);
- });
-
- it('should unwrap HTML comments in inline code blocks', async () => {
- const { code } = await renderAstroMd(`\`{/*<!-- HTML comment -->*/}\``);
-
- chai.expect(code).to.equal('<p><code is:raw>&lt;!-- HTML comment --&gt;</code></p>');
- });
-
- it('should unwrap HTML comments in code fences', async () => {
- const { code } = await renderAstroMd(
- `
- \`\`\`
- <!-- HTML comment -->
- \`\`\`
- `
- );
-
- chai.expect(code).to.match(/(?<!{\/\*)&lt;!-- HTML comment --&gt;(?!\*\/})/);
- });
-});
diff --git a/packages/markdown/remark/test/strictness.test.js b/packages/markdown/remark/test/strictness.test.js
deleted file mode 100644
index 324415c6a..000000000
--- a/packages/markdown/remark/test/strictness.test.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import { renderMarkdown } from '../dist/index.js';
-import chai from 'chai';
-
-describe('strictness in Astro-flavored markdown', () => {
- const renderAstroMd = (text, opts) => renderMarkdown(text, { isAstroFlavoredMd: true, ...opts });
-
- it('should allow self-closing HTML tags (void elements)', async () => {
- const { code } = await renderAstroMd(
- `Use self-closing void elements<br>like word<wbr>break and images: <img src="hi.jpg">`,
- {}
- );
-
- chai
- .expect(code)
- .to.equal(
- `<p>Use self-closing void elements<br />like word<wbr />break and images: ` +
- `<img src="hi.jpg" /></p>`
- );
- });
-
- it('should allow attribute names starting with ":" after element names', async () => {
- const { code } = await renderAstroMd(`<div :class="open ? '' : 'hidden'">Test</div>`, {});
-
- chai.expect(code.trim()).to.equal(`<div :class="open ? '' : 'hidden'">Test</div>`);
- });
-
- it('should allow attribute names starting with ":" after local element names', async () => {
- const { code } = await renderAstroMd(`<div.abc :class="open ? '' : 'hidden'">x</div.abc>`, {});
-
- chai.expect(code.trim()).to.equal(`<div.abc :class="open ? '' : 'hidden'">x</div.abc>`);
- });
-
- it('should allow attribute names starting with ":" after attribute names', async () => {
- const { code } = await renderAstroMd(`<input type="text" disabled :placeholder="hi">`, {});
-
- chai.expect(code.trim()).to.equal(`<input type="text" disabled :placeholder="hi" />`);
- });
-
- it('should allow attribute names starting with ":" after local attribute names', async () => {
- const { code } = await renderAstroMd(
- `<input type="text" x-test:disabled :placeholder="hi">`,
- {}
- );
-
- chai.expect(code.trim()).to.equal(`<input type="text" x-test:disabled :placeholder="hi" />`);
- });
-
- it('should allow attribute names starting with ":" after attribute values', async () => {
- const { code } = await renderAstroMd(`<input type="text" :placeholder="placeholder">`, {});
-
- chai.expect(code.trim()).to.equal(`<input type="text" :placeholder="placeholder" />`);
- });
-
- it('should allow attribute names starting with "@" after element names', async () => {
- const { code } = await renderAstroMd(`<button @click="handleClick">Test</button>`, {});
-
- chai.expect(code.trim()).to.equal(`<button @click="handleClick">Test</button>`);
- });
-
- it('should allow attribute names starting with "@" after local element names', async () => {
- const { code } = await renderAstroMd(
- `<button.local @click="handleClick">Test</button.local>`,
- {}
- );
-
- chai.expect(code.trim()).to.equal(`<button.local @click="handleClick">Test</button.local>`);
- });
-
- it('should allow attribute names starting with "@" after attribute names', async () => {
- const { code } = await renderAstroMd(`<button disabled @click="handleClick">Test</button>`, {});
-
- chai.expect(code.trim()).to.equal(`<button disabled @click="handleClick">Test</button>`);
- });
-
- it('should allow attribute names starting with "@" after local attribute names', async () => {
- const { code } = await renderAstroMd(
- `<button x-test:disabled @click="handleClick">Test</button>`,
- {}
- );
-
- chai.expect(code.trim()).to.equal(`<button x-test:disabled @click="handleClick">Test</button>`);
- });
-
- it('should allow attribute names starting with "@" after attribute values', async () => {
- const { code } = await renderAstroMd(
- `<button type="submit" @click="handleClick">Test</button>`,
- {}
- );
-
- chai.expect(code.trim()).to.equal(`<button type="submit" @click="handleClick">Test</button>`);
- });
-
- it('should allow attribute names containing dots', async () => {
- const { code } = await renderAstroMd(`<input x-on:input.debounce.500ms="fetchResults">`, {});
-
- chai.expect(code.trim()).to.equal(`<input x-on:input.debounce.500ms="fetchResults" />`);
- });
-});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 43cb19094..64e0f0b3c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3462,7 +3462,6 @@ importers:
packages/markdown/remark:
specifiers:
- '@astrojs/micromark-extension-mdx-jsx': ^1.0.3
'@astrojs/prism': ^1.0.0
'@types/chai': ^4.3.1
'@types/github-slugger': ^1.3.0
@@ -3471,19 +3470,11 @@ importers:
'@types/mocha': ^9.1.1
'@types/unist': ^2.0.6
acorn: ^8.7.1
- acorn-jsx: ^5.3.2
astro-scripts: workspace:*
chai: ^4.3.6
github-slugger: ^1.4.0
hast-util-to-html: ^8.0.3
import-meta-resolve: ^2.1.0
- mdast-util-from-markdown: ^1.2.0
- mdast-util-mdx-expression: ^1.2.1
- mdast-util-mdx-jsx: ^1.2.0
- micromark-extension-mdx-expression: ^1.0.3
- micromark-extension-mdx-md: ^1.0.0
- micromark-util-combine-extensions: ^1.0.0
- micromark-util-types: ^1.0.2
mocha: ^9.2.2
rehype-raw: ^6.1.1
rehype-stringify: ^9.0.3
@@ -3493,23 +3484,14 @@ importers:
remark-smartypants: ^2.0.0
shiki: ^0.11.1
unified: ^10.1.2
- unist-util-map: ^3.1.1
unist-util-visit: ^4.1.0
vfile: ^5.3.2
dependencies:
- '@astrojs/micromark-extension-mdx-jsx': 1.0.3
'@astrojs/prism': link:../../astro-prism
acorn: 8.8.1
- acorn-jsx: 5.3.2_acorn@8.8.1
github-slugger: 1.5.0
hast-util-to-html: 8.0.3
import-meta-resolve: 2.2.1
- mdast-util-from-markdown: 1.2.0
- mdast-util-mdx-expression: 1.3.1
- mdast-util-mdx-jsx: 1.2.0
- micromark-extension-mdx-expression: 1.0.3
- micromark-extension-mdx-md: 1.0.0
- micromark-util-combine-extensions: 1.0.0
rehype-raw: 6.1.1
rehype-stringify: 9.0.3
remark-gfm: 3.0.1
@@ -3518,7 +3500,6 @@ importers:
remark-smartypants: 2.0.0
shiki: 0.11.1
unified: 10.1.2
- unist-util-map: 3.1.2
unist-util-visit: 4.1.1
vfile: 5.3.6
devDependencies:
@@ -3530,7 +3511,6 @@ importers:
'@types/unist': 2.0.6
astro-scripts: link:../../../scripts
chai: 4.3.7
- micromark-util-types: 1.0.2
mocha: 9.2.2
packages/telemetry: