1
1
mirror of https://github.com/mdx-js/mdx.git synced 2024-08-16 18:30:27 +03:00

Refactor some more

This commit is contained in:
Titus Wormer 2023-10-18 16:32:48 +02:00
parent a362bb43ee
commit 780fa02778
No known key found for this signature in database
GPG Key ID: E6E581152ED04E2E
12 changed files with 468 additions and 411 deletions

View File

@ -322,7 +322,7 @@ function Playground() {
return (
<>
<form className="playground-editor">
<form>
<div className="playground-area">
<div className="playground-inner">
<div className="playground-draw">

View File

@ -1205,15 +1205,6 @@ button.success {
}
}
/* To do: clean from here */
.playground {
display: grid;
grid-template-columns: 49% 49%;
min-height: 40rem;
gap: calc(1em + 1ex);
margin-inline: calc(1em + 1ex);
}
.playground-area,
.playground-controls,
.playground-result {

23
package-lock.json generated
View File

@ -27,6 +27,8 @@
"@types/mdx": "^2.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/ungap__structured-clone": "^0.3.0",
"@ungap/structured-clone": "^1.0.0",
"@vue/babel-plugin-jsx": "^1.0.0",
"@vue/server-renderer": "^3.0.0",
"@wooorm/starry-night": "^3.0.0",
@ -47,7 +49,10 @@
"eslint-plugin-react-hooks": "^4.0.0",
"estree-util-value-to-estree": "^3.0.0",
"globby": "^13.0.0",
"hast-util-from-html": "^2.0.0",
"hast-util-sanitize": "^5.0.0",
"hast-util-select": "^6.0.0",
"hast-util-to-html": "^9.0.0",
"hast-util-to-jsx-runtime": "^2.0.0",
"hast-util-to-text": "^4.0.0",
"hastscript": "^8.0.0",
@ -74,7 +79,6 @@
"rehype-preset-minify": "^7.0.0",
"rehype-raw": "^7.0.0",
"rehype-remove-comments": "^6.0.0",
"rehype-sanitize": "^6.0.0",
"rehype-shift-heading": "^2.0.0",
"rehype-slug": "^6.0.0",
"rehype-stringify": "^10.0.0",
@ -95,8 +99,7 @@
"rollup": "^4.0.0",
"type-coverage": "^2.0.0",
"typescript": "^5.0.0",
"unified": "^11.0.3",
"unist-builder": "^4.0.0",
"unified": "^11.0.0",
"unist-util-remove-position": "^5.0.0",
"unist-util-visit": "^5.0.0",
"vfile": "^6.0.0",
@ -13532,20 +13535,6 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/rehype-sanitize": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/rehype-sanitize/-/rehype-sanitize-6.0.0.tgz",
"integrity": "sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==",
"dev": true,
"dependencies": {
"@types/hast": "^3.0.0",
"hast-util-sanitize": "^5.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/rehype-shift-heading": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/rehype-shift-heading/-/rehype-shift-heading-2.0.0.tgz",

View File

@ -31,6 +31,8 @@
"@types/mdx": "^2.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/ungap__structured-clone": "^0.3.0",
"@ungap/structured-clone": "^1.0.0",
"@vue/babel-plugin-jsx": "^1.0.0",
"@vue/server-renderer": "^3.0.0",
"@wooorm/starry-night": "^3.0.0",
@ -51,7 +53,10 @@
"eslint-plugin-react-hooks": "^4.0.0",
"estree-util-value-to-estree": "^3.0.0",
"globby": "^13.0.0",
"hast-util-from-html": "^2.0.0",
"hast-util-sanitize": "^5.0.0",
"hast-util-select": "^6.0.0",
"hast-util-to-html": "^9.0.0",
"hast-util-to-jsx-runtime": "^2.0.0",
"hast-util-to-text": "^4.0.0",
"hastscript": "^8.0.0",
@ -78,7 +83,6 @@
"rehype-preset-minify": "^7.0.0",
"rehype-raw": "^7.0.0",
"rehype-remove-comments": "^6.0.0",
"rehype-sanitize": "^6.0.0",
"rehype-shift-heading": "^2.0.0",
"rehype-slug": "^6.0.0",
"rehype-stringify": "^10.0.0",
@ -99,8 +103,7 @@
"rollup": "^4.0.0",
"type-coverage": "^2.0.0",
"typescript": "^5.0.0",
"unified": "^11.0.3",
"unist-builder": "^4.0.0",
"unified": "^11.0.0",
"unist-util-remove-position": "^5.0.0",
"unist-util-visit": "^5.0.0",
"vfile": "^6.0.0",

View File

@ -1,5 +1,6 @@
/**
* @typedef {import('node:module').Module} Module
* @typedef {import('mdx/types.js').MDXModule} MDXModule
*/
/**
@ -67,8 +68,7 @@ function register(options) {
*/
function mdx(module, path) {
const file = processSync(fs.readFileSync(path))
// To do: type `run`.
/** @type {{default: unknown}} */
/** @type {MDXModule} */
const result = runSync(file, runtime)
// Something going weird here w/ `type-coverage`.
// type-coverage:ignore-next-line

View File

@ -11,7 +11,6 @@ import remarkMdx from 'remark-mdx'
import remarkParse from 'remark-parse'
import remarkStringify from 'remark-stringify'
import {unified} from 'unified'
import {u} from 'unist-builder'
import {removePosition} from 'unist-util-remove-position'
import {visit} from 'unist-util-visit'
@ -31,16 +30,24 @@ test('remark-mdx: parse', async function (t) {
clean(tree)
assert.deepEqual(
tree,
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxJsxTextElement', {name: 'b', attributes: []}, []),
u('text', ' charlie.')
])
])
)
assert.deepEqual(tree, {
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: 'b',
attributes: [],
children: []
},
{type: 'text', value: ' charlie.'}
]
}
]
})
})
await t.test('should parse an opening and a closing tag', function () {
@ -48,16 +55,24 @@ test('remark-mdx: parse', async function (t) {
clean(tree)
assert.deepEqual(
tree,
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxJsxTextElement', {name: 'b', attributes: []}, []),
u('text', ' charlie.')
])
])
)
assert.deepEqual(tree, {
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: 'b',
attributes: [],
children: []
},
{type: 'text', value: ' charlie.'}
]
}
]
})
})
await t.test('should parse fragments', function () {
@ -65,16 +80,24 @@ test('remark-mdx: parse', async function (t) {
clean(tree)
assert.deepEqual(
tree,
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxJsxTextElement', {name: null, attributes: []}, []),
u('text', ' charlie.')
])
])
)
assert.deepEqual(tree, {
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: null,
attributes: [],
children: []
},
{type: 'text', value: ' charlie.'}
]
}
]
})
})
await t.test('should parse markdown inside tags', function () {
@ -82,18 +105,26 @@ test('remark-mdx: parse', async function (t) {
clean(tree)
assert.deepEqual(
tree,
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxJsxTextElement', {name: 'b', attributes: []}, [
u('emphasis', [u('text', 'bravo')])
]),
u('text', ' charlie.')
])
])
)
assert.deepEqual(tree, {
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: 'b',
attributes: [],
children: [
{type: 'emphasis', children: [{type: 'text', value: 'bravo'}]}
]
},
{type: 'text', value: ' charlie.'}
]
}
]
})
})
await t.test('should parse expressions', function () {
@ -101,16 +132,23 @@ test('remark-mdx: parse', async function (t) {
clean(tree)
assert.deepEqual(
tree,
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxTextExpression', {data: {estree: undefined}}, '1 + 1'),
u('text', ' charlie.')
])
])
)
assert.deepEqual(tree, {
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxTextExpression',
data: {estree: undefined},
value: '1 + 1'
},
{type: 'text', value: ' charlie.'}
]
}
]
})
})
})
@ -119,93 +157,124 @@ test('remark-mdx: stringify', async function (t) {
await t.test('should serialize an empty nameless fragment', function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxJsxTextElement', {name: null, attributes: []}, []),
u('text', ' charlie.')
])
])
),
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: null,
attributes: [],
children: []
},
{type: 'text', value: ' charlie.'}
]
}
]
}),
'Alpha <></> charlie.\n'
)
})
await t.test('should serialize a tag with a name', function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxJsxTextElement', {name: 'b', attributes: []}, []),
u('text', ' charlie.')
])
])
),
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: 'b',
attributes: [],
children: []
},
{type: 'text', value: ' charlie.'}
]
}
]
}),
'Alpha <b /> charlie.\n'
)
})
await t.test('should serialize a boolean attribute (element)', function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u(
'mdxJsxTextElement',
{name: 'b', attributes: [u('mdxJsxAttribute', {name: 'bravo'})]},
[]
),
u('text', ' charlie.')
])
])
),
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: 'b',
attributes: [{type: 'mdxJsxAttribute', name: 'bravo'}],
children: []
},
{type: 'text', value: ' charlie.'}
]
}
]
}),
'Alpha <b bravo /> charlie.\n'
)
})
await t.test('should serialize an attribute (element)', function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u(
'mdxJsxTextElement',
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: 'b',
attributes: [u('mdxJsxAttribute', {name: 'bravo'}, 'bravo')]
attributes: [
{type: 'mdxJsxAttribute', name: 'bravo', value: 'bravo'}
],
children: []
},
[]
),
u('text', ' charlie.')
])
])
),
{type: 'text', value: ' charlie.'}
]
}
]
}),
'Alpha <b bravo="bravo" /> charlie.\n'
)
})
await t.test('should serialize a prefixed attribute (element)', function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u(
'mdxJsxTextElement',
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: 'b',
attributes: [u('mdxJsxAttribute', {name: 'br:avo'}, 'bravo')]
attributes: [
{type: 'mdxJsxAttribute', name: 'br:avo', value: 'bravo'}
],
children: []
},
[]
),
u('text', ' charlie.')
])
])
),
{type: 'text', value: ' charlie.'}
]
}
]
}),
'Alpha <b br:avo="bravo" /> charlie.\n'
)
})
@ -214,22 +283,27 @@ test('remark-mdx: stringify', async function (t) {
'should serialize a attribute expression (element)',
function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u(
'mdxJsxTextElement',
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: 'b',
attributes: [u('mdxJsxExpressionAttribute', '...props')]
attributes: [
{type: 'mdxJsxExpressionAttribute', value: '...props'}
],
children: []
},
[]
),
u('text', ' charlie.')
])
])
),
{type: 'text', value: ' charlie.'}
]
}
]
}),
'Alpha <b {...props} /> charlie.\n'
)
}
@ -239,31 +313,35 @@ test('remark-mdx: stringify', async function (t) {
'should serialize an expression attribute (element)',
function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u(
'mdxJsxTextElement',
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: 'b',
attributes: [
u('mdxJsxAttribute', {
{
type: 'mdxJsxAttribute',
name: 'b',
value: u(
'mdxJsxAttributeValueExpression',
{data: {estree: undefined}},
'1 + 1'
)
})
]
value: {
type: 'mdxJsxAttributeValueExpression',
data: {estree: undefined},
value: '1 + 1'
}
}
],
children: []
},
[]
),
u('text', ' charlie.')
])
])
),
{type: 'text', value: ' charlie.'}
]
}
]
}),
'Alpha <b b={1 + 1} /> charlie.\n'
)
}
@ -271,79 +349,107 @@ test('remark-mdx: stringify', async function (t) {
await t.test('should write out a url as the raw value', function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('link', {url: 'https://mdxjs.com'}, [
u('text', 'https://mdxjs.com')
])
])
])
),
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{
type: 'link',
url: 'https://mdxjs.com',
children: [{type: 'text', value: 'https://mdxjs.com'}]
}
]
}
]
}),
'[https://mdxjs.com](https://mdxjs.com)\n'
)
})
await t.test('should encode `<` in text', function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxJsxTextElement', {name: null, attributes: []}, [
u('text', '1 < 3')
]),
u('text', ' bravo.')
])
])
),
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: null,
attributes: [],
children: [{type: 'text', value: '1 < 3'}]
},
{type: 'text', value: ' bravo.'}
]
}
]
}),
'Alpha <>1 \\< 3</> bravo.\n'
)
})
await t.test('should encode `{` in text', function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxJsxTextElement', {name: null, attributes: []}, [
u('text', '1 { 3')
]),
u('text', ' bravo.')
])
])
),
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{
type: 'mdxJsxTextElement',
name: null,
attributes: [],
children: [{type: 'text', value: '1 { 3'}]
},
{type: 'text', value: ' bravo.'}
]
}
]
}),
'Alpha <>1 \\{ 3</> bravo.\n'
)
})
await t.test('should serialize empty expressions', function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxTextExpression', ''),
u('text', ' bravo.')
])
])
),
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{type: 'mdxTextExpression', value: ''},
{type: 'text', value: ' bravo.'}
]
}
]
}),
'Alpha {} bravo.\n'
)
})
await t.test('should serialize expressions', function () {
assert.equal(
basic.stringify(
u('root', [
u('paragraph', [
u('text', 'Alpha '),
u('mdxTextExpression', '1 + 1'),
u('text', ' bravo.')
])
])
),
basic.stringify({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{type: 'text', value: 'Alpha '},
{type: 'mdxTextExpression', value: '1 + 1'},
{type: 'text', value: ' bravo.'}
]
}
]
}),
'Alpha {1 + 1} bravo.\n'
)
})

