diff --git a/packages/loader/index.js b/packages/loader/index.js
index 383f3434f..18f8b3cde 100644
--- a/packages/loader/index.js
+++ b/packages/loader/index.js
@@ -1,10 +1,7 @@
const {getOptions} = require('loader-utils')
const mdx = require('@mdx-js/mdx')
-const DEFAULT_RENDERER = `
-import React from 'react'
-import {mdx} from '@mdx-js/react'
-`
+const DEFAULT_RENDERER = 'import React from "react"'
module.exports = async function (content) {
const callback = this.async()
diff --git a/packages/loader/test/index.test.js b/packages/loader/test/index.test.js
index e073eb0a7..e67518d7b 100644
--- a/packages/loader/test/index.test.js
+++ b/packages/loader/test/index.test.js
@@ -5,9 +5,7 @@ const webpack = require('webpack')
const MemoryFs = require('memory-fs')
const React = require('react')
const {renderToString} = require('react-dom/server')
-const _extends = require('@babel/runtime/helpers/extends')
-const _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties')
-const {mdx} = require('../../react')
+const {useMDXComponents} = require('../../react')
const transform = (filePath, options) => {
return new Promise((resolve, reject) => {
@@ -57,30 +55,18 @@ const transform = (filePath, options) => {
}
const run = value => {
- // Webpack 5 (replace everything in this function with):
- // const val = 'return ' + value.replace(/__webpack_require__\(0\)/, 'return $&')
- //
- // // eslint-disable-next-line no-new-func
- // return new Function(val)().default
// Replace import/exports w/ parameters and return value.
const val = value
- .replace(
- /import _objectWithoutProperties from "@babel\/runtime\/helpers\/objectWithoutProperties";/,
- ''
- )
- .replace(/import _extends from "@babel\/runtime\/helpers\/extends";/, '')
- .replace(/import React from 'react';/, '')
- .replace(/import \{ mdx } from '@mdx-js\/react';/, '')
+ .replace(/import "core-js\/.+";/g, '')
+ .replace(/import React from "react";/, '')
+ .replace(/import \{.+?\} from "@mdx-js\/react";/g, '')
.replace(/export default/, 'return')
// eslint-disable-next-line no-new-func
- return new Function(
- 'mdx',
- 'React',
- '_extends',
- '_objectWithoutProperties',
- val
- )(mdx, React, _extends, _objectWithoutProperties)
+ return new Function('React', '__provideComponents', val)(
+ React,
+ useMDXComponents
+ )
}
describe('@mdx-js/loader', () => {
diff --git a/packages/mdx/.babelrc b/packages/mdx/.babelrc
index a8aaa0476..1938ea380 100644
--- a/packages/mdx/.babelrc
+++ b/packages/mdx/.babelrc
@@ -7,6 +7,11 @@
"useBuiltIns": "usage"
}
],
- "@babel/react"
+ [
+ "@babel/react",
+ {
+ "throwIfNamespace": false
+ }
+ ]
]
}
diff --git a/packages/mdx/estree-to-js.js b/packages/mdx/estree-to-js.js
index f05a5c9c9..558f44126 100644
--- a/packages/mdx/estree-to-js.js
+++ b/packages/mdx/estree-to-js.js
@@ -1,4 +1,5 @@
const astring = require('astring')
+const stringifyEntities = require('stringify-entities/light')
module.exports = estreeToJs
@@ -20,7 +21,7 @@ const customGenerator = Object.assign({}, astring.baseGenerator, {
})
function estreeToJs(estree) {
- return astring.generate(estree, {generator: customGenerator})
+ return astring.generate(estree, {generator: customGenerator, comments: true})
}
// `attr="something"`
@@ -30,7 +31,16 @@ function JSXAttribute(node, state) {
if (node.value != null) {
state.write('=')
- this[node.value.type](node.value, state)
+
+ // Encode double quotes in attribute values.
+ if (node.value.type === 'Literal' && typeof node.value.value === 'string') {
+ state.write(
+ '"' + stringifyEntities(node.value.value, {subset: ['"']}) + '"',
+ node
+ )
+ } else {
+ this[node.value.type](node.value, state)
+ }
}
}
diff --git a/packages/mdx/index.js b/packages/mdx/index.js
index b5ea9a823..433e10a91 100644
--- a/packages/mdx/index.js
+++ b/packages/mdx/index.js
@@ -6,10 +6,6 @@ const minifyWhitespace = require('rehype-minify-whitespace')
const mdxAstToMdxHast = require('./mdx-ast-to-mdx-hast')
const mdxHastToJsx = require('./mdx-hast-to-jsx')
-const pragma = `/* @jsxRuntime classic */
-/* @jsx mdx */
-/* @jsxFrag mdx.Fragment */`
-
function createMdxAstCompiler(options = {}) {
return unified()
.use(remarkParse)
@@ -37,13 +33,13 @@ function createConfig(mdx, options) {
}
function sync(mdx, options = {}) {
- const file = createCompiler(options).processSync(createConfig(mdx, options))
- return pragma + '\n' + String(file)
+ return String(createCompiler(options).processSync(createConfig(mdx, options)))
}
async function compile(mdx, options = {}) {
- const file = await createCompiler(options).process(createConfig(mdx, options))
- return pragma + '\n' + String(file)
+ return String(
+ await createCompiler(options).process(createConfig(mdx, options))
+ )
}
module.exports = compile
diff --git a/packages/mdx/mdx-hast-to-jsx.js b/packages/mdx/mdx-hast-to-jsx.js
index e739e258d..ed61b140e 100644
--- a/packages/mdx/mdx-hast-to-jsx.js
+++ b/packages/mdx/mdx-hast-to-jsx.js
@@ -1,30 +1,110 @@
const toEstree = require('hast-util-to-estree')
+const isIdentifierName = require('estree-util-is-identifier-name').name
const walk = require('estree-walker').walk
const periscopic = require('periscopic')
const estreeToJs = require('./estree-to-js')
+const own = {}.hasOwnProperty
+
+const tags = [
+ 'a',
+ 'blockquote',
+ 'code',
+ 'del',
+ 'em',
+ 'h1',
+ 'h2',
+ 'h3',
+ 'h4',
+ 'h5',
+ 'h6',
+ 'hr',
+ 'img',
+ 'inlineCode',
+ 'li',
+ 'ol',
+ 'p',
+ 'pre',
+ 'strong',
+ 'table',
+ 'tbody',
+ 'td',
+ 'th',
+ 'thead',
+ 'tr',
+ 'ul'
+]
+
+const parentChildComponents = {
+ li: ['ol', 'ul'],
+ p: ['blockquote']
+}
+
+const componentDefaults = {
+ inlineCode: 'code'
+}
+
function serializeEstree(estree, options) {
const {
// Default options
skipExport = false,
- wrapExport
+ wrapExport,
+ mdxProviderImportSource = '@mdx-js/react',
+
+ jsxImportSource,
+ jsxRuntime = jsxImportSource ? 'automatic' : 'classic',
+ pragma = 'React.createElement',
+ pragmaFrag = 'React.Fragment'
} = options
- let layout
- let children = []
- let mdxLayoutDefault
+ const comments = []
+ const doc = []
+ let hasMdxLayout
+ let hasMdxContent
+
+ if (jsxRuntime) {
+ comments.push({type: 'Block', value: '@jsxRuntime ' + jsxRuntime})
+ }
+
+ if (jsxRuntime === 'automatic' && jsxImportSource) {
+ comments.push({type: 'Block', value: '@jsxImportSource ' + jsxImportSource})
+ }
+
+ if (jsxRuntime === 'classic' && pragma) {
+ comments.push({type: 'Block', value: '@jsx ' + pragma})
+ }
+
+ if (jsxRuntime === 'classic' && pragmaFrag) {
+ comments.push({type: 'Block', value: '@jsxFrag ' + pragmaFrag})
+ }
+
+ // Add JSX pragma comments.
+ estree.comments.unshift(...comments)
// Find the `export default`, the JSX expression, and leave the rest
// (import/exports) as they are.
- estree.body = estree.body.filter(child => {
+ estree.body.forEach(child => {
// ```js
- // export default a = 1
+ // export default props => <>{props.children}>
// ```
- if (child.type === 'ExportDefaultDeclaration') {
- layout = child.declaration
- return false
+ //
+ // Treat it as an inline layout declaration.
+ if (!hasMdxLayout && child.type === 'ExportDefaultDeclaration') {
+ hasMdxLayout = true
+ doc.push({
+ type: 'VariableDeclaration',
+ declarations: [
+ {
+ type: 'VariableDeclarator',
+ id: {type: 'Identifier', name: 'MDXLayout'},
+ init: child.declaration
+ }
+ ],
+ kind: 'const'
+ })
}
-
+ // Look for default “reexports”.
+ //
// ```js
// export {default} from "a"
// export {default as a} from "b"
@@ -32,148 +112,453 @@ function serializeEstree(estree, options) {
// export {a as default} from "b"
// export {a as default, b} from "c"
// ```
- if (child.type === 'ExportNamedDeclaration' && child.source) {
+ else if (child.type === 'ExportNamedDeclaration' && child.source) {
// Remove `default` or `as default`, but not `default as`, specifier.
child.specifiers = child.specifiers.filter(specifier => {
- if (specifier.exported.name === 'default') {
- mdxLayoutDefault = {local: specifier.local, source: child.source}
+ if (!hasMdxLayout && specifier.exported.name === 'default') {
+ hasMdxLayout = true
+ // Make it just an import: `import MDXLayout from "..."`.
+ doc.push({
+ type: 'ImportDeclaration',
+ specifiers: [
+ // Default as default / something else as default.
+ specifier.local.name === 'default'
+ ? {
+ type: 'ImportDefaultSpecifier',
+ local: {type: 'Identifier', name: 'MDXLayout'}
+ }
+ : {
+ type: 'ImportSpecifier',
+ imported: specifier.local,
+ local: {type: 'Identifier', name: 'MDXLayout'}
+ }
+ ],
+ source: {type: 'Literal', value: child.source.value}
+ })
+
return false
}
return true
})
- // Keep the export if there are other specifiers, drop it if there was
- // just a default.
- return child.specifiers.length > 0
- }
-
- if (
+ // If there are other things imported, keep it.
+ if (child.specifiers.length) {
+ doc.push(child)
+ }
+ } else if (
child.type === 'ExpressionStatement' &&
(child.expression.type === 'JSXFragment' ||
child.expression.type === 'JSXElement')
) {
- children =
- child.expression.type === 'JSXFragment'
- ? child.expression.children
- : [child.expression]
- return false
+ let expression = child.expression
+
+ // Depending on the hast, we’ll almost always have a fragment.
+ // Use a `
` if fragments are not supported.
+ if (expression.type === 'JSXFragment' && options.mdxFragment === false) {
+ expression = {
+ type: 'JSXElement',
+ openingElement: {
+ type: 'JSXOpeningElement',
+ attributes: [],
+ name: {type: 'JSXIdentifier', name: 'div'}
+ },
+ closingElement: {
+ type: 'JSXClosingElement',
+ name: {type: 'JSXIdentifier', name: 'div'}
+ },
+ children: expression.children
+ }
+ }
+
+ hasMdxContent = true
+ doc.push(...createMdxContent(expression))
+ } else {
+ doc.push(child)
+ }
+ })
+
+ // If there was no JSX content at all, add an empty function.
+ if (!hasMdxContent) {
+ doc.push(...createMdxContent())
+ }
+
+ if (!skipExport) {
+ let declaration = {type: 'Identifier', name: 'MDXContent'}
+
+ if (wrapExport) {
+ declaration = {
+ type: 'CallExpression',
+ callee: {type: 'Identifier', name: wrapExport},
+ arguments: [declaration]
+ }
}
- return true
+ doc.push({type: 'ExportDefaultDeclaration', declaration: declaration})
+ }
+
+ estree.body = doc
+
+ const info = rewriteIdentifiers(estree, {
+ ...options,
+ // Find everything that’s defined in the top-level scope.
+ inTopScope: [...periscopic.analyze(estree).scope.declarations.keys()]
})
- // Find everything that’s defined in the top-level scope.
- // Do this here because `estree` currently only includes import/exports
- // and we don’t have to walk all the JSX to figure out the top scope.
- const inTopScope = [
- 'MDXLayout',
- 'MDXContent',
- ...periscopic.analyze(estree).scope.declarations.keys()
- ]
+ // If there are “shortcodes” (undefined components expected to be passed),
+ // add the helper.
+ if (info.useShortcodeHelper) {
+ estree.body.unshift(
+ createShortcodeFallbackHelper(options.mdxFragment === false)
+ )
+ }
- estree.body = [
- ...estree.body,
- ...createMdxLayout(layout, mdxLayoutDefault),
- ...createMdxContent(children)
- ]
+ // Import the provider when needed.
+ if (info.useProvidedComponentsHelper) {
+ estree.body.unshift({
+ type: 'ImportDeclaration',
+ specifiers: [
+ {
+ type: 'ImportSpecifier',
+ imported: {type: 'Identifier', name: 'useMDXComponents'},
+ local: {type: 'Identifier', name: '__provideComponents'}
+ }
+ ],
+ source: {type: 'Literal', value: mdxProviderImportSource}
+ })
+ }
+
+ return estreeToJs(estree)
+}
- // Add `mdxType`, `parentName` props to JSX elements.
- const magicShortcodes = []
+function compile(options = {}) {
+ function compiler(tree) {
+ return serializeEstree(toEstree(tree), options)
+ }
+
+ this.Compiler = compiler
+}
+
+module.exports = compile
+compile.default = compile
+
+function rewriteIdentifiers(estree, options) {
const stack = []
+ let useShortcodeHelper = false
+ let useProvidedComponentsHelper = false
walk(estree, {
+ // eslint-disable-next-line complexity
enter: function (node) {
if (
- node.type === 'JSXElement' &&
- // To do: support members (`
`).
- node.openingElement.name.type === 'JSXIdentifier'
+ node.type === 'FunctionDeclaration' ||
+ node.type === 'FunctionExpression' ||
+ node.type === 'ArrowFunctionExpression'
) {
- const name = node.openingElement.name.name
+ stack.push({
+ node,
+ objects: [],
+ components: [],
+ markdownComponents: [],
+ elements: []
+ })
+ }
- if (stack.length > 1) {
- const parentName = stack[stack.length - 1]
+ if (node.type === 'JSXElement' && stack.length) {
+ // Note: inject into the top-level function that contains JSX.
+ const scope = stack[0]
+ const nameNode = node.openingElement.name
- node.openingElement.attributes.push({
- type: 'JSXAttribute',
- name: {type: 'JSXIdentifier', name: 'parentName'},
- value: {
- type: 'Literal',
- value: parentName,
- raw: JSON.stringify(parentName)
- }
- })
+ // ``, ``, ``.
+ if (nameNode.type === 'JSXMemberExpression') {
+ let left = nameNode
+
+ while (left.type === 'JSXMemberExpression') {
+ left = left.object
+ }
+
+ // `left` is now always an identifier.
+ if (!scope.objects.includes(left.name)) {
+ scope.objects.push(left.name)
+ }
}
+ // ``.
+ else if (nameNode.type === 'JSXNamespacedName') {
+ // Ignore namespaces.
+ } else {
+ const name = nameNode.name
+ // If the name is a valid ES identifier, and it doesn’t start with a
+ // lowecase letter, it’s a component.
+ // For example, `$foo`, `_bar`, `Baz` are all component names.
+ // But `foo` and `b-ar` are tag names.
+ if (isIdentifierName(name) && !/^[a-z]/.test(name)) {
+ if (!scope.components.includes(name)) {
+ scope.components.push(name)
+ }
+ } else if (tags.includes(name)) {
+ let selector = name
+ const parent = scope.elements[scope.elements.length - 1]
+
+ if (
+ own.call(parentChildComponents, name) &&
+ parent &&
+ parent.openingElement.name.type === 'JSXMemberExpression' &&
+ parent.openingElement.name.object.type === 'JSXIdentifier' &&
+ parent.openingElement.name.object.name === '__components' &&
+ parentChildComponents[name].includes(
+ parent.openingElement.name.property.name
+ )
+ ) {
+ selector = parent.openingElement.name.property.name + '.' + name
+ }
- const head = name.charAt(0)
+ if (!scope.markdownComponents.includes(selector)) {
+ scope.markdownComponents.push(selector)
+ }
- // A component.
- if (head === head.toUpperCase() && name !== 'MDXLayout') {
- node.openingElement.attributes.push({
- type: 'JSXAttribute',
- name: {type: 'JSXIdentifier', name: 'mdxType'},
- value: {type: 'Literal', value: name, raw: JSON.stringify(name)}
- })
+ node.openingElement.name = {
+ type: 'JSXMemberExpression',
+ object: {type: 'JSXIdentifier', name: '__components'},
+ property: {
+ type: 'JSXIdentifier',
+ name: selectorToIdentifierName(selector)
+ }
+ }
- if (!inTopScope.includes(name) && !magicShortcodes.includes(name)) {
- magicShortcodes.push(name)
+ if (node.closingElement) {
+ node.closingElement.name = {
+ type: 'JSXMemberExpression',
+ object: {type: 'JSXIdentifier', name: '__components'},
+ property: {
+ type: 'JSXIdentifier',
+ name: selectorToIdentifierName(selector)
+ }
+ }
+ }
}
}
- stack.push(name)
+ scope.elements.push(node)
}
},
leave: function (node) {
if (
- node.type === 'JSXElement' &&
- // To do: support members (``).
- node.openingElement.name.type === 'JSXIdentifier'
+ node.type === 'FunctionDeclaration' ||
+ node.type === 'FunctionExpression' ||
+ node.type === 'ArrowFunctionExpression'
) {
- stack.pop()
+ const scope = stack.pop()
+ const info = injectComponents(scope.node, scope, options)
+
+ if (info.useShortcodeHelper) useShortcodeHelper = true
+ if (info.useProvidedComponentsHelper) useProvidedComponentsHelper = true
+ }
+
+ if (node.type === 'JSXElement' && stack.length) {
+ stack[stack.length - 1].elements.pop()
}
}
})
- const exports = []
+ return {useShortcodeHelper, useProvidedComponentsHelper}
+}
- if (!skipExport) {
- let declaration = {type: 'Identifier', name: 'MDXContent'}
+function injectComponents(func, state, options) {
+ const {inTopScope, mdxProviderImportSource = '@mdx-js/react'} = options
+ const markdownComponents = [
+ ...new Set(
+ state.markdownComponents.map(member => member.split('.').pop()).sort()
+ )
+ ]
+ const parentalMarkdownComponents = state.markdownComponents
+ .filter(member => member.indexOf('.') > -1)
+ .sort()
+ const components = state.components.filter(id => !inTopScope.includes(id))
+ const requiredComponents = components.filter(id => id !== 'MDXLayout')
+ const objects = state.objects.filter(id => !inTopScope.includes(id))
+ const isMdxContent =
+ func.type === 'FunctionDeclaration' && func.id.name === 'MDXContent'
+ const injectLayout = isMdxContent && !inTopScope.includes('MDXLayout')
+ const nodes = []
+ let useShortcodeHelper = false
+ let useProvidedComponentsHelper = false
+
+ // We need to define some variables, add them here:
+ let declarations = []
+
+ if (
+ markdownComponents.length ||
+ components.length ||
+ objects.length ||
+ injectLayout
+ ) {
+ useShortcodeHelper = requiredComponents.length > 0
+
+ const parameters = [
+ {
+ type: 'ObjectExpression',
+ properties: [
+ ...markdownComponents.map(member => ({
+ type: 'Property',
+ key: {type: 'Identifier', name: member},
+ value: {
+ type: 'Literal',
+ value:
+ member in componentDefaults ? componentDefaults[member] : member
+ },
+ kind: 'init'
+ })),
+ ...requiredComponents.map(id => ({
+ type: 'Property',
+ key: {type: 'Identifier', name: id},
+ value: {
+ type: 'CallExpression',
+ callee: {type: 'Identifier', name: 'mdxShortcodeFallback'},
+ arguments: [{type: 'Literal', value: id}]
+ },
+ kind: 'init'
+ }))
+ ]
+ }
+ ]
- if (wrapExport) {
- declaration = {
+ // Accept provided components if there is an import source defined.
+ if (mdxProviderImportSource) {
+ useProvidedComponentsHelper = true
+ parameters.push({
type: 'CallExpression',
- callee: {type: 'Identifier', name: wrapExport},
- arguments: [declaration]
- }
+ callee: {type: 'Identifier', name: '__provideComponents'},
+ arguments: []
+ })
}
- exports.push({type: 'ExportDefaultDeclaration', declaration: declaration})
- }
+ // Accept `components` as a prop if this is the `MDXContent` component.
+ if (isMdxContent) {
+ parameters.push({
+ type: 'MemberExpression',
+ object: {type: 'Identifier', name: '__props'},
+ property: {type: 'Identifier', name: 'components'}
+ })
+ }
- estree.body = [
- ...createMakeShortcodeHelper(
- magicShortcodes,
- options.mdxFragment === false
- ),
- ...estree.body,
- ...exports
- ]
+ declarations.push({
+ type: 'VariableDeclarator',
+ id: {type: 'Identifier', name: '__components'},
+ init:
+ parameters.length > 1
+ ? {
+ type: 'CallExpression',
+ callee: {
+ type: 'MemberExpression',
+ object: {type: 'Identifier', name: 'Object'},
+ property: {type: 'Identifier', name: 'assign'}
+ },
+ arguments: parameters
+ }
+ : parameters[0]
+ })
- return estreeToJs(estree)
-}
+ // Add components to scope.
+ // For `['MyComponent', 'MDXLayout']` this generates:
+ // ```js
+ // const {MyComponent, wrapper: MDXLayout} = __components
+ // ```
+ // Note that MDXLayout is special as it’s taken from `__components.wrapper`.
+ if (components.length || objects.length) {
+ declarations.push({
+ type: 'VariableDeclarator',
+ id: {
+ type: 'ObjectPattern',
+ properties: [
+ ...objects.map(id => ({
+ type: 'Property',
+ shorthand: true,
+ key: {type: 'Identifier', name: id},
+ value: {type: 'Identifier', name: id},
+ kind: 'init'
+ })),
+ ...components.map(id => ({
+ type: 'Property',
+ shorthand: id !== 'MDXLayout',
+ key: {
+ type: 'Identifier',
+ name: id === 'MDXLayout' ? 'wrapper' : id
+ },
+ value: {type: 'Identifier', name: id},
+ kind: 'init'
+ }))
+ ]
+ },
+ init: {type: 'Identifier', name: '__components'}
+ })
+ }
-function compile(options = {}) {
- function compiler(tree, file) {
- return serializeEstree(toEstree(tree), {filename: file.path, ...options})
+ // Flush the declared variables.
+ nodes.push({
+ type: 'VariableDeclaration',
+ declarations: declarations,
+ kind: 'const'
+ })
+
+ if (parentalMarkdownComponents.length) {
+ // For `parent.child` combos we default to their child.
+ //
+ // For `['blockquote.p', 'ol.li']` this generates:
+ // ```js
+ // __components.blockquoteP = __components['blockquote.p'] || __components.p
+ // __components.olLi = __components['ol.li'] || __components.li
+ // ```
+ parentalMarkdownComponents.forEach(name => {
+ nodes.push({
+ type: 'ExpressionStatement',
+ expression: {
+ type: 'AssignmentExpression',
+ operator: '=',
+ left: {
+ type: 'MemberExpression',
+ object: {type: 'Identifier', name: '__components'},
+ property: {
+ type: 'Identifier',
+ name: selectorToIdentifierName(name)
+ }
+ },
+ right: {
+ type: 'LogicalExpression',
+ left: {
+ type: 'MemberExpression',
+ object: {type: 'Identifier', name: '__components'},
+ property: {type: 'Literal', value: name},
+ computed: true
+ },
+ right: {
+ type: 'MemberExpression',
+ object: {type: 'Identifier', name: '__components'},
+ property: {type: 'Identifier', name: name.split('.').pop()}
+ },
+ operator: '||'
+ }
+ }
+ })
+ })
+ }
}
- this.Compiler = compiler
-}
+ if (nodes.length) {
+ // Arrow functions with an implied return:
+ if (func.body.type !== 'BlockStatement') {
+ func.body = {
+ type: 'BlockStatement',
+ body: [{type: 'ReturnStatement', argument: func.body}]
+ }
+ }
-module.exports = compile
-compile.default = compile
+ func.body.body = [...nodes, ...func.body.body]
+ }
+
+ return {useShortcodeHelper, useProvidedComponentsHelper}
+}
-function createMdxContent(children) {
+function createMdxContent(content) {
return [
{
type: 'FunctionDeclaration',
@@ -181,54 +566,51 @@ function createMdxContent(children) {
expression: false,
generator: false,
async: false,
- params: [
- {
- type: 'ObjectPattern',
- properties: [
- {
- type: 'Property',
- method: false,
- shorthand: true,
- computed: false,
- key: {type: 'Identifier', name: 'components'},
- kind: 'init',
- value: {type: 'Identifier', name: 'components'}
- },
- {type: 'RestElement', argument: {type: 'Identifier', name: 'props'}}
- ]
- }
- ],
+ params: [{type: 'Identifier', name: '__props'}],
body: {
type: 'BlockStatement',
body: [
+ {
+ type: 'VariableDeclaration',
+ declarations: [
+ {
+ type: 'VariableDeclarator',
+ id: {type: 'Identifier', name: '__content'},
+ init: content || {type: 'Literal', value: null}
+ }
+ ],
+ kind: 'const'
+ },
{
type: 'ReturnStatement',
argument: {
- type: 'JSXElement',
- openingElement: {
- type: 'JSXOpeningElement',
- attributes: [
- {
- type: 'JSXAttribute',
- name: {type: 'JSXIdentifier', name: 'components'},
- value: {
- type: 'JSXExpressionContainer',
- expression: {type: 'Identifier', name: 'components'}
+ type: 'ConditionalExpression',
+ test: {type: 'Identifier', name: 'MDXLayout'},
+ consequent: {
+ type: 'JSXElement',
+ openingElement: {
+ type: 'JSXOpeningElement',
+ attributes: [
+ {
+ type: 'JSXSpreadAttribute',
+ argument: {type: 'Identifier', name: '__props'}
}
- },
+ ],
+ name: {type: 'JSXIdentifier', name: 'MDXLayout'},
+ selfClosing: false
+ },
+ closingElement: {
+ type: 'JSXClosingElement',
+ name: {type: 'JSXIdentifier', name: 'MDXLayout'}
+ },
+ children: [
{
- type: 'JSXSpreadAttribute',
- argument: {type: 'Identifier', name: 'props'}
+ type: 'JSXExpressionContainer',
+ expression: {type: 'Identifier', name: '__content'}
}
- ],
- name: {type: 'JSXIdentifier', name: 'MDXLayout'},
- selfClosing: false
+ ]
},
- closingElement: {
- type: 'JSXClosingElement',
- name: {type: 'JSXIdentifier', name: 'MDXLayout'}
- },
- children: children
+ alternate: {type: 'Identifier', name: '__content'}
}
}
]
@@ -252,46 +634,13 @@ function createMdxContent(children) {
]
}
-function createMdxLayout(declaration, mdxLayoutDefault) {
- const id = {type: 'Identifier', name: 'MDXLayout'}
- const init = {type: 'Literal', value: 'wrapper', raw: '"wrapper"'}
-
- return [
- mdxLayoutDefault
- ? {
- type: 'ImportDeclaration',
- specifiers: [
- mdxLayoutDefault.local.name === 'default'
- ? {type: 'ImportDefaultSpecifier', local: id}
- : {
- type: 'ImportSpecifier',
- imported: mdxLayoutDefault.local,
- local: id
- }
- ],
- source: {
- type: 'Literal',
- value: mdxLayoutDefault.source.value,
- raw: mdxLayoutDefault.source.raw
- }
- }
- : {
- type: 'VariableDeclaration',
- declarations: [
- {type: 'VariableDeclarator', id: id, init: declaration || init}
- ],
- kind: 'const'
- }
- ]
-}
-
-function createMakeShortcodeHelper(names, useElement) {
- const func = {
+function createShortcodeFallbackHelper(useElement) {
+ return {
type: 'VariableDeclaration',
declarations: [
{
type: 'VariableDeclarator',
- id: {type: 'Identifier', name: 'makeShortcode'},
+ id: {type: 'Identifier', name: 'mdxShortcodeFallback'},
init: {
type: 'ArrowFunctionExpression',
id: null,
@@ -305,7 +654,7 @@ function createMakeShortcodeHelper(names, useElement) {
expression: false,
generator: false,
async: false,
- params: [{type: 'Identifier', name: 'props'}],
+ params: [{type: 'Identifier', name: '__props'}],
body: {
type: 'BlockStatement',
body: [
@@ -340,7 +689,7 @@ function createMakeShortcodeHelper(names, useElement) {
attributes: [
{
type: 'JSXSpreadAttribute',
- argument: {type: 'Identifier', name: 'props'}
+ argument: {type: 'Identifier', name: '__props'}
}
],
name: {type: 'JSXIdentifier', name: 'div'},
@@ -358,7 +707,7 @@ function createMakeShortcodeHelper(names, useElement) {
type: 'JSXExpressionContainer',
expression: {
type: 'MemberExpression',
- object: {type: 'Identifier', name: 'props'},
+ object: {type: 'Identifier', name: '__props'},
property: {type: 'Identifier', name: 'children'},
computed: false
}
@@ -374,22 +723,12 @@ function createMakeShortcodeHelper(names, useElement) {
],
kind: 'const'
}
+}
- const shortcodes = names.map(name => ({
- type: 'VariableDeclaration',
- declarations: [
- {
- type: 'VariableDeclarator',
- id: {type: 'Identifier', name: String(name)},
- init: {
- type: 'CallExpression',
- callee: {type: 'Identifier', name: 'makeShortcode'},
- arguments: [{type: 'Literal', value: String(name)}]
- }
- }
- ],
- kind: 'const'
- }))
+function selectorToIdentifierName(selector) {
+ return selector.replace(/\../g, replace)
- return shortcodes.length > 0 ? [func, ...shortcodes] : []
+ function replace($0) {
+ return $0.charAt(1).toUpperCase()
+ }
}
diff --git a/packages/mdx/package.json b/packages/mdx/package.json
index c25bb84fc..182f3616c 100644
--- a/packages/mdx/package.json
+++ b/packages/mdx/package.json
@@ -46,6 +46,7 @@
"@mdx-js/util": "2.0.0-next.1",
"astring": "^1.4.0",
"detab": "^2.0.0",
+ "estree-util-is-identifier-name": "^1.0.0",
"estree-walker": "^2.0.0",
"hast-util-to-estree": "^1.1.0",
"mdast-util-to-hast": "^10.1.0",
@@ -54,10 +55,12 @@
"remark-mdx": "^2.0.0-next.8",
"remark-parse": "^9.0.0",
"remark-squeeze-paragraphs": "^4.0.0",
+ "stringify-entities": "^3.1.0",
"unified": "^9.2.0",
"unist-builder": "^2.0.0"
},
"devDependencies": {
+ "@emotion/react": "^11.0.0",
"remark-footnotes": "^3.0.0",
"remark-gfm": "^1.0.0",
"rehype-katex": "^4.0.0",
diff --git a/packages/mdx/test/index.test.js b/packages/mdx/test/index.test.js
index 6ad30e603..41708fe32 100644
--- a/packages/mdx/test/index.test.js
+++ b/packages/mdx/test/index.test.js
@@ -2,8 +2,10 @@ const path = require('path')
const babel = require('@babel/core')
const unified = require('unified')
const React = require('react')
+const reactRuntime = require('react/jsx-runtime')
+const emotionRuntime = require('@emotion/react/jsx-runtime')
const {renderToStaticMarkup} = require('react-dom/server')
-const {mdx: mdxReact, MDXProvider} = require('../../react')
+const {MDXProvider, useMDXComponents} = require('../../react')
const mdx = require('..')
const toMdxHast = require('../mdx-ast-to-mdx-hast')
const toJsx = require('../mdx-hast-to-jsx')
@@ -13,27 +15,36 @@ const math = require('remark-math')
const katex = require('rehype-katex')
const run = async (value, options = {}) => {
- const doc = await mdx(value, {...options, skipExport: true})
+ let doc = await mdx(value, {...options, skipExport: true})
+
+ // Remove the import.
+ doc = doc.replace(/import \{.+?\} from "@mdx-js\/react";/g, '')
// …and that into serialized JS.
const {code} = await babel.transformAsync(doc, {
configFile: false,
plugins: [
- '@babel/plugin-transform-react-jsx',
+ ['@babel/plugin-transform-react-jsx', {throwIfNamespace: false}],
path.resolve(__dirname, '../../babel-plugin-remove-export-keywords')
]
})
// …and finally run it, returning the component.
// eslint-disable-next-line no-new-func
- return new Function('mdx', `${code}; return MDXContent`)(mdxReact)
+ return new Function(
+ 'React',
+ '__provideComponents',
+ `${code}; return MDXContent`
+ )(React, useMDXComponents)
}
describe('@mdx-js/mdx', () => {
it('should generate JSX', async () => {
const result = await mdx('Hello World')
- expect(result).toMatch(/\{"Hello World"\}<\/p>/)
+ expect(result).toMatch(
+ /<__components\.p>\{"Hello World"\}<\/__components\.p>/
+ )
})
it('should generate runnable JSX', async () => {
@@ -488,10 +499,10 @@ describe('@mdx-js/mdx', () => {
// something else.
result = await mdx('export {default as a} from "b"')
expect(result).toMatch(/export {default as a} from "b"/)
- expect(result).toMatch(/const MDXLayout = "wrapper"/)
+ expect(result).toMatch(/wrapper: MDXLayout/)
result = await mdx('export {default as a, b} from "c"')
expect(result).toMatch(/export {default as a, b} from "c"/)
- expect(result).toMatch(/const MDXLayout = "wrapper"/)
+ expect(result).toMatch(/wrapper: MDXLayout/)
// These are export defaults.
result = await mdx('export {a as default} from "b"')
@@ -542,7 +553,7 @@ describe('@mdx-js/mdx', () => {
})
it('should support overwriting missing compile-time components at run-time', async () => {
- const Content = await run('x z')
+ const Content = await run('x z w.')
expect(
renderToStaticMarkup(
@@ -557,12 +568,65 @@ describe('@mdx-js/mdx', () => {
).toEqual(
renderToStaticMarkup(
- x z
+ x z{' '}
+ w.
+
+ )
+ )
+ })
+
+ it('should not be able to overwrite markdown constructs with an export', async () => {
+ const Content = await run('export const em = () => !\n\n*?*')
+
+ expect(renderToStaticMarkup()).toEqual(
+ renderToStaticMarkup(
+
+ ?
+
+ )
+ )
+ })
+
+ it('should prefer provided components over inline exported components', async () => {
+ const Content = await run('export const Em = () => !\n\n?')
+
+ expect(
+ renderToStaticMarkup(
+ .
+ }}
+ >
+
+
+ )
+ ).toEqual(
+ renderToStaticMarkup(
+
+ !
)
)
})
+ it('should overwrite components in inline exports with provided components', async () => {
+ const Content = await run(
+ 'export const Component = () => !\n\n'
+ )
+
+ expect(
+ renderToStaticMarkup(
+ .
+ }}
+ >
+
+
+ )
+ ).toEqual(renderToStaticMarkup(.))
+ })
+
it('should not crash but issue a warning when an undefined component is used', async () => {
const Content = await run('w y z')
const warn = console.warn
@@ -580,6 +644,30 @@ describe('@mdx-js/mdx', () => {
console.warn = warn
})
+ it('should not use a fragment to wrap missing components w/ `mdxFragment: false`', async () => {
+ const Content = await run('a', {mdxFragment: false})
+
+ const warn = console.warn
+ console.warn = jest.fn()
+
+ expect(renderToStaticMarkup()).toEqual(
+ renderToStaticMarkup(
+
+ )
+ )
+
+ expect(console.warn).toHaveBeenCalledWith(
+ 'Component `%s` was not imported, exported, or provided by MDXProvider as global scope',
+ 'X'
+ )
+
+ console.warn = warn
+ })
+
it('should support `.` in component names for members', async () => {
const Content = await run(
'export var x = {y: props => }\n\n'
@@ -590,6 +678,163 @@ describe('@mdx-js/mdx', () => {
)
})
+ it('should support given member components', async () => {
+ const Content = await run('*em*, ')
+
+ expect(
+ renderToStaticMarkup(
+ {children},
+ z: ({children}) => {children}
+ }
+ }
+ }}
+ />
+ )
+ ).toEqual(
+ renderToStaticMarkup(
+
+
+ em
+
+ {', '}
+
+
+ )
+ )
+ })
+
+ it('should support provided member components', async () => {
+ const Content = await run('*em*')
+
+ expect(
+ renderToStaticMarkup(
+ {children}}}
+ }}
+ >
+
+
+ )
+ ).toEqual(
+ renderToStaticMarkup(
+
+
+ em
+
+
+ )
+ )
+ })
+
+ it('should crash on missing member components', async () => {
+ const Content = await run('')
+
+ expect(() => {
+ renderToStaticMarkup()
+ }).toThrow(/Cannot read property 'y' of undefined/)
+ })
+
+ it('should support namespace tags', async () => {
+ const Content = await run('*em*')
+
+ expect(renderToStaticMarkup()).toEqual(
+ /* eslint-disable react/jsx-no-undef */
+ renderToStaticMarkup(
+
+
+ em
+
+
+ )
+ /* eslint-enable react/jsx-no-undef */
+ )
+ })
+
+ it('should support given parent-child components', async () => {
+ const Content = await run('* a\n1. b\n> c')
+
+ expect(
+ renderToStaticMarkup(
+ {children},
+ 'blockquote.p': ({children}) => {children}
+ }}
+ />
+ )
+ ).toEqual(
+ renderToStaticMarkup(
+ <>
+
+
+ b
+
+
+ c
+
+ >
+ )
+ )
+ })
+
+ it('should support providing the child component for potential parent-child components', async () => {
+ const Content = await run('* a\n1. b')
+
+ expect(
+ renderToStaticMarkup(
+ {children}
+ }}
+ />
+ )
+ ).toEqual(
+ renderToStaticMarkup(
+ <>
+
+
+ b
+
+ >
+ )
+ )
+ })
+
+ it('should support providing a child component and a parent-child component', async () => {
+ const Content = await run('* a\n1. b')
+
+ expect(
+ renderToStaticMarkup(
+ {children},
+ li: ({children}) => {children}
+ }}
+ />
+ )
+ ).toEqual(
+ renderToStaticMarkup(
+ <>
+
+
+ b
+
+ >
+ )
+ )
+ })
+
it('should crash on unknown nodes in mdxhast', async () => {
const plugin = () => tree => {
// A leaf.
@@ -654,6 +899,25 @@ describe('@mdx-js/mdx', () => {
expect(Content.isMDXComponent).toEqual(true)
})
+ it('should handle quotes in attribute values', async () => {
+ const Content = await run(
+ '```x"y"z\ncode()\n```\n\nc'
+ )
+
+ expect(renderToStaticMarkup()).toEqual(
+ renderToStaticMarkup(
+ <>
+
+ code(){'\n'}
+
+
+ c
+
+ >
+ )
+ )
+ })
+
it('should escape what could look like template literal placeholders in text', async () => {
/* eslint-disable no-template-curly-in-string */
const Content = await run('`${x}`')
@@ -707,11 +971,148 @@ describe('@mdx-js/mdx', () => {
)
)
})
+
+ it('should work w/o `mdxProviderImportSource`', async () => {
+ const doc = await mdx('\n*em*', {mdxProviderImportSource: null})
+
+ expect(doc).not.toMatch(/__provideComponents/)
+ })
+
+ it('should warn on missing components w/o `mdxProviderImportSource`', async () => {
+ const Content = await run('\n*em*', {mdxProviderImportSource: null})
+
+ const warn = console.warn
+ console.warn = jest.fn()
+
+ expect(renderToStaticMarkup()).toEqual(
+ renderToStaticMarkup(
+
+ em
+
+ )
+ )
+
+ expect(console.warn).toHaveBeenCalledWith(
+ 'Component `%s` was not imported, exported, or provided by MDXProvider as global scope',
+ 'X'
+ )
+
+ console.warn = warn
+ })
+
+ it('should support inline components w/o `mdxProviderImportSource`', async () => {
+ const Content = await run(
+ 'export const X = props => <>{props.children}.>\n\n\n',
+ {mdxProviderImportSource: null}
+ )
+
+ expect(renderToStaticMarkup()).toEqual(
+ renderToStaticMarkup(
+ <>
+
+ .
+ >
+ )
+ )
+ })
+
+ it('should work w/o `jsxRuntime`', async () => {
+ const doc = await mdx('\n*em*', {jsxRuntime: null})
+
+ expect(doc).not.toMatch(/@jsxRuntime/)
+ })
+
+ it('should support the automatic runtime', async () => {
+ let doc = await mdx('*Emphasis*, **strong**, `code`.', {
+ skipExport: true,
+ jsxRuntime: 'automatic'
+ })
+
+ // Compile JSX away.
+ let {code} = await babel.transformAsync(doc, {
+ configFile: false,
+ plugins: ['@babel/plugin-transform-react-jsx']
+ })
+
+ // Remove the imports.
+ code = code
+ .replace(/import \{.+?} from "react\/jsx-runtime";/g, '')
+ .replace(/import \{.+?} from "@mdx-js\/react";/g, '')
+
+ // eslint-disable-next-line no-new-func
+ const Content = new Function(
+ '_Fragment',
+ '_jsxs',
+ '_jsx',
+ '__provideComponents',
+ `${code}; return MDXContent`
+ )(
+ reactRuntime.Fragment,
+ reactRuntime.jsxs,
+ reactRuntime.jsx,
+ useMDXComponents
+ )
+
+ expect(renderToStaticMarkup()).toEqual(
+ renderToStaticMarkup(
+
+ Emphasis
+ {', '}
+ strong
+ {', '}
+ code
.
+
+ )
+ )
+ })
+
+ it('should support a `jsxImportSource`', async () => {
+ let doc = await mdx('*Emphasis* & ', {
+ skipExport: true,
+ jsxImportSource: '@emotion/react'
+ })
+
+ // Compile JSX away.
+ let {code} = await babel.transformAsync(doc, {
+ configFile: false,
+ plugins: ['@babel/plugin-transform-react-jsx']
+ })
+
+ code = code
+ .replace(/import \{.+?} from "@emotion\/react\/jsx-runtime";/g, '')
+ .replace(/import \{.+?} from "@mdx-js\/react";/g, '')
+
+ // eslint-disable-next-line no-new-func
+ const Content = new Function(
+ '_Fragment',
+ '_jsxs',
+ '_jsx',
+ '__provideComponents',
+ `${code}; return MDXContent`
+ )(
+ emotionRuntime.Fragment,
+ emotionRuntime.jsxs,
+ emotionRuntime.jsx,
+ useMDXComponents
+ )
+
+ expect(renderToStaticMarkup()).toEqual(
+ renderToStaticMarkup(
+
+ Emphasis
+ {' & '}
+
+
+ )
+ )
+ })
})
describe('default', () => {
it('should be async', async () => {
- expect(mdx('x')).resolves.toMatch(/{"x"}<\/p>/)
+ expect(mdx('x')).resolves.toMatch(
+ /<__components\.p>\{"x"\}<\/__components\.p>/
+ )
})
it('should support `remarkPlugins`', async () => {
@@ -723,7 +1124,7 @@ describe('default', () => {
describe('sync', () => {
it('should be sync', () => {
- expect(mdx.sync('x')).toMatch(/
{"x"}<\/p>/)
+ expect(mdx.sync('x')).toMatch(/<__components\.p>\{"x"\}<\/__components\.p>/)
})
it('should support `remarkPlugins`', () => {
@@ -772,7 +1173,7 @@ describe('createMdxAstCompiler', () => {
describe('createCompiler', () => {
it('should create a unified processor', () => {
expect(String(mdx.createCompiler().processSync('x'))).toMatch(
- /
{"x"}<\/p>/
+ /<__components\.p>\{"x"\}<\/__components\.p>/
)
})
})
diff --git a/packages/parcel-plugin-mdx/src/MDXAsset.js b/packages/parcel-plugin-mdx/src/MDXAsset.js
index d7e776f14..4d1c647f1 100644
--- a/packages/parcel-plugin-mdx/src/MDXAsset.js
+++ b/packages/parcel-plugin-mdx/src/MDXAsset.js
@@ -3,7 +3,6 @@ const {Asset} = require('parcel-bundler')
const mdx = require('@mdx-js/mdx')
const prefix = `import React from 'react'
-import {mdx} from '@mdx-js/react'
`
class MDXAsset extends Asset {
diff --git a/packages/parcel-plugin-mdx/test/index.test.js b/packages/parcel-plugin-mdx/test/index.test.js
index ef4eabb6a..80bd5833d 100644
--- a/packages/parcel-plugin-mdx/test/index.test.js
+++ b/packages/parcel-plugin-mdx/test/index.test.js
@@ -23,10 +23,10 @@ describe('MDXAsset', () => {
const results = await asset.process()
const result = results[0]
- expect(result.value).toContain('
{"Test"}
')
-
expect(result.value).toContain(
- '{"component"}'
+ '<__components.h1>{"Test"}'
)
+
+ expect(result.value).toContain('{"component"}')
})
})
diff --git a/packages/preact/src/create-element.js b/packages/preact/src/create-element.js
deleted file mode 100644
index 905c05cc6..000000000
--- a/packages/preact/src/create-element.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import {h, Fragment} from 'preact'
-import {forwardRef} from 'preact/compat'
-
-import {useMDXComponents} from './context'
-
-const TYPE_PROP_NAME = 'mdxType'
-
-const DEFAULTS = {
- inlineCode: 'code',
- wrapper: ({children}) => h(Fragment, {}, children)
-}
-
-const MDXCreateElement = forwardRef((props, ref) => {
- const {
- components: propComponents,
- mdxType,
- originalType,
- parentName,
- ...etc
- } = props
-
- const components = useMDXComponents(propComponents)
- const type = mdxType
- const Component =
- components[`${parentName}.${type}`] ||
- components[type] ||
- DEFAULTS[type] ||
- originalType
-
- /* istanbul ignore if - To do: what is this useful for? */
- if (propComponents) {
- return h(Component, {
- ref,
- ...etc,
- components: propComponents
- })
- }
-
- return h(Component, {ref, ...etc})
-})
-
-MDXCreateElement.displayName = 'MDXCreateElement'
-
-function mdx(type, props) {
- const args = arguments
- const mdxType = props && props.mdxType
-
- if (typeof type === 'string' || mdxType) {
- const argsLength = args.length
-
- const createElementArgArray = new Array(argsLength)
- createElementArgArray[0] = MDXCreateElement
-
- const newProps = {}
- for (let key in props) {
- /* istanbul ignore else - folks putting stuff in `prototype`. */
- if (hasOwnProperty.call(props, key)) {
- newProps[key] = props[key]
- }
- }
-
- newProps.originalType = type
- newProps[TYPE_PROP_NAME] = typeof type === 'string' ? type : mdxType
-
- createElementArgArray[1] = newProps
-
- for (let i = 2; i < argsLength; i++) {
- createElementArgArray[i] = args[i]
- }
-
- return h.apply(null, createElementArgArray)
- }
-
- return h.apply(null, args)
-}
-
-mdx.Fragment = Fragment
-
-export default mdx
diff --git a/packages/preact/src/index.js b/packages/preact/src/index.js
index 954f81f91..38be5b677 100644
--- a/packages/preact/src/index.js
+++ b/packages/preact/src/index.js
@@ -4,5 +4,3 @@ export {
useMDXComponents,
withMDXComponents
} from './context'
-
-export {default as mdx} from './create-element'
diff --git a/packages/preact/test/test.js b/packages/preact/test/test.js
index dd715e064..b9127cf94 100644
--- a/packages/preact/test/test.js
+++ b/packages/preact/test/test.js
@@ -5,11 +5,17 @@ import {h, Fragment} from 'preact'
import {render} from 'preact-render-to-string'
import {transformAsync as babelTransform} from '@babel/core'
import mdxTransform from '../../mdx'
-import {MDXProvider, withMDXComponents, mdx} from '../src'
+import {MDXProvider, useMDXComponents, withMDXComponents} from '../src'
const run = async value => {
// Turn the serialized MDX code into serialized JSX…
- const doc = await mdxTransform(value, {skipExport: true})
+ let doc = await mdxTransform(value, {
+ skipExport: true,
+ pragma: 'h',
+ pragmaFrag: 'Fragment'
+ })
+
+ doc = doc.replace(/import \{.+?\} from "@mdx-js\/react";/g, '')
// …and that into serialized JS.
const {code} = await babelTransform(doc, {
@@ -22,7 +28,12 @@ const run = async value => {
// …and finally run it, returning the component.
// eslint-disable-next-line no-new-func
- return new Function('mdx', `${code}; return MDXContent`)(mdx)
+ return new Function(
+ 'h',
+ 'Fragment',
+ '__provideComponents',
+ `${code}; return MDXContent`
+ )(h, Fragment, useMDXComponents)
}
describe('@mdx-js/preact', () => {
@@ -70,15 +81,6 @@ describe('@mdx-js/preact', () => {
expect(render()).toEqual('!')
})
-
- test('should not crash if weird values could come from JSX', async () => {
- // As JSX is function calls, that function can also be used directly in
- // MDX. Definitely not a great idea, but it’s an easy way to pass in funky
- // values.
- const Content = await run('{mdx(1)}')
-
- expect(render()).toEqual('<1>1>')
- })
})
describe('MDXProvider', () => {
diff --git a/packages/preact/types/index.d.ts b/packages/preact/types/index.d.ts
index 475aed1a5..c168f3175 100644
--- a/packages/preact/types/index.d.ts
+++ b/packages/preact/types/index.d.ts
@@ -1,7 +1,6 @@
// TypeScript Version: 3.4
import {
- h,
Context,
AnyComponent,
FunctionComponent
@@ -53,17 +52,11 @@ declare function withMDXComponents(
child: AnyComponent
): ReactElement | null
-/**
- * Preact hyperscript function wrapped with handler for MDX content
- */
-declare const mdx: typeof h
-
export {
ComponentDictionary,
ComponentsProp,
MDXContext,
MDXProvider,
useMDXComponents,
- withMDXComponents,
- mdx
+ withMDXComponents
}
diff --git a/packages/react/src/create-element.js b/packages/react/src/create-element.js
deleted file mode 100644
index ae5c4c48c..000000000
--- a/packages/react/src/create-element.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import React from 'react'
-
-import {useMDXComponents} from './context'
-
-const TYPE_PROP_NAME = 'mdxType'
-
-const DEFAULTS = {
- inlineCode: 'code',
- wrapper: ({children}) => React.createElement(React.Fragment, {}, children)
-}
-
-const MDXCreateElement = React.forwardRef((props, ref) => {
- const {
- components: propComponents,
- mdxType,
- originalType,
- parentName,
- ...etc
- } = props
-
- const components = useMDXComponents(propComponents)
- const type = mdxType
- const Component =
- components[`${parentName}.${type}`] ||
- components[type] ||
- DEFAULTS[type] ||
- originalType
-
- /* istanbul ignore if - To do: what is this useful for? */
- if (propComponents) {
- return React.createElement(Component, {
- ref,
- ...etc,
- components: propComponents
- })
- }
-
- return React.createElement(Component, {ref, ...etc})
-})
-
-MDXCreateElement.displayName = 'MDXCreateElement'
-
-function mdx(type, props) {
- const args = arguments
- const mdxType = props && props.mdxType
-
- if (typeof type === 'string' || mdxType) {
- const argsLength = args.length
-
- const createElementArgArray = new Array(argsLength)
- createElementArgArray[0] = MDXCreateElement
-
- const newProps = {}
- for (let key in props) {
- /* istanbul ignore else - folks putting stuff in `prototype`. */
- if (hasOwnProperty.call(props, key)) {
- newProps[key] = props[key]
- }
- }
-
- newProps.originalType = type
- newProps[TYPE_PROP_NAME] = typeof type === 'string' ? type : mdxType
-
- createElementArgArray[1] = newProps
-
- for (let i = 2; i < argsLength; i++) {
- createElementArgArray[i] = args[i]
- }
-
- return React.createElement.apply(null, createElementArgArray)
- }
-
- return React.createElement.apply(null, args)
-}
-
-mdx.Fragment = React.Fragment
-
-export default mdx
diff --git a/packages/react/src/index.js b/packages/react/src/index.js
index 954f81f91..38be5b677 100644
--- a/packages/react/src/index.js
+++ b/packages/react/src/index.js
@@ -4,5 +4,3 @@ export {
useMDXComponents,
withMDXComponents
} from './context'
-
-export {default as mdx} from './create-element'
diff --git a/packages/react/test/test.js b/packages/react/test/test.js
index 3bf34409d..0f9aa980c 100644
--- a/packages/react/test/test.js
+++ b/packages/react/test/test.js
@@ -5,11 +5,13 @@ import React from 'react'
import {renderToString} from 'react-dom/server'
import {transformAsync as babelTransform} from '@babel/core'
import mdxTransform from '../../mdx'
-import {MDXProvider, withMDXComponents, mdx} from '../src'
+import {MDXProvider, useMDXComponents, withMDXComponents} from '../src'
const run = async value => {
// Turn the serialized MDX code into serialized JSX…
- const doc = await mdxTransform(value, {skipExport: true})
+ let doc = await mdxTransform(value, {skipExport: true})
+
+ doc = doc.replace(/import \{.+?\} from "@mdx-js\/react";/g, '')
// …and that into serialized JS.
const {code} = await babelTransform(doc, {
@@ -22,7 +24,11 @@ const run = async value => {
// …and finally run it, returning the component.
// eslint-disable-next-line no-new-func
- return new Function('mdx', `${code}; return MDXContent`)(mdx)
+ return new Function(
+ 'React',
+ '__provideComponents',
+ `${code}; return MDXContent`
+ )(React, useMDXComponents)
}
describe('@mdx-js/react', () => {
@@ -70,23 +76,6 @@ describe('@mdx-js/react', () => {
expect(renderToString()).toEqual('!')
})
-
- test('should crash if weird values could come from JSX', async () => {
- // As JSX is function calls, that function can also be used directly in
- // MDX. Definitely not a great idea, but it’s an easy way to pass in funky
- // values.
- const Content = await run('{mdx(1)}')
- const error = console.error
- console.error = jest.fn()
-
- expect(() => {
- renderToString()
- }).toThrow('Element type is invalid')
-
- expect(console.error).toHaveBeenCalled()
-
- console.error = error
- })
})
describe('MDXProvider', () => {
diff --git a/packages/react/types/index.d.ts b/packages/react/types/index.d.ts
index aa9a2da9c..88aefff69 100644
--- a/packages/react/types/index.d.ts
+++ b/packages/react/types/index.d.ts
@@ -5,8 +5,7 @@ import {
Consumer,
ComponentType,
FunctionComponent,
- ReactElement,
- createElement
+ ReactElement
} from 'react'
/**
@@ -61,17 +60,11 @@ declare function withMDXComponents(
child: ComponentType
): ReactElement | null
-/**
- * React createElement function wrapped with handler for MDX content
- */
-declare const mdx: typeof createElement
-
export {
ComponentDictionary,
ComponentsProp,
MDXContext,
MDXProvider,
useMDXComponents,
- withMDXComponents,
- mdx
+ withMDXComponents
}
diff --git a/packages/runtime/src/index.js b/packages/runtime/src/index.js
index 5a0967174..22d15369a 100644
--- a/packages/runtime/src/index.js
+++ b/packages/runtime/src/index.js
@@ -1,7 +1,7 @@
import React from 'react'
import {transform} from 'buble-jsx-only'
import mdx from '@mdx-js/mdx'
-import {MDXProvider, mdx as createElement} from '@mdx-js/react'
+import {MDXProvider, useMDXComponents} from '@mdx-js/react'
const suffix = `return React.createElement(
MDXProvider,
@@ -18,8 +18,9 @@ export default ({
...props
}) => {
const fullScope = {
- mdx: createElement,
+ React,
MDXProvider,
+ __provideComponents: useMDXComponents,
components,
props,
...scope
@@ -31,7 +32,7 @@ export default ({
rehypePlugins,
skipExport: true
})
- .trim()
+ .replace(/import \{.+?\} from "@mdx-js\/react";/g, '')
const code = transform(jsx, {objectAssign: 'Object.assign'}).code
@@ -39,7 +40,7 @@ export default ({
const values = Object.values(fullScope)
// eslint-disable-next-line no-new-func
- const fn = new Function('React', ...keys, `${code}\n\n${suffix}`)
+ const fn = new Function(...keys, `${code}\n\n${suffix}`)
- return fn(React, ...values)
+ return fn(...values)
}
diff --git a/packages/vue-loader/index.js b/packages/vue-loader/index.js
index becb39b09..45e2b02e8 100644
--- a/packages/vue-loader/index.js
+++ b/packages/vue-loader/index.js
@@ -1,10 +1,7 @@
const {getOptions} = require('loader-utils')
const mdx = require('@mdx-js/mdx')
-const prefix = `// Vue babel plugin doesn't support pragma replacement
-import {mdx} from '@mdx-js/vue'
-let h
-`
+const prefix = `let h`
const suffix = `export default {
name: 'Mdx',
@@ -19,7 +16,7 @@ const suffix = `export default {
}
},
render(createElement) {
- h = mdx.bind({createElement, components: this.components})
+ h = createElement
return MDXContent({components: this.components})
}
}
@@ -38,7 +35,12 @@ async function mdxLoader(content) {
result = await mdx(content, {
...options,
skipExport: true,
- mdxFragment: false
+ mdxFragment: false,
+ mdxProviderImportSource: null,
+ // Don’t add the comments.
+ jsxRuntime: null,
+ pragma: null,
+ pragmaFrag: null
})
} catch (err) {
return callback(err)
diff --git a/packages/vue-loader/test/test.js b/packages/vue-loader/test/test.js
index eb97ba5d3..7aede7348 100644
--- a/packages/vue-loader/test/test.js
+++ b/packages/vue-loader/test/test.js
@@ -2,8 +2,6 @@ const path = require('path')
const webpack = require('webpack')
const MemoryFs = require('memory-fs')
const {mount} = require('@vue/test-utils')
-const vueMergeProps = require('babel-helper-vue-jsx-merge-props')
-const {mdx} = require('../../vue')
// See `loader`’s tests for how to upgrade these to webpack 5.
const transform = (filePath, options) => {
@@ -45,22 +43,18 @@ const transform = (filePath, options) => {
const run = value => {
// Replace import/exports w/ parameters and return value.
- const val = value
- .replace(
- /import _mergeJSXProps from "babel-helper-vue-jsx-merge-props";/,
- ''
- )
- .replace(/import \{ mdx } from '@mdx-js\/vue';/, '')
- .replace(/export default/, 'return')
+ const val = value.replace(/export default/, 'return')
// eslint-disable-next-line no-new-func
- return new Function('mdx', '_mergeJSXProps', val)(mdx, vueMergeProps)
+ return new Function(val)()
}
describe('@mdx-js/vue-loader', () => {
test('should create runnable code', async () => {
const file = await transform('./fixture.mdx')
- expect(mount(run(file.source)).html()).toEqual('Hello, world!
')
+ expect(mount(run(file.source)).html()).toEqual(
+ '\n
Hello, world!
\n'
+ )
})
test('should handle MDX throwing exceptions', async () => {
@@ -77,7 +71,7 @@ describe('@mdx-js/vue-loader', () => {
})
expect(mount(run(file.source)).html()).toEqual(
- 'Hello, world!
'
+ '\n
Hello, world!
\n'
)
})
})
diff --git a/packages/vue/src/create-element.js b/packages/vue/src/create-element.js
deleted file mode 100644
index 7a7c68f55..000000000
--- a/packages/vue/src/create-element.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * MDX default components
- */
-const defaults = {
- inlineCode: 'code',
- wrapper: {
- name: 'MDXWrapper',
- render: function (h) {
- const children = this.$slots.default
- return children.length === 1 ? children : h('div', {}, children)
- }
- }
-}
-
-const own = {}.hasOwnProperty
-
-export default function createMdxElement(type, props, children) {
- if (own.call(this.components, type)) {
- type = this.components[type]
- } else if (own.call(defaults, type)) {
- type = defaults[type]
- }
-
- if (!children) {
- children = []
- }
-
- if (props && typeof props === 'object' && !Array.isArray(props)) {
- // Empty.
- } else {
- children.unshift(props)
- props = {}
- }
-
- children = children.map(d =>
- typeof d === 'number' || typeof d === 'string'
- ? this.createElement('d', {}, String(d)).children[0]
- : d
- )
-
- if (props.attrs) {
- // Vue places the special MDX props in `props.attrs`, move them back into
- // `props`.
- const {components, mdxType, parentName, ...attrs} = props.attrs
- props = {...props, components, mdxType, parentName, attrs}
- }
-
- // Just a render function.
- if (typeof type === 'function') {
- /* istanbul ignore next - V8 is really good at inferring names, but add a name anyway. */
- const name = type.displayName || type.name || 'mdxFunction'
-
- type = {name, render: type}
- }
-
- // Vue component.
- return this.createElement(type, props, children)
-}
diff --git a/packages/vue/src/index.js b/packages/vue/src/index.js
index 22a61a23b..8e843ce13 100644
--- a/packages/vue/src/index.js
+++ b/packages/vue/src/index.js
@@ -1,2 +1 @@
-export {default as mdx} from './create-element'
export {default as MDXProvider} from './mdx-provider'
diff --git a/packages/vue/src/mdx-provider.js b/packages/vue/src/mdx-provider.js
index be1d12041..9e637c2a3 100644
--- a/packages/vue/src/mdx-provider.js
+++ b/packages/vue/src/mdx-provider.js
@@ -4,8 +4,8 @@ const MDXProvider = {
provide() {
return {$mdxComponents: () => this.components}
},
- render(h) {
- return h('div', this.$slots.default)
+ render() {
+ return this.$slots.default
}
}
diff --git a/packages/vue/test/test.js b/packages/vue/test/test.js
index ac9894122..0541d95a2 100644
--- a/packages/vue/test/test.js
+++ b/packages/vue/test/test.js
@@ -1,13 +1,20 @@
import path from 'path'
import {mount} from '@vue/test-utils'
import mdxTransform from '../../mdx'
-import vueMergeProps from 'babel-helper-vue-jsx-merge-props'
import {transformAsync as babelTransform} from '@babel/core'
-import {MDXProvider, mdx} from '../src'
+import {MDXProvider} from '../src'
const run = async value => {
// Turn the serialized MDX code into serialized JSX…
- const doc = await mdxTransform(value, {skipExport: true, mdxFragment: false})
+ const doc = await mdxTransform(value, {
+ skipExport: true,
+ mdxFragment: false,
+ mdxProviderImportSource: null,
+ // Don’t add the comments.
+ jsxRuntime: null,
+ pragma: null,
+ pragmaFrag: null
+ })
// …and that into serialized JS.
const {code} = await babelTransform(doc, {
@@ -21,13 +28,8 @@ const run = async value => {
// …and finally run it, returning the component.
// eslint-disable-next-line no-new-func
return new Function(
- 'mdx',
- '_mergeJSXProps',
`let h;
- ${code.replace(
- /import _mergeJSXProps from "babel-helper-vue-jsx-merge-props";/,
- ''
- )};
+ ${code};
return {
name: 'Mdx',
@@ -42,18 +44,18 @@ const run = async value => {
}
},
render(createElement) {
- h = mdx.bind({createElement, components: this.components})
+ h = createElement
return MDXContent({components: this.components})
}
}`
- )(mdx, vueMergeProps)
+ )()
}
describe('@mdx-js/vue', () => {
test('should evaluate MDX code', async () => {
const Content = await run('# hi')
- expect(mount(Content).html()).toEqual('hi
')
+ expect(mount(Content).html()).toEqual('\n
hi
\n')
})
test('should evaluate some more complex MDX code (text, inline)', async () => {
@@ -62,7 +64,7 @@ describe('@mdx-js/vue', () => {
)
expect(mount(Content).html()).toEqual(
- 'a b c
MDX
'
+ ''
)
})
@@ -90,7 +92,7 @@ describe('@mdx-js/vue', () => {
const warn = console.warn
console.warn = jest.fn()
- expect(mount(Content).html()).toEqual('')
+ expect(mount(Content).html()).toEqual('\n \n
')
expect(console.warn).toHaveBeenCalledWith(
'Component `%s` was not imported, exported, or provided by MDXProvider as global scope',
@@ -105,7 +107,7 @@ describe('@mdx-js/vue', () => {
'export const A = {render() { return ! }}\n\n'
)
- expect(mount(Content).html()).toEqual('!')
+ expect(mount(Content).html()).toEqual('!
')
})
})
@@ -119,7 +121,7 @@ describe('MDXProvider', () => {
})
test('should support `components`', async () => {
- const Content = await run('*a* and c.')
+ const Content = await run('*a* and c and .')
expect(
mount(MDXProvider, {
@@ -136,36 +138,19 @@ describe('MDXProvider', () => {
this.$slots.default
)
}
+ },
+ Custom: {
+ name: 'Custom',
+ render: function (h) {
+ return h('br')
+ }
}
}
}
}).html()
).toEqual(
- ''
- )
- })
-
- test('should support functional `components`', async () => {
- const Content = await run('*a* and c.')
- const error = console.error
- console.error = jest.fn() // Ignore the warnings that Vue emits.
-
- expect(
- mount(MDXProvider, {
- slots: {default: [Content]},
- propsData: {
- components: {
- em: function (h) {
- return h('i', {style: {fontWeight: 'bold'}}, this.$slots.default)
- }
- }
- }
- }).html()
- ).toEqual(
- ''
+ ''
)
-
- console.error = error
})
test('should support the readme example', async () => {
diff --git a/packages/vue/types/index.d.ts b/packages/vue/types/index.d.ts
index 44f4d0361..66e5f0383 100644
--- a/packages/vue/types/index.d.ts
+++ b/packages/vue/types/index.d.ts
@@ -1,5 +1,7 @@
// TypeScript Version: 3.4
+// To do: remove this and type the `MDXProvider` component.
+
import {CreateElement} from 'vue'
/**
diff --git a/yarn.lock b/yarn.lock
index 52f3adf99..4064eb4d1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1521,6 +1521,17 @@
"@emotion/utils" "0.11.3"
"@emotion/weak-memoize" "0.2.5"
+"@emotion/cache@^11.1.3":
+ version "11.1.3"
+ resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.1.3.tgz#c7683a9484bcd38d5562f2b9947873cf66829afd"
+ integrity sha512-n4OWinUPJVaP6fXxWZD9OUeQ0lY7DvtmtSuqtRWT0Ofo/sBLCVSgb4/Oa0Q5eFxcwablRKjUXqXtNZVyEwCAuA==
+ dependencies:
+ "@emotion/memoize" "^0.7.4"
+ "@emotion/sheet" "^1.0.0"
+ "@emotion/utils" "^1.0.0"
+ "@emotion/weak-memoize" "^0.2.5"
+ stylis "^4.0.3"
+
"@emotion/core@10.0.28":
version "10.0.28"
resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.28.tgz#bb65af7262a234593a9e952c041d0f1c9b9bef3d"
@@ -1559,7 +1570,7 @@
"@emotion/utils" "0.11.3"
babel-plugin-emotion "^10.0.27"
-"@emotion/hash@0.8.0":
+"@emotion/hash@0.8.0", "@emotion/hash@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
@@ -1576,11 +1587,24 @@
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
-"@emotion/memoize@^0.7.1":
+"@emotion/memoize@^0.7.1", "@emotion/memoize@^0.7.4":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
+"@emotion/react@^11.0.0":
+ version "11.1.4"
+ resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.1.4.tgz#ddee4247627ff7dd7d0c6ae52f1cfd6b420357d2"
+ integrity sha512-9gkhrW8UjV4IGRnEe4/aGPkUxoGS23aD9Vu6JCGfEDyBYL+nGkkRBoMFGAzCT9qFdyUvQp4UUtErbKWxq/JS4A==
+ dependencies:
+ "@babel/runtime" "^7.7.2"
+ "@emotion/cache" "^11.1.3"
+ "@emotion/serialize" "^1.0.0"
+ "@emotion/sheet" "^1.0.1"
+ "@emotion/utils" "^1.0.0"
+ "@emotion/weak-memoize" "^0.2.5"
+ hoist-non-react-statics "^3.3.1"
+
"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16":
version "0.11.16"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad"
@@ -1592,11 +1616,27 @@
"@emotion/utils" "0.11.3"
csstype "^2.5.7"
+"@emotion/serialize@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.0.tgz#1a61f4f037cf39995c97fc80ebe99abc7b191ca9"
+ integrity sha512-zt1gm4rhdo5Sry8QpCOpopIUIKU+mUSpV9WNmFILUraatm5dttNEaYzUWWSboSMUE6PtN2j1cAsuvcugfdI3mw==
+ dependencies:
+ "@emotion/hash" "^0.8.0"
+ "@emotion/memoize" "^0.7.4"
+ "@emotion/unitless" "^0.7.5"
+ "@emotion/utils" "^1.0.0"
+ csstype "^3.0.2"
+
"@emotion/sheet@0.9.4":
version "0.9.4"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5"
integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==
+"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.1.tgz#245f54abb02dfd82326e28689f34c27aa9b2a698"
+ integrity sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g==
+
"@emotion/styled-base@^10.0.27":
version "10.0.31"
resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.31.tgz#940957ee0aa15c6974adc7d494ff19765a2f742a"
@@ -1620,7 +1660,7 @@
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
-"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.0":
+"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.0", "@emotion/unitless@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
@@ -1630,7 +1670,12 @@
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924"
integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==
-"@emotion/weak-memoize@0.2.5":
+"@emotion/utils@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af"
+ integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==
+
+"@emotion/weak-memoize@0.2.5", "@emotion/weak-memoize@^0.2.5":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
@@ -13280,7 +13325,7 @@ hoist-non-react-statics@^2.5.5:
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==
-hoist-non-react-statics@^3.3.0:
+hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@@ -25094,6 +25139,11 @@ stylis@3.5.4, stylis@^3.5.0:
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==
+stylis@^4.0.3:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.6.tgz#0d8b97b6bc4748bea46f68602b6df27641b3c548"
+ integrity sha512-1igcUEmYFBEO14uQHAJhCUelTR5jPztfdVKrYxRnDa5D5Dn3w0NxXupJNPr/VV/yRfZYEAco8sTIRZzH3sRYKg==
+
sudo-prompt@^8.2.0:
version "8.2.5"
resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-8.2.5.tgz#cc5ef3769a134bb94b24a631cc09628d4d53603e"