diff --git a/.changeset/warm-terms-admire.md b/.changeset/warm-terms-admire.md
new file mode 100644
index 000000000..6a7575706
--- /dev/null
+++ b/.changeset/warm-terms-admire.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fix issue where Markdown could close it's parent element early (#494)
diff --git a/examples/with-markdown/src/layouts/main.astro b/examples/with-markdown/src/layouts/main.astro
index 26993bcaf..c3ef56d60 100644
--- a/examples/with-markdown/src/layouts/main.astro
+++ b/examples/with-markdown/src/layouts/main.astro
@@ -1,4 +1,5 @@
---
+const { content } = Astro.props;
---
diff --git a/examples/with-markdown/src/pages/external.astro b/examples/with-markdown/src/pages/external.astro
new file mode 100644
index 000000000..1149666b2
--- /dev/null
+++ b/examples/with-markdown/src/pages/external.astro
@@ -0,0 +1,17 @@
+---
+import { Markdown } from 'astro/components';
+import Layout from '../layouts/main.astro';
+
+const title = `External Markdown`;
+const content = `Markdown *content* to render`;
+---
+
+
+
+
+ Lastly...
+
+
diff --git a/packages/astro/src/compiler/codegen/index.ts b/packages/astro/src/compiler/codegen/index.ts
index 843ecc428..ea094a32c 100644
--- a/packages/astro/src/compiler/codegen/index.ts
+++ b/packages/astro/src/compiler/codegen/index.ts
@@ -509,6 +509,12 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
async function pushMarkdownToBuffer() {
const md = buffers.markdown;
const { markdownOptions = {} } = astroConfig;
+ if (!md.trim()) {
+ buffers.out += ',' + md;
+ buffers.markdown = '';
+ curr = 'out';
+ return;
+ }
const { $scope: scopedClassName } = state.markers.insideMarkdown as Record<'$scope', any>;
let { content: rendered } = await renderMarkdown(dedent(md), {
...(markdownOptions as AstroMarkdownOptions),
@@ -627,7 +633,8 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
if (componentName === 'Markdown') {
const { $scope } = attributes ?? {};
state.markers.insideMarkdown = typeof state.markers.insideMarkdown === 'object' ? { $scope, count: state.markers.insideMarkdown.count + 1 } : { $scope, count: 1 };
- if (attributes.content) {
+ const keys = Object.keys(attributes).filter(attr => attr !== '$scope');
+ if (keys.length > 0) {
if (curr === 'markdown') {
await pushMarkdownToBuffer();
}
@@ -717,7 +724,7 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
case 'Body':
case 'Title':
case 'Element': {
- if (state.markers.insideMarkdown) {
+ if (curr === 'markdown') {
await pushMarkdownToBuffer();
}
if (paren !== -1) {
@@ -732,6 +739,10 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
if ((state.markers.insideMarkdown as Record).count <= 0) {
state.markers.insideMarkdown = false;
}
+ const hasAttrs = (node.attributes.filter(({ name }: Attribute) => name !== '$scope')).length > 0;
+ if (hasAttrs) {
+ return;
+ }
}
if (curr === 'markdown' && buffers.markdown !== '') {
await pushMarkdownToBuffer();
diff --git a/packages/astro/test/astro-markdown.test.js b/packages/astro/test/astro-markdown.test.js
index cadb255bd..73e17a5f8 100644
--- a/packages/astro/test/astro-markdown.test.js
+++ b/packages/astro/test/astro-markdown.test.js
@@ -82,4 +82,12 @@ Markdown('Renders dynamic content though the content attribute', async ({ runtim
assert.ok($('#inner').is('[class]'), 'Scoped class passed down');
});
+Markdown('Does not close parent early when using content attribute (#494)', async ({ runtime }) => {
+ const result = await runtime.load('/close');
+ if (result.error) throw new Error(result.error);
+
+ const $ = doc(result.contents);
+ assert.equal($('#target').children().length, 2, ' closed div#target early');
+});
+
Markdown.run();
diff --git a/packages/astro/test/fixtures/astro-markdown/src/pages/close.astro b/packages/astro/test/fixtures/astro-markdown/src/pages/close.astro
new file mode 100644
index 000000000..1da319c03
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-markdown/src/pages/close.astro
@@ -0,0 +1,12 @@
+---
+import { Markdown } from 'astro/components';
+const content = `Markdown *content* to render`;
+---
+
+
+
+ Lastly...
+