View File

@ -3,176 +3,176 @@
"trailingSlash": true,
"redirects": [
{
"source": "/about/",
"destination": "/community/about/"
"destination": "/community/about/",
"source": "/about/"
},
{
"source": "/advanced/",
"destination": "/guides/"
"destination": "/guides/",
"source": "/advanced/"
},
{
"source": "/advanced/api/",
"destination": "/packages/mdx/#api"
"destination": "/packages/mdx/#api",
"source": "/advanced/api/"
},
{
"source": "/advanced/ast/",
"destination": "/packages/remark-mdx/#syntax-tree"
"destination": "/packages/remark-mdx/#syntax-tree",
"source": "/advanced/ast/"
},
{
"source": "/advanced/components/",
"destination": "/docs/using-mdx/"
"destination": "/docs/using-mdx/",
"source": "/advanced/components/"
},
{
"source": "/advanced/contributing/",
"destination": "/community/contribute/"
"destination": "/community/contribute/",
"source": "/advanced/contributing/"
},
{
"source": "/advanced/custom-loader/",
"destination": "/guides/frontmatter/"
"destination": "/guides/frontmatter/",
"source": "/advanced/custom-loader/"
},
{
"source": "/advanced/retext-plugins/",
"destination": "/docs/extending-mdx/#using-plugins"
"destination": "/docs/extending-mdx/#using-plugins",
"source": "/advanced/retext-plugins/"
},
{
"source": "/advanced/plugins/",
"destination": "/docs/extending-mdx/"
"destination": "/docs/extending-mdx/",
"source": "/advanced/plugins/"
},
{
"source": "/advanced/runtime/",
"destination": "/packages/mdx/#evaluatefile-options"
"destination": "/packages/mdx/#evaluatefile-options",
"source": "/advanced/runtime/"
},
{
"source": "/advanced/specification/",
"destination": "/packages/remark-mdx/#syntax-tree"
"destination": "/packages/remark-mdx/#syntax-tree",
"source": "/advanced/specification/"
},
{
"source": "/advanced/sync-api/",
"destination": "/packages/mdx/#api"
"destination": "/packages/mdx/#api",
"source": "/advanced/sync-api/"
},
{
"source": "/advanced/transform-content/",
"destination": "/packages/remark-mdx/"
"destination": "/packages/remark-mdx/",
"source": "/advanced/transform-content/"
},
{
"source": "/advanced/typescript/",
"destination": "/docs/getting-started/#types"
"destination": "/docs/getting-started/#types",
"source": "/advanced/typescript/"
},
{
"source": "/advanced/writing-a-plugin/",
"destination": "/guides/frontmatter/"
"destination": "/guides/frontmatter/",
"source": "/advanced/writing-a-plugin/"
},
{
"source": "/contributing/",
"destination": "/community/contribute/"
"destination": "/community/contribute/",
"source": "/contributing/"
},
{
"source": "/editor-plugins/",
"destination": "/docs/getting-started/#editor"
"destination": "/docs/getting-started/#editor",
"source": "/editor-plugins/"
},
{
"source": "/editors/",
"destination": "/docs/getting-started/#editor"
"destination": "/docs/getting-started/#editor",
"source": "/editors/"
},
{
"source": "/getting-started/create-react-app/",
"destination": "/docs/getting-started/#create-react-app-cra"
"destination": "/docs/getting-started/#create-react-app-cra",
"source": "/getting-started/create-react-app/"
},
{
"source": "/getting-started/gatsby/",
"destination": "/docs/getting-started/#gatsby"
"destination": "/docs/getting-started/#gatsby",
"source": "/getting-started/gatsby/"
},
{
"source": "/getting-started/next/",
"destination": "/docs/getting-started/#nextjs"
"destination": "/docs/getting-started/#nextjs",
"source": "/getting-started/next/"
},
{
"source": "/getting-started/parcel/",
"destination": "/docs/getting-started/#parcel"
"destination": "/docs/getting-started/#parcel",
"source": "/getting-started/parcel/"
},
{
"source": "/getting-started/react-static/",
"destination": "/docs/getting-started/#react-static"
"destination": "/docs/getting-started/#react-static",
"source": "/getting-started/react-static/"
},
{
"source": "/getting-started/table-of-components/",
"destination": "/table-of-components/"
"destination": "/table-of-components/",
"source": "/getting-started/table-of-components/"
},
{
"source": "/getting-started/typescript/",
"destination": "/docs/getting-started/#types"
"destination": "/docs/getting-started/#types",
"source": "/getting-started/typescript/"
},
{
"source": "/getting-started/webpack/",
"destination": "/docs/getting-started/#webpack"
"destination": "/docs/getting-started/#webpack",
"source": "/getting-started/webpack/"
},
{
"source": "/getting-started/",
"destination": "/docs/getting-started/"
"destination": "/docs/getting-started/",
"source": "/getting-started/"
},
{
"source": "/guides/custom-loader/",
"destination": "/guides/frontmatter/"
"destination": "/guides/frontmatter/",
"source": "/guides/custom-loader/"
},
{
"source": "/guides/live-code/",
"destination": "/guides/syntax-highlighting/#syntax-highlighting-with-the-meta-field"
"destination": "/guides/syntax-highlighting/#syntax-highlighting-with-the-meta-field",
"source": "/guides/live-code/"
},
{
"source": "/guides/markdown-in-components/",
"destination": "/docs/what-is-mdx/"
"destination": "/docs/what-is-mdx/",
"source": "/guides/markdown-in-components/"
},
{
"source": "/guides/math-blocks/",
"destination": "/guides/math/"
"destination": "/guides/math/",
"source": "/guides/math-blocks/"
},
{
"source": "/guides/mdx-embed/",
"destination": "/guides/embed/#embeds-at-run-time"
"destination": "/guides/embed/#embeds-at-run-time",
"source": "/guides/mdx-embed/"
},
{
"source": "/guides/table-of-contents/",
"destination": "/docs/extending-mdx/"
"destination": "/docs/extending-mdx/",
"source": "/guides/table-of-contents/"
},
{
"source": "/guides/terminal/",
"destination": "/docs/getting-started/#ink"
"destination": "/docs/getting-started/#ink",
"source": "/guides/terminal/"
},
{
"source": "/guides/vue/",
"destination": "/docs/getting-started/#vue"
"destination": "/docs/getting-started/#vue",
"source": "/guides/vue/"
},
{
"source": "/guides/wrapper-customization/",
"destination": "/docs/using-mdx/#layout"
"destination": "/docs/using-mdx/#layout",
"source": "/guides/wrapper-customization/"
},
{
"source": "/guides/writing-a-plugin/",
"destination": "/docs/extending-mdx/#creating-plugins"
"destination": "/docs/extending-mdx/#creating-plugins",
"source": "/guides/writing-a-plugin/"
},
{
"source": "/mdx/",
"destination": "/docs/what-is-mdx/"
"destination": "/docs/what-is-mdx/",
"source": "/mdx/"
},
{
"source": "/plugins/",
"destination": "/docs/extending-mdx/#using-plugins"
"destination": "/docs/extending-mdx/#using-plugins",
"source": "/plugins/"
},
{
"source": "/projects/",
"destination": "/community/projects/"
"destination": "/community/projects/",
"source": "/projects/"
},
{
"source": "/support/",
"destination": "/community/support/"
"destination": "/community/support/",
"source": "/support/"
},
{
"source": "/syntax/",
"destination": "/docs/getting-started/#syntax"
"destination": "/docs/getting-started/#syntax",
"source": "/syntax/"
},
{
"source": "/vue/",
"destination": "/docs/getting-started/#vue"
"destination": "/docs/getting-started/#vue",
"source": "/vue/"
}
]
}

