Skip to content

Commit

Permalink
[Markdoc] Fix: Support render: null (#6723)
Browse files Browse the repository at this point in the history
* fix: handle array of tree nodes

* test: render null in document node

* chore: lock

* refactor: consolidate render test logic

* chore: changeset
  • Loading branch information
bholmesdev committed Apr 3, 2023
1 parent ad80d83 commit 73fcc76
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 60 deletions.
5 changes: 5 additions & 0 deletions .changeset/mean-guests-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/markdoc': patch
---

Fix: when using `render: null` in your config, content is now rendered without a wrapper element.
10 changes: 9 additions & 1 deletion packages/integrations/markdoc/components/TreeNode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { AstroInstance } from 'astro';
import { Fragment } from 'astro/jsx-runtime';
import type { RenderableTreeNode } from '@markdoc/markdoc';
import Markdoc from '@markdoc/markdoc';
import { createComponent, renderComponent, render } from 'astro/runtime/server/index.js';
Expand Down Expand Up @@ -44,9 +45,16 @@ export const ComponentNode = createComponent({
propagation: 'none',
});

export function createTreeNode(node: RenderableTreeNode): TreeNode {
export function createTreeNode(node: RenderableTreeNode | RenderableTreeNode[]): TreeNode {
if (typeof node === 'string' || typeof node === 'number') {
return { type: 'text', content: String(node) };
} else if (Array.isArray(node)) {
return {
type: 'component',
component: Fragment,
props: {},
children: node.map((child) => createTreeNode(child)),
};
} else if (node === null || typeof node !== 'object' || !Markdoc.Tag.isTag(node)) {
return { type: 'text', content: '' };
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from 'astro/config';
import markdoc from '@astrojs/markdoc';

// https://astro.build/config
export default defineConfig({
integrations: [markdoc()],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { defineMarkdocConfig } from '@astrojs/markdoc/config';

export default defineMarkdocConfig({
nodes: {
document: {
render: null,

// Defaults from `Markdoc.nodes.document`
children: [
'heading',
'paragraph',
'image',
'table',
'tag',
'fence',
'blockquote',
'comment',
'list',
'hr',
],
attributes: {
frontmatter: { render: false },
},
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@test/markdoc-render-null",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/markdoc": "workspace:*",
"astro": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: Post with render null
---

## Post with render null

This should render the contents inside a fragment!
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
import { getEntryBySlug } from "astro:content";
const post = await getEntryBySlug('blog', 'render-null');
const { Content } = await post.render();
---

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Content</title>
</head>
<body>
<Content />
</body>
</html>
134 changes: 80 additions & 54 deletions packages/integrations/markdoc/test/render.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@ describe('Markdoc - render', () => {

const res = await fixture.fetch('/');
const html = await res.text();
const { document } = parseHTML(html);
const h2 = document.querySelector('h2');
expect(h2.textContent).to.equal('Simple post');
const p = document.querySelector('p');
expect(p.textContent).to.equal('This is a simple Markdoc post.');

renderSimpleChecks(html);

await server.stop();
});
Expand All @@ -31,17 +28,8 @@ describe('Markdoc - render', () => {

const res = await fixture.fetch('/');
const html = await res.text();
const { document } = parseHTML(html);
const h2 = document.querySelector('h2');
expect(h2.textContent).to.equal('Post with config');
const textContent = html;

expect(textContent).to.not.include('Hello');
expect(textContent).to.include('Hola');
expect(textContent).to.include(`Konnichiwa`);

const runtimeVariable = document.querySelector('#runtime-variable');
expect(runtimeVariable?.textContent?.trim()).to.equal('working!');
renderConfigChecks(html);

await server.stop();
});
Expand All @@ -52,19 +40,20 @@ describe('Markdoc - render', () => {

const res = await fixture.fetch('/');
const html = await res.text();
const { document } = parseHTML(html);
const h2 = document.querySelector('h2');
expect(h2.textContent).to.equal('Post with components');

// Renders custom shortcode component
const marquee = document.querySelector('marquee');
expect(marquee).to.not.be.null;
expect(marquee.hasAttribute('data-custom-marquee')).to.equal(true);
renderComponentsChecks(html);

await server.stop();
});

// Renders Astro Code component
const pre = document.querySelector('pre');
expect(pre).to.not.be.null;
expect(pre.className).to.equal('astro-code');
it('renders content - with `render: null` in document', async () => {
const fixture = await getFixture('render-null');
const server = await fixture.startDevServer();

const res = await fixture.fetch('/');
const html = await res.text();

renderNullChecks(html);

await server.stop();
});
Expand All @@ -76,49 +65,86 @@ describe('Markdoc - render', () => {
await fixture.build();

const html = await fixture.readFile('/index.html');
const { document } = parseHTML(html);
const h2 = document.querySelector('h2');
expect(h2.textContent).to.equal('Simple post');
const p = document.querySelector('p');
expect(p.textContent).to.equal('This is a simple Markdoc post.');

renderSimpleChecks(html);
});

it('renders content - with config', async () => {
const fixture = await getFixture('render-with-config');
await fixture.build();

const html = await fixture.readFile('/index.html');
const { document } = parseHTML(html);
const h2 = document.querySelector('h2');
expect(h2.textContent).to.equal('Post with config');
const textContent = html;

expect(textContent).to.not.include('Hello');
expect(textContent).to.include('Hola');
expect(textContent).to.include(`Konnichiwa`);

const runtimeVariable = document.querySelector('#runtime-variable');
expect(runtimeVariable?.textContent?.trim()).to.equal('working!');
renderConfigChecks(html);
});

it('renders content - with components', async () => {
const fixture = await getFixture('render-with-components');
await fixture.build();

const html = await fixture.readFile('/index.html');
const { document } = parseHTML(html);
const h2 = document.querySelector('h2');
expect(h2.textContent).to.equal('Post with components');

// Renders custom shortcode component
const marquee = document.querySelector('marquee');
expect(marquee).to.not.be.null;
expect(marquee.hasAttribute('data-custom-marquee')).to.equal(true);

// Renders Astro Code component
const pre = document.querySelector('pre');
expect(pre).to.not.be.null;
expect(pre.className).to.equal('astro-code');

renderComponentsChecks(html);
});

it('renders content - with `render: null` in document', async () => {
const fixture = await getFixture('render-null');
await fixture.build();

const html = await fixture.readFile('/index.html');

renderNullChecks(html);
});
});
});

/**
* @param {string} html
*/
function renderNullChecks(html) {
const { document } = parseHTML(html);
const h2 = document.querySelector('h2');
expect(h2.textContent).to.equal('Post with render null');
expect(h2.parentElement?.tagName).to.equal('BODY');
}

/** @param {string} html */
function renderComponentsChecks(html) {
const { document } = parseHTML(html);
const h2 = document.querySelector('h2');
expect(h2.textContent).to.equal('Post with components');

// Renders custom shortcode component
const marquee = document.querySelector('marquee');
expect(marquee).to.not.be.null;
expect(marquee.hasAttribute('data-custom-marquee')).to.equal(true);

// Renders Astro Code component
const pre = document.querySelector('pre');
expect(pre).to.not.be.null;
expect(pre.className).to.equal('astro-code');
}

/** @param {string} html */
function renderConfigChecks(html) {
const { document } = parseHTML(html);
const h2 = document.querySelector('h2');
expect(h2.textContent).to.equal('Post with config');
const textContent = html;

expect(textContent).to.not.include('Hello');
expect(textContent).to.include('Hola');
expect(textContent).to.include(`Konnichiwa`);

const runtimeVariable = document.querySelector('#runtime-variable');
expect(runtimeVariable?.textContent?.trim()).to.equal('working!');
}

/** @param {string} html */
function renderSimpleChecks(html) {
const { document } = parseHTML(html);
const h2 = document.querySelector('h2');
expect(h2.textContent).to.equal('Simple post');
const p = document.querySelector('p');
expect(p.textContent).to.equal('This is a simple Markdoc post.');
}

0 comments on commit 73fcc76

Please sign in to comment.