UNPKG

2.69 kBJavaScriptView Raw
1const React = require('react');
2const unified = require('unified');
3const sanitize = require('hast-util-sanitize/lib/github.json');
4const Variable = require('@readme/variable');
5const remarkRehype = require('remark-rehype');
6const rehypeRaw = require('rehype-raw');
7const remarkParse = require('remark-parse');
8const rehypeSanitize = require('rehype-sanitize');
9const rehypeReact = require('rehype-react');
10const breaks = require('remark-breaks');
11
12const variableParser = require('./variable-parser');
13const gemojiParser = require('./gemoji-parser');
14
15const table = require('./components/Table');
16const heading = require('./components/Heading');
17const anchor = require('./components/Anchor');
18const code = require('./components/Code');
19
20// This is for checklists in <li>
21sanitize.tagNames.push('input');
22sanitize.ancestors.input = ['li'];
23
24const GlossaryItem = require('./GlossaryItem');
25
26/*
27 * This is kinda complicated. Our "markdown" within ReadMe
28 * can often not be just markdown, but also include regular HTML.
29 *
30 * In addition, we also have a few special markdown features
31 * e.g. <<variables>>
32 *
33 * We use the https://github.com/unifiedjs/unified
34 * to parse/transform and output React components.
35 *
36 * The order for this process goes like follows:
37 * - Parse regular markdown
38 * - Parse out our markdown add-ons using custom compilers
39 * - Convert from a remark mdast (markdown ast) to a rehype hast (hypertext ast)
40 * - Extract any raw HTML elements
41 * - Sanitize and remove any disallowed attributes
42 * - Output the hast to a React vdom with our custom components
43 */
44module.exports = function markdown(text, opts = {}) {
45 if (!text) return null;
46
47 return unified()
48 .use(remarkParse)
49 .use(variableParser.sanitize(sanitize))
50 .use(!opts.correctnewlines ? breaks : () => {})
51 .use(gemojiParser.sanitize(sanitize))
52 .use(remarkRehype, { allowDangerousHtml: true })
53 .use(rehypeRaw)
54 .use(rehypeSanitize)
55 .use(rehypeReact, {
56 createElement: React.createElement,
57 components: {
58 'readme-variable': Variable,
59 'readme-glossary-item': GlossaryItem,
60 table: table(sanitize),
61 h1: heading('h1', sanitize),
62 h2: heading('h2', sanitize),
63 h3: heading('h3', sanitize),
64 h4: heading('h4', sanitize),
65 h5: heading('h5', sanitize),
66 h6: heading('h6', sanitize),
67 a: anchor(sanitize),
68 code: code(sanitize),
69 // Remove enclosing <div>
70 // https://github.com/mapbox/remark-react/issues/54
71 // eslint-disable-next-line react/display-name
72 div: props => React.createElement(React.Fragment, props),
73 },
74 })
75 .processSync(text).contents;
76};