UNPKG

3.46 kBJavaScriptView Raw
1const unified = require('unified')
2const toMDAST = require('remark-parse')
3const remarkMdx = require('remark-mdx')
4const footnotes = require('remark-footnotes')
5const squeeze = require('remark-squeeze-paragraphs')
6const visit = require('unist-util-visit')
7const raw = require('hast-util-raw')
8const toMDXAST = require('./md-ast-to-mdx-ast')
9const mdxAstToMdxHast = require('./mdx-ast-to-mdx-hast')
10const mdxHastToJsx = require('./mdx-hast-to-jsx')
11
12const DEFAULT_OPTIONS = {
13 remarkPlugins: [],
14 rehypePlugins: [],
15 compilers: []
16}
17
18function createMdxAstCompiler(options) {
19 const mdPlugins = options.mdPlugins
20 const remarkPlugins = options.remarkPlugins
21 const plugins = mdPlugins || remarkPlugins
22
23 if (mdPlugins) {
24 console.error(`
25 @mdx-js/mdx: The mdPlugins option has been deprecated in favor of remarkPlugins
26 Support for mdPlugins will be removed in MDX v2
27 `)
28 }
29
30 const fn = unified()
31 .use(toMDAST, options)
32 .use(remarkMdx, options)
33 .use(footnotes, options)
34 .use(squeeze, options)
35 .use(toMDXAST, options)
36
37 plugins.forEach(plugin => {
38 // Handle [plugin, pluginOptions] syntax
39 if (Array.isArray(plugin) && plugin.length > 1) {
40 fn.use(plugin[0], plugin[1])
41 } else {
42 fn.use(plugin)
43 }
44 })
45
46 fn.use(mdxAstToMdxHast, options)
47
48 return fn
49}
50
51function applyHastPluginsAndCompilers(compiler, options) {
52 const hastPlugins = options.hastPlugins
53 const rehypePlugins = options.rehypePlugins
54 const plugins = hastPlugins || rehypePlugins
55
56 if (hastPlugins) {
57 console.error(`
58 @mdx-js/mdx: The hastPlugins option has been deprecated in favor of rehypePlugins
59 Support for hastPlugins will be removed in MDX v2
60 `)
61 }
62
63 const compilers = options.compilers
64
65 // Convert raw nodes into HAST
66 compiler.use(() => ast => {
67 visit(ast, 'raw', node => {
68 const {children, tagName, properties} = raw(node)
69 node.type = 'element'
70 node.children = children
71 node.tagName = tagName
72
73 node.properties = properties
74 })
75 })
76
77 plugins.forEach(plugin => {
78 // Handle [plugin, pluginOptions] syntax
79 if (Array.isArray(plugin) && plugin.length > 1) {
80 compiler.use(plugin[0], plugin[1])
81 } else {
82 compiler.use(plugin)
83 }
84 })
85
86 compiler.use(mdxHastToJsx, options)
87
88 for (const compilerPlugin of compilers) {
89 compiler.use(compilerPlugin, options)
90 }
91
92 return compiler
93}
94
95function createCompiler(options = {}) {
96 const opts = Object.assign({}, DEFAULT_OPTIONS, options)
97 const compiler = createMdxAstCompiler(opts)
98 const compilerWithPlugins = applyHastPluginsAndCompilers(compiler, opts)
99
100 return compilerWithPlugins
101}
102
103function sync(mdx, options = {}) {
104 const compiler = createCompiler(options)
105
106 const fileOpts = {contents: mdx}
107 if (options.filepath) {
108 fileOpts.path = options.filepath
109 }
110
111 const {contents} = compiler.processSync(fileOpts)
112
113 return `/* @jsx mdx */
114${contents}`
115}
116
117async function compile(mdx, options = {}) {
118 const compiler = createCompiler(options)
119
120 const fileOpts = {contents: mdx}
121 if (options.filepath) {
122 fileOpts.path = options.filepath
123 }
124
125 const {contents} = await compiler.process(fileOpts)
126
127 return `/* @jsx mdx */
128${contents}`
129}
130
131compile.sync = sync
132
133module.exports = compile
134exports = compile
135exports.sync = sync
136exports.createMdxAstCompiler = createMdxAstCompiler
137exports.createCompiler = createCompiler
138exports.default = compile