/
remarkSquashReferences.js
73 lines (64 loc) · 2.07 KB
/
remarkSquashReferences.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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) };
}
}