Skip to content

Commit

Permalink
feat: options.target
Browse files Browse the repository at this point in the history
add MDX 3.0 support

BREAKING CHANGE: wrapping `img-html-base64/inline-svg` in paragraph
  • Loading branch information
Airkro committed Dec 1, 2023
1 parent 074f203 commit dc0927b
Show file tree
Hide file tree
Showing 20 changed files with 868 additions and 163 deletions.
92 changes: 91 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,36 @@ remark()
.catch((error) => console.warn(error));
```

### Docusaurus project
### Docusaurus v3 project

```mjs
// docusaurus.config.mjs
import { remarkKroki } from 'remark-kroki';

export default {
presets: [
[
'classic',
{
docs: {
remarkPlugins: [
[
remarkKroki,
{
// ...options here
alias: ['plantuml'],
target: 'mdx3'
}
]
]
}
}
]
]
};
```

### Docusaurus v2 project

```cjs
// docusaurus.config.js
Expand Down Expand Up @@ -94,6 +123,14 @@ HTTP headers to send to the server for custom authentication.

Alias code language name to treat as kroki code block, meta.type will be ignored.

### Options.target

- type: string
- default: `'html'`
- enum: `['html', 'mdx3']`

Transform HTML tags as MDX 3.0 AST or not. When you using Docusaurus v3, you should use `mdx3`.

### Options.output

- type: string
Expand Down Expand Up @@ -138,8 +175,61 @@ Into
```
````

## Troubleshooting

When you using `inline-svg` with `mdx3` mode, You may get following error:

```log
Error: Cannot handle unknown node `raw` when using with `@mdx-js/mdx`
```

You need to add `rehype-raw` to the complier, for example:

```mjs
// docusaurus.config.mjs
import rehypeRaw from 'rehype-raw';
import { remarkKroki } from 'remark-kroki';