View File

@ -37,8 +37,10 @@
import assert from 'node:assert'
import fs from 'node:fs/promises'
import {fileURLToPath} from 'node:url'
import structuredClone from '@ungap/structured-clone'
import {globby} from 'globby'
import {h} from 'hastscript'
import {sanitize} from 'hast-util-sanitize'
import {select} from 'hast-util-select'
import pAll from 'p-all'
import React from 'react'
@ -48,7 +50,6 @@ import rehypeMeta from 'rehype-meta'
import rehypeMinifyUrl from 'rehype-minify-url'
import rehypeParse from 'rehype-parse'
import rehypePresetMinify from 'rehype-preset-minify'
import rehypeSanitize from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import {unified} from 'unified'
import {VFile} from 'vfile'
@ -111,10 +112,10 @@ const allInfo = await pAll(
// Sanitize the hast description:
if (data.meta && data.meta.descriptionHast) {
data.meta.descriptionHast = unified()
.use(rehypeSanitize, schema)
// @ts-expect-error: to do: use hast utils; element is fine.
.runSync(data.meta.descriptionHast)
// Cast because we get a root back.
data.meta.descriptionHast = /** @type {Root} */ (
sanitize(data.meta.descriptionHast, schema)
)
}
return {Content, data, ghUrl, jsonUrl, name, url}
@ -197,8 +198,7 @@ await pAll(
.use(rehypeParse, {fragment: true})
.use(rehypeDocument, {
css: ['/index.css'],
// To do: only include editor on playground?
// Or use more editors.
// Idea: only include editor on playground? Use more editors.
js: ['/index.js', '/editor.js'],
language: 'en',
link: [
@ -254,7 +254,7 @@ await pAll(
])
.use(rehypePresetMinify)
.use(rehypeMinifyUrl, {from: canonical.href})
.use(rehypeStringify, {bogusComments: false})
.use(rehypeStringify)
.process(
new VFile({
data,
@ -296,17 +296,16 @@ function rehypeLazyCss(styles) {
let index = -1
while (++index < styles.length) {
// To do: structured clone.
const props = styles[index]
enabled.push(
h('link', {
...props,
...structuredClone(props),
as: 'style',
onLoad: "this.onload=undefined;this.rel='stylesheet'",
rel: 'preload'
})
)
disabled.push(h('link', {...props, rel: 'stylesheet'}))
disabled.push(h('link', {...structuredClone(props), rel: 'stylesheet'}))
}
head.children.push(...enabled)

View File

@ -70,10 +70,8 @@ const options = {
}
],
[rehypeStarryNight, {grammars: [...common, sourceMdx, sourceTsx]}],
// Minify things — mostly needed so `prerender` can also minify.
// To do: can be removed?
rehypePresetMinify,
[rehypeMinifyUrl, {ignoreMissingSource: true}]
rehypeMinifyUrl
],
remarkPlugins: [
remarkFrontmatter,
@ -84,15 +82,7 @@ const options = {
[remarkMdxFrontmatter, {name: 'matter'}],
remarkStripBadges,
remarkSqueezeParagraphs,
[
remarkToc,
{
// To do: remove, this is the default now.
heading: 'contents|toc|table[ -]of[ -]contents?',
maxDepth: 3,
tight: true
}
]
[remarkToc, {maxDepth: 3}]
]
}

View File

@ -25,16 +25,13 @@ import process from 'node:process'
import {fileURLToPath} from 'node:url'
import chromium from '@sparticuz/chromium'
import {globby} from 'globby'
import {fromHtml} from 'hast-util-from-html'
import {sanitize, defaultSchema} from 'hast-util-sanitize'
import {select} from 'hast-util-select'
import {toHtml} from 'hast-util-to-html'
import {h, s} from 'hastscript'
import pAll from 'p-all'
import puppeteer from 'puppeteer'
import rehypeParse from 'rehype-parse'
import rehypeSanitize, {defaultSchema} from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import {unified} from 'unified'
import {u} from 'unist-builder'
import {VFile} from 'vfile'
import {rss} from 'xast-util-feed'
import {toXml} from 'xast-util-to-xml'
import {config} from '../docs/_config.js'
@ -102,46 +99,34 @@ const entries = await pAll(
*/
return async function () {
const buf = await fs.readFile(new URL('index.html', url))
const file = await unified()
.use(rehypeParse)
.use(function () {
/**
* @param {Root} tree
* Tree
*/
return function (tree) {
const node = select('.body', tree)
assert(node)
return {type: 'root', children: node.children}
}
})
.use(rehypeSanitize, {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
code: [
[
'className',
'language-diff',
'language-html',
'language-js',
'language-jsx',
'language-md',
'language-mdx',
'language-sh',
'language-ts'
]
const tree = fromHtml(buf)
const body = select('.body', tree)
assert(body)
const clean = sanitize(body, {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
code: [
[
'className',
'language-diff',
'language-html',
'language-js',
'language-jsx',
'language-md',
'language-mdx',
'language-sh',
'language-ts'
]
},
clobber: []
})
.use(rehypeStringify)
.process(buf)
]
},
clobber: []
})
return {
author: info.meta.author,
description: info.meta.description,
descriptionHtml: String(file),
descriptionHtml: toHtml(clean),
modified: info.meta.modified,
published: info.meta.published,
title: info.meta.title,
@ -205,14 +190,10 @@ await pAll(
// Dont regenerate to improve performance.
if (stats) return
const processor = unified().use(rehypeStringify)
const file = new VFile({path: url})
// To do: use hast instead of unified?
file.value = processor.stringify(
u('root', [
// To do: remove `name`.
u('doctype', {name: 'html'}),
const value = toHtml({
type: 'root',
children: [
{type: 'doctype'},
h('html', {lang: 'en'}, [
h('head', [
h('meta', {charSet: 'utf8'}),
@ -337,10 +318,7 @@ await pAll(
h('.og-description', [
h('.og-description-inside', [
info.meta.descriptionHast
? unified()
.use(rehypeSanitize, schema)
// @ts-expect-error: to do: use hast utilities; element is fine.
.runSync(info.meta.descriptionHast)
? sanitize(info.meta.descriptionHast, schema)
: info.meta.description || info.matter.description
])
]),
@ -364,8 +342,8 @@ await pAll(
])
])
])
])
)
]
})
try {
await fs.unlink(output)
@ -377,7 +355,7 @@ await pAll(
await page.emulateMediaFeatures([
{name: 'prefers-color-scheme', value: 'light'}
])
await page.setContent(file.value)
await page.setContent(value)
const screenshot = await page.screenshot()
await page.close()

View File

@ -21,7 +21,6 @@ import rehypeMinifyUrl from 'rehype-minify-url'
import rehypePresetMinify from 'rehype-preset-minify'
import rehypeStringify from 'rehype-stringify'
import {unified} from 'unified'
import {u} from 'unist-builder'
import {VFile} from 'vfile'
import {config, redirect} from '../docs/_config.js'
@ -105,29 +104,31 @@ console.log('✔ `vercel.json` redirects')
*
* @param {string} to
* Redirect to.
* @returns {Root}
* @returns {Root}
* Tree.
*/
function buildRedirect(to) {
const abs = new URL(to, config.site)
return u('root', [
// To do: remove `name`.
u('doctype', {name: 'html'}),
h('html', {lang: 'en'}, [
h('head', [
h('meta', {charSet: 'utf8'}),
h('title', 'Redirecting…'),
h('link', {href: String(abs), rel: 'canonical'}),
h('script', 'location = ' + JSON.stringify(abs)),
h('meta', {content: '0;url=' + abs, httpEquiv: 'refresh'}),
h('meta', {content: 'noindex', name: 'robots'})
]),
h('body', [
h('h1', 'Redirecting…'),
h('p', [
h('a', {href: String(abs)}, 'Click here if you are not redirected.')
return {
type: 'root',
children: [
{type: 'doctype'},
h('html', {lang: 'en'}, [
h('head', [
h('meta', {charSet: 'utf8'}),
h('title', 'Redirecting…'),
h('link', {href: String(abs), rel: 'canonical'}),
h('script', 'location = ' + JSON.stringify(abs)),
h('meta', {content: '0;url=' + abs, httpEquiv: 'refresh'}),
h('meta', {content: 'noindex', name: 'robots'})
]),
h('body', [
h('h1', 'Redirecting…'),
h('p', [
h('a', {href: String(abs)}, 'Click here if you are not redirected.')
])
])
])
])
])
]
}
}

View File

@ -1,9 +1,9 @@
/**
* @typedef {import('rehype-sanitize').Options} Options
* @typedef {import('hast-util-sanitize').Schema} Schema
*/
/**
* @type {Readonly<Options>}
* @type {Readonly<Schema>}
*/
export const schema = {
ancestors: {},