From 5846bf9d365848a5cb6107967298100a19cd08a6 Mon Sep 17 00:00:00 2001
From: John Otander <johnotander@gmail.com>
Date: Fri, 5 Apr 2019 18:34:41 -0600
Subject: [PATCH 1/2] Implement first pass of MDXs

This implements the basic idea of MDXs. Though
we still need to figure out how to best handle
the layout mechanism.

cc/ @christopherbiscardi, @jxnblk, @timneutkens

---

Related #454
---
 packages/mdx/index.js                         |  3 +-
 packages/remark-mdxs/index.js                 | 76 +++++++++++++++++++
 packages/remark-mdxs/license                  | 21 +++++
 packages/remark-mdxs/package.json             | 54 +++++++++++++
 packages/remark-mdxs/readme.md                | 55 ++++++++++++++
 .../test/__snapshots__/test.js.snap           | 41 ++++++++++
 packages/remark-mdxs/test/test.js             | 30 ++++++++
 7 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 packages/remark-mdxs/index.js
 create mode 100644 packages/remark-mdxs/license
 create mode 100644 packages/remark-mdxs/package.json
 create mode 100644 packages/remark-mdxs/readme.md
 create mode 100644 packages/remark-mdxs/test/__snapshots__/test.js.snap
 create mode 100644 packages/remark-mdxs/test/test.js

diff --git a/packages/mdx/index.js b/packages/mdx/index.js
index d5cdd889b..0feb733f8 100644
--- a/packages/mdx/index.js
+++ b/packages/mdx/index.js
@@ -30,6 +30,7 @@ function createMdxAstCompiler(options) {
   const fn = unified()
     .use(toMDAST, options)
     .use(remarkMdx, options)
+    .use(mdxHastToJsx, options) // Set JSX compiler early so it can be overridden
     .use(squeeze, options)
     .use(toMDXAST, options)
 
@@ -81,8 +82,6 @@ function applyHastPluginsAndCompilers(compiler, options) {
     }
   })
 
-  compiler.use(mdxHastToJsx, options)
-
   for (const compilerPlugin of compilers) {
     compiler.use(compilerPlugin, options)
   }
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) => `  <MDXSContent${i} {...props} />`).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 <johnotander@gmail.com> (https://johno.com)",
+  "contributors": [
+    "John Otander <johnotander@gmail.com> (http://johnotander.com)",
+    "Brent Jackson <jacksonblack@gmail.com> (https://jxnblk.com)",
+    "Tim Neutkens <tim@zeit.co>",
+    "Matija Marohnić <matija.marohnic@gmail.com>",
+    "Titus Wormer <tituswormer@gmail.com> (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..4645b2e03
--- /dev/null
+++ b/packages/remark-mdxs/readme.md
@@ -0,0 +1,55 @@
+# [remark][]-[mdx][]s
+
+[![Build Status][build-badge]][build]
+[![lerna][lerna-badge]][lerna]
+[![Join the community on Spectrum][spectrum-badge]][spectrum]
+
+> :warning: This project is currently in alpha
+
+[MDXs][] syntax support for [remark][].
+
+## Installation
+
+```sh
+npm install --save remark-mdxs
+```
+
+## 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][] © [Titus Wormer][author] and [John Otander][author2]
+
+<!-- Definitions -->
+
+[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
+
+[remark]: https://github.com/remarkjs/remark
+
+[mdx]: https://github.com/mdx-js/mdx
+
+[author]: https://wooorm.com
+
+[author2]: 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 (
+    <h1>{\`Hello, world! \`}<Foo bar={{ baz: 'qux' }} /></h1>
+  )
+}
+
+function MDXSContent1({ components, ...props }) {
+  return (
+    <Baz>
+  Hi!
+</Baz>
+  )
+}
+
+function MDXSContent2({ components, ...props }) {
+  return (
+    <h1>{\`I'm another document\`}</h1>
+
+
+<p>{\`over here.\`}</p>
+  )
+}
+
+const MDXSWrapper = props => [
+  <MDXSContent0 {...props} />,
+  <MDXSContent1 {...props} />,
+  <MDXSContent2 {...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..cb25266c0
--- /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! <Foo bar={{ baz: 'qux' }} />
+
+---
+
+<Baz>
+  Hi!
+</Baz>
+
+---
+
+# I'm another document
+
+over here.
+`
+
+it('correctly transpiles', async () => {
+  const result = await mdx(FIXTURE, {
+    remarkPlugins: [remarkMdxs]
+  })
+
+  expect(result).toMatchSnapshot()
+})

From 05eb9422cd604b247f5f3af98e6875f9081ba4cf Mon Sep 17 00:00:00 2001
From: John Otander <johnotander@gmail.com>
Date: Wed, 10 Apr 2019 15:43:25 -0600
Subject: [PATCH 2/2] Improve readme, use compilers API

---
 packages/mdx/index.js             |  3 ++-
 packages/remark-mdxs/readme.md    | 36 +++++++++++++++++++++++--------
 packages/remark-mdxs/test/test.js |  2 +-
 3 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/packages/mdx/index.js b/packages/mdx/index.js
index 0feb733f8..d5cdd889b 100644
--- a/packages/mdx/index.js
+++ b/packages/mdx/index.js
@@ -30,7 +30,6 @@ function createMdxAstCompiler(options) {
   const fn = unified()
     .use(toMDAST, options)
     .use(remarkMdx, options)
-    .use(mdxHastToJsx, options) // Set JSX compiler early so it can be overridden
     .use(squeeze, options)
     .use(toMDXAST, options)
 
@@ -82,6 +81,8 @@ function applyHastPluginsAndCompilers(compiler, options) {
     }
   })
 
+  compiler.use(mdxHastToJsx, options)
+
   for (const compilerPlugin of compilers) {
     compiler.use(compilerPlugin, options)
   }
diff --git a/packages/remark-mdxs/readme.md b/packages/remark-mdxs/readme.md
index 4645b2e03..abff2fbe6 100644
--- a/packages/remark-mdxs/readme.md
+++ b/packages/remark-mdxs/readme.md
@@ -1,4 +1,4 @@
-# [remark][]-[mdx][]s
+# @[mdx][]-js/mdxs
 
 [![Build Status][build-badge]][build]
 [![lerna][lerna-badge]][lerna]
@@ -6,12 +6,34 @@
 
 > :warning: This project is currently in alpha
 
-[MDXs][] syntax support for [remark][].
+Multi-doc syntax support for MDX.
 
 ## Installation
 
 ```sh
-npm install --save remark-mdxs
+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
@@ -24,7 +46,7 @@ abide by its terms.
 
 ## License
 
-[MIT][] © [Titus Wormer][author] and [John Otander][author2]
+[MIT][] © [John Otander][author]
 
 <!-- Definitions -->
 
@@ -46,10 +68,6 @@ abide by its terms.
 
 [mit]: license
 
-[remark]: https://github.com/remarkjs/remark
-
 [mdx]: https://github.com/mdx-js/mdx
 
-[author]: https://wooorm.com
-
-[author2]: https://johno.com
+[author]: https://johno.com
diff --git a/packages/remark-mdxs/test/test.js b/packages/remark-mdxs/test/test.js
index cb25266c0..4319ba0ee 100644
--- a/packages/remark-mdxs/test/test.js
+++ b/packages/remark-mdxs/test/test.js
@@ -23,7 +23,7 @@ over here.
 
 it('correctly transpiles', async () => {
   const result = await mdx(FIXTURE, {
-    remarkPlugins: [remarkMdxs]
+    compilers: [remarkMdxs]
   })
 
   expect(result).toMatchSnapshot()