Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .remarkrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module.exports = {
plugins: [
'./packages/remark-mdx',
'./packages/remark-mdxjs',
'preset-wooorm',
'preset-prettier',
['retext', false],
Expand Down
2 changes: 0 additions & 2 deletions docs/advanced/typescript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ improve the developer experience for TypeScript users.
- `@mdx-js/runtime`
- `@mdx-js/vue`
- `remark-mdx`
- `remark-mdx-remove-exports`
- `remark-mdx-remove-imports`

Include types, no additional setup needed.

Expand Down
5 changes: 2 additions & 3 deletions packages/gatsby-theme-mdx/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,9 @@
"react-helmet": "6.1.0",
"react-live": "2.2.2",
"remark-emoji": "2.1.0",
"remark-mdx-remove-exports": "^2.0.0-next.8",
"remark-mdx-remove-imports": "^2.0.0-next.8",
"remark-slug": "6.0.0",
"theme-ui": "0.3.4"
"theme-ui": "0.3.4",
"unist-util-remove": "^2.0.0"
},
"gitHead": "bf7deab69996449cb99c2217dff75e65855eb2c1"
}
7 changes: 4 additions & 3 deletions packages/gatsby-theme-mdx/src/components/playground-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@ import {MDXProvider, mdx as createElement} from '@mdx-js/react'
import * as Rebass from '@rebass/emotion'
import {ThemeContext} from '@emotion/core'
import {css} from 'theme-ui'
import removeImports from 'remark-mdx-remove-imports'
import removeExports from 'remark-mdx-remove-exports'
import remove from 'unist-util-remove'

import CodeBlock from './code-block'

const removeEsm = () => tree => remove(tree, 'mdxjsEsm')

