diff --git a/.changeset/beige-kings-listen.md b/.changeset/beige-kings-listen.md new file mode 100644 index 000000000..49ca26919 --- /dev/null +++ b/.changeset/beige-kings-listen.md @@ -0,0 +1,5 @@ +--- +'@astrojs/markdown-remark': patch +--- + +Fix bug where code blocks would not be escaped properly diff --git a/.changeset/curvy-glasses-rest.md b/.changeset/curvy-glasses-rest.md new file mode 100644 index 000000000..8d0ae9c1f --- /dev/null +++ b/.changeset/curvy-glasses-rest.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix error with Markdown content attribute parsing diff --git a/.changeset/young-steaks-report.md b/.changeset/young-steaks-report.md new file mode 100644 index 000000000..c2d65335a --- /dev/null +++ b/.changeset/young-steaks-report.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix bug with attribute serialization diff --git a/packages/astro/src/runtime/server/index.ts b/packages/astro/src/runtime/server/index.ts index ea4a50ed9..2a5543d49 100644 --- a/packages/astro/src/runtime/server/index.ts +++ b/packages/astro/src/runtime/server/index.ts @@ -208,6 +208,8 @@ export function createAstro(fileURLStr: string, site: string): TopLevelAstro { }; } +const toAttributeString = (value: any) => String(value).replace(/&/g, '&').replace(/"/g, '"') + // A helper used to turn expressions into attribute key/value export function addAttribute(value: any, key: string) { if (value == null || value === false) { @@ -216,10 +218,10 @@ export function addAttribute(value: any, key: string) { // support "class" from an expression passed into an element (#782) if (key === 'class:list') { - return ` ${key.slice(0, -5)}="${serializeListValue(value)}"`; + return ` ${key.slice(0, -5)}="${toAttributeString(serializeListValue(value))}"`; } - return ` ${key}="${value}"`; + return ` ${key}="${toAttributeString(value)}"`; } // Adds support for ` diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts index 82ebd4d43..927b5b9d2 100644 --- a/packages/astro/src/vite-plugin-markdown/index.ts +++ b/packages/astro/src/vite-plugin-markdown/index.ts @@ -40,10 +40,11 @@ export default function markdown({ config }: AstroPluginOptions): Plugin { ${layout ? `import Layout from '${layout}';` : ''} ${components ? `import * from '${components}';` : ''} ${setup} +const $$content = ${JSON.stringify(content)} ---`; // If the user imported "Layout", wrap the content in a Layout if (/\bLayout\b/.test(prelude)) { - astroResult = `${prelude}\n\n\n${astroResult}\n\n`; + astroResult = `${prelude}\n\n\n${astroResult}\n\n`; } else { astroResult = `${prelude}\n${astroResult}`; } diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts index 5c707a4db..8ea5263b8 100644 --- a/packages/markdown/remark/src/index.ts +++ b/packages/markdown/remark/src/index.ts @@ -7,6 +7,7 @@ import rehypeExpressions from './rehype-expressions.js'; import rehypeIslands from './rehype-islands.js'; import { remarkJsx, loadRemarkJsx } from './remark-jsx.js'; import rehypeJsx from './rehype-jsx.js'; +import rehypeEscape from './rehype-escape.js'; import remarkPrism from './remark-prism.js'; import remarkUnwrap from './remark-unwrap.js'; import { loadPlugins } from './load-plugins.js'; @@ -76,6 +77,7 @@ export async function renderMarkdown(content: string, opts?: MarkdownRenderingOp .use(isMDX ? [rehypeJsx] : []) .use(isMDX ? [rehypeExpressions] : []) .use(isMDX ? [] : [rehypeRaw]) + .use(isMDX ? [rehypeEscape] : []) .use(rehypeIslands); let result: string; diff --git a/packages/markdown/remark/src/rehype-escape.ts b/packages/markdown/remark/src/rehype-escape.ts new file mode 100644 index 000000000..e0094b463 --- /dev/null +++ b/packages/markdown/remark/src/rehype-escape.ts @@ -0,0 +1,12 @@ +import { SKIP, visit } from 'unist-util-visit'; + +export default function rehypeEscape(): any { + return function (node: any): any { + return visit(node, 'element', (el) => { + if (el.tagName === 'code' || el.tagName === 'pre') { + el.properties['data-astro-raw'] = true; + } + return el; + }); + }; +}