2019-12-16 12:17:37 -05:00
|
|
|
import React from 'react';
|
2017-07-31 12:58:45 -04:00
|
|
|
import { map, has } from 'lodash';
|
|
|
|
import { renderToString } from 'react-dom/server';
|
|
|
|
import u from 'unist-builder';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This plugin doesn't actually transform Remark (MDAST) nodes to Rehype
|
|
|
|
* (HAST) nodes, but rather, it prepares an MDAST shortcode node for HAST
|
|
|
|
* conversion by replacing the shortcode text with stringified HTML for
|
|
|
|
* previewing the shortcode output.
|
|
|
|
*/
|
2019-12-16 12:17:37 -05:00
|
|
|
export default function remarkToRehypeShortcodes({ plugins, getAsset, resolveWidget }) {
|
2017-07-31 12:58:45 -04:00
|
|
|
return transform;
|
|
|
|
|
2019-12-18 18:16:02 +02:00
|
|
|
async function transform(root) {
|
|
|
|
const transformedChildren = await Promise.all(map(root.children, processShortcodes));
|
2017-07-31 12:58:45 -04:00
|
|
|
return { ...root, children: transformedChildren };
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mapping function to transform nodes that contain shortcodes.
|
|
|
|
*/
|
2019-12-18 18:16:02 +02:00
|
|
|
async function processShortcodes(node) {
|
2017-07-31 12:58:45 -04:00
|
|
|
/**
|
|
|
|
* If the node doesn't contain shortcode data, return the original node.
|
|
|
|
*/
|
|
|
|
if (!has(node, ['data', 'shortcode'])) return node;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get shortcode data from the node, and retrieve the matching plugin by
|
|
|
|
* key.
|
|
|
|
*/
|
|
|
|
const { shortcode, shortcodeData } = node.data;
|
|
|
|
const plugin = plugins.get(shortcode);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Run the shortcode plugin's `toPreview` method, which will return either
|
|
|
|
* an HTML string or a React component. If a React component is returned,
|
|
|
|
* render it to an HTML string.
|
|
|
|
*/
|
2019-12-18 18:16:02 +02:00
|
|
|
const value = await getPreview(plugin, shortcodeData);
|
2017-07-31 12:58:45 -04:00
|
|
|
const valueHtml = typeof value === 'string' ? value : renderToString(value);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a new 'html' type node containing the shortcode preview markup.
|
|
|
|
*/
|
|
|
|
const textNode = u('html', valueHtml);
|
2018-08-07 14:46:54 -06:00
|
|
|
const children = [textNode];
|
2017-07-31 12:58:45 -04:00
|
|
|
return { ...node, children };
|
|
|
|
}
|
2019-12-16 12:17:37 -05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the shortcode preview component.
|
|
|
|
*/
|
2019-12-18 18:16:02 +02:00
|
|
|
async function getPreview(plugin, shortcodeData) {
|
2020-02-10 18:05:47 +02:00
|
|
|
const { toPreview, widget, fields } = plugin;
|
2019-12-16 12:17:37 -05:00
|
|
|
if (toPreview) {
|
2020-02-10 18:05:47 +02:00
|
|
|
return toPreview(shortcodeData, getAsset, fields);
|
2019-12-16 12:17:37 -05:00
|
|
|
}
|
|
|
|
const preview = resolveWidget(widget);
|
|
|
|
return React.createElement(preview.preview, {
|
|
|
|
value: shortcodeData,
|
|
|
|
field: plugin,
|
|
|
|
getAsset,
|
|
|
|
});
|
|
|
|
}
|
2017-07-31 12:58:45 -04:00
|
|
|
}
|