74 lines
2.1 KiB
JavaScript
74 lines
2.1 KiB
JavaScript
import { without, flatten } from 'lodash';
|
|
import u from 'unist-builder';
|
|
import mdastDefinitions from 'mdast-util-definitions';
|
|
|
|
/**
|
|
* Raw markdown may contain image references or link references. Because there
|
|
* is no way to maintain these references within the Slate AST, we convert image
|
|
* and link references to standard images and links by putting their url's
|
|
* inline. The definitions are then removed from the document.
|
|
*
|
|
* For example, the following markdown:
|
|
*
|
|
* ```
|
|
* ![alpha][bravo]
|
|
*
|
|
* [bravo]: http://example.com/example.jpg
|
|
* ```
|
|
*
|
|
* Yields:
|
|
*
|
|
* ```
|
|
* ![alpha](http://example.com/example.jpg)
|
|
* ```
|
|
*
|
|
*/
|
|
export default function remarkSquashReferences() {
|
|
return getTransform;
|
|
|
|
function getTransform(node) {
|
|
const getDefinition = mdastDefinitions(node);
|
|
return transform.call(null, getDefinition, node);
|
|
}
|
|
|
|
function transform(getDefinition, node) {
|
|
/**
|
|
* Bind the `getDefinition` function to `transform` and recursively map all
|
|
* nodes.
|
|
*/
|
|
const boundTransform = transform.bind(null, getDefinition);
|
|
const children = node.children ? node.children.map(boundTransform) : node.children;
|
|
|
|
/**
|
|
* Combine reference and definition nodes into standard image and link
|
|
* nodes.
|
|
*/
|
|
if (['imageReference', 'linkReference'].includes(node.type)) {
|
|
const type = node.type === 'imageReference' ? 'image' : 'link';
|
|
const definition = getDefinition(node.identifier);
|
|
|
|
if (definition) {
|
|
const { title, url } = definition;
|
|
return u(type, { title, url, alt: node.alt }, children);
|
|
}
|
|
|
|
const pre = u('text', node.type === 'imageReference' ? '![' : '[');
|
|
const post = u('text', ']');
|
|
const nodes = children || [u('text', node.alt)];
|
|
return [pre, ...nodes, post];
|
|
}
|
|
|
|
/**
|
|
* Remove definition nodes and filter the resulting null values from the
|
|
* filtered children array.
|
|
*/
|
|
if (node.type === 'definition') {
|
|
return null;
|
|
}
|
|
|
|
const filteredChildren = without(children, null);
|
|
|
|
return { ...node, children: flatten(filteredChildren) };
|
|
}
|
|
}
|