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:
parent
a362bb43ee
commit
780fa02778
@ -322,7 +322,7 @@ function Playground() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<form className="playground-editor">
|
||||
<form>
|
||||
<div className="playground-area">
|
||||
<div className="playground-inner">
|
||||
<div className="playground-draw">
|
||||
|
@ -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
23
package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
)
|
||||
})
|
||||
|
172
vercel.json
172
vercel.json
@ -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/"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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}]
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
// Don’t 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()
|
||||
|
||||
|
@ -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.')
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -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: {},
|
||||
|
Loading…
Reference in New Issue
Block a user