const transformCode = src => {
let transpiledMDX = ''

try {
transpiledMDX = mdx.sync(src, {
skipExport: true,
remarkPlugins: [removeImports, removeExports]
remarkPlugins: [removeEsm]
})
} catch (_e) {
return ''
Expand Down
2 changes: 0 additions & 2 deletions packages/mdx/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const unified = require('unified')
const remarkParse = require('remark-parse')
const remarkMdx = require('remark-mdx')
const remarkMdxJs = require('remark-mdxjs')
const squeeze = require('remark-squeeze-paragraphs')
const mdxAstToMdxHast = require('./mdx-ast-to-mdx-hast')
const mdxHastToJsx = require('./mdx-hast-to-jsx')
Expand All @@ -12,7 +11,6 @@ function createMdxAstCompiler(options = {}) {
return unified()
.use(remarkParse)
.use(remarkMdx)
.use(remarkMdxJs)
.use(squeeze)
.use(options.remarkPlugins)
.use(mdxAstToMdxHast)
Expand Down
21 changes: 8 additions & 13 deletions packages/mdx/mdx-ast-to-mdx-hast.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,20 @@ function mdxAstToMdxHast() {
h(node, 'code', props, [u('text', value)])
])
},
// To do: rename to `mdxJsImport`
import(h, node) {
return Object.assign({}, node, {type: 'import'})
mdxjsEsm(h, node) {
return node
},
// To do: rename to `mdxJsExport`
export(h, node) {
return Object.assign({}, node, {type: 'export'})
},
mdxBlockElement(h, node) {
mdxJsxFlowElement(h, node) {
return Object.assign({}, node, {children: all(h, node)})
},
mdxSpanElement(h, node) {
mdxJsxTextElement(h, node) {
return Object.assign({}, node, {children: all(h, node)})
},
mdxBlockExpression(h, node) {
return Object.assign({}, node, {type: 'mdxBlockExpression'})
mdxFlowExpression(h, node) {
return node
},
mdxSpanExpression(h, node) {
return Object.assign({}, node, {type: 'mdxSpanExpression'})
mdxTextExpression(h, node) {
return node
}
}
})
Expand Down
181 changes: 133 additions & 48 deletions packages/mdx/mdx-hast-to-jsx.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
const {transformSync} = require('@babel/core')
const uniq = require('lodash.uniq')
const {serializeTags} = require('remark-mdx/lib/serialize/mdx-element')
const serializeMdxExpression = require('remark-mdx/lib/serialize/mdx-expression')
const encode = require('stringify-entities/light')
const toH = require('hast-to-hyperscript')
const recast = require('recast')
const BabelPluginApplyMdxProp = require('babel-plugin-apply-mdx-type-prop')
const BabelPluginExtractImportNames = require('babel-plugin-extract-import-names')
const BabelPluginExtractExportNames = require('babel-plugin-extract-export-names')

// To do: `recast` might be heavy (have to check), and `astring` might be a good
// alternative.
// However, `astring` doesn’t support JSX.
// When we start compiling JSX away, `astring` might be a good fit though.

function toJSX(node, parentNode = {}, options = {}) {
if (node.type === 'root') {
return serializeRoot(node, options)
Expand All @@ -21,18 +26,14 @@ function toJSX(node, parentNode = {}, options = {}) {
return serializeText(node, options, parentNode)
}

if (node.type === 'mdxBlockExpression' || node.type === 'mdxSpanExpression') {
if (node.type === 'mdxFlowExpression' || node.type === 'mdxTextExpression') {
return serializeMdxExpression(node)
}

// To do: pass `parentName` in?
if (node.type === 'mdxBlockElement' || node.type === 'mdxSpanElement') {
if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') {
return serializeComponent(node, options, parentNode)
}

if (node.type === 'import' || node.type === 'export') {
return serializeEsSyntax(node)
}
}

function serializeRoot(node, options) {
Expand All @@ -42,31 +43,28 @@ function serializeRoot(node, options) {
wrapExport
} = options

const groups = {import: [], export: [], rest: []}
const groups = {mdxjsEsm: [], rest: []}

for (const child of node.children) {
groups[
child.type === 'import' || child.type === 'export' ? child.type : 'rest'
].push(child)
}
node.children.forEach(child => {
groups[child.type === 'mdxjsEsm' ? child.type : 'rest'].push(child)
})

// Find a default export, assumes there’s zero or one.
const defaultExport = groups.export.find(child => child.default)

const layout = defaultExport
? defaultExport.value
.replace(/^export\s+default\s+/, '')
.replace(/;\s*$/, '')
: null

const importStatements = groups.import
.map(childNode => toJSX(childNode, node))
.join('\n')

const exportStatements = groups.export
.filter(child => !child.default)
.map(childNode => toJSX(childNode, node))
.join('\n')
const importStatements = []
const exportStatements = []
let layout

groups.mdxjsEsm.forEach(child => {
child.data.estree.body.forEach(eschild => {
if (eschild.type === 'ImportDeclaration') {
importStatements.push(recast.prettyPrint(eschild).code)
} else if (eschild.type === 'ExportDefaultDeclaration') {
layout = recast.prettyPrint(eschild.declaration).code
} else {
exportStatements.push(recast.prettyPrint(eschild).code)
}
})
})

const doc = groups.rest
.map(childNode => toJSX(childNode, node, options))
Expand All @@ -85,7 +83,9 @@ MDXContent.isMDXComponent = true`
// Check JSX nodes against imports
const babelPluginExtractImportNamesInstance = new BabelPluginExtractImportNames()
const babelPluginExtractExportNamesInstance = new BabelPluginExtractExportNames()
const importsAndExports = [importStatements, exportStatements].join('\n')
const importsAndExports = []
.concat(importStatements, exportStatements)
Comment on lines +86 to +87
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this causing an issue?
Would spread syntax be appropriate here?

Suggested change
const importsAndExports = []
.concat(importStatements, exportStatements)
const importsAndExports = [...importStatements, ...exportStatements]

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they used to be two strings, now they’re two arrays.
I’m fine with spread or whatnot but there doesn’t seem to be a well defined baseline on what is and isn’t allowed, so I just did what I was familiar with!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Node 8-15 support spread syntax, as well as every major browser (except IE) https://kangax.github.io/compat-table/es6/

.join('\n')

transformSync(importsAndExports, {
configFile: false,
Expand Down Expand Up @@ -115,15 +115,18 @@ MDXContent.isMDXComponent = true`
]
}).code

const exportStatementsPostMdxTypeProps = transformSync(exportStatements, {
configFile: false,
babelrc: false,
plugins: [
require('@babel/plugin-syntax-jsx'),
require('@babel/plugin-syntax-object-rest-spread'),
babelPluginApplyMdxPropToExportsInstance.plugin
]
}).code
const exportStatementsPostMdxTypeProps = transformSync(
exportStatements.join('\n'),
{
configFile: false,
babelrc: false,
plugins: [
require('@babel/plugin-syntax-jsx'),
require('@babel/plugin-syntax-object-rest-spread'),
babelPluginApplyMdxPropToExportsInstance.plugin
]
}
).code

const allJsxNames = [
...babelPluginApplyMdxPropInstance.state.names,
Expand Down Expand Up @@ -187,12 +190,10 @@ function serializeElement(node, options, parentNode) {
}

function serializeComponent(node, options) {
const tags = serializeTags(node)
let content = serializeChildren(node, options)
const tags = serializeTags(
Object.assign({}, node, {children: content ? ['!'] : []})
)

if (node.type === 'mdxBlockElement' && content) {
if (node.type === 'mdxJsxFlowElement' && content) {
content = '\n' + content + '\n'
}

Expand All @@ -212,10 +213,6 @@ function serializeText(node, options, parentNode) {
return toTemplateLiteral(node.value)
}

function serializeEsSyntax(node) {
return node.value
}

function serializeChildren(node, options) {
const children = node.children || []
const childOptions = Object.assign({}, options, {
Expand Down Expand Up @@ -261,3 +258,91 @@ function compile(options = {}) {
module.exports = compile
compile.default = compile
compile.toJSX = toJSX

// To do: this is all extracted (and simplified) from `mdast-util-mdx-jsx` for
// now.
// We can remove it when we drop JSX!

const eol = /\r?\n|\r/g

function serializeTags(node) {
const selfClosing = node.name && (!node.children || !node.children.length)
const attributes = []
let index = -1
let attribute
let result

// None.
if (node.attributes && node.attributes.length) {
if (!node.name) {
throw new Error('Cannot serialize fragment w/ attributes')
}

while (++index < node.attributes.length) {
attribute = node.attributes[index]

if (attribute.type === 'mdxJsxExpressionAttribute') {
result = '{' + (attribute.value || '') + '}'
} else {
if (!attribute.name) {
throw new Error('Cannot serialize attribute w/o name')
}

result =
attribute.name +
(attribute.value == null
? ''
: '=' +
(typeof attribute.value === 'object'
? '{' + (attribute.value.value || '') + '}'
: '"' + encode(attribute.value, {subset: ['"']}) + '"'))
}

attributes.push(result)
}
}

return {
open:
'<' +
(node.name || '') +
(node.type === 'mdxJsxFlowElement' && attributes.length > 1
? // Flow w/ multiple attributes.
'\n' + indent(attributes.join('\n')) + '\n'
: attributes.length // Text or flow w/ a single attribute.
? ' ' + dedentStart(indent(attributes.join(' ')))
: '') +
(selfClosing ? '/' : '') +
'>',
close: selfClosing ? '' : '</' + (node.name || '') + '>'
}
}

function serializeMdxExpression(node) {
const value = node.value || ''
return '{' + (node.type === 'mdxFlowExpression' ? indent(value) : value) + '}'
}

function dedentStart(value) {
return value.replace(/^ +/, '')
}

function indent(value) {
const result = []
let start = 0
let match

while ((match = eol.exec(value))) {
one(value.slice(start, match.index))
result.push(match[0])
start = match.index + match[0].length
}

one(value.slice(start))

return result.join('')

function one(slice) {
result.push((slice ? ' ' : '') + slice)
}
}
12 changes: 7 additions & 5 deletions packages/mdx/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,20 @@
"detab": "2.0.3",
"hast-to-hyperscript": "9.0.0",
"lodash.uniq": "4.5.0",
"mdast-util-to-hast": "9.1.0",
"mdast-util-to-hast": "10.0.1",
"recast": "^0.20.4",
"remark-mdx": "^2.0.0-next.8",
"remark-mdxjs": "^2.0.0-next.8",
"remark-parse": "8.0.2",
"remark-parse": "9.0.0",
"remark-squeeze-paragraphs": "4.0.0",
"stringify-entities": "^3.1.0",
"unified": "9.0.0",
"unist-builder": "2.0.3"
},
"devDependencies": {
"remark-footnotes": "1.0.0",
"remark-footnotes": "3.0.0",
"remark-gfm": "1.0.0",
"rehype-katex": "^4.0.0",
"remark-math": "^3.0.0"
"remark-math": "^4.0.0"
},
"gitHead": "bf7deab69996449cb99c2217dff75e65855eb2c1"
}
Loading