diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-callout-tests-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-callout-tests-without-surprises-1-snap.png index 9c0f106bb..2b3a70cd9 100644 Binary files a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-callout-tests-without-surprises-1-snap.png and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-callout-tests-without-surprises-1-snap.png differ diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-embeds-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-embeds-without-surprises-1-snap.png index 627d1a58e..00f30622e 100644 Binary files a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-embeds-without-surprises-1-snap.png and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-embeds-without-surprises-1-snap.png differ diff --git a/__tests__/compilers/compatability.test.ts b/__tests__/compilers/compatability.test.ts new file mode 100644 index 000000000..33b2d7e8b --- /dev/null +++ b/__tests__/compilers/compatability.test.ts @@ -0,0 +1,49 @@ +import { mdx } from '../../index'; + +describe('compatability with RDMD', () => { + it('compiles variable nodes', () => { + const ast = { + type: 'readme-variable', + text: 'parliament', + data: { + hName: 'readme-variable', + hProperties: { + variable: 'parliament', + }, + }, + }; + + expect(mdx(ast).trim()).toBe(''); + }); + + it('compiles glossary nodes', () => { + const ast = { + type: 'readme-glossary-item', + data: { + hProperties: { + term: 'parliament', + }, + }, + }; + + expect(mdx(ast).trim()).toBe('parliament'); + }); + + it('compiles reusable-content nodes', () => { + const ast = { + type: 'reusable-content', + tag: 'Parliament', + }; + + expect(mdx(ast).trim()).toBe(''); + }); + + it('compiles html comments to JSX comments', () => { + const ast = { + type: 'html', + value: '', + }; + + expect(mdx(ast).trim()).toBe('{/* commentable */}'); + }); +}); diff --git a/__tests__/components/index.test.ts b/__tests__/components/index.test.ts index 3ad2d879d..10f099992 100644 --- a/__tests__/components/index.test.ts +++ b/__tests__/components/index.test.ts @@ -68,7 +68,7 @@ describe('Components', () => { component = await run(code1); ({ container } = render(React.createElement(component))); - expect(container.innerHTML).toMatchInlineSnapshot(`"

🚧

Callout with no title.

"`); + expect(container.innerHTML).toMatchInlineSnapshot(`"

🚧

Callout with no title.

"`); cleanup(); }); diff --git a/__tests__/parsers/__snapshots__/callouts.test.js.snap b/__tests__/parsers/__snapshots__/callouts.test.js.snap index a993d76e9..001cd713f 100644 --- a/__tests__/parsers/__snapshots__/callouts.test.js.snap +++ b/__tests__/parsers/__snapshots__/callouts.test.js.snap @@ -21,7 +21,7 @@ exports[`Parse RDMD Callouts > renders an info callout 1`] = ` }, }, "type": "text", - "value": "â„šī¸ Info Callout", + "value": "Info Callout", }, ], "position": { @@ -72,6 +72,13 @@ exports[`Parse RDMD Callouts > renders an info callout 1`] = ` "type": "paragraph", }, ], + "data": { + "hName": "Callout", + "hProperties": { + "empty": false, + "icon": "â„šī¸", + }, + }, "position": { "end": { "column": 60, @@ -84,7 +91,7 @@ exports[`Parse RDMD Callouts > renders an info callout 1`] = ` "offset": 1, }, }, - "type": "blockquote", + "type": "rdme-callout", }, ], "position": { diff --git a/__tests__/parsers/callouts.test.js b/__tests__/parsers/callouts.test.js index e334106d4..89b833589 100644 --- a/__tests__/parsers/callouts.test.js +++ b/__tests__/parsers/callouts.test.js @@ -1,6 +1,6 @@ import { mdast } from '../../index'; -describe.skip('Parse RDMD Callouts', () => { +describe('Parse RDMD Callouts', () => { it('renders an info callout', () => { const text = ` > â„šī¸ Info Callout @@ -10,18 +10,6 @@ describe.skip('Parse RDMD Callouts', () => { expect(mdast(text)).toMatchSnapshot(); }); - it('supports a default theme', () => { - const text = ` -> đŸĨ‡ Themeless -> -> Lorem ipsum dolor sit amet consectetur adipisicing elit.`; - - const tree = mdast(text); - - expect(tree.children[0].type).toBe('rdme-callout'); - expect(tree.children[0].data.hProperties.theme).toBe('default'); - }); - it('parses a callout with no title', () => { const text = ` > â„šī¸ @@ -31,8 +19,8 @@ describe.skip('Parse RDMD Callouts', () => { const tree = mdast(text); expect(tree.children[0].type).toBe('rdme-callout'); - expect(tree.children[0].data.hProperties.theme).toBe('info'); - expect(tree.children[0].data.hProperties.title).toBe(''); + expect(tree.children[0].data.hProperties.icon).toBe('â„šī¸'); + expect(tree.children[0].data.hProperties.empty).toBe(true); }); describe('edge cases', () => { @@ -44,8 +32,8 @@ describe.skip('Parse RDMD Callouts', () => { `; const tree = mdast(text); - expect(tree.children[0].data.hProperties.value).toBe('With html!'); - expect(tree.children[0].children[1].children[0].type).toBe('html'); + expect(tree.children[0].children[1].children[0].children[0].value).toBe('With html!'); + expect(tree.children[0].children[1].children[0].type).toBe('mdxJsxTextElement'); }); it('allows trailing spaces after the icon', () => { @@ -56,7 +44,7 @@ describe.skip('Parse RDMD Callouts', () => { const tree = mdast(text); expect(tree.children[0].data.hProperties.icon).toBe('🛑'); expect(tree.children[0].children[0].children[0].value).toBe( - 'Compact headings must be followed by two line breaks before the following block.' + 'Compact headings must be followed by two line breaks before the following block.', ); }); }); @@ -83,20 +71,20 @@ describe.skip('Parse RDMD Callouts', () => { expect(tree.children[0].children[0].children[1].type).toBe('rdme-callout'); }); - it('does not require a line break between the title and the body', () => { + it('does require a line break between the title and the body', () => { const text = ` > 💁 Undocumented Behavior > Lorem ipsum dolor sit amet consectetur adipisicing elit.`; const tree = mdast(text); - expect(tree.children[0].data.hProperties.title).toBe( + expect(tree.children[0].children[0].children[0].value).toBe( `Undocumented Behavior -Lorem ipsum dolor sit amet consectetur adipisicing elit.` +Lorem ipsum dolor sit amet consectetur adipisicing elit.`, ); }); }); -describe.skip('emoji modifier support', () => { +describe('emoji modifier support', () => { const emojis = ['📘', '🚧', 'âš ī¸', '👍', '✅', 'â—ī¸', '❗', '🛑', 'â‰ī¸', 'â€ŧī¸', 'â„šī¸', '⚠']; emojis.forEach(emoji => { diff --git a/__tests__/transformers/callouts.test.ts b/__tests__/transformers/callouts.test.ts index d26ed61bf..51461f857 100644 --- a/__tests__/transformers/callouts.test.ts +++ b/__tests__/transformers/callouts.test.ts @@ -1,4 +1,4 @@ -import { mdast, hast } from '../../index'; +import { mdast } from '../../index'; describe('callouts transformer', () => { it('can parse callouts', () => { diff --git a/__tests__/transformers/readme-components.test.ts b/__tests__/transformers/readme-components.test.ts index 2adb51da0..edcdb97c1 100644 --- a/__tests__/transformers/readme-components.test.ts +++ b/__tests__/transformers/readme-components.test.ts @@ -18,7 +18,10 @@ describe('Readme Components Transformer', () => { const docs = { ['rdme-callout']: { md: `> 📘 It works!`, - mdx: ``, + mdx: ` + + It works! +`, }, code: { md: ` diff --git a/components/Callout/index.tsx b/components/Callout/index.tsx index 8ff54f21c..60330cfe2 100644 --- a/components/Callout/index.tsx +++ b/components/Callout/index.tsx @@ -4,7 +4,7 @@ interface Props extends React.PropsWithChildren = { @@ -23,20 +23,17 @@ const themes: Record = { }; const Callout = (props: Props) => { - const { attributes, children, icon } = props; - + const { attributes, children, icon, empty } = props; let theme = props.theme || themes[icon] || 'default'; - const [heading, ...body] = Array.isArray(children) ? children : [children]; - const empty = !heading.props.children; return ( // @ts-ignore

{icon} - {!empty && heading} + {empty || children[0]}

- {body} + {empty ? children : React.Children.toArray(children).slice(1)}
); }; diff --git a/docs/callout-tests.md b/docs/callout-tests.md index b36f63c6d..c0b0060ed 100644 --- a/docs/callout-tests.md +++ b/docs/callout-tests.md @@ -15,8 +15,10 @@ hidden: true > - was only rendering > - one child - - ### Even supports markdown + +Now with MDX + +### Even supports markdown Much _wow_ diff --git a/enums.ts b/enums.ts index 1eab3a97f..68ee05f12 100644 --- a/enums.ts +++ b/enums.ts @@ -5,5 +5,8 @@ export enum NodeTypes { i = 'i', image = 'image', htmlBlock = 'html-block', - embed = 'rdme-embed' + embed = 'rdme-embed', + variable = 'readme-variable', + glossary = 'readme-glossary-item', + reusableContent = 'reusable-content', } diff --git a/package-lock.json b/package-lock.json index 96eeb9c3e..e43b852a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -99,7 +99,7 @@ }, "peerDependencies": { "@mdx-js/react": "^3.0.0", - "@readme/variable": "^16.0.0", + "@readme/variable": "^16.1.0", "@tippyjs/react": "^4.1.0", "react": "16.x || 17.x || 18.x", "react-dom": "16.x || 17.x || 18.x" @@ -5065,9 +5065,9 @@ } }, "node_modules/@readme/variable": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@readme/variable/-/variable-16.0.0.tgz", - "integrity": "sha512-22KYVEtZQSrDTpXv5Xs3tykBB5b8JgjzRSm0t1iSrXVJ+5HAOFuTzsv2PX7/yLuQyn/PNMES2U1kp6yVX+AdLQ==", + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/@readme/variable/-/variable-16.1.0.tgz", + "integrity": "sha512-f4FDP4YE92Wjtie4IFw89FaM4Vgy4vkhsOxcozqRl6/7X2uPvAMVku4s3z7FKsKf0p52LgoeYkESnweUGMjexQ==", "peer": true, "dependencies": { "classnames": "^2.2.6", diff --git a/package.json b/package.json index efddaf03f..ff23ce28e 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ }, "peerDependencies": { "@mdx-js/react": "^3.0.0", - "@readme/variable": "^16.0.0", + "@readme/variable": "^16.1.0", "@tippyjs/react": "^4.1.0", "react": "16.x || 17.x || 18.x", "react-dom": "16.x || 17.x || 18.x" diff --git a/processor/compile/compatibility.ts b/processor/compile/compatibility.ts new file mode 100644 index 000000000..671c8bb56 --- /dev/null +++ b/processor/compile/compatibility.ts @@ -0,0 +1,25 @@ +import { Html } from 'mdast'; +import { NodeTypes } from '../../enums'; + +type CompatNodes = + | { type: NodeTypes.variable; text: string } + | { type: NodeTypes.glossary; data: { hProperties: { term: string } } } + | { type: NodeTypes.reusableContent; tag: string } + | Html; + +const compatibility = (node: CompatNodes) => { + switch (node.type) { + case NodeTypes.variable: + return ``; + case NodeTypes.glossary: + return `${node.data.hProperties.term}`; + case NodeTypes.reusableContent: + return `<${node.tag} />`; + case 'html': + return node.value.replaceAll(//g, '{/*$1*/}'); + default: + throw new Error('Unhandled node type!'); + } +}; + +export default compatibility; diff --git a/processor/compile/index.ts b/processor/compile/index.ts index d097605ea..cc4a8d2fd 100644 --- a/processor/compile/index.ts +++ b/processor/compile/index.ts @@ -4,6 +4,7 @@ import embed from './embed'; import gemoji from './gemoji'; import htmlBlock from './html-block'; import image from './image'; +import compatibility from './compatibility'; import { NodeTypes } from '../../enums'; function compilers() { @@ -18,6 +19,10 @@ function compilers() { [NodeTypes.embed]: embed, [NodeTypes.htmlBlock]: htmlBlock, [NodeTypes.image]: image, + [NodeTypes.variable]: compatibility, + [NodeTypes.glossary]: compatibility, + [NodeTypes.reusableContent]: compatibility, + html: compatibility, }; toMarkdownExtensions.push({ extensions: [{ handlers }] }); diff --git a/processor/transform/callouts.ts b/processor/transform/callouts.ts index 9f6a19474..b02ef4196 100644 --- a/processor/transform/callouts.ts +++ b/processor/transform/callouts.ts @@ -16,15 +16,18 @@ const calloutTransformer = () => { if (icon && match) { const heading = startText.slice(match.length); - node.children[0].children[0].value = heading; - node.type = NodeTypes.callout; - node.data = { - hName: 'Callout', - hProperties: { - icon, + + Object.assign(node, { + type: NodeTypes.callout, + data: { + hName: 'Callout', + hProperties: { + icon, + empty: !heading.length, + }, }, - }; + }); } }); }; diff --git a/processor/transform/readme-components.ts b/processor/transform/readme-components.ts index 0079623dd..19af324ba 100644 --- a/processor/transform/readme-components.ts +++ b/processor/transform/readme-components.ts @@ -78,17 +78,15 @@ const coerceJsxToMd = parent.children[index] = mdNode; } else if (node.name === 'Callout') { - const { heading, icon } = attributes<{ heading?: string; icon: string }>(node); - - const child = mdast(heading); + const { icon, empty = false } = attributes<{ empty?: boolean; icon: string }>(node); // @ts-ignore const mdNode: Callout = { - children: [child?.children?.[0], ...node.children].filter(Boolean) as any, + children: node.children as any, type: NodeTypes.callout, data: { hName: node.name, - hProperties: { icon }, + hProperties: { icon, empty }, }, position: node.position, }; diff --git a/types.d.ts b/types.d.ts index 021eb3aba..29be84890 100644 --- a/types.d.ts +++ b/types.d.ts @@ -7,6 +7,7 @@ type Callout = Omit & { hName: 'Callout'; hProperties: { icon: string; + empty: boolean; }; }; };