1
1
mirror of https://github.com/jxnblk/mdx-deck.git synced 2024-12-01 21:42:08 +03:00
mdx-deck/packages/mdx-plugin/index.js
2019-04-05 19:54:22 -04:00

128 lines
3.1 KiB
JavaScript

const visit = require('unist-util-visit')
const is = require('unist-util-is')
const mdxAstToMdxHast = require('@mdx-js/mdx/mdx-ast-to-mdx-hast')
// custom implementation
// this can be removed in favor of https://github.com/mdx-js/mdx/issues/454
const toTemplateLiteral = text =>
'{`' + text.replace(/\\/g, '\\\\').replace(/`/g, '\\`') + '`}'
const toJSX = (node, parent, opts = {}) => {
const { preserveNewlines = false } = opts
let children = ''
if (node.type === 'root') {
const jsxNodes = []
let layout = ''
for (const child of node.children) {
// imports/exports should already be handled for the root mdx component
if (child.type === 'import') continue
if (child.type === 'export') {
if (!child.default) continue
layout = child.value
.replace(/^export\s+default\s+/, '')
.replace(/;\s*$/, '')
continue
}
jsxNodes.push(child)
}
return [
'(props => {',
` const __MDXDECK_LAYOUT__ = ${layout ? layout : '"div"'}`,
' return <__MDXDECK_LAYOUT__',
' name="wrapper"',
' components={props.components}>',
' ' + jsxNodes.map(child => toJSX(child, node)).join('\n '),
' </__MDXDECK_LAYOUT__>',
'})',
]
.filter(Boolean)
.join('\n')
}
if (node.children) {
children = node.children
.map(child => {
return toJSX(child, node, {
preserveNewlines: preserveNewlines || node.tagName === 'pre',
})
})
.join('')
}
if (node.type === 'element') {
let props = ''
if (Object.keys(node.properties).length > 0) {
props = JSON.stringify(node.properties)
}
return [
`<${node.tagName}`,
parent.tagName && ` parentName="${parent.tagName}"`,
props && ` {...${props}}`,
'>',
children,
`</${node.tagName}>`,
]
.filter(Boolean)
.join('')
}
if (node.type === 'text') {
const shouldPreserveNewlines = preserveNewlines || parent.tagName === 'p'
if (node.value === '\n' && !shouldPreserveNewlines) {
return node.value
}
return toTemplateLiteral(node.value)
}
if (node.type === 'comment') {
return `{/*${node.value}*/}`
}
return node.value
}
const delimiter = 'thematicBreak'
module.exports = (opts = {}) => {
return (tree, file) => {
const { children } = tree
const splits = []
const slides = []
visit(tree, node => {
if (is(delimiter, node)) {
const i = children.indexOf(node)
splits.push(i)
}
})
let previousSplit = 0
for (let i = 0; i < splits.length; i++) {
const split = splits[i]
slides.push(children.slice(previousSplit, split))
previousSplit = split + 1
}
slides.push(children.slice(previousSplit))
const jsx = slides.map(slide => {
const hast = mdxAstToMdxHast()({
type: 'root',
children: slide,
})
const code = toJSX(hast, {}, { skipExport: true })
return code
})
tree.children.push({
type: 'export',
default: false,
value: `export const slides = [${jsx.join(',\n')}]`,
})
}
}