diff --git a/.changeset/large-berries-grow.md b/.changeset/large-berries-grow.md new file mode 100644 index 000000000..81589045d --- /dev/null +++ b/.changeset/large-berries-grow.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'@astrojs/markdown-remark': patch +--- + +Fix components in markdown regressions diff --git a/packages/astro/test/astro-markdown.test.js b/packages/astro/test/astro-markdown.test.js index e5daa1b46..b001c6a83 100644 --- a/packages/astro/test/astro-markdown.test.js +++ b/packages/astro/test/astro-markdown.test.js @@ -82,7 +82,6 @@ describe('Astro Markdown', () => { // https://github.com/withastro/astro/issues/3254 it('Can handle scripts in markdown pages', async () => { const html = await fixture.readFile('/script/index.html'); - console.log(html); expect(html).not.to.match(new RegExp('/src/scripts/test.js')); }); @@ -273,4 +272,42 @@ describe('Astro Markdown', () => { expect($('code').eq(2).text()).to.contain('title: import.meta.env.TITLE'); expect($('blockquote').text()).to.contain('import.meta.env.TITLE'); }); + + it('Escapes HTML tags in code blocks', async () => { + const html = await fixture.readFile('/code-in-md/index.html'); + const $ = cheerio.load(html); + + expect($('code').eq(0).html()).to.equal('<script>'); + expect($('blockquote').length).to.equal(1); + expect($('code').eq(1).html()).to.equal('</script>'); + expect($('pre').html()).to.contain('>This should also work without any problems.<'); + }); + + it('Allows defining slot contents in component children', async () => { + const html = await fixture.readFile('/slots/index.html'); + const $ = cheerio.load(html); + + const slots = $('article').eq(0); + expect(slots.find('> .fragmentSlot > div').text()).to.contain('1:'); + expect(slots.find('> .fragmentSlot > div + p').text()).to.contain('2:'); + expect(slots.find('> .pSlot > p[title="hello"]').text()).to.contain('3:'); + expect(slots.find('> .defaultSlot').text().replace(/\s+/g, ' ')).to.equal(` + 4: Div in default slot + 5: Paragraph in fragment in default slot + 6: Regular text in default slot + `.replace(/\s+/g, ' ')); + + const nestedSlots = $('article').eq(1); + expect(nestedSlots.find('> .fragmentSlot').html()).to.contain('1:'); + expect(nestedSlots.find('> .pSlot > p').text()).to.contain('2:'); + expect(nestedSlots.find('> .defaultSlot > article').text().replace(/\s+/g, ' ')).to.equal(` + 3: nested fragmentSlot + 4: nested pSlot + 5: nested text in default slot + `.replace(/\s+/g, ' ')); + + expect($('article').eq(3).text().replace(/[^❌]/g, '')).to.equal('❌❌❌'); + + expect($('article').eq(4).text().replace(/[^❌]/g, '')).to.equal('❌❌❌'); + }); }); diff --git a/packages/astro/test/fixtures/astro-markdown/src/components/SlotComponent.astro b/packages/astro/test/fixtures/astro-markdown/src/components/SlotComponent.astro new file mode 100644 index 000000000..f0aa9fc1c --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/components/SlotComponent.astro @@ -0,0 +1,13 @@ +
+
+ ❌ Missing content for slot "fragmentSlot" +
+ +
+ ❌ Missing content for slot "pSlot" +
+ +
+ ❌ Missing content for default slot +
+
diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/code-in-md.md b/packages/astro/test/fixtures/astro-markdown/src/pages/code-in-md.md new file mode 100644 index 000000000..52a799ab1 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/code-in-md.md @@ -0,0 +1,16 @@ +# Inline code blocks + +`` tags without any problems. + +# Fenced code blocks + +```html + +
This should also work without any problems.
+ +``` diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/slots.md b/packages/astro/test/fixtures/astro-markdown/src/pages/slots.md new file mode 100644 index 000000000..c7e8367b8 --- /dev/null +++ b/packages/astro/test/fixtures/astro-markdown/src/pages/slots.md @@ -0,0 +1,38 @@ +--- +layout: ../layouts/content.astro +setup: import SlotComponent from '../components/SlotComponent.astro'; +--- + +# Component with slot contents in children + + +
4: Div in default slot
+ +
1: Div in fragmentSlot
+

2: Paragraph in fragmentSlot

+
+

5: Paragraph in fragment in default slot

+ 6: Regular text in default slot +

3: p with title as pSlot

+
+ +# Component with nested component in children + + +

2: pSlot

+ +

4: nested pSlot

+ 5: nested text in default slot + 3: nested fragmentSlot +
+ 1: fragmentSlot +
+ +# Missing content due to empty children + + + + +# Missing content due to self-closing tag + + diff --git a/packages/markdown/remark/src/rehype-escape.ts b/packages/markdown/remark/src/rehype-escape.ts index bb56166be..5cf463608 100644 --- a/packages/markdown/remark/src/rehype-escape.ts +++ b/packages/markdown/remark/src/rehype-escape.ts @@ -5,6 +5,11 @@ export default function rehypeEscape(): 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 `