16 | Try and change the background color to \`tomato\`.
17 |
`
18 |
19 | # Playground
20 |
21 | Here you can play with the MDX format.
22 | Write some MDX to find out what it turns into. {/* more */}
23 | You can see the rendered result, the generated code, and the intermediary
24 | ASTs.
25 | This can be helpful for debugging or exploring.
26 | To read about how the MDX format works, we recommend that you start with
27 | [§ What is MDX][what].
28 |
29 |
30 |
31 | [what]: /docs/what-is-mdx/
32 |
--------------------------------------------------------------------------------
/packages/mdx/lib/util/estree-util-declaration-to-expression.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Declaration} Declaration
3 | * @typedef {import('estree-jsx').Expression} Expression
4 | */
5 |
6 | /**
7 | * Turn a declaration into an expression.
8 | * Doesn’t work for variable declarations, but that’s fine for our use case
9 | * because currently we’re using this utility for export default declarations,
10 | * which can’t contain variable declarations.
11 | *
12 | * @param {Declaration} declaration
13 | * @returns {Expression}
14 | */
15 | export function declarationToExpression(declaration) {
16 | if (declaration.type === 'FunctionDeclaration') {
17 | return {...declaration, type: 'FunctionExpression'}
18 | }
19 |
20 | if (declaration.type === 'ClassDeclaration') {
21 | return {...declaration, type: 'ClassExpression'}
22 | /* Internal utility so the next shouldn’t happen or a maintainer is making a
23 | * mistake. */
24 | /* c8 ignore next 4 */
25 | }
26 |
27 | // Probably `VariableDeclaration`.
28 | throw new Error('Cannot turn `' + declaration.type + '` into an expression')
29 | }
30 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Compositor and Vercel, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/rollup/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Titus Wormer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/esbuild/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Titus Wormer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/node-loader/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Titus Wormer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/register/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Titus Wormer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/loader/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Compositor and Vercel, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/preact/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Compositor and Vercel, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/react/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Compositor and Vercel, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/mdx/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Compositor, Inc. and Vercel, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/vue/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Compositor, Inc. and Vercel, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/remark-mdx/license:
--------------------------------------------------------------------------------
1 | (The MIT License)
2 |
3 | Copyright (c) 2020 Titus Wormer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | 'Software'), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: main
2 | on:
3 | - pull_request
4 | - push
5 | jobs:
6 | small:
7 | name: test / ${{matrix.os}} / ${{matrix.node}}
8 | runs-on: ${{matrix.os}}
9 | env:
10 | PUPPETEER_SKIP_DOWNLOAD: 1
11 | steps:
12 | - uses: actions/checkout@v3
13 | with:
14 | fetch-depth: 0
15 | - uses: actions/setup-node@v3
16 | with:
17 | node-version: ${{matrix.node}}
18 | cache: npm
19 | - run: npm install -g npm && npm install
20 | - run: npm run test-api
21 | strategy:
22 | matrix:
23 | os:
24 | - macos-latest
25 | - windows-latest
26 | node:
27 | - '*'
28 | include:
29 | - os: ubuntu-latest
30 | node: lts/fermium
31 | full:
32 | name: full build
33 | runs-on: ubuntu-latest
34 | env:
35 | PUPPETEER_SKIP_DOWNLOAD: 1
36 | steps:
37 | - uses: actions/checkout@v3
38 | with:
39 | fetch-depth: 0
40 | - uses: actions/setup-node@v3
41 | with:
42 | node-version: '*'
43 | cache: npm
44 | - run: npm install -g npm && npm install
45 | - run: npm test
46 | - uses: codecov/codecov-action@v2
47 |
--------------------------------------------------------------------------------
/docs/_component/icon/github.server.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export function GitHub() {
4 | return (
5 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/packages/mdx/lib/plugin/recma-stringify.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Program} Program
3 | * @typedef {typeof import('source-map').SourceMapGenerator} SourceMapGenerator
4 | *
5 | * @typedef RecmaStringifyOptions
6 | * @property {SourceMapGenerator} [SourceMapGenerator]
7 | * Generate a source map by passing a `SourceMapGenerator` from `source-map`
8 | * in.
9 | */
10 |
11 | import {toJs, jsx} from 'estree-util-to-js'
12 |
13 | /**
14 | * A plugin that adds an esast compiler: a small wrapper around `astring` to add
15 | * support for serializing JSX.
16 | *
17 | * @type {import('unified').Plugin<[RecmaStringifyOptions]|[], Program, string>}
18 | */
19 | export function recmaStringify(options = {}) {
20 | const {SourceMapGenerator} = options
21 |
22 | Object.assign(this, {Compiler: compiler})
23 |
24 | /** @type {import('unified').CompilerFunction} */
25 | function compiler(tree, file) {
26 | const result = SourceMapGenerator
27 | ? toJs(tree, {
28 | filePath: file.path || 'unknown.mdx',
29 | SourceMapGenerator,
30 | handlers: jsx
31 | })
32 | : toJs(tree, {handlers: jsx})
33 |
34 | file.map = result.map
35 |
36 | return result.value
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/docs/_component/sort.js:
--------------------------------------------------------------------------------
1 | import dlv from 'dlv'
2 |
3 | const collator = new Intl.Collator('en').compare
4 |
5 | export function sortItems(items, sortString = 'navSortSelf,meta.title') {
6 | const fields = sortString.split(',').map((d) => {
7 | const [field, order = 'asc'] = d.split(':')
8 |
9 | if (order !== 'asc' && order !== 'desc') {
10 | throw new Error('Cannot order as `' + order + '`')
11 | }
12 |
13 | return [field, order]
14 | })
15 |
16 | return [...items].sort((left, right) => {
17 | let index = -1
18 |
19 | while (++index < fields.length) {
20 | const [field, order] = fields[index]
21 | let a = dlv(left.data, field)
22 | let b = dlv(right.data, field)
23 |
24 | if (a && typeof a === 'object' && 'valueOf' in a) a = a.valueOf()
25 | if (b && typeof b === 'object' && 'valueOf' in b) b = b.valueOf()
26 |
27 | const score =
28 | typeof a === 'number' || typeof b === 'number'
29 | ? a === null || a === undefined
30 | ? 1
31 | : b === null || b === undefined
32 | ? -1
33 | : a - b
34 | : collator(a, b)
35 | const result = order === 'asc' ? score : -score
36 | if (result) return result
37 | }
38 |
39 | return 0
40 | })
41 | }
42 |
--------------------------------------------------------------------------------
/packages/node-loader/test/index.test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('mdx/types').MDXContent} MDXContent
3 | */
4 |
5 | import {promises as fs} from 'fs'
6 | import {test} from 'uvu'
7 | import * as assert from 'uvu/assert'
8 | import React from 'react'
9 | import {renderToStaticMarkup} from 'react-dom/server'
10 |
11 | test('@mdx-js/node-loader', async () => {
12 | await fs.writeFile(
13 | new URL('esm-loader.mdx', import.meta.url),
14 | 'export const Message = () => <>World!>\n\n# Hello, '
15 | )
16 |
17 | /** @type {MDXContent} */
18 | let Content
19 |
20 | try {
21 | Content = (await import('./esm-loader.mdx')).default // type-coverage:ignore-line
22 | } catch (error) {
23 | const exception = /** @type {NodeJS.ErrnoException} */ (error)
24 | if (exception.code === 'ERR_UNKNOWN_FILE_EXTENSION') {
25 | await fs.unlink(new URL('esm-loader.mdx', import.meta.url))
26 | throw new Error(
27 | 'Please run Node with `--experimental-loader=./esm-loader.js` to test the ESM loader'
28 | )
29 | }
30 |
31 | throw error
32 | }
33 |
34 | assert.equal(
35 | renderToStaticMarkup(React.createElement(Content)),
36 | '
` (so it has no knowledge of “HTML”).
15 | * It also marks JSX as being explicitly JSX, so when a user passes a `h1`
16 | * component, it is used for `# heading` but not for `
72 | )
73 | }
74 |
75 | export function BlogGroup(props) {
76 | const {items, className, sort = 'navSortSelf,meta.title', ...rest} = props
77 | const sorted = sortItems(items, sort)
78 |
79 | return (
80 | <>
81 | {sorted.map((d) => (
82 |
83 | ))}
84 | >
85 | )
86 | }
87 |
--------------------------------------------------------------------------------
/docs/migrating/v1.server.mdx:
--------------------------------------------------------------------------------
1 | import {Note} from '../_component/note.server.js'
2 | export const navExclude = true
3 | export const info = {
4 | author: [
5 | {name: 'John Otander', github: 'johno', twitter: '4lpine'}
6 | ],
7 | published: new Date('2019-04-04'),
8 | modified: new Date('2021-11-01')
9 | }
10 |
11 |
12 | **Note**: This is an old migration guide.
13 | See [§ Migrating from v1 to v2](/migrating/v2/).
14 | The below is kept as is for historical purposes.
15 |
16 |
17 | # Migrating from v0 to v1
18 |
19 | Unfortunately, we’ve had to introduce a few breaking changes, so we’ve written a
20 | migration guide.
21 | In order to ensure as seamless of an upgrade as possible we plan on supporting
22 | v0 for the next 12 months so there’s not a huge rush to update (though we’d
23 | love for you to ASAP) 📆.
24 |
25 | ## ⚠️ Breaking changes
26 |
27 | * [🚨`@mdx-js/tag` is replaced by `@mdx-js/react` and an `mdx` pragma](#pragma) 🚨
28 | * [MDXProvider now merges component contexts when nested](#mdxprovider)
29 | * [React support now requires `>= 16.8` in `@mdx-js/react`](#react)
30 |
31 | ## Pragma
32 |
33 | For v1 you need to remove `@mdx-js/tag` and replace it with `@mdx-js/react`:
34 |
35 | ```sh
36 | yarn remove @mdx-js/tag
37 | yarn add @mdx-js/react
38 | ```
39 |
40 | ### What’s different?
41 |
42 | The MDXTag implementation has been removed with a custom pragma implementation
43 | inspired by
44 | [Emotion](https://emotion.sh/docs/css-prop#jsx-pragma).
45 | This ensures that transpiled JSX is more readable and that JSX blocks use the
46 | same component as its markdown counterpart.
47 | It also allows MDXProvider to provide global component scope like a `Youtube`
48 | or `Twitter` component.
49 |
50 | The pragma implementation will also cause JSX HTML elements to be rendered with
51 | the component mapping passed to MDXProvider.
52 | So, the following will result in two identically rendered `h1`s:
53 |
54 | ```js
55 | # Hello, world!
56 |
57 |
Hello, world!
58 | ```
59 |
60 | [See the blog post for further reading](/blog/custom-pragma/)
61 |
62 | ## MDXProvider
63 |
64 | This shouldn’t affect most usecases, however if you’re nesting component
65 | contexts and rely on them not being merged you will have to use the functional
66 | form which allows you to customize the merge.
67 | By ignoring outer context components and returning a new component mapping, you
68 | will restore the old behavior:
69 |
70 | ```js
71 |
72 | newComponents}>
73 | {children}
74 |
75 |
76 | ```
77 |
78 | ## React
79 |
80 | Before upgrading to `@mdx-js/mdx@1`, update your website/application to
81 | `react@16.8 react-dom@16.8` and ensure it works as expected.
82 | Then upgrade to v1.
83 |
--------------------------------------------------------------------------------
/packages/mdx/lib/util/create-format-aware-processors.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('vfile').VFileCompatible} VFileCompatible
3 | * @typedef {import('vfile').VFile} VFile
4 | * @typedef {import('unified').Processor} Processor
5 | * @typedef {import('../compile.js').CompileOptions} CompileOptions
6 | */
7 |
8 | import {createProcessor} from '../core.js'
9 | import {md, mdx} from './extnames.js'
10 | import {resolveFileAndOptions} from './resolve-file-and-options.js'
11 |
12 | /**
13 | * Create smart processors to handle different formats.
14 | *
15 | * @param {CompileOptions} [compileOptions]
16 | * @return {{extnames: Array, process: process, processSync: processSync}}
17 | */
18 | export function createFormatAwareProcessors(compileOptions = {}) {
19 | const mdExtensions = compileOptions.mdExtensions || md
20 | const mdxExtensions = compileOptions.mdxExtensions || mdx
21 | /** @type {Processor} */
22 | let cachedMarkdown
23 | /** @type {Processor} */
24 | let cachedMdx
25 |
26 | return {
27 | extnames:
28 | compileOptions.format === 'md'
29 | ? mdExtensions
30 | : compileOptions.format === 'mdx'
31 | ? mdxExtensions
32 | : mdExtensions.concat(mdxExtensions),
33 | process,
34 | processSync
35 | }
36 |
37 | /**
38 | * Smart processor.
39 | *
40 | * @param {VFileCompatible} vfileCompatible
41 | * MDX or markdown document.
42 | * @return {Promise}
43 | */
44 | function process(vfileCompatible) {
45 | const {file, processor} = split(vfileCompatible)
46 | return processor.process(file)
47 | }
48 |
49 | /**
50 | * Sync smart processor.
51 | *
52 | * @param {VFileCompatible} vfileCompatible
53 | * MDX or markdown document.
54 | * @return {VFile}
55 | */
56 | // C8 does not cover `.cjs` files (this is only used for the require hook,
57 | // which has to be CJS).
58 | /* c8 ignore next 4 */
59 | function processSync(vfileCompatible) {
60 | const {file, processor} = split(vfileCompatible)
61 | return processor.processSync(file)
62 | }
63 |
64 | /**
65 | * Make a full vfile from what’s given, and figure out which processor
66 | * should be used for it.
67 | * This caches processors (one for markdown and one for MDX) so that they do
68 | * not have to be reconstructed for each file.
69 | *
70 | * @param {VFileCompatible} vfileCompatible
71 | * MDX or markdown document.
72 | * @return {{file: VFile, processor: Processor}}
73 | */
74 | function split(vfileCompatible) {
75 | const {file, options} = resolveFileAndOptions(
76 | vfileCompatible,
77 | compileOptions
78 | )
79 | const processor =
80 | options.format === 'md'
81 | ? cachedMarkdown || (cachedMarkdown = createProcessor(options))
82 | : cachedMdx || (cachedMdx = createProcessor(options))
83 | return {file, processor}
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/packages/mdx/lib/util/estree-util-specifiers-to-declarations.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Identifier} Identifier
3 | * @typedef {import('estree-jsx').ImportSpecifier} ImportSpecifier
4 | * @typedef {import('estree-jsx').ImportDefaultSpecifier} ImportDefaultSpecifier
5 | * @typedef {import('estree-jsx').ImportNamespaceSpecifier} ImportNamespaceSpecifier
6 | * @typedef {import('estree-jsx').ExportSpecifier} ExportSpecifier
7 | * @typedef {import('estree-jsx').ObjectPattern} ObjectPattern
8 | * @typedef {import('estree-jsx').VariableDeclarator} VariableDeclarator
9 | * @typedef {import('estree-jsx').Expression} Expression
10 | */
11 |
12 | import {create} from './estree-util-create.js'
13 |
14 | /**
15 | * @param {Array} specifiers
16 | * @param {Expression} init
17 | * @returns {Array}
18 | */
19 | export function specifiersToDeclarations(specifiers, init) {
20 | let index = -1
21 | /** @type {Array} */
22 | const declarations = []
23 | /** @type {Array} */
24 | const otherSpecifiers = []
25 | // Can only be one according to JS syntax.
26 | /** @type {ImportNamespaceSpecifier|undefined} */
27 | let importNamespaceSpecifier
28 |
29 | while (++index < specifiers.length) {
30 | const specifier = specifiers[index]
31 |
32 | if (specifier.type === 'ImportNamespaceSpecifier') {
33 | importNamespaceSpecifier = specifier
34 | } else {
35 | otherSpecifiers.push(specifier)
36 | }
37 | }
38 |
39 | if (importNamespaceSpecifier) {
40 | declarations.push(
41 | create(importNamespaceSpecifier, {
42 | type: 'VariableDeclarator',
43 | id: importNamespaceSpecifier.local,
44 | init
45 | })
46 | )
47 | }
48 |
49 | declarations.push({
50 | type: 'VariableDeclarator',
51 | id: {
52 | type: 'ObjectPattern',
53 | properties: otherSpecifiers.map((specifier) => {
54 | /** @type {Identifier} */
55 | let key =
56 | specifier.type === 'ImportSpecifier'
57 | ? specifier.imported
58 | : specifier.type === 'ExportSpecifier'
59 | ? specifier.exported
60 | : {type: 'Identifier', name: 'default'}
61 | let value = specifier.local
62 |
63 | // Switch them around if we’re exporting.
64 | if (specifier.type === 'ExportSpecifier') {
65 | value = key
66 | key = specifier.local
67 | }
68 |
69 | return create(specifier, {
70 | type: 'Property',
71 | kind: 'init',
72 | shorthand: key.name === value.name,
73 | method: false,
74 | computed: false,
75 | key,
76 | value
77 | })
78 | })
79 | },
80 | init: importNamespaceSpecifier
81 | ? {type: 'Identifier', name: importNamespaceSpecifier.local.name}
82 | : init
83 | })
84 |
85 | return declarations
86 | }
87 |
--------------------------------------------------------------------------------
/docs/guides/frontmatter.server.mdx:
--------------------------------------------------------------------------------
1 | export const navSortSelf = 2
2 | export const info = {
3 | author: [
4 | {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'}
5 | ],
6 | published: new Date('2021-10-06'),
7 | modified: new Date('2022-06-17')
8 | }
9 |
10 | # Frontmatter
11 |
12 | This guide explores how to support YAML frontmatter in MDX. {/* more */}
13 | MDX supports standard markdown syntax ([CommonMark][]).
14 | That means frontmatter is not supported by default.
15 |
16 | MDX comes with a powerful and dynamic alternative to frontmatter, namely ESM
17 | (`import`/`export`).
18 | These exports:
19 |
20 | ```mdx path="post.mdx"
21 | export const name = 'World'
22 | export const title = 'Hi, ' + name + '!'
23 |
24 | # {title}
25 | ```
26 |
27 | Can be used like so:
28 |
29 | ```js path="example.js"
30 | import * as Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.
31 |
32 | console.log(Post.title) // Prints 'Hi, World!'
33 | ```
34 |
35 | You might prefer frontmatter though, as it lets you define data that can be
36 | extracted from the file system *before* compiling.
37 | Say our MDX with frontmatter looked like this:
38 |
39 | ```mdx path="post.mdx"
40 | ---
41 | title: Hi, World!
42 | ---
43 |
44 | # Hi, World!
45 | ```
46 |
47 | Then without compiling or evaluating the metadata can be accessed like so:
48 |
49 | ```js path="example.js"
50 | import {promises as fs} from 'node:fs'
51 | import yaml from 'js-yaml'
52 |
53 | console.log(yaml.loadAll(await fs.readFile('post.mdx'))[0])
54 | // Prints `{title: 'Hi, World!'}`
55 | ```
56 |
57 | Our compiler, `@mdx-js/mdx`, doesn’t understand YAML frontmatter by default but
58 | it can be enabled by using a remark plugin,
59 | [`remark-frontmatter`][remark-frontmatter]:
60 |
61 | ```js path="example.js"
62 | import {promises as fs} from 'node:fs'
63 | import remarkFrontmatter from 'remark-frontmatter'
64 | import {compile} from '@mdx-js/mdx'
65 |
66 | console.log(
67 | await compile(await fs.readFile('post.mdx'), {
68 | remarkPlugins: [remarkFrontmatter]
69 | })
70 | )
71 | ```
72 |
73 | Now it “works”.
74 | The frontmatter is ignored.
75 | But the data embedded in the frontmatter isn’t available from *inside* the MDX.
76 | What if we wanted that too?
77 | Like so:
78 |
79 | ```mdx path="post.mdx"
80 | ---
81 | title: Hi, World!
82 | ---
83 |
84 | # {title}
85 | ```
86 |
87 | That’s exactly what the remark plugin
88 | [`remark-mdx-frontmatter`][remark-mdx-frontmatter] does.
89 |
90 | remark plugins can be passed in
91 | [`options.remarkPlugins`][options-remark-plugins].
92 | More info on plugins is available in [§ Extending MDX][extend]
93 |
94 | [commonmark]: https://spec.commonmark.org/current/
95 |
96 | [remark-frontmatter]: https://github.com/remarkjs/remark-frontmatter
97 |
98 | [remark-mdx-frontmatter]: https://github.com/remcohaszing/remark-mdx-frontmatter
99 |
100 | [options-remark-plugins]: /packages/mdx/#optionsremarkplugins
101 |
102 | [extend]: /docs/extending-mdx/
103 |
--------------------------------------------------------------------------------
/packages/preact/lib/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('preact').ComponentChildren} ComponentChildren
3 | * @typedef {import('mdx/types').MDXComponents} Components
4 | *
5 | * @typedef Props
6 | * Configuration.
7 | * @property {Components} [components]
8 | * Mapping of names for JSX components to Preact components.
9 | * @property {boolean} [disableParentContext=false]
10 | * Turn off outer component context.
11 | * @property {ComponentChildren} [children]
12 | * Children.
13 | *
14 | * @callback MergeComponents
15 | * @param {Components} currentComponents
16 | * Current components from the context.
17 | * @returns {Components}
18 | * Merged components.
19 | */
20 |
21 | import {createContext, h} from 'preact'
22 | import {useContext} from 'preact/hooks'
23 |
24 | /**
25 | * @type {import('preact').Context}
26 | * @deprecated
27 | * This export is marked as a legacy feature.
28 | * That means it’s no longer recommended for use as it might be removed
29 | * in a future major release.
30 | *
31 | * Please use `useMDXComponents` to get context based components and
32 | * `MDXProvider` to set context based components instead.
33 | */
34 | export const MDXContext = createContext({})
35 |
36 | /**
37 | * @param {import('react').ComponentType} Component
38 | * @deprecated
39 | * This export is marked as a legacy feature.
40 | * That means it’s no longer recommended for use as it might be removed
41 | * in a future major release.
42 | *
43 | * Please use `useMDXComponents` to get context based components instead.
44 | */
45 | export function withMDXComponents(Component) {
46 | return boundMDXComponent
47 |
48 | /**
49 | * @param {Record & {components?: Components}} props
50 | * @returns {JSX.Element}
51 | */
52 | function boundMDXComponent(props) {
53 | const allComponents = useMDXComponents(props.components)
54 | // @ts-expect-error: React + Preact in this repo mess with TS.
55 | return h(Component, {...props, allComponents})
56 | }
57 | }
58 |
59 | /**
60 | * Get current components from the MDX Context.
61 | *
62 | * @param {Components|MergeComponents} [components]
63 | * Additional components to use or a function that takes the current
64 | * components and filters/merges/changes them.
65 | * @returns {Components}
66 | * Current components.
67 | */
68 | export function useMDXComponents(components) {
69 | const contextComponents = useContext(MDXContext)
70 |
71 | // Custom merge via a function prop
72 | if (typeof components === 'function') {
73 | return components(contextComponents)
74 | }
75 |
76 | return {...contextComponents, ...components}
77 | }
78 |
79 | /**
80 | * Provider for MDX context
81 | *
82 | * @param {Props} props
83 | * @returns {JSX.Element}
84 | */
85 | export function MDXProvider({components, children, disableParentContext}) {
86 | let allComponents = useMDXComponents(components)
87 |
88 | if (disableParentContext) {
89 | allComponents = components || {}
90 | }
91 |
92 | // @ts-expect-error: preact types are wrong.
93 | return h(MDXContext.Provider, {value: allComponents}, children)
94 | }
95 |
--------------------------------------------------------------------------------
/packages/react/lib/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('react').ReactNode} ReactNode
3 | * @typedef {import('mdx/types').MDXComponents} Components
4 | *
5 | * @typedef Props
6 | * Configuration.
7 | * @property {Components} [components]
8 | * Mapping of names for JSX components to React components.
9 | * @property {boolean} [disableParentContext=false]
10 | * Turn off outer component context.
11 | * @property {ReactNode} [children]
12 | * Children.
13 | *
14 | * @callback MergeComponents
15 | * @param {Components} currentComponents
16 | * Current components from the context.
17 | * @returns {Components}
18 | * Merged components.
19 | */
20 |
21 | import React from 'react'
22 |
23 | /**
24 | * @type {import('react').Context}
25 | * @deprecated
26 | * This export is marked as a legacy feature.
27 | * That means it’s no longer recommended for use as it might be removed
28 | * in a future major release.
29 | *
30 | * Please use `useMDXComponents` to get context based components and
31 | * `MDXProvider` to set context based components instead.
32 | */
33 | export const MDXContext = React.createContext({})
34 |
35 | /**
36 | * @param {import('react').ComponentType} Component
37 | * @deprecated
38 | * This export is marked as a legacy feature.
39 | * That means it’s no longer recommended for use as it might be removed
40 | * in a future major release.
41 | *
42 | * Please use `useMDXComponents` to get context based components instead.
43 | */
44 | export function withMDXComponents(Component) {
45 | return boundMDXComponent
46 |
47 | /**
48 | * @param {Record & {components?: Components}} props
49 | * @returns {JSX.Element}
50 | */
51 | function boundMDXComponent(props) {
52 | const allComponents = useMDXComponents(props.components)
53 | return React.createElement(Component, {...props, allComponents})
54 | }
55 | }
56 |
57 | /**
58 | * Get current components from the MDX Context.
59 | *
60 | * @param {Components|MergeComponents} [components]
61 | * Additional components to use or a function that takes the current
62 | * components and filters/merges/changes them.
63 | * @returns {Components}
64 | * Current components.
65 | */
66 | export function useMDXComponents(components) {
67 | const contextComponents = React.useContext(MDXContext)
68 | // Memoize to avoid unnecessary top-level context changes
69 | return React.useMemo(() => {
70 | // Custom merge via a function prop
71 | if (typeof components === 'function') {
72 | return components(contextComponents)
73 | }
74 |
75 | return {...contextComponents, ...components}
76 | }, [contextComponents, components])
77 | }
78 |
79 | /** @type {Components} */
80 | const emptyObject = {}
81 |
82 | /**
83 | * Provider for MDX context
84 | *
85 | * @param {Props} props
86 | * @returns {JSX.Element}
87 | */
88 | export function MDXProvider({components, children, disableParentContext}) {
89 | let allComponents = useMDXComponents(components)
90 |
91 | if (disableParentContext) {
92 | allComponents = components || emptyObject
93 | }
94 |
95 | return React.createElement(
96 | MDXContext.Provider,
97 | {value: allComponents},
98 | children
99 | )
100 | }
101 |
--------------------------------------------------------------------------------
/docs/guides/math.server.mdx:
--------------------------------------------------------------------------------
1 | import {Note} from '../_component/note.server.js'
2 | export const navSortSelf = 3
3 | export const info = {
4 | author: [
5 | {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'}
6 | ],
7 | published: new Date('2021-10-06'),
8 | modified: new Date('2022-06-17')
9 | }
10 |
11 | # Math
12 |
13 | This guide explores how to support math (LaTeX) in MDX. {/* more */}
14 | MDX supports standard markdown syntax ([CommonMark][]).
15 | That means math is not supported by default.
16 | Math can be enabled by using a remark plugin: [`remark-math`][remark-math],
17 | combined with a rehype plugin: either
18 | [`rehype-katex`][rehype-katex] (KaTeX) or [`rehype-mathjax`][rehype-mathjax]
19 | (MathJax).
20 | remark plugins can be passed in
21 | [`options.remarkPlugins`][options-remark-plugins] and rehype
22 | plugins in [`options.rehypePlugins`][options-rehype-plugins].
23 | More info on plugins is available in [§ Extending MDX][extend]
24 |
25 | Say we have an MDX file like this:
26 |
27 | ```mdx path="example.mdx"
28 | # $\sqrt{a^2 + b^2}$
29 | ```
30 |
31 | The above MDX with math can be transformed with the following module:
32 |
33 | ```js path="example.js"
34 | import {promises as fs} from 'node:fs'
35 | import {compile} from '@mdx-js/mdx'
36 | import rehypeKatex from 'rehype-katex'
37 | import remarkMath from 'remark-math'
38 |
39 | console.log(
40 | String(
41 | await compile(await fs.readFile('example.mdx'), {
42 | remarkPlugins: [remarkMath],
43 | rehypePlugins: [rehypeKatex]
44 | })
45 | )
46 | )
47 | ```
48 |
49 |
50 | Expand equivalent JSX
51 |
52 | ```jsx path="output.jsx"
53 | <>
54 |
55 |
56 |
57 |
58 |
59 |
60 | …
61 |
62 |
63 |
64 | >
65 | ```
66 |
67 |
68 |
69 | **Important**: if you chose `rehype-katex`, you should also use `katex.css`
70 | somewhere on the page to style math properly.
71 | At the time of writing, the last version is:
72 |
73 | ```html
74 |
75 | ```
76 |
77 |
78 |
79 | **Note:** see also
80 | [`remark-mdx-math-enhanced`](https://github.com/goodproblems/remark-mdx-math-enhanced),
81 | which you can use to support JavaScript expressions inside of math (such as to
82 | access props or to make calculations)
83 |
84 |
85 | [commonmark]: https://spec.commonmark.org/current/
86 |
87 | [remark-math]: https://github.com/remarkjs/remark-math/tree/main/packages/remark-math
88 |
89 | [rehype-katex]: https://github.com/remarkjs/remark-math/tree/main/packages/rehype-katex
90 |
91 | [rehype-mathjax]: https://github.com/remarkjs/remark-math/tree/main/packages/rehype-mathjax
92 |
93 | [options-remark-plugins]: /packages/mdx/#optionsremarkplugins
94 |
95 | [options-rehype-plugins]: /packages/mdx/#optionsrehypeplugins
96 |
97 | [extend]: /docs/extending-mdx/
98 |
--------------------------------------------------------------------------------
/docs/guides/mdx-on-demand.server.mdx:
--------------------------------------------------------------------------------
1 | import {Note} from '../_component/note.server.js'
2 | export const navSortSelf = 6
3 | export const info = {
4 | author: [
5 | {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'}
6 | ],
7 | published: new Date('2021-11-13'),
8 | modified: new Date('2021-11-13')
9 | }
10 |
11 | # MDX on demand
12 |
13 | This guide shows how to use `@mdx-js/mdx` to compile MDX on the server and run
14 | the result on clients. {/* more */}
15 | Some frameworks, such as Next.js and Remix, make it easy to split work between
16 | servers and clients.
17 | Using that it’s possible to for example do most of the work on demand on the
18 | server instead of at build time, then pass the resulting data to clients, where
19 | they finally use it.
20 |
21 | This is similar to what [`mdx-bundler`][mdx-bundler] and
22 | [`next-mdx-remote`][next-mdx-remote] also do, but they add more features.
23 |
24 | ## Quick example
25 |
26 | On the server:
27 |
28 | ```js path="server.js"
29 | import {compile} from '@mdx-js/mdx'
30 |
31 | const code = String(await compile('# hi', {outputFormat: 'function-body' /* …otherOptions */ }))
32 | // To do: send `code` to the client somehow.
33 | ```
34 |
35 | On the client:
36 |
37 | ```js path="client.js"
38 | import {run} from '@mdx-js/mdx'
39 | import * as runtime from 'react/jsx-runtime'
40 |
41 | const code = '' // To do: get `code` from server somehow.
42 |
43 | const {default: Content} = await run(code, runtime)
44 | ```
45 |
46 | `Content` is now an `MDXContent` component that you can use like normal in your
47 | framework (see [§ Using MDX][use]).
48 |
49 | More information is available in the API docs of `@mdx-js/mdx` for
50 | [`compile`][compile] and [`run`][run].
51 | For other use cases, you can also use [`evaluate`][eval], which both compiles
52 | and runs in one.
53 |
54 |
55 | **Note**: MDX is not a bundler (esbuild, webpack, and Rollup are bundlers):
56 | you can’t import other code from the server within the string of MDX and get a
57 | nicely minified bundle out or so.
58 |
59 |
60 | ## Next.js example
61 |
62 | Some frameworks let you write the server and client code in one file, such as
63 | Next.
64 |
65 | ```js path="pages/hello.js"
66 | import {useState, useEffect, Fragment} from 'react'
67 | import * as runtime from 'react/jsx-runtime'
68 | import {compile, run} from '@mdx-js/mdx'
69 |
70 | export default function Page({code}) {
71 | const [mdxModule, setMdxModule] = useState()
72 | const Content = mdxModule ? mdxModule.default : Fragment
73 |
74 | useEffect(() => {
75 | ;(async () => {
76 | setMdxModule(await run(code, runtime))
77 | })()
78 | }, [code])
79 |
80 | return
81 | }
82 |
83 | export async function getStaticProps() {
84 | const code = String(
85 | await compile('# hi', {outputFormat: 'function-body' /* …otherOptions */})
86 | )
87 | return {props: {code}}
88 | }
89 | ```
90 |
91 | [mdx-bundler]: https://github.com/kentcdodds/mdx-bundler
92 |
93 | [next-mdx-remote]: https://github.com/hashicorp/next-mdx-remote
94 |
95 | [use]: /docs/using-mdx/
96 |
97 | [compile]: /packages/mdx/#compilefile-options
98 |
99 | [run]: /packages/mdx/#runfunctionbody-options
100 |
101 | [eval]: /packages/mdx/#evaluatefile-options
102 |
--------------------------------------------------------------------------------
/packages/mdx/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@mdx-js/mdx",
3 | "version": "2.1.5",
4 | "description": "MDX compiler",
5 | "license": "MIT",
6 | "keywords": [
7 | "mdx",
8 | "markdown",
9 | "jsx",
10 | "remark",
11 | "mdxast"
12 | ],
13 | "homepage": "https://mdxjs.com",
14 | "repository": {
15 | "type": "git",
16 | "url": "https://github.com/mdx-js/mdx",
17 | "directory": "packages/mdx"
18 | },
19 | "bugs": "https://github.com/mdx-js/mdx/issues",
20 | "funding": {
21 | "type": "opencollective",
22 | "url": "https://opencollective.com/unified"
23 | },
24 | "author": "John Otander (https://johno.com)",
25 | "contributors": [
26 | "John Otander (https://johno.com)",
27 | "Tim Neutkens ",
28 | "Matija Marohnić ",
29 | "Titus Wormer (https://wooorm.com)",
30 | "JounQin (https://www.1stg.me)",
31 | "Christian Murphy "
32 | ],
33 | "type": "module",
34 | "sideEffects": false,
35 | "main": "index.js",
36 | "types": "index.d.ts",
37 | "browser": {
38 | "./lib/condition.js": "./lib/condition.browser.js"
39 | },
40 | "react-native": {
41 | "./lib/condition.js": "./lib/condition.browser.js"
42 | },
43 | "files": [
44 | "lib/",
45 | "index.d.ts",
46 | "index.js"
47 | ],
48 | "dependencies": {
49 | "@types/estree-jsx": "^1.0.0",
50 | "@types/mdx": "^2.0.0",
51 | "estree-util-build-jsx": "^2.0.0",
52 | "estree-util-is-identifier-name": "^2.0.0",
53 | "estree-util-to-js": "^1.1.0",
54 | "estree-walker": "^3.0.0",
55 | "hast-util-to-estree": "^2.0.0",
56 | "markdown-extensions": "^1.0.0",
57 | "periscopic": "^3.0.0",
58 | "remark-mdx": "^2.0.0",
59 | "remark-parse": "^10.0.0",
60 | "remark-rehype": "^10.0.0",
61 | "unified": "^10.0.0",
62 | "unist-util-position-from-estree": "^1.0.0",
63 | "unist-util-stringify-position": "^3.0.0",
64 | "unist-util-visit": "^4.0.0",
65 | "vfile": "^5.0.0"
66 | },
67 | "devDependencies": {
68 | "@emotion/react": "^11.0.0",
69 | "@mdx-js/react": "^2.0.0",
70 | "nanoid": "^4.0.0",
71 | "preact": "^10.0.0",
72 | "preact-render-to-string": "^5.0.0",
73 | "react": "^18.0.0",
74 | "react-dom": "^18.0.0",
75 | "rehype-katex": "^6.0.0",
76 | "rehype-raw": "^6.0.0",
77 | "remark-frontmatter": "^4.0.0",
78 | "remark-gfm": "^3.0.0",
79 | "remark-math": "^5.0.0",
80 | "source-map": "^0.7.0",
81 | "source-map-support": "^0.5.0",
82 | "unist-util-remove-position": "^4.0.0"
83 | },
84 | "scripts": {
85 | "prepack": "npm run build",
86 | "build": "rimraf \"lib/**/*.d.ts\" \"test/**/*.d.ts\" \"*.d.ts\" && tsc && type-coverage",
87 | "test-api": "uvu test \"^(compile|evaluate)\\.js$\"",
88 | "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api",
89 | "test": "npm run build && npm run test-coverage"
90 | },
91 | "xo": false,
92 | "typeCoverage": {
93 | "atLeast": 100,
94 | "detail": true,
95 | "strict": true,
96 | "ignoreCatch": true,
97 | "ignoreFiles": [
98 | "lib/util/resolve-evaluate-options.{d.ts,js}"
99 | ]
100 | },
101 | "gitHead": "bf7deab69996449cb99c2217dff75e65855eb2c1"
102 | }
103 |
--------------------------------------------------------------------------------
/packages/node-loader/lib/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('@mdx-js/mdx/lib/compile.js').CompileOptions} CompileOptions
3 | *
4 | * @typedef LoaderOptions
5 | * @property {boolean} [fixRuntimeWithoutExportMap=true]
6 | * Several JSX runtimes, notably React below 18 and Emotion below 11.10.0,
7 | * don’t yet have a proper export map set up.
8 | * Export maps are needed to map `xxx/jsx-runtime` to an actual file in ESM.
9 | * This option fixes React et al by turning those into `xxx/jsx-runtime.js`.
10 | *
11 | * @typedef {CompileOptions & LoaderOptions} Options
12 | */
13 |
14 | import {promises as fs} from 'node:fs'
15 | import path from 'node:path'
16 | import {URL, fileURLToPath} from 'node:url'
17 | import {VFile} from 'vfile'
18 | import {createFormatAwareProcessors} from '@mdx-js/mdx/lib/util/create-format-aware-processors.js'
19 |
20 | /**
21 | * Create smart processors to handle different formats.
22 | *
23 | * @param {Options} [options]
24 | */
25 | export function createLoader(options = {}) {
26 | const {extnames, process} = createFormatAwareProcessors(options)
27 | let fixRuntimeWithoutExportMap = options.fixRuntimeWithoutExportMap
28 |
29 | if (
30 | fixRuntimeWithoutExportMap === null ||
31 | fixRuntimeWithoutExportMap === undefined
32 | ) {
33 | fixRuntimeWithoutExportMap = true
34 | }
35 |
36 | return {load, getFormat, transformSource}
37 |
38 | /* c8 ignore start */
39 | // Node version 17.
40 | /**
41 | * @param {string} url
42 | * @param {unknown} context
43 | * @param {Function} defaultLoad
44 | */
45 | async function load(url, context, defaultLoad) {
46 | if (!extnames.includes(path.extname(url))) {
47 | return defaultLoad(url, context, defaultLoad)
48 | }
49 |
50 | /* eslint-disable-next-line security/detect-non-literal-fs-filename */
51 | const value = await fs.readFile(fileURLToPath(new URL(url)))
52 | const file = await process(new VFile({value, path: new URL(url)}))
53 | let source = String(file)
54 |
55 | if (fixRuntimeWithoutExportMap) {
56 | source = String(file).replace(/\/jsx-runtime(?=["'])/, '$&.js')
57 | }
58 |
59 | return {format: 'module', source, shortCircuit: true}
60 | }
61 |
62 | // Pre version 17.
63 | /**
64 | * @param {string} url
65 | * @param {unknown} context
66 | * @param {Function} defaultGetFormat
67 | * @deprecated
68 | * This is an obsolete legacy function that no longer works in Node 17.
69 | */
70 | function getFormat(url, context, defaultGetFormat) {
71 | return extnames.includes(path.extname(url))
72 | ? {format: 'module'}
73 | : defaultGetFormat(url, context, defaultGetFormat)
74 | }
75 |
76 | /**
77 | * @param {string} value
78 | * @param {{url: string, [x: string]: unknown}} context
79 | * @param {Function} defaultTransformSource
80 | * @deprecated
81 | * This is an obsolete legacy function that no longer works in Node 17.
82 | */
83 | async function transformSource(value, context, defaultTransformSource) {
84 | if (!extnames.includes(path.extname(context.url))) {
85 | return defaultTransformSource(value, context, defaultTransformSource)
86 | }
87 |
88 | const file = await process(new VFile({value, path: new URL(context.url)}))
89 | let source = String(file)
90 |
91 | if (fixRuntimeWithoutExportMap) {
92 | source = String(file).replace(/\/jsx-runtime(?=["'])/, '$&.js')
93 | }
94 |
95 | return {source}
96 | }
97 | /* c8 ignore end */
98 | }
99 |
--------------------------------------------------------------------------------
/packages/loader/lib/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('vfile').VFileCompatible} VFileCompatible
3 | * @typedef {import('vfile').VFile} VFile
4 | * @typedef {import('vfile-message').VFileMessage} VFileMessage
5 | * @typedef {import('@mdx-js/mdx').CompileOptions} CompileOptions
6 | * @typedef {Pick} Defaults
7 | * @typedef {Omit} Options
8 | * @typedef {import('webpack').LoaderContext} LoaderContext
9 | * @typedef {import('webpack').Compiler} WebpackCompiler
10 | * @typedef {(vfileCompatible: VFileCompatible) => Promise} Process
11 | */
12 |
13 | import {createHash} from 'node:crypto'
14 | import path from 'node:path'
15 | import {SourceMapGenerator} from 'source-map'
16 | import {createFormatAwareProcessors} from '@mdx-js/mdx/lib/util/create-format-aware-processors.js'
17 |
18 | const own = {}.hasOwnProperty
19 |
20 | // Note: the cache is heavily inspired by:
21 | //
22 | const marker = /** @type {WebpackCompiler} */ ({})
23 | /** @type {WeakMap>} */
24 | const cache = new WeakMap()
25 |
26 | /**
27 | * A Webpack (5+) loader for MDX.
28 | * See `webpack.cjs`, which wraps this, because Webpack loaders must currently
29 | * be CommonJS.
30 | *
31 | * @this {LoaderContext}
32 | * @param {string} value
33 | * @param {(error: Error|null|undefined, content?: string|Buffer, map?: Object) => void} callback
34 | */
35 | export function loader(value, callback) {
36 | /** @type {Defaults} */
37 | const defaults = this.sourceMap ? {SourceMapGenerator} : {}
38 | const options = /** @type {CompileOptions} */ (this.getOptions())
39 | const config = {...defaults, ...options}
40 | const hash = getOptionsHash(options)
41 | // Some loaders set `undefined` (see `TypeStrong/ts-loader`).
42 | /* c8 ignore next */
43 | const compiler = this._compiler || marker
44 |
45 | /* Removed option. */
46 | /* c8 ignore next 5 */
47 | if ('renderer' in config) {
48 | throw new Error(
49 | '`options.renderer` is no longer supported. Please see for more information'
50 | )
51 | }
52 |
53 | let map = cache.get(compiler)
54 |
55 | if (!map) {
56 | map = new Map()
57 | cache.set(compiler, map)
58 | }
59 |
60 | let process = map.get(hash)
61 |
62 | if (!process) {
63 | process = createFormatAwareProcessors(config).process
64 | map.set(hash, process)
65 | }
66 |
67 | process({value, path: this.resourcePath}).then(
68 | (file) => {
69 | callback(null, file.value, file.map)
70 | },
71 | (/** @type VFileMessage */ error) => {
72 | const fpath = path.relative(this.context, this.resourcePath)
73 | error.message = `${fpath}:${error.name}: ${error.message}`
74 | callback(error)
75 | }
76 | )
77 | }
78 |
79 | /**
80 | * @param {Options} options
81 | */
82 | function getOptionsHash(options) {
83 | const hash = createHash('sha256')
84 | /** @type {keyof Options} */
85 | let key
86 |
87 | for (key in options) {
88 | if (own.call(options, key)) {
89 | const value = options[key]
90 |
91 | if (value !== undefined) {
92 | const valueString = JSON.stringify(value)
93 | hash.update(key + valueString)
94 | }
95 | }
96 | }
97 |
98 | return hash.digest('hex').slice(0, 16)
99 | }
100 |
--------------------------------------------------------------------------------
/website/prep.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | import {promises as fs} from 'fs'
3 | import {fileURLToPath} from 'url'
4 | import pAll from 'p-all'
5 | import {globby} from 'globby'
6 | import {u} from 'unist-builder'
7 | import {h} from 'hastscript'
8 | import {VFile} from 'vfile'
9 | import {unified} from 'unified'
10 | import rehypePresetMinify from 'rehype-preset-minify'
11 | import rehypeMinifyUrl from 'rehype-minify-url'
12 | import rehypeStringify from 'rehype-stringify'
13 | import {config, redirect} from '../docs/_config.js'
14 |
15 | const own = {}.hasOwnProperty
16 |
17 | main().catch((error) => {
18 | throw error
19 | })
20 |
21 | async function main() {
22 | await fs.mkdir(config.output, {recursive: true})
23 |
24 | const from = new URL('_static/', config.input)
25 | const files = await globby('**/*', {cwd: fileURLToPath(from)})
26 |
27 | await pAll(
28 | files.map(
29 | (d) => async () =>
30 | fs.copyFile(new URL(d, from), new URL(d, config.output))
31 | ),
32 | {concurrency: 6}
33 | )
34 |
35 | console.log('✔ `/_static/*`')
36 |
37 | await fs.writeFile(
38 | new URL('robots.txt', config.output),
39 | [
40 | 'User-agent: *',
41 | 'Allow: /',
42 | 'Sitemap: ' + new URL('sitemap.xml', config.site),
43 | ''
44 | ].join('\n')
45 | )
46 |
47 | console.log('✔ `/robots.txt`')
48 |
49 | await pAll(
50 | Object.keys(redirect).map((from) => async () => {
51 | const to = redirect[from]
52 | const canonical = new URL(from + '/../', config.site).href
53 | const processor = unified()
54 | .use(rehypePresetMinify)
55 | .use(rehypeMinifyUrl, {from: canonical})
56 | .use(rehypeStringify)
57 | const file = new VFile({path: new URL('.' + from, config.output)})
58 | const tree = await processor.run(buildRedirect(to), file)
59 | file.value = processor.stringify(tree)
60 | await fs.mkdir(file.dirname, {recursive: true})
61 | await fs.writeFile(file.path, String(file))
62 | }),
63 | {concurrency: 6}
64 | )
65 |
66 | console.log('✔ %d redirects', Object.keys(redirect).length)
67 |
68 | const vercelRedirects = []
69 | let redirectFrom
70 |
71 | for (redirectFrom in redirect) {
72 | if (own.call(redirect, redirectFrom)) {
73 | const source = redirectFrom.replace(/\/index.html$/, '/')
74 | const destination = redirect[redirectFrom]
75 | vercelRedirects.push({source, destination})
76 | }
77 | }
78 |
79 | const vercelInfo = JSON.parse(await fs.readFile('vercel.json'))
80 | await fs.writeFile(
81 | 'vercel.json',
82 | JSON.stringify({...vercelInfo, redirects: vercelRedirects}, null, 2) + '\n'
83 | )
84 |
85 | console.log('✔ `vercel.json` redirects')
86 | }
87 |
88 | function buildRedirect(to) {
89 | const abs = new URL(to, config.site)
90 | return u('root', [
91 | u('doctype'),
92 | h('html', {lang: 'en'}, [
93 | h('head', [
94 | h('meta', {charSet: 'utf8'}),
95 | h('title', 'Redirecting…'),
96 | h('link', {rel: 'canonical', href: abs}),
97 | h('script', 'location = ' + JSON.stringify(abs)),
98 | h('meta', {httpEquiv: 'refresh', content: '0;url=' + abs}),
99 | h('meta', {name: 'robots', content: 'noindex'})
100 | ]),
101 | h('body', [
102 | h('h1', 'Redirecting…'),
103 | h('p', [h('a', {href: abs}, 'Click here if you are not redirected.')])
104 | ])
105 | ])
106 | ])
107 | }
108 |
--------------------------------------------------------------------------------
/packages/mdx/lib/util/estree-util-to-id-or-member-expression.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Identifier} Identifier
3 | * @typedef {import('estree-jsx').Literal} Literal
4 | * @typedef {import('estree-jsx').JSXIdentifier} JSXIdentifier
5 | * @typedef {import('estree-jsx').MemberExpression} MemberExpression
6 | * @typedef {import('estree-jsx').JSXMemberExpression} JSXMemberExpression
7 | */
8 |
9 | import {
10 | start as esStart,
11 | cont as esCont,
12 | name as isIdentifierName
13 | } from 'estree-util-is-identifier-name'
14 |
15 | export const toIdOrMemberExpression = toIdOrMemberExpressionFactory(
16 | 'Identifier',
17 | 'MemberExpression',
18 | isIdentifierName
19 | )
20 |
21 | export const toJsxIdOrMemberExpression =
22 | // @ts-expect-error: fine
23 | /** @type {(ids: Array) => JSXIdentifier|JSXMemberExpression)} */
24 | (
25 | toIdOrMemberExpressionFactory(
26 | 'JSXIdentifier',
27 | 'JSXMemberExpression',
28 | isJsxIdentifierName
29 | )
30 | )
31 |
32 | /**
33 | * @param {string} idType
34 | * @param {string} memberType
35 | * @param {(value: string) => boolean} isIdentifier
36 | */
37 | function toIdOrMemberExpressionFactory(idType, memberType, isIdentifier) {
38 | return toIdOrMemberExpression
39 | /**
40 | * @param {Array} ids
41 | * @returns {Identifier|MemberExpression}
42 | */
43 | function toIdOrMemberExpression(ids) {
44 | let index = -1
45 | /** @type {Identifier|Literal|MemberExpression|undefined} */
46 | let object
47 |
48 | while (++index < ids.length) {
49 | const name = ids[index]
50 | const valid = typeof name === 'string' && isIdentifier(name)
51 |
52 | // A value of `asd.123` could be turned into `asd['123']` in the JS form,
53 | // but JSX does not have a form for it, so throw.
54 | /* c8 ignore next 3 */
55 | if (idType === 'JSXIdentifier' && !valid) {
56 | throw new Error('Cannot turn `' + name + '` into a JSX identifier')
57 | }
58 |
59 | /** @type {Identifier|Literal} */
60 | // @ts-expect-error: JSX is fine.
61 | const id = valid ? {type: idType, name} : {type: 'Literal', value: name}
62 | // @ts-expect-error: JSX is fine.
63 | object = object
64 | ? {
65 | type: memberType,
66 | object,
67 | property: id,
68 | computed: id.type === 'Literal',
69 | optional: false
70 | }
71 | : id
72 | }
73 |
74 | // Just for types.
75 | /* c8 ignore next 3 */
76 | if (!object) throw new Error('Expected non-empty `ids` to be passed')
77 | if (object.type === 'Literal')
78 | throw new Error('Expected identifier as left-most value')
79 |
80 | return object
81 | }
82 | }
83 |
84 | /**
85 | * Checks if the given string is a valid JSX identifier name.
86 | * @param {string} name
87 | */
88 | function isJsxIdentifierName(name) {
89 | let index = -1
90 |
91 | while (++index < name.length) {
92 | // We currently receive valid input, but this catches bugs and is needed
93 | // when externalized.
94 | /* c8 ignore next */
95 | if (!(index ? jsxCont : esStart)(name.charCodeAt(index))) return false
96 | }
97 |
98 | // `false` if `name` is empty.
99 | return index > 0
100 | }
101 |
102 | /**
103 | * Checks if the given character code can continue a JSX identifier.
104 | * @param {number} code
105 | */
106 | function jsxCont(code) {
107 | return code === 45 /* `-` */ || esCont(code)
108 | }
109 |
--------------------------------------------------------------------------------
/docs/_config.js:
--------------------------------------------------------------------------------
1 | const site = new URL('https://mdxjs.com')
2 | const git = new URL('../', import.meta.url)
3 | const gh = new URL('https://github.com/mdx-js/mdx/')
4 |
5 | export const config = {
6 | input: new URL('docs/', git),
7 | output: new URL('public/', git),
8 | git,
9 | gh,
10 | ghBlob: new URL('blob/main/', gh),
11 | ghTree: new URL('tree/main/', gh),
12 | site,
13 | twitter: new URL('https://twitter.com/mdx_js'),
14 | oc: new URL('https://opencollective.com/unified'),
15 | color: '#010409',
16 | title: 'MDX',
17 | tags: ['mdx', 'markdown', 'jsx', 'oss', 'react'],
18 | author: 'MDX contributors'
19 | }
20 |
21 | export const redirect = {
22 | '/about/index.html': '/community/about/',
23 | '/advanced/index.html': '/guides/',
24 | '/advanced/api/index.html': '/packages/mdx/#api',
25 | '/advanced/ast/index.html': '/packages/remark-mdx/#syntax-tree',
26 | '/advanced/components/index.html': '/docs/using-mdx/',
27 | '/advanced/contributing/index.html': '/community/contribute/',
28 | '/advanced/custom-loader/index.html': '/guides/frontmatter/',
29 | '/advanced/retext-plugins/index.html': '/docs/extending-mdx/#using-plugins',
30 | '/advanced/plugins/index.html': '/docs/extending-mdx/',
31 | '/advanced/runtime/index.html': '/packages/mdx/#evaluatefile-options',
32 | '/advanced/specification/index.html': '/packages/remark-mdx/#syntax-tree',
33 | '/advanced/sync-api/index.html': '/packages/mdx/#api',
34 | '/advanced/transform-content/index.html': '/packages/remark-mdx/',
35 | '/advanced/typescript/index.html': '/docs/getting-started/#types',
36 | '/advanced/writing-a-plugin/index.html': '/guides/frontmatter/',
37 | '/contributing/index.html': '/community/contribute/',
38 | '/editor-plugins/index.html': '/docs/getting-started/#editor',
39 | '/editors/index.html': '/docs/getting-started/#editor',
40 | '/getting-started/create-react-app/index.html':
41 | '/docs/getting-started/#create-react-app-cra',
42 | '/getting-started/gatsby/index.html': '/docs/getting-started/#gatsby',
43 | '/getting-started/next/index.html': '/docs/getting-started/#nextjs',
44 | '/getting-started/parcel/index.html': '/docs/getting-started/#parcel',
45 | '/getting-started/react-static/index.html':
46 | '/docs/getting-started/#react-static',
47 | '/getting-started/table-of-components/index.html': '/table-of-components/',
48 | '/getting-started/typescript/index.html': '/docs/getting-started/#types',
49 | '/getting-started/webpack/index.html': '/docs/getting-started/#webpack',
50 | '/getting-started/index.html': '/docs/getting-started/',
51 | '/guides/custom-loader/index.html': '/guides/frontmatter/',
52 | '/guides/live-code/index.html':
53 | '/guides/syntax-highlighting/#syntax-highlighting-with-the-meta-field',
54 | '/guides/markdown-in-components/index.html': '/docs/what-is-mdx/',
55 | '/guides/math-blocks/index.html': '/guides/math/',
56 | '/guides/mdx-embed/index.html': '/guides/embed/#embeds-at-run-time',
57 | '/guides/table-of-contents/index.html': '/docs/extending-mdx/',
58 | '/guides/terminal/index.html': '/docs/getting-started/#ink',
59 | '/guides/vue/index.html': '/docs/getting-started/#vue',
60 | '/guides/wrapper-customization/index.html': '/docs/using-mdx/#layout',
61 | '/guides/writing-a-plugin/index.html':
62 | '/docs/extending-mdx/#creating-plugins',
63 | '/mdx/index.html': '/docs/what-is-mdx/',
64 | '/plugins/index.html': '/docs/extending-mdx/#using-plugins',
65 | '/projects/index.html': '/community/projects/',
66 | '/support/index.html': '/community/support/',
67 | '/syntax/index.html': '/docs/getting-started/#syntax',
68 | '/vue/index.html': '/docs/getting-started/#vue'
69 | }
70 |
--------------------------------------------------------------------------------
/docs/guides/gfm.server.mdx:
--------------------------------------------------------------------------------
1 | export const navSortSelf = 1
2 | export const info = {
3 | author: [
4 | {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'}
5 | ],
6 | published: new Date('2021-10-06'),
7 | modified: new Date('2022-06-17')
8 | }
9 |
10 | # GitHub flavored markdown (GFM)
11 |
12 | This guide explores how to support GFM features such as autolink literals,
13 | footnotes, strikethrough, tables, and task lists. {/* more */}
14 | MDX supports standard markdown syntax ([CommonMark][]).
15 | That means [GitHub flavored markdown (GFM)][gfm] extensions are not supported by
16 | default.
17 | They can be enabled by using a remark plugin: [`remark-gfm`][remark-gfm].
18 | Such plugins can be passed in [`options.remarkPlugins`][options-remark-plugins].
19 | More info on plugins is available in [§ Extending MDX][extend]
20 |
21 | Say we have an MDX file like this:
22 |
23 | ```mdx path="example.mdx"
24 | # GFM
25 |
26 | ## Autolink literals
27 |
28 | www.example.com, https://example.com, and contact@example.com.
29 |
30 | ## Footnote
31 |
32 | A note[^1]
33 |
34 | [^1]: Big note.
35 |
36 | ## Strikethrough
37 |
38 | ~one~ or ~~two~~ tildes.
39 |
40 | ## Table
41 |
42 | | a | b | c | d |
43 | | - | :- | -: | :-: |
44 |
45 | ## Tasklist
46 |
47 | * [ ] to do
48 | * [x] done
49 | ```
50 |
51 | The above MDX with GFM can be transformed with the following module:
52 |
53 | ```js path="example.js"
54 | import {promises as fs} from 'node:fs'
55 | import {compile} from '@mdx-js/mdx'
56 | import remarkGfm from 'remark-gfm'
57 |
58 | console.log(
59 | String(
60 | await compile(await fs.readFile('example.mdx'), {remarkPlugins: [remarkGfm]})
61 | )
62 | )
63 | ```
64 |
65 |
66 | Expand equivalent JSX
67 |
68 | ```jsx path="output.jsx"
69 | <>
70 |
112 |
113 |
114 | >
115 | ```
116 |
117 |
118 | [commonmark]: https://spec.commonmark.org/current/
119 |
120 | [gfm]: https://github.github.com/gfm/
121 |
122 | [remark-gfm]: https://github.com/remarkjs/remark-gfm
123 |
124 | [options-remark-plugins]: /packages/mdx/#optionsremarkplugins
125 |
126 | [extend]: /docs/extending-mdx/
127 |
--------------------------------------------------------------------------------
/docs/guides/embed.server.mdx:
--------------------------------------------------------------------------------
1 | export const navSortSelf = 5
2 | export const info = {
3 | author: [
4 | {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'}
5 | ],
6 | published: new Date('2021-10-06'),
7 | modified: new Date('2022-06-17')
8 | }
9 |
10 | # Embed
11 |
12 | This guide explores how to embed things like tweets, gists or codepens in
13 | markdown. {/* more */}
14 | MDX supports standard markdown syntax ([CommonMark][]).
15 | It does not support embeds by default.
16 |
17 | There are two ways to accomplish embeds: at compile time or at runtime.
18 | Doing it at compile time means the effort is spent upfront so that readers will
19 | have a fast experience as no requests have to be made on the client.
20 | Doing it at runtime gives more flexibility by moving the work to the client.
21 | This can result in a slow experience for readers though.
22 | It also depends on what framework you use (as in it’s specific to React, Preact,
23 | Vue, etc.)
24 |
25 | ## Embeds at compile time
26 |
27 | You can use [`@remark-embedder/core`][remark-embedder] by doing something like
28 | this:
29 |
30 | ```js path="example.js"
31 | import {compile} from '@mdx-js/mdx'
32 | // Node currently can’t pick up on the default exports by `@remark-embedder`.
33 | import fauxRemarkEmbedder from '@remark-embedder/core'
34 | import fauxOembedTransformer from '@remark-embedder/transformer-oembed'
35 | const remarkEmbedder = fauxRemarkEmbedder.default
36 | const oembedTransformer = fauxOembedTransformer.default
37 |
38 | const code = `
39 | Check out this video:
40 |
41 | https://www.youtube.com/watch?v=dQw4w9WgXcQ
42 | `
43 |
44 | console.log(
45 | String(
46 | await compile(code, {
47 | remarkPlugins: [[remarkEmbedder, {transformers: [oembedTransformer]}]]
48 | })
49 | )
50 | )
51 | ```
52 |
53 |
54 | Expand equivalent JSX
55 |
56 | ```jsx path="output.jsx"
57 | <>
58 |
Check out this video:
59 |
60 | >
61 | ```
62 |
63 |
64 | ## Embeds at run time
65 |
66 | You can use the React-specific [MDX Embed][mdx-embed] to embed things in MDX.
67 | Here is an example MDX file that uses a specific embed without `@mdx-js/react`:
68 |
69 | ```mdx path="example.mdx"
70 | import {CodePen} from 'mdx-embed'
71 |
72 | Here’s a codepen, and some other blog post text.
73 |
74 |
75 | ```
76 |
77 |
78 | Expand equivalent JSX
79 |
80 | ```js path="output.jsx"
81 | <>
82 |
Here’s a codepen, and some other blog post text.
83 |
84 | >
85 | ```
86 |
87 |
88 | If you don’t want to use explicit imports in MDX files:
89 |
90 | ```mdx path="example.mdx"
91 | Here’s a codepen, and some other blog post text.
92 |
93 |
94 | ```
95 |
96 | Then you can either pass all components:
97 |
98 | ```jsx path="example.jsx"
99 | import * as embeds from 'mdx-embed'
100 | import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.
101 |
102 |
103 | ```
104 |
105 | Or, if you’ve installed and configured [`@mdx-js/react`][mdx-react], you can
106 | also use `MDXEmbedProvider`:
107 |
108 | ```jsx path="example.jsx"
109 | import {MDXEmbedProvider} from 'mdx-embed'
110 | import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.
111 |
112 |
113 |
114 |
115 | ```
116 |
117 | [commonmark]: https://spec.commonmark.org/current/
118 |
119 | [remark-embedder]: https://github.com/remark-embedder/core
120 |
121 | [mdx-embed]: https://www.mdx-embed.com/
122 |
123 | [mdx-react]: /packages/react/
124 |
--------------------------------------------------------------------------------
/docs/blog/conf.server.mdx:
--------------------------------------------------------------------------------
1 | import {Note} from '../_component/note.server.js'
2 | export const info = {
3 | author: [
4 | {name: 'John Otander', github: 'johno', twitter: '4lpine'}
5 | ],
6 | published: new Date('2020-07-31'),
7 | modified: new Date('2021-11-01')
8 | }
9 |
10 |
11 | **Note**: This is an old blog post.
12 | The below is kept as is for historical purposes.
13 |
14 |
15 | # MDXConf
16 |
17 | MDXConf is a free and online conference for the MDX community.
18 | Whether you’re just learning about MDX or an expert, there’ll be something for
19 | you! {/* more */}
20 |
21 | August 24th, 2020 at 8am PDT/3pm UST Online • Free
22 |
23 | ## Watch
24 |
25 | The conference is now over, but you can still watch the recordings!
26 |
27 | [Watch the talks →](https://egghead.io/playlists/mdx-conf-3fc2)
28 |
29 | ## About
30 |
31 | Join us for the first MDX conference!
32 | We’ll stream it directly to you, for free.
33 |
34 | MDX has grown rapidly since the [first commit][] two and a half years ago.
35 | We’d like to celebrate our accomplishments so far, and talk about what lies
36 | ahead.
37 | We’ve got lots of plans.
38 |
39 | Learn how MDX increases developer productivity, improves educational
40 | content authoring, and even peek behind the curtains to see how MDX works.
41 |
42 | ## Speakers
43 |
44 | ### [Chris Biscardi](https://twitter.com/chrisbiscardi)
45 |
46 | [](https://twitter.com/chrisbiscardi)
47 |
48 | Keynote: The past, present, and future of MDX
49 |
50 | ### [Monica Powell](https://twitter.com/waterproofheart)
51 |
52 | [](https://twitter.com/waterproofheart)
53 |
54 | Migrating to MDX
55 |
56 | ### [Laurie Barth](https://twitter.com/laurieontech)
57 |
58 | [](https://twitter.com/laurieontech)
59 |
60 | MDX v2 syntax
61 |
62 | ### [Cole Bemis](https://twitter.com/colebemis)
63 |
64 | [](https://twitter.com/colebemis)
65 |
66 | Demystifying MDX
67 |
68 | ### [Prince Wilson](https://twitter.com/maxcell)
69 |
70 | [](https://twitter.com/maxcell)
71 |
72 | Personal site playgrounds
73 |
74 | ### [Kathleen McMahon](https://twitter.com/resource11)
75 |
76 | [](https://twitter.com/resource11)
77 |
78 | Digital gardening with MDX magic
79 |
80 | ### [Rodrigo Pombo](https://twitter.com/pomber)
81 |
82 | [](https://twitter.com/pomber)
83 |
84 | The X in MDX
85 |
86 | ### [Jonathan Bakebwa](https://twitter.com/codebender828)
87 |
88 | [](https://twitter.com/codebender828)
89 |
90 | MDX and Vue/Nuxt
91 |
92 | ## Sign up
93 |
94 |
95 | **Note**: Sign up is closed.
96 |
97 |
98 | ## FAQ
99 |
100 | ### What if I can’t make it on August 24th?
101 |
102 | We’ll miss you, but you won’t miss out!
103 | All talks will be recorded and released the day of the conference.
104 | You can catch up with the talks, or rewatch them, whenever convenient.
105 |
106 | ### Will the talks be transcribed?
107 |
108 | Yes.
109 |
110 | ### Is there a code of conduct?
111 |
112 | Absolutely.
113 | We’re dedicated to providing a harassment-free experience for everyone.
114 | We will not tolerate harassment of participants in any form.
115 | We’ve adopted the [Party Corgi Network’s Code of Conduct][coc].
116 | We will have moderators to ensure that the code of conduct is followed.
117 |
118 | ### Do you have a different question?
119 |
120 | Reach out to us on [Twitter][].
121 |
122 | [first commit]: https://github.com/mdx-js/mdx/commit/dee47dc20b08d534132e3b966cdccf3b88c7bca5
123 |
124 | [twitter]: https://twitter.com/mdx_js
125 |
126 | [coc]: https://github.com/partycorgi/partycorgi/blob/corgi/CODE_OF_CONDUCT.md
127 |
--------------------------------------------------------------------------------
/packages/vue/test/test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('mdx/types').MDXComponents} Components
3 | * @typedef {import('mdx/types').MDXContent} MDXContent
4 | * @typedef {import('mdx/types').MDXModule} MDXModule
5 | * @typedef {import('vue').Component} AnyComponent
6 | */
7 |
8 | import {test} from 'uvu'
9 | import * as assert from 'uvu/assert'
10 | import * as babel from '@babel/core'
11 | import {compile} from '@mdx-js/mdx'
12 | import {run} from '@mdx-js/mdx/lib/run.js'
13 | import * as vue from 'vue'
14 | import serverRenderer from '@vue/server-renderer'
15 | import {useMDXComponents, MDXProvider} from '../index.js'
16 |
17 | /**
18 | * @param {string} value
19 | * @returns {Promise}
20 | */
21 | async function evaluate(value) {
22 | const file = await compile(value, {
23 | providerImportSource: '#',
24 | jsx: true,
25 | outputFormat: 'function-body'
26 | })
27 | const result = await babel.transformAsync(String(file), {
28 | parserOpts: {allowReturnOutsideFunction: true},
29 | plugins: ['@vue/babel-plugin-jsx']
30 | })
31 | if (!result || !result.code) throw new Error('Whoops!')
32 | const body = result.code.replace(
33 | /import {(.+)} from "vue"/,
34 | (_, /** @type {string} */ $1) =>
35 | 'const {' + $1.replace(/ as /g, ': ') + '} = arguments[0].vue'
36 | )
37 | return run(body, {vue, useMDXComponents})
38 | }
39 |
40 | /**
41 | * @param {AnyComponent} root
42 | * @param {Record} [rootProps]
43 | * @returns {Promise}
44 | */
45 | async function vueToString(root, rootProps) {
46 | const result = await serverRenderer.renderToString(
47 | vue.createSSRApp(root, rootProps)
48 | )
49 | // Remove SSR comments used to hydrate.
50 | return result.replace(//g, '')
51 | }
52 |
53 | test('should evaluate MDX code', async () => {
54 | const {default: Content} = await evaluate('# hi')
55 |
56 | assert.equal(await vueToString(Content), '
49 | ## New: MDX 2!
50 |
51 | Version 2 of MDX was released after years of hard work, and has many
52 | improvements.
53 | Here are the highlights:
54 |
55 |
56 | * 📝 **Improved syntax** makes it easier to use markdown in JSX
57 | * 🧑💻 **JavaScript expressions** turn `{2 * Math.PI}` into {2 * Math.PI}
58 | * 🔌 New **esbuild**, **Rollup**, and **Node.js** integrations
59 | * ⚛️ **Any JSX runtime**: React, Preact, Vue, Emotion, you name it, they’re
60 | all supported
61 | * 🌳 **Improved AST** exposes more info in greater detail
62 | * 🏃♀️ Compiles at least **25% faster**
63 | * 🚴 Generated code runs twice as fast (**100% faster**)
64 | * 🚄 Bundle size of `@mdx-js/mdx` is more than three times as small
65 | (**250% smaller**)
66 | * 🧵 …and much, so much more
67 |
68 |
69 | [Continue reading »][v2]
70 |
71 |
72 | ## What does MDX do?
73 |
74 |
75 |
76 | You write markdown with embedded components through JSX:
77 |
78 | ```mdx path="example.mdx"
79 | import {Chart} from './snowfall.js'
80 | export const year = 2018
81 |
82 | # Last year’s snowfall
83 |
84 | In {year}, the snowfall was above average.
85 | It was followed by a warm spring which caused
86 | flood conditions in many of the nearby rivers.
87 |
88 |
89 | ```
90 |
91 |
92 |
93 | It gets compiled to JavaScript that you can use in any framework that
94 | supports JSX:
95 |
96 | {/* lint disable */}
97 |
98 |
99 | # Last year’s snowfall
100 |
101 | In {year}, the snowfall was above average.
102 | It was followed by a warm spring which caused flood conditions in many of
103 | the nearby rivers.
104 |
105 |
106 |
107 |
108 | {/* lint enable */}
109 |
110 |
111 |
112 | We made an interactive playground where you can try MDX out and see what it
113 | turns into.
114 | [Play »][playground]
115 |
116 | ## Get started
117 |
118 | There are integrations for most bundlers, frameworks, and editors.
119 | Whether you build with Next.js, Docusaurus, or Gatsby.
120 | You prefer esbuild, Rollup, or webpack.
121 | You’re using React, Preact, or Vue.
122 | [Get started »][getting-started]
123 |
124 | ## MDX in short
125 |
126 |
127 | * ❤️ **Powerful**: MDX blends markdown and JSX syntax to fit perfectly in
128 | JSX-based projects
129 | * 💻 **Everything is a component**: Use existing components in your
130 | MDX and import other MDX files as components
131 | * 🔧 **Customizable**: Decide which component is rendered for each markdown
132 | construct (`{h1: MyHeading}`)
133 | * 📚 **Markdown-based**: The simplicity and elegance of markdown remains,
134 | you use JSX only when you want to
135 | * 🔥 **Blazingly blazing fast**: MDX has no runtime, all compilation occurs
136 | during the build stage
137 |
138 |
139 | {/* To do: quotes. */}
140 |
141 | > It’s extremely useful for using design system components to render markdown
142 | > and weaving interactive components in with existing markdown.
143 | >
144 | > — [**@chrisbiscardi**][quote]
145 |
146 | [quote]: https://twitter.com/chrisbiscardi/status/1022304288326864896
147 |
148 | [what]: /docs/what-is-mdx/
149 |
150 | [v2]: /blog/v2/
151 |
152 | [playground]: /playground/
153 |
154 | [getting-started]: /docs/getting-started/
155 |
--------------------------------------------------------------------------------