diff --git a/packages/remark-mdxs/index.js b/packages/remark-mdxs/index.js new file mode 100644 index 000000000..177f4d5b6 --- /dev/null +++ b/packages/remark-mdxs/index.js @@ -0,0 +1,76 @@ +const visit = require('unist-util-visit') +const remove = require('unist-util-remove') +const {toJSX} = require('@mdx-js/mdx/mdx-hast-to-jsx') + +module.exports = function({delimiter = 'hr'}) { + this.Compiler = tree => { + const splits = [] + const documents = [] + + const importNodes = tree.children.filter(n => n.type === 'import') + const exportNodes = tree.children.filter(n => n.type === 'export') + + const layout = exportNodes.find(node => node.default) + + // We don't care about imports and exports when handling + // multiple MDX documents + let mdxsTree = remove(remove(tree, 'export'), 'import') + const {children} = mdxsTree + + visit(mdxsTree, node => { + if (node.tagName === delimiter) { + splits.push(children.indexOf(node)) + } + }) + + let previousSplit = 0 + for (let i = 0; i < splits.length; i++) { + const split = splits[i] + documents.push(children.slice(previousSplit, split)) + previousSplit = split + 1 + } + + documents.push(children.slice(previousSplit)) + + const jsxFragments = documents + .map(nodes => nodes.map(toJSX).join('\n')) + .map((jsx, i) => + ` +function MDXSContent${i}({ components, ...props }) { + return ( + ${jsx.trim()} + ) +} + `.trim() + ) + + const defaultExport = ` +const MDXSWrapper = props => [ +${jsxFragments.map((_, i) => ` `).join(',\n')} +] + +export default MDXWrapper + `.trim() + + return [ + importNodes.map(n => n.value.trim()).join('\n'), + '', + exportNodes + .filter(n => !n.default) + .map(n => n.value.trim()) + .join('\n'), + '', + `const MDXSLayout = ${ + layout + ? layout.value + .replace(/^export\s+default\s+/, '') + .replace(/;\s*$/, '') + : '"wrapper"' + }`, + '', + jsxFragments.join('\n\n'), + '', + defaultExport + ].join('\n') + } +} diff --git a/packages/remark-mdxs/license b/packages/remark-mdxs/license new file mode 100644 index 000000000..dc4d4beab --- /dev/null +++ b/packages/remark-mdxs/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 John Otander and Brent Jackson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/remark-mdxs/package.json b/packages/remark-mdxs/package.json new file mode 100644 index 000000000..76c653ea4 --- /dev/null +++ b/packages/remark-mdxs/package.json @@ -0,0 +1,54 @@ +{ + "name": "remark-mdxs", + "version": "1.0.0-rc.0", + "description": "Support for multiple MDX documents in a single file", + "license": "MIT", + "keywords": [ + "mdx", + "mdxs", + "markdown", + "react", + "jsx", + "remark", + "mdxast" + ], + "homepage": "https://mdxjs.com", + "repository": "mdx-js/mdx", + "bugs": "https://github.com/mdx-js/mdx/issues", + "author": "John Otander (https://johno.com)", + "contributors": [ + "John Otander (http://johnotander.com)", + "Brent Jackson (https://jxnblk.com)", + "Tim Neutkens ", + "Matija Marohnić ", + "Titus Wormer (https://wooorm.com)" + ], + "files": [ + "index.js" + ], + "dependencies": { + "@babel/core": "^7.2.2", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.3.2", + "@babel/plugin-syntax-jsx": "^7.2.0", + "is-alphabetical": "^1.0.2", + "remark-parse": "^6.0.0", + "unified": "^7.0.0", + "unist-util-remove": "^1.0.1", + "unist-util-visit": "^1.4.0" + }, + "peerDependencies": { + "@mdx-js/mdx": "*" + }, + "scripts": { + "test": "jest" + }, + "jest": { + "testEnvironment": "node" + }, + "devDependencies": { + "jest": "^24.0.0", + "remark-stringify": "^6.0.4", + "vfile": "^4.0.0" + } +} diff --git a/packages/remark-mdxs/readme.md b/packages/remark-mdxs/readme.md new file mode 100644 index 000000000..abff2fbe6 --- /dev/null +++ b/packages/remark-mdxs/readme.md @@ -0,0 +1,73 @@ +# @[mdx][]-js/mdxs + +[![Build Status][build-badge]][build] +[![lerna][lerna-badge]][lerna] +[![Join the community on Spectrum][spectrum-badge]][spectrum] + +> :warning: This project is currently in alpha + +Multi-doc syntax support for MDX. + +## Installation + +```sh +npm install --save mdxs +``` + +## Usage + +```js +const mdx = require('@mdx-js/mdx') +const mdxs = require('@mdx-js/mdxs') + +const jsx = await mdx(FIXTURE, { + compilers: [mdxs] +}) +``` + +## Syntax + +```md + +# Hello, I'm document 1 + +--- + +# Hello, I'm document 2 +``` + +## Contribute + +See [`contributing.md` in `mdx-js/mdx`][contributing] for ways to get started. + +This organisation has a [Code of Conduct][coc]. +By interacting with this repository, organisation, or community you agree to +abide by its terms. + +## License + +[MIT][] © [John Otander][author] + + + +[build]: https://travis-ci.org/mdx-js/mdx + +[build-badge]: https://travis-ci.org/mdx-js/mdx.svg?branch=master + +[lerna]: https://lernajs.io/ + +[lerna-badge]: https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg + +[spectrum]: https://spectrum.chat/mdx + +[spectrum-badge]: https://withspectrum.github.io/badge/badge.svg + +[contributing]: https://github.com/mdx-js/mdx/blob/master/contributing.md + +[coc]: https://github.com/mdx-js/mdx/blob/master/code-of-conduct.md + +[mit]: license + +[mdx]: https://github.com/mdx-js/mdx + +[author]: https://johno.com diff --git a/packages/remark-mdxs/test/__snapshots__/test.js.snap b/packages/remark-mdxs/test/__snapshots__/test.js.snap new file mode 100644 index 000000000..d528eae18 --- /dev/null +++ b/packages/remark-mdxs/test/__snapshots__/test.js.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`correctly transpiles 1`] = ` +"/* @jsx mdx */ +import Foo from './bar' + +export const author = 'fred' + +const MDXSLayout = Foo + +function MDXSContent0({ components, ...props }) { + return ( +

{\`Hello, world! \`}

+ ) +} + +function MDXSContent1({ components, ...props }) { + return ( + + Hi! + + ) +} + +function MDXSContent2({ components, ...props }) { + return ( +

{\`I'm another document\`}

+ + +

{\`over here.\`}

+ ) +} + +const MDXSWrapper = props => [ + , + , + +] + +export default MDXWrapper" +`; diff --git a/packages/remark-mdxs/test/test.js b/packages/remark-mdxs/test/test.js new file mode 100644 index 000000000..4319ba0ee --- /dev/null +++ b/packages/remark-mdxs/test/test.js @@ -0,0 +1,30 @@ +const mdx = require('../../mdx') +const remarkMdxs = require('..') + +const FIXTURE = ` +import Foo from './bar' +export const author = 'fred' +export default Foo + +# Hello, world! + +--- + + + Hi! + + +--- + +# I'm another document + +over here. +` + +it('correctly transpiles', async () => { + const result = await mdx(FIXTURE, { + compilers: [remarkMdxs] + }) + + expect(result).toMatchSnapshot() +})