From 86273b5881cc61ebee11d40280b4c0aba8f4bb2e Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 21 Mar 2023 08:17:20 -0400 Subject: [PATCH] [Markdoc] Refactor Renderer internals to use `renderComponent()` (#6607) * wip: new TreeNode setup * fix: pass children through `render` * deps: remove stringify-attributes * chore: changeset --------- Co-authored-by: Nate Moore Co-authored-by: Nate Moore --- .changeset/thirty-crews-love.md | 5 ++ .../markdoc/components/RenderNode.astro | 30 ------- .../markdoc/components/Renderer.astro | 5 +- .../markdoc/components/TreeNode.ts | 81 +++++++++++++++++++ .../markdoc/components/astroNode.ts | 51 ------------ packages/integrations/markdoc/package.json | 1 - pnpm-lock.yaml | 2 - 7 files changed, 88 insertions(+), 87 deletions(-) create mode 100644 .changeset/thirty-crews-love.md delete mode 100644 packages/integrations/markdoc/components/RenderNode.astro create mode 100644 packages/integrations/markdoc/components/TreeNode.ts delete mode 100644 packages/integrations/markdoc/components/astroNode.ts diff --git a/.changeset/thirty-crews-love.md b/.changeset/thirty-crews-love.md new file mode 100644 index 000000000..fd9efd9c2 --- /dev/null +++ b/.changeset/thirty-crews-love.md @@ -0,0 +1,5 @@ +--- +'@astrojs/markdoc': patch +--- + +Fix: Update Markdoc renderer internals to remove unneeded dependencies diff --git a/packages/integrations/markdoc/components/RenderNode.astro b/packages/integrations/markdoc/components/RenderNode.astro deleted file mode 100644 index a683cd983..000000000 --- a/packages/integrations/markdoc/components/RenderNode.astro +++ /dev/null @@ -1,30 +0,0 @@ ---- -import stringifyAttributes from 'stringify-attributes'; -import type { AstroNode } from './astroNode'; - -type Props = { - node: AstroNode; -}; - -const Node = (Astro.props as Props).node; ---- - -{ - typeof Node === 'string' ? ( - - ) : 'component' in Node ? ( - - {Node.children.map((child) => ( - - ))} - - ) : ( - - `} /> - {Node.children.map((child) => ( - - ))} - `} /> - - ) -} diff --git a/packages/integrations/markdoc/components/Renderer.astro b/packages/integrations/markdoc/components/Renderer.astro index 4fce72b04..6ae8ee850 100644 --- a/packages/integrations/markdoc/components/Renderer.astro +++ b/packages/integrations/markdoc/components/Renderer.astro @@ -2,8 +2,7 @@ import type { RenderableTreeNode } from '@markdoc/markdoc'; import type { AstroInstance } from 'astro'; import { validateComponentsProp } from '../dist/utils.js'; -import { createAstroNode } from './astroNode'; -import RenderNode from './RenderNode.astro'; +import { ComponentNode, createTreeNode } from './TreeNode.js'; type Props = { content: RenderableTreeNode; @@ -18,4 +17,4 @@ if (components) { } --- - + diff --git a/packages/integrations/markdoc/components/TreeNode.ts b/packages/integrations/markdoc/components/TreeNode.ts new file mode 100644 index 000000000..36fd63fee --- /dev/null +++ b/packages/integrations/markdoc/components/TreeNode.ts @@ -0,0 +1,81 @@ +import type { AstroInstance } from 'astro'; +import type { RenderableTreeNode } from '@markdoc/markdoc'; +import { createComponent, renderComponent, render } from 'astro/runtime/server/index.js'; +import Markdoc from '@markdoc/markdoc'; +import { MarkdocError, isCapitalized } from '../dist/utils.js'; + +export type TreeNode = + | { + type: 'text'; + content: string; + } + | { + type: 'component'; + component: AstroInstance['default']; + props: Record; + children: TreeNode[]; + } + | { + type: 'element'; + tag: string; + attributes: Record; + children: TreeNode[]; + }; + +export const ComponentNode = createComponent({ + factory(result: any, { treeNode }: { treeNode: TreeNode }) { + if (treeNode.type === 'text') return render`${treeNode.content}`; + const slots = { + default: () => render`${treeNode.children.map((child) => + renderComponent(result, 'ComponentNode', ComponentNode, { treeNode: child }) + )}`, + }; + if (treeNode.type === 'component') { + return renderComponent( + result, + treeNode.component.name, + treeNode.component, + treeNode.props, + slots + ); + } + return renderComponent(result, treeNode.tag, treeNode.tag, treeNode.attributes, slots); + }, + propagation: 'none', +}); + +export function createTreeNode( + node: RenderableTreeNode, + components: Record = {} +): TreeNode { + if (typeof node === 'string' || typeof node === 'number') { + return { type: 'text', content: String(node) }; + } else if (node === null || typeof node !== 'object' || !Markdoc.Tag.isTag(node)) { + return { type: 'text', content: '' }; + } + + if (node.name in components) { + const component = components[node.name]; + const props = node.attributes; + const children = node.children.map((child) => createTreeNode(child, components)); + + return { + type: 'component', + component, + props, + children, + }; + } else if (isCapitalized(node.name)) { + throw new MarkdocError({ + message: `Unable to render ${JSON.stringify(node.name)}.`, + hint: 'Did you add this to the "components" prop on your component?', + }); + } else { + return { + type: 'element', + tag: node.name, + attributes: node.attributes, + children: node.children.map((child) => createTreeNode(child, components)), + }; + } +} diff --git a/packages/integrations/markdoc/components/astroNode.ts b/packages/integrations/markdoc/components/astroNode.ts deleted file mode 100644 index 12a0cd0a6..000000000 --- a/packages/integrations/markdoc/components/astroNode.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { AstroInstance } from 'astro'; -import type { RenderableTreeNode } from '@markdoc/markdoc'; -import Markdoc from '@markdoc/markdoc'; -import { MarkdocError, isCapitalized } from '../dist/utils.js'; - -export type AstroNode = - | string - | { - component: AstroInstance['default']; - props: Record; - children: AstroNode[]; - } - | { - tag: string; - attributes: Record; - children: AstroNode[]; - }; - -export function createAstroNode( - node: RenderableTreeNode, - components: Record = {} -): AstroNode { - if (typeof node === 'string' || typeof node === 'number') { - return String(node); - } else if (node === null || typeof node !== 'object' || !Markdoc.Tag.isTag(node)) { - return ''; - } - - if (node.name in components) { - const component = components[node.name]; - const props = node.attributes; - const children = node.children.map((child) => createAstroNode(child, components)); - - return { - component, - props, - children, - }; - } else if (isCapitalized(node.name)) { - throw new MarkdocError({ - message: `Unable to render ${JSON.stringify(node.name)}.`, - hint: 'Did you add this to the "components" prop on your component?', - }); - } else { - return { - tag: node.name, - attributes: node.attributes, - children: node.children.map((child) => createAstroNode(child, components)), - }; - } -} diff --git a/packages/integrations/markdoc/package.json b/packages/integrations/markdoc/package.json index e1cb6b84c..1c9629e3d 100644 --- a/packages/integrations/markdoc/package.json +++ b/packages/integrations/markdoc/package.json @@ -33,7 +33,6 @@ "dependencies": { "@markdoc/markdoc": "^0.2.2", "gray-matter": "^4.0.3", - "stringify-attributes": "^3.0.0", "zod": "^3.17.3" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8413313b7..0c78b695b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3078,13 +3078,11 @@ importers: gray-matter: ^4.0.3 linkedom: ^0.14.12 mocha: ^9.2.2 - stringify-attributes: ^3.0.0 vite: ^4.0.3 zod: ^3.17.3 dependencies: '@markdoc/markdoc': 0.2.2 gray-matter: 4.0.3 - stringify-attributes: 3.0.0 zod: 3.20.6 devDependencies: '@types/chai': 4.3.4