export default {
presets: [
[
'classic',
{
docs: {
remarkPlugins: [
[
remarkKroki,
{
// ...options here
target: 'mdx3',
output: 'inline-svg'
}
]
],
rehypePlugins: [
[
rehypeRaw,
{
passThrough: [
'mdxFlowExpression',
'mdxJsxFlowElement',
'mdxJsxTextElement',
'mdxTextExpression',
'mdxjsEsm'
]
}
]
]
}
}
]
]
};
```

## Related

- [markdown-code-block-meta](https://github.com/nice-move/markdown-code-block-meta)
- [rehype-extended-table](https://github.com/nice-move/rehype-extended-table)
- [remark-code-example](https://github.com/nice-move/remark-code-example)
- [remark-docusaurus](https://github.com/nice-move/remark-docusaurus)
20 changes: 20 additions & 0 deletions lib/ast.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function attrString(attributes = []) {
return attributes.length > 0
? attributes.map(({ name, value }) => ` ${name}="${value}"`).join('')
: '';
}

export function create(target, ast) {
if (target === 'mdx3') {
return ast;
}

const { name, attributes, children: [{ value: child } = {}] = [] } = ast;

return {
type: target,
value: child
? [`<${name}${attrString(attributes)}>`, child, `</${name}>`].join('')
: `<${name}${attrString(attributes)} />`,
};
}
18 changes: 18 additions & 0 deletions lib/fetch.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import nodeFetch from 'node-fetch';

export function httpPost({ url, body, headers }) {
return nodeFetch(url, {
method: 'POST',
body,
headers: {
...headers,
'Content-Type': 'text/plain',
},
}).then(async (response) => {
if (!response.ok) {
throw new Error(await response.text());
}

return response.arrayBuffer();
});
}
5 changes: 3 additions & 2 deletions lib/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ export function remarkKroki({
headers = {},
alias = [],
output = outputType[0],
target = 'html',
} = {}) {
validate({ server, headers, alias, output });
validate({ server, headers, alias, output, target });

const condition = isKroki(alias);

return async (tree) => {
const temp = [];

visit(tree, condition, (node) => {
temp.push(transform({ node, server, headers, output }));
temp.push(transform({ node, server, headers, output, target }));
});

// eslint-disable-next-line no-empty
Expand Down
145 changes: 116 additions & 29 deletions lib/transform.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getValue, parse } from 'markdown-code-block-meta';

import { create } from './ast.mjs';
import { fetchData, mime, toDataURL } from './utils.mjs';

/* eslint-disable no-param-reassign */
Expand All @@ -9,39 +10,125 @@ function removeXML(string) {
}

const modes = {
'img-base64': ({ node, diagramType, data, alt }) => {
node.type = 'paragraph';
node.children = [
{
type: 'image',
alt: alt || diagramType,
url: toDataURL(data),
},
];
'img-base64': ({ diagramType, data, alt }) => {
return {
type: 'paragraph',
children: [
{
type: 'image',
_meta: { kroki: true, type: diagramType },
alt: alt || diagramType,
url: toDataURL(data),
},
],
};
},
'object-base64': ({ node, diagramType, data, alt }) => {
node.type = 'html';
node.value = `<object type="${mime}" class="kroki-object" data-type="${diagramType}" title="${
alt || diagramType
}" data="${toDataURL(data)}">Load SVG fail...</object>`;
'object-base64': ({ target, diagramType, data, alt }) => {
return create(target, {
type: 'mdxJsxFlowElement',
name: 'object',
children: [
{
type: 'text',
value: 'Load SVG fail...',
},
],
attributes: [
{
type: 'mdxJsxAttribute',
name: 'type',
value: mime,
},
{
type: 'mdxJsxAttribute',
name: 'class',
value: 'kroki-object',
},
{
type: 'mdxJsxAttribute',
name: 'data-type',
value: diagramType,
},
{
type: 'mdxJsxAttribute',
name: 'title',
value: alt || diagramType,
},
{
type: 'mdxJsxAttribute',
name: 'data',
value: toDataURL(data),
},
],
});
},
'img-html-base64': ({ node, diagramType, data, alt }) => {
node.type = 'html';
node.value = `<img class="kroki-image" alt="${
alt || diagramType
}" src="${toDataURL(data)}" />`;
'img-html-base64': ({ target, diagramType, data, alt }) => {
return {
type: 'paragraph',
children: [
create(target, {
type: 'mdxJsxTextElement',
name: 'img',
attributes: [
{
type: 'mdxJsxAttribute',
name: 'class',
value: 'kroki-image',
},
{
type: 'mdxJsxAttribute',
name: 'alt',
value: alt || diagramType,
},
{
type: 'mdxJsxAttribute',
name: 'data-type',
value: diagramType,
},
{
type: 'mdxJsxAttribute',
name: 'src',
value: toDataURL(data),
},
],
}),
],
};
},
'inline-svg': ({ node, diagramType, data, alt }) => {
node.type = 'html';
node.value = `<div class="kroki-inline-svg" data-type="${diagramType}" data-alt="${
alt || diagramType
}">${removeXML(data.toString())}</div>`;
'inline-svg': ({ target, diagramType, data, alt }) => {
return create(target, {
type: 'mdxJsxFlowElement',
name: 'p',
attributes: [
{
type: 'mdxJsxAttribute',
name: 'class',
value: 'kroki-inline-svg',
},
{
type: 'mdxJsxAttribute',
name: 'data-type',
value: diagramType,
},
{
type: 'mdxJsxAttribute',
name: 'data-alt',
value: alt || diagramType,
},
],
children: [
{
type: 'html',
value: removeXML(data.toString()),
},
],
});
},
};

export const outputType = Object.keys(modes);

export async function transform({ node, server, headers, output }) {
export async function transform({ node, server, headers, output, target }) {
const { meta, value, lang } = node;

const object = parse(meta);
Expand All @@ -58,9 +145,9 @@ export async function transform({ node, server, headers, output }) {
value,
});

delete node.lang;
delete node.value;
delete node.meta;
for (const key of Object.keys(node)) {
delete node[key];
}

modes[output]({ node, diagramType, data, alt });
Object.assign(node, modes[output]({ diagramType, data, alt, target }));
}
Loading

0 comments on commit dc0927b

Please sign in to comment.