summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Tony Sullivan <tony.f.sullivan@outlook.com> 2022-06-20 17:12:42 +0000
committerGravatar GitHub <noreply@github.com> 2022-06-20 17:12:42 +0000
commit80c71c7c56d15dc05ec0c5a848130aad222d7d51 (patch)
tree9b1c74594b3f9f04b97b93aa100025d454e50f17
parent6523591a8aaefa8e4115be519b9a996f5f9906b0 (diff)
downloadastro-80c71c7c56d15dc05ec0c5a848130aad222d7d51.tar.gz
astro-80c71c7c56d15dc05ec0c5a848130aad222d7d51.tar.zst
astro-80c71c7c56d15dc05ec0c5a848130aad222d7d51.zip
Fixes rendering of HTML comments inside markdown code blocks (#3638)
* JS comment wrappers should be removed from HTML comments in code blocks * chore: add changeset
-rw-r--r--.changeset/empty-bats-grow.md5
-rw-r--r--packages/astro/src/vite-plugin-markdown/index.ts1
-rw-r--r--packages/astro/test/astro-markdown.test.js14
-rw-r--r--packages/astro/test/fixtures/astro-markdown/src/pages/comment-with-js.md6
-rw-r--r--packages/markdown/remark/src/index.ts3
-rw-r--r--packages/markdown/remark/src/remark-escape.ts17
-rw-r--r--packages/markdown/remark/test/expressions.test.js20
7 files changed, 65 insertions, 1 deletions
diff --git a/.changeset/empty-bats-grow.md b/.changeset/empty-bats-grow.md
new file mode 100644
index 000000000..4ad7871c9
--- /dev/null
+++ b/.changeset/empty-bats-grow.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/markdown-remark': patch
+---
+
+Fix: HTML comments in markdown code blocks should not be wrapped in JS comments
diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts
index ba749e249..2bcc0b241 100644
--- a/packages/astro/src/vite-plugin-markdown/index.ts
+++ b/packages/astro/src/vite-plugin-markdown/index.ts
@@ -141,6 +141,7 @@ export default function markdown({ config }: AstroPluginOptions): Plugin {
// Turn HTML comments into JS comments while preventing nested `*/` sequences
// from ending the JS comment by injecting a zero-width space
+ // Inside code blocks, this is removed during renderMarkdown by the remark-escape plugin.
markdownContent = markdownContent.replace(
/<\s*!--([^-->]*)(.*?)-->/gs,
(whole) => `{/*${whole.replace(/\*\//g, '*\u200b/')}*/}`
diff --git a/packages/astro/test/astro-markdown.test.js b/packages/astro/test/astro-markdown.test.js
index dd40bc071..0afbfdf36 100644
--- a/packages/astro/test/astro-markdown.test.js
+++ b/packages/astro/test/astro-markdown.test.js
@@ -79,6 +79,20 @@ describe('Astro Markdown', () => {
expect($('h1').text()).to.equal('It still works!');
});
+ it.only('Can handle HTML comments in inline code', async () => {
+ const html = await fixture.readFile('/comment-with-js/index.html');
+ const $ = cheerio.load(html);
+
+ expect($('p code').text()).to.equal('<!-- HTML comments in code -->');
+ });
+
+ it('Can handle HTML comments in code fences', async () => {
+ const html = await fixture.readFile('/comment-with-js/index.html');
+ const $ = cheerio.load(html);
+
+ expect($('body > code').text()).to.equal('<!-- HTML comments in code fence -->')
+ });
+
// https://github.com/withastro/astro/issues/3254
it('Can handle scripts in markdown pages', async () => {
const html = await fixture.readFile('/script/index.html');
diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/comment-with-js.md b/packages/astro/test/fixtures/astro-markdown/src/pages/comment-with-js.md
index 387b8380e..374463d2d 100644
--- a/packages/astro/test/fixtures/astro-markdown/src/pages/comment-with-js.md
+++ b/packages/astro/test/fixtures/astro-markdown/src/pages/comment-with-js.md
@@ -14,4 +14,10 @@ function test() {
```
-->
+```
+<!-- HTML comments in code fence -->
+```
+
+`<!-- HTML comments in code -->`
+
# It still works!
diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts
index 9dfc0e38c..7034564c3 100644
--- a/packages/markdown/remark/src/index.ts
+++ b/packages/markdown/remark/src/index.ts
@@ -6,6 +6,7 @@ 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 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';
@@ -46,7 +47,7 @@ export async function renderMarkdown(
let parser = unified()
.use(markdown)
.use(isMDX ? [remarkMdxish, remarkMarkAndUnravel] : [])
- .use([remarkUnwrap]);
+ .use([remarkUnwrap, remarkEscape]);
if (remarkPlugins.length === 0 && rehypePlugins.length === 0) {
remarkPlugins = [...DEFAULT_REMARK_PLUGINS];
diff --git a/packages/markdown/remark/src/remark-escape.ts b/packages/markdown/remark/src/remark-escape.ts
new file mode 100644
index 000000000..312bbe2cd
--- /dev/null
+++ b/packages/markdown/remark/src/remark-escape.ts
@@ -0,0 +1,17 @@
+import { visit } from 'unist-util-visit';
+import type { Literal } from 'unist';
+
+// In code blocks, this removes the JS comment wrapper added to
+// HTML comments by vite-plugin-markdown.
+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/test/expressions.test.js b/packages/markdown/remark/test/expressions.test.js
index 2963ff7f1..12ddc1f48 100644
--- a/packages/markdown/remark/test/expressions.test.js
+++ b/packages/markdown/remark/test/expressions.test.js
@@ -79,4 +79,24 @@ describe('expressions', () => {
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 renderMarkdown(
+ `\`{/*<!-- 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 renderMarkdown(
+ `
+ \`\`\`
+ <!-- HTML comment -->
+ \`\`\`
+ `
+ );
+
+ chai.expect(code).to.match(/(?<!{\/\*)&lt;!-- HTML comment --&gt;(?!\*\/})/);
+ });
});