diff --git a/.gitignore b/.gitignore index 155b16c05..0d2641381 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,6 @@ .DS_Store coverage/ node_modules/ -/packages/esbuild/**/*.d.ts -/packages/loader/lib/**/*.d.ts -/packages/loader/test/**/*.d.ts -/packages/mdx/**/*.d.ts -/packages/node-loader/**/*.d.ts -/packages/preact/lib/**/*.d.ts -/packages/preact/test/**/*.d.ts -/packages/preact/index.d.ts -/packages/react/lib/**/*.d.ts -/packages/react/test/**/*.d.ts -/packages/react/index.d.ts -/packages/register/**/*.d.ts -/packages/remark-mdx/test/**/*.d.ts -/packages/remark-mdx/*.d.ts -/packages/rollup/**/*.d.ts -/packages/vue/lib/**/*.d.ts -/packages/vue/test/**/*.d.ts -/packages/vue/index.d.ts +*.d.cts +*.d.ts /public/ diff --git a/docs/_asset/editor.jsx b/docs/_asset/editor.jsx index 071d89341..f07b6b03d 100644 --- a/docs/_asset/editor.jsx +++ b/docs/_asset/editor.jsx @@ -5,6 +5,15 @@ * @typedef {import('mdx/types.js').MDXModule} MDXModule * @typedef {import('react-error-boundary').FallbackProps} FallbackProps * @typedef {import('unified').PluggableList} PluggableList + * @typedef {import('estree').Program} Program + * @typedef {import('estree').Node} EstreeNode + * @typedef {import('hast').Root} HastRoot + * @typedef {import('hast').Nodes} HastNodes + * @typedef {import('mdast').Root} MdastRoot + * @typedef {import('mdast').Nodes} MdastNodes + * @typedef {import('mdast-util-mdx-jsx').MdxJsxAttribute} MdxJsxAttribute + * @typedef {import('mdast-util-mdx-jsx').MdxJsxExpressionAttribute} MdxJsxExpressionAttribute + * @typedef {import('mdast-util-mdx-jsx').MdxJsxAttributeValueExpression} MdxJsxAttributeValueExpression * @typedef {import('unist').Node} UnistNode */ @@ -155,9 +164,9 @@ function Playground() { value }) - if (show === 'esast') recmaPlugins.push([capture, {name: 'esast'}]) - if (show === 'hast') rehypePlugins.push([capture, {name: 'hast'}]) - if (show === 'mdast') remarkPlugins.push([capture, {name: 'mdast'}]) + if (show === 'esast') recmaPlugins.push([captureEsast]) + if (show === 'hast') rehypePlugins.push([captureHast]) + if (show === 'mdast') remarkPlugins.push([captureMdast]) /** @type {UnistNode | undefined} */ let tree @@ -213,24 +222,35 @@ function Playground() { ) - /** - * @param {{name: string}} options - */ - function capture(options) { + function captureMdast() { /** - * @param {UnistNode} node + * @param {MdastRoot} tree */ - return function (node) { - const clone = structuredClone(node) + return function (tree) { + const clone = structuredClone(tree) + if (!positions) cleanUnistTree(clone) + tree = clone + } + } - if (!positions) { - if (options.name === 'esast') { - cleanEstree(clone) - } else { - cleanUnistTree(clone) - } - } + function captureHast() { + /** + * @param {HastRoot} tree + */ + return function (tree) { + const clone = structuredClone(tree) + if (!positions) cleanUnistTree(clone) + tree = clone + } + } + function captureEsast() { + /** + * @param {Program} tree + */ + return function (tree) { + const clone = structuredClone(tree) + if (!positions) visitEstree(clone, removeFromEstree) tree = clone } } @@ -542,57 +562,49 @@ function DisplayError(props) { } /** - * @param {UnistNode} node + * @param {HastRoot | MdastRoot} node */ function cleanUnistTree(node) { removePosition(node, {force: true}) - - visit(node, function (node) { - if ( - node.type === 'mdxJsxAttribute' && - 'value' in node && - node.value && - typeof node.value === 'object' - ) { - // @ts-expect-error: unist. - cleanUnistTree(node.value) - } - - if ( - 'attributes' in node && - node.attributes && - Array.isArray(node.attributes) - ) { - for (const attr of node.attributes) { - cleanUnistTree(attr) - } - } - - if (node.data && node.data.estree) { - // @ts-expect-error: estree. - visitEstree(node.data.estree, removeFromEstree) - } - }) + visit(node, cleanUnistNode) } /** - * @param {UnistNode} node + * @param {HastNodes | MdastNodes | MdxJsxAttribute | MdxJsxExpressionAttribute | MdxJsxAttributeValueExpression} node */ -function cleanEstree(node) { - // @ts-expect-error: fine. - visitEstree(node, removeFromEstree) +function cleanUnistNode(node) { + if ( + node.type === 'mdxJsxAttribute' && + 'value' in node && + node.value && + typeof node.value === 'object' + ) { + cleanUnistNode(node.value) + } + + if ( + 'attributes' in node && + node.attributes && + Array.isArray(node.attributes) + ) { + for (const attr of node.attributes) { + cleanUnistNode(attr) + } + } + + if (node.data && 'estree' in node.data && node.data.estree) { + visitEstree(node.data.estree, removeFromEstree) + } } /** - * @param {UnistNode} node + * @param {EstreeNode} node */ function removeFromEstree(node) { - // @ts-expect-error: untyped. delete node.loc - // @ts-expect-error: untyped. + // @ts-expect-error: acorn. delete node.start - // @ts-expect-error: untyped. + // @ts-expect-error: acorn. delete node.end - // @ts-expect-error: untyped. delete node.range } diff --git a/docs/_component/blog.jsx b/docs/_component/blog.jsx index 2ab3c4005..c20b67a0a 100644 --- a/docs/_component/blog.jsx +++ b/docs/_component/blog.jsx @@ -1,3 +1,17 @@ +/** + * @typedef {import('./sort.js').Item} Item + */ + +/** + * @typedef EntryProps + * @property {Item} item + * + * @typedef GroupProps + * @property {string | undefined} [className] + * @property {Array} items + * @property {string | undefined} [sort] + */ + import React from 'react' // @ts-expect-error: untyped. import {Fragment, jsx, jsxs} from 'react/jsx-runtime' @@ -9,6 +23,12 @@ const runtime = {Fragment, jsx, jsxs} const dateTimeFormat = new Intl.DateTimeFormat('en', {dateStyle: 'long'}) +/** + * @param {EntryProps} props + * Props. + * @returns {JSX.Element} + * Element. + */ export function BlogEntry(props) { const {item} = props const {name, data = {}} = item @@ -61,7 +81,7 @@ export function BlogEntry(props) { ) : undefined} Reading time: {timeLabel} - {meta.published ? ( + {meta.published && typeof meta.published === 'object' ? (
Published on{' '} @@ -76,6 +96,12 @@ export function BlogEntry(props) { ) } +/** + * @param {GroupProps} props + * Props. + * @returns {JSX.Element} + * Element. + */ export function BlogGroup(props) { const {items, className, sort = 'navSortSelf,meta.title', ...rest} = props const sorted = sortItems(items, sort) diff --git a/docs/_component/home.jsx b/docs/_component/home.jsx index 2faf3c737..036778f59 100644 --- a/docs/_component/home.jsx +++ b/docs/_component/home.jsx @@ -1,19 +1,40 @@ +/** + * @typedef {import('react').ReactNode} ReactNode + * @typedef {Exclude} Meta + * @typedef {import('./sort.js').Item} Item + */ + +/** + * @typedef Props + * @property {string} name + * @property {ReactNode} children + * @property {Item} navTree + * @property {Meta} meta + */ + import React from 'react' import {NavSite, NavSiteSkip} from './nav-site.jsx' import {FootSite} from './foot-site.jsx' +/** + * @param {Props} props + * Props. + * @returns {JSX.Element} + * Element. + */ export function Home(props) { - const {name, navTree, children} = props + const {name, meta, navTree, children} = props + /** @type {unknown} */ + // @ts-expect-error: to do: type. + const schema = meta.schemaOrg return (
- {props.meta.schemaOrg && ( - - )} + {schema ? ( + + ) : undefined}
{children}
diff --git a/docs/_component/layout.jsx b/docs/_component/layout.jsx index 6a4b17d85..a91c10c14 100644 --- a/docs/_component/layout.jsx +++ b/docs/_component/layout.jsx @@ -1,3 +1,18 @@ +/** + * @typedef {import('vfile').Data['meta']} DataMeta + * @typedef {import('./sort.js').Item} Item + * @typedef {import('../../website/generate.js').Author} Author + */ + +/** + * @typedef Props + * @property {string} name + * @property {URL} ghUrl + * @property {DataMeta | undefined} [meta] + * @property {Item} navTree + * @property {JSX.Element} children + */ + import React from 'react' import {NavSite, NavSiteSkip} from './nav-site.jsx' import {FootSite} from './foot-site.jsx' @@ -5,16 +20,27 @@ import {sortItems} from './sort.js' const dateTimeFormat = new Intl.DateTimeFormat('en', {dateStyle: 'long'}) +/** + * + * @param {Props} props + * @returns {JSX.Element} + */ export function Layout(props) { const {name, navTree, ghUrl} = props const [self, parent] = findSelfAndParent(navTree) || [] + const navSortItems = parent ? parent.data.navSortItems : undefined const siblings = parent - ? sortItems(parent.children, parent.data.navSortItems) + ? sortItems( + parent.children, + typeof navSortItems === 'string' ? navSortItems : undefined + ) : [] const meta = (self ? self.data.meta : props.meta) || {} - const index = siblings.indexOf(self) + const index = self ? siblings.indexOf(self) : -1 const previous = index === -1 ? undefined : siblings[index - 1] const next = index === -1 ? undefined : siblings[index + 1] + /** @type {Array} */ + // @ts-expect-error: to do: augment types. const metaAuthors = meta.authors || [] const metaTime = ( self @@ -33,24 +59,6 @@ export function Layout(props) { timeLabel = metaTime[0] + ' minute' + (metaTime[0] > 1 ? 's' : '') } - function accumulateReadingTime(d) { - const time = (d.data.meta || {}).readingTime - const total = time ? (Array.isArray(time) ? time : [time, time]) : [] - - let index = -1 - while (++index < d.children.length) { - const childTime = accumulateReadingTime(d.children[index]) - if (childTime[0]) total[0] = (total[0] || 0) + childTime[0] - if (childTime[1]) total[1] = (total[1] || 0) + childTime[1] - } - - return total - } - - function entryToTitle(d) { - return (d.data.matter || {}).title || (d.data.meta || {}).title - } - const up = parent && self && parent !== navTree ? (
@@ -90,23 +98,25 @@ export function Layout(props) {
) - const published = meta.published ? ( - <> - Published on{' '} - - - ) : undefined + const published = + meta.published && typeof meta.published === 'object' ? ( + <> + Published on{' '} + + + ) : undefined - const modified = meta.modified ? ( - <> - Modified on{' '} - - - ) : undefined + const modified = + meta.modified && typeof meta.modified === 'object' ? ( + <> + Modified on{' '} + + + ) : undefined const date = published || modified ? ( @@ -196,6 +206,11 @@ export function Layout(props) {
) + /** + * @param {Item} item + * @param {Item | undefined} [parent] + * @returns {[self: Item, parent: Item | undefined] | undefined} + */ function findSelfAndParent(item, parent) { if (item.name === name) return [item, parent] @@ -208,3 +223,30 @@ export function Layout(props) { } } } + +/** + * @param {Item} d + * @returns {string | undefined} + */ +function entryToTitle(d) { + return d.data.matter?.title || d.data.meta?.title || undefined +} + +/** + * @param {Item} d + * @returns {[number, number] | [number] | []} + */ +function accumulateReadingTime(d) { + const time = (d.data.meta || {}).readingTime + /** @type {[number, number] | [number] | []} */ + const total = time ? (Array.isArray(time) ? time : [time, time]) : [] + + let index = -1 + while (++index < d.children.length) { + const childTime = accumulateReadingTime(d.children[index]) + if (childTime[0]) total[0] = (total[0] || 0) + childTime[0] + if (childTime[1]) total[1] = (total[1] || 0) + childTime[1] + } + + return total +} diff --git a/docs/_component/nav-site.jsx b/docs/_component/nav-site.jsx index 686ff805f..e8b4e92a1 100644 --- a/docs/_component/nav-site.jsx +++ b/docs/_component/nav-site.jsx @@ -1,3 +1,13 @@ +/** + * @typedef {import('./sort.js').Item} Item + */ + +/** + * @typedef Props + * @property {string} name + * @property {Item} navTree + */ + import React from 'react' import {config} from '../_config.js' import {NavGroup} from './nav.jsx' @@ -18,6 +28,10 @@ export function NavSiteSkip() { ) } +/** + * @param {Props} props + * @returns {JSX.Element} + */ export function NavSite(props) { const {name, navTree} = props diff --git a/docs/_component/nav.jsx b/docs/_component/nav.jsx index d60d09c32..19afa7a46 100644 --- a/docs/_component/nav.jsx +++ b/docs/_component/nav.jsx @@ -1,3 +1,25 @@ +// Augment vfile data: +/// + +/** + * @typedef {import('hast').ElementContent} ElementContent + * @typedef {import('./sort.js').Item} Item + */ + +/** + * @typedef ItemProps + * @property {boolean | undefined} [includeDescription] + * @property {boolean | undefined} [includePublished] + * @property {Item} item + * @property {string | undefined} [name] + * + * @typedef GroupProps + * @property {string | undefined} [className] + * @property {Array} items + * @property {string | undefined} [sort] + * @property {string | undefined} [name] + */ + import React from 'react' // @ts-expect-error: untyped. import {Fragment, jsx, jsxs} from 'react/jsx-runtime' @@ -9,6 +31,10 @@ const runtime = {Fragment, jsx, jsxs} const dateTimeFormat = new Intl.DateTimeFormat('en', {dateStyle: 'long'}) +/** + * @param {GroupProps} props + * @returns {JSX.Element} + */ export function NavGroup(props) { const {items, className, sort = 'navSortSelf,meta.title', ...rest} = props @@ -21,6 +47,10 @@ export function NavGroup(props) { ) } +/** + * @param {ItemProps} props + * @returns {JSX.Element} + */ export function NavItem(props) { const {item, name: activeName, includeDescription, includePublished} = props const {name, children, data = {}} = item @@ -34,12 +64,16 @@ export function NavItem(props) { if (includeDescription) { if (meta.descriptionHast) { + const children = /** @type {Array} */ ( + meta.descriptionHast.children + ) + description = toJsxRuntime( { type: 'element', tagName: 'div', properties: {className: ['nav-description']}, - children: meta.descriptionHast.children + children }, runtime ) @@ -56,8 +90,12 @@ export function NavItem(props) { } } - if (includePublished && (matter.published || meta.published)) { - published = dateTimeFormat.format(matter.published || meta.published) + const pub = matter.published || meta.published + + if (includePublished && pub) { + published = dateTimeFormat.format( + typeof pub === 'string' ? new Date(pub) : pub || undefined + ) } return ( @@ -72,7 +110,11 @@ export function NavItem(props) { {published ? ' — ' + published : null} {description || null} {!navExcludeGroup && children.length > 0 ? ( - + ) : null} ) diff --git a/docs/_component/note.jsx b/docs/_component/note.jsx index 9c10616a7..0e175238e 100644 --- a/docs/_component/note.jsx +++ b/docs/_component/note.jsx @@ -1,7 +1,26 @@ +/** + * @typedef {import('react').ReactNode} ReactNode + */ + +/** + * @typedef {'info' | 'legacy' | 'important'} NoteType + * + * @typedef Props + * @property {NoteType} type + * @property {ReactNode} children + */ + import React from 'react' +/** @type {Set} */ const known = new Set(['info', 'legacy', 'important']) +/** + * @param {Props} props + * Props. + * @returns {JSX.Element} + * Element. + */ export function Note(props) { const {children, type} = props const className = ['note'] diff --git a/docs/_component/snowfall.jsx b/docs/_component/snowfall.jsx index 37e7c058a..1cbf88c1b 100644 --- a/docs/_component/snowfall.jsx +++ b/docs/_component/snowfall.jsx @@ -1,7 +1,19 @@ +/** + * @typedef Props + * @property {string} color + * @property {number} year + */ + import React from 'react' const data = [6, 5, 2, 4.5, 1.5, 2.5, 2, 2.5, 1.5, 2.5, 3.5, 7] +/** + * @param {Props} props + * Props. + * @returns {JSX.Element} + * Element. + */ export function Chart(props) { return (
diff --git a/docs/_component/sort.js b/docs/_component/sort.js index a45ce16cc..627941919 100644 --- a/docs/_component/sort.js +++ b/docs/_component/sort.js @@ -1,8 +1,25 @@ +/** + * @typedef {import('vfile').Data} Data + */ + +/** + * @typedef Item + * @property {string} name + * @property {Data} data + * @property {Array} children + */ + import dlv from 'dlv' const collator = new Intl.Collator('en').compare +/** + * @param {Array} items + * @param {string | undefined} [sortString] + * @returns {Array} + */ export function sortItems(items, sortString = 'navSortSelf,meta.title') { + /** @type {Array<[string, 'asc' | 'desc']>} */ const fields = sortString.split(',').map((d) => { const [field, order = 'asc'] = d.split(':') diff --git a/package-lock.json b/package-lock.json index 51f6b3a3a..e98dd24d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ ], "devDependencies": { "@node-loader/core": "^2.0.0", + "@types/dlv": "^1.1.2", "@wooorm/starry-night": "^3.0.0", "acorn": "^8.0.0", "ajv": "^8.12.0", @@ -49,7 +50,7 @@ "postcss": "^8.0.0", "postcss-cli": "^10.0.0", "prettier": "^3.0.0", - "puppeteer-core": "^21.0.0", + "puppeteer-core": "^20.0.0", "react": "^18.0.0", "react-dom": "^18.0.0", "react-error-boundary": "^4.0.0", @@ -1912,6 +1913,11 @@ "@types/node": "*" } }, + "node_modules/@types/deasync": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@types/deasync/-/deasync-0.1.3.tgz", + "integrity": "sha512-81h2bv/enjJliBXtJxDb00oh/zTAn4sbwVsrV1aUFwS33tqHTQdWi2H5kcGNV/kvC1eXrpW+Z7dzPYqV2i2r7w==" + }, "node_modules/@types/debug": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.9.tgz", @@ -1920,6 +1926,12 @@ "@types/ms": "*" } }, + "node_modules/@types/dlv": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/dlv/-/dlv-1.1.2.tgz", + "integrity": "sha512-OyiZ3jEKu7RtGO1yp9oOdK0cTwZ/10oE9PDJ6fyN3r9T5wkyOcvr6awdugjYdqF6KVO5eUvt7jx7rk2Eylufow==", + "dev": true + }, "node_modules/@types/eslint": { "version": "8.44.4", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.4.tgz", @@ -2030,16 +2042,6 @@ "integrity": "sha512-CeVMX9EhVUW8MWnei05eIRks4D5Wscw/W9Byz1s3PA+yJvcdvq9SaDjiUKvRvEgjpdTyJMjQA43ae4KTwsvOPg==", "dev": true }, - "node_modules/@types/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-I71X8yySVQW6DuXr78/McC+enpUYQ68JxAYlgVyuMvl5mb7jFUZpFAu1qURZcwvbITXwxPnrA7hbV0W3HHsbbg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/webpack": "^4" - } - }, "node_modules/@types/mdast": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.1.tgz", @@ -2144,48 +2146,18 @@ "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", "dev": true }, - "node_modules/@types/source-list-map": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.3.tgz", - "integrity": "sha512-I9R/7fUjzUOyDy6AFkehCK711wWoAXEaBi80AfjZt1lIkbe6AcXKd3ckQc3liMvQExWvfOeh/8CtKzrfUFN5gA==", - "dev": true - }, "node_modules/@types/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/@types/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-dPWnWsf+kzIG140B8z2w3fr5D03TLWbOAFQl45xUpI3vcizeXriNR5VYkWZ+WTMsUHqZ9Xlt3hrxGNANFyNQfw==", "dev": true }, - "node_modules/@types/tapable": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.9.tgz", - "integrity": "sha512-fOHIwZua0sRltqWzODGUM6b4ffZrf/vzGUmNXdR+4DzuJP42PMbM5dLKcdzlYvv8bMJ3GALOzkk1q7cDm2zPyA==", - "dev": true - }, "node_modules/@types/text-table": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@types/text-table/-/text-table-0.2.3.tgz", "integrity": "sha512-MUW7DN7e178wJ2dB9rHuhwUWRUJGrl8fCng37BEWV0r2r5VpzkRFRiMfnX6sjXlu4tMn41lrjzsVh/z1XrKc+A==", "dev": true }, - "node_modules/@types/uglify-js": { - "version": "3.17.2", - "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.2.tgz", - "integrity": "sha512-9SjrHO54LINgC/6Ehr81NjAxAYvwEZqjUHLjJYvC4Nmr9jbLQCIZbWSvl4vXQkkmR1UAuaKDycau3O1kWGFyXQ==", - "dev": true, - "dependencies": { - "source-map": "^0.6.1" - } - }, - "node_modules/@types/uglify-js/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@types/ungap__structured-clone": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@types/ungap__structured-clone/-/ungap__structured-clone-0.3.0.tgz", @@ -2197,40 +2169,6 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz", "integrity": "sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w==" }, - "node_modules/@types/webpack": { - "version": "4.41.34", - "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.34.tgz", - "integrity": "sha512-CN2aOGrR3zbMc2v+cKqzaClYP1ldkpPOgtdNvgX+RmlWCSWxHxpzz6WSCVQZRkF8D60ROlkRzAoEpgjWQ+bd2g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/tapable": "^1", - "@types/uglify-js": "*", - "@types/webpack-sources": "*", - "anymatch": "^3.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/@types/webpack-sources": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-3.2.1.tgz", - "integrity": "sha512-iLC3Fsx62ejm3ST3PQ8vBMC54Rb3EoCprZjeJGI5q+9QjfDLGt9jeg/k245qz1G9AQnORGk0vqPicJFPT1QODQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/source-list-map": "*", - "source-map": "^0.7.3" - } - }, - "node_modules/@types/webpack/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@types/xast": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/xast/-/xast-2.0.1.tgz", @@ -3850,13 +3788,12 @@ } }, "node_modules/chromium-bidi": { - "version": "0.4.31", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.31.tgz", - "integrity": "sha512-OtvEg2JMRQrHsmLx4FV3u1Hf9waYxB5PmL+yM0HkFpc9H2x3TMbUqS+GP2/fC4399hzOO+EQF8uVU43By9ILag==", + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", "dev": true, "dependencies": { - "mitt": "3.0.1", - "urlpattern-polyfill": "9.0.0" + "mitt": "3.0.0" }, "peerDependencies": { "devtools-protocol": "*" @@ -4684,9 +4621,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1179426", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1179426.tgz", - "integrity": "sha512-KKC7IGwdOr7u9kTGgjUvGTov/z1s2H7oHi3zKCdR9eSDyCPia5CBi4aRhtp7d8uR7l0GS5UTDw3TjKGu5CqINg==", + "version": "0.0.1147663", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz", + "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==", "dev": true }, "node_modules/diff": { @@ -11445,9 +11382,9 @@ } }, "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==", "dev": true }, "node_modules/mkdirp-classic": { @@ -13091,19 +13028,19 @@ } }, "node_modules/proxy-agent": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", - "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz", + "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==", "dev": true, "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.0", "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.1", + "pac-proxy-agent": "^7.0.0", "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.2" + "socks-proxy-agent": "^8.0.1" }, "engines": { "node": ">= 14" @@ -13190,32 +13127,40 @@ } }, "node_modules/puppeteer-core": { - "version": "21.3.8", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-21.3.8.tgz", - "integrity": "sha512-yv12E/+zZ7Lei5tJB4sUkSrsuqKibuYpYxLGbmtLUjjYIqGE5HKz9OUI2I/RFHEvF+pHi2bTbv5bWydeCGJ6Mw==", + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz", + "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==", "dev": true, "dependencies": { - "@puppeteer/browsers": "1.7.1", - "chromium-bidi": "0.4.31", + "@puppeteer/browsers": "1.4.6", + "chromium-bidi": "0.4.16", "cross-fetch": "4.0.0", "debug": "4.3.4", - "devtools-protocol": "0.0.1179426", - "ws": "8.14.2" + "devtools-protocol": "0.0.1147663", + "ws": "8.13.0" }, "engines": { "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/puppeteer-core/node_modules/@puppeteer/browsers": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.7.1.tgz", - "integrity": "sha512-nIb8SOBgDEMFY2iS2MdnUZOg2ikcYchRrBoF+wtdjieRFKR2uGRipHY/oFLo+2N6anDualyClPzGywTHRGrLfw==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz", + "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==", "dev": true, "dependencies": { "debug": "4.3.4", "extract-zip": "2.0.1", "progress": "2.0.3", - "proxy-agent": "6.3.1", + "proxy-agent": "6.3.0", "tar-fs": "3.0.4", "unbzip2-stream": "1.4.3", "yargs": "17.7.1" @@ -13225,6 +13170,14 @@ }, "engines": { "node": ">=16.3.0" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/puppeteer-core/node_modules/ansi-regex": { @@ -13353,12 +13306,6 @@ "integrity": "sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg==", "dev": true }, - "node_modules/puppeteer/node_modules/mitt": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", - "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==", - "dev": true - }, "node_modules/puppeteer/node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -13409,27 +13356,6 @@ } } }, - "node_modules/puppeteer/node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -28924,12 +28850,6 @@ "requires-port": "^1.0.0" } }, - "node_modules/urlpattern-polyfill": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-9.0.0.tgz", - "integrity": "sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g==", - "dev": true - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -29767,9 +29687,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, "engines": { "node": ">=10.0.0" @@ -30202,7 +30122,6 @@ "source-map": "^0.7.0" }, "devDependencies": { - "@types/loader-utils": "^2.0.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@vue/babel-plugin-jsx": "^1.0.0", @@ -30252,7 +30171,7 @@ "devDependencies": { "@emotion/react": "^11.0.0", "@mdx-js/react": "^2.0.0", - "nanoid": "^5.0.0", + "nanoid": "^4.0.0", "preact": "^10.0.0", "preact-render-to-string": "^6.0.0", "react": "^18.0.0", @@ -30271,9 +30190,9 @@ } }, "packages/mdx/node_modules/nanoid": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.1.tgz", - "integrity": "sha512-vWeVtV5Cw68aML/QaZvqN/3QQXc6fBfIieAlu05m7FZW2Dgb+3f0xc0TTxuJW+7u30t7iSDTV/j3kVI0oJqIfQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz", + "integrity": "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==", "dev": true, "funding": [ { @@ -30285,7 +30204,7 @@ "nanoid": "bin/nanoid.js" }, "engines": { - "node": "^18 || >=20" + "node": "^14 || ^16 || >=18" } }, "packages/node-loader": { @@ -30355,7 +30274,8 @@ "version": "2.3.0", "license": "MIT", "dependencies": { - "@mdx-js/mdx": "^2.0.0" + "@mdx-js/mdx": "^2.0.0", + "@types/deasync": "^0.1.0" }, "devDependencies": { "@types/react": "^18.0.0", diff --git a/package.json b/package.json index 40df1282e..6596b013f 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ ], "devDependencies": { "@node-loader/core": "^2.0.0", + "@types/dlv": "^1.1.2", "@wooorm/starry-night": "^3.0.0", "acorn": "^8.0.0", "ajv": "^8.12.0", @@ -53,7 +54,7 @@ "postcss": "^8.0.0", "postcss-cli": "^10.0.0", "prettier": "^3.0.0", - "puppeteer-core": "^21.0.0", + "puppeteer-core": "^20.0.0", "react": "^18.0.0", "react-dom": "^18.0.0", "react-error-boundary": "^4.0.0", @@ -103,12 +104,11 @@ "docs-post": "node website/post.js", "docs": "npm run docs-prep && npm run docs-generate && npm run docs-post", "docs-deploy": "vercel && vercel alias $(pbpaste) mdxjs.com && vercel alias $(pbpaste) www.mdxjs.com", - "#": " && xo --fix", - "##": "remark . -qfo && remark . -e mdx -u mdx -qfo && ", - "###": "remark . -qf && remark . -e mdx -u mdx -qf && ", - "format": "prettier . -w --log-level warn", - "lint": "prettier . -c --log-level warn", - "build": "npm run build --workspaces --if-present", + "#": "remark . -qfo && remark . -e mdx -u mdx -qfo && ", + "##": "remark . -qf && remark . -e mdx -u mdx -qf && ", + "format": "prettier . -w --log-level warn && xo --fix", + "lint": "prettier . -c --log-level warn && xo", + "build": "tsc --build --clean && tsc --build && type-coverage", "test-api": "npm run test-api --workspaces --if-present", "test-coverage": "npm run test-coverage --workspaces --if-present", "test": "npm run build && npm run format && npm run test-coverage" @@ -136,6 +136,7 @@ "unicorn/prefer-at": "off", "unicorn/prefer-logical-operator-over-ternary": "off", "unicorn/prefer-node-protocol": "off", + "unicorn/prefer-string-replace-all": "off", "unicorn/prefer-top-level-await": "off", "complexity": "off" }, diff --git a/packages/esbuild/package.json b/packages/esbuild/package.json index a677df74b..e5eec2db9 100644 --- a/packages/esbuild/package.json +++ b/packages/esbuild/package.json @@ -55,11 +55,9 @@ "vfile-message": "^4.0.0" }, "scripts": { - "prepack": "npm run build", - "build": "tsc --build --clean && tsc --build && type-coverage", "test-api": "node test/index.js", "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", - "test": "npm run build && npm run test-coverage" + "test": "npm run test-coverage" }, "xo": { "prettier": true, diff --git a/packages/esbuild/tsconfig.json b/packages/esbuild/tsconfig.json index 6cac7d0aa..4082f16a5 100644 --- a/packages/esbuild/tsconfig.json +++ b/packages/esbuild/tsconfig.json @@ -1,5 +1,3 @@ { - "extends": "../../tsconfig.json", - "include": ["**/*.cjs", "**/*.js", "**/*.jsx"], - "exclude": ["coverage/", "node_modules/"] + "extends": "../../tsconfig.json" } diff --git a/packages/loader/index.d.cts b/packages/loader/index.d.cts index ee1fe0ee9..c97792c16 100644 --- a/packages/loader/index.d.cts +++ b/packages/loader/index.d.cts @@ -1,19 +1,3 @@ -// Some TS versions use this file, some `index.d.cts`. -import type {ProcessorOptions} from '@mdx-js/mdx/lib/core.js' -import type {LoaderContext} from 'webpack' - -/** - * A Webpack loader to compile MDX to JavaScript. - * - * [Reference for Loader API](https://webpack.js.org/api/loaders/) - * - * @this {LoaderContext} - * @param {string} value - * The original module source code. - * @returns {void} - */ -declare function mdxLoader(this: LoaderContext, value: string): void - -export default mdxLoader - -export type Options = ProcessorOptions +declare function _exports(this: LoaderContext, code: string): void; +export = _exports; +export type LoaderContext = import('webpack').LoaderContext; diff --git a/packages/loader/package.json b/packages/loader/package.json index 58a8e95fa..a7282738e 100644 --- a/packages/loader/package.json +++ b/packages/loader/package.json @@ -51,7 +51,6 @@ "webpack": ">=4" }, "devDependencies": { - "@types/loader-utils": "^2.0.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "@vue/babel-plugin-jsx": "^1.0.0", @@ -65,11 +64,9 @@ "webpack": "^5.0.0" }, "scripts": { - "prepack": "npm run build", - "build": "tsc --build --clean && tsc --build && type-coverage", "test-api": "node test/index.js", "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", - "test": "npm run build && npm run test-coverage" + "test": "npm run test-coverage" }, "xo": { "prettier": true, diff --git a/packages/loader/test/index.js b/packages/loader/test/index.js index 369572192..301887641 100644 --- a/packages/loader/test/index.js +++ b/packages/loader/test/index.js @@ -1,7 +1,6 @@ /** * @typedef {import('mdx/types.js').MDXContent} MDXContent * @typedef {import('preact').FunctionComponent} PreactComponent - * @typedef {import('vue').Component} VueComponent */ import assert from 'node:assert/strict' @@ -14,8 +13,6 @@ import React from 'react' import {renderToStaticMarkup} from 'react-dom/server' import {h} from 'preact' import {render} from 'preact-render-to-string' -import * as vue from 'vue' -import serverRenderer from '@vue/server-renderer' test('@mdx-js/loader', async () => { // Setup. @@ -139,6 +136,7 @@ webpack.mdx:1:22: Unexpected end of file in expression, expected a corresponding ) assert.equal( + // To do: fix? // @ts-expect-error: preact + react conflict. render(h(modPreact.default.default, {})), '

Hello, World!

', @@ -160,61 +158,6 @@ webpack.mdx:1:22: Unexpected end of file in expression, expected a corresponding await fs.unlink(new URL('preact.cjs', base)) - // Vue. - const vueBuild = await promisify(webpack)({ - // @ts-expect-error To do: webpack types miss support for `context`. - context: fileURLToPath(base), - entry: './webpack.mdx', - mode: 'none', - externals: ['vue'], - module: { - rules: [ - { - test: /\.mdx$/, - use: [ - { - loader: 'babel-loader', - options: {configFile: false, plugins: ['@vue/babel-plugin-jsx']} - }, - { - loader: fileURLToPath(new URL('../index.cjs', import.meta.url)), - options: {jsx: true} - } - ] - } - ] - }, - output: { - path: fileURLToPath(base), - filename: 'vue.cjs', - libraryTarget: 'commonjs' - } - }) - - assert.ok(!vueBuild?.hasErrors()) - - // One for ESM loading CJS, one for webpack. - const modVue = /** @type {{default: {default: VueComponent}}} */ ( - // @ts-ignore file is dynamically generated - await import('./vue.cjs') - ) - - const vueResult = await serverRenderer.renderToString( - vue.createSSRApp({ - components: {Content: modVue.default.default}, - template: '' - }) - ) - - assert.equal( - // Remove SSR comments used to hydrate (I guess). - vueResult.replace(//g, ''), - '

Hello, World!

', - 'should compile (vue)' - ) - - await fs.unlink(new URL('vue.cjs', base)) - // Clean. await fs.unlink(new URL('webpack.mdx', base)) }) diff --git a/packages/loader/tsconfig.json b/packages/loader/tsconfig.json index 1a560ac14..4082f16a5 100644 --- a/packages/loader/tsconfig.json +++ b/packages/loader/tsconfig.json @@ -1,5 +1,3 @@ { - "extends": "../../tsconfig.json", - "include": ["**/*.cjs", "**/*.js", "**/*.jsx", "index.d.ts", "index.d.cts"], - "exclude": ["coverage/", "node_modules/"] + "extends": "../../tsconfig.json" } diff --git a/packages/mdx/package.json b/packages/mdx/package.json index 9e9798c54..064eb9f0e 100644 --- a/packages/mdx/package.json +++ b/packages/mdx/package.json @@ -70,7 +70,7 @@ "devDependencies": { "@emotion/react": "^11.0.0", "@mdx-js/react": "^2.0.0", - "nanoid": "^5.0.0", + "nanoid": "^4.0.0", "preact": "^10.0.0", "preact-render-to-string": "^6.0.0", "react": "^18.0.0", @@ -84,11 +84,9 @@ "unist-util-remove-position": "^5.0.0" }, "scripts": { - "prepack": "npm run build", - "build": "tsc --build --clean && tsc --build && type-coverage", "test-api": "node test/index.js", "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", - "test": "npm run build && npm run test-coverage" + "test": "npm run test-coverage" }, "xo": { "prettier": true, diff --git a/packages/mdx/tsconfig.json b/packages/mdx/tsconfig.json index 6cac7d0aa..4082f16a5 100644 --- a/packages/mdx/tsconfig.json +++ b/packages/mdx/tsconfig.json @@ -1,5 +1,3 @@ { - "extends": "../../tsconfig.json", - "include": ["**/*.cjs", "**/*.js", "**/*.jsx"], - "exclude": ["coverage/", "node_modules/"] + "extends": "../../tsconfig.json" } diff --git a/packages/node-loader/package.json b/packages/node-loader/package.json index 3190fdc86..800830875 100644 --- a/packages/node-loader/package.json +++ b/packages/node-loader/package.json @@ -47,11 +47,9 @@ "react-dom": "^18.0.0" }, "scripts": { - "prepack": "npm run build", - "build": "tsc --build --clean && tsc --build && type-coverage", "test-api": "node --no-warnings --experimental-loader=./test/react-18-node-loader.js test/index.js", "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", - "test": "npm run build && npm run test-coverage" + "test": "npm run test-coverage" }, "xo": { "prettier": true, diff --git a/packages/node-loader/tsconfig.json b/packages/node-loader/tsconfig.json index 6cac7d0aa..4082f16a5 100644 --- a/packages/node-loader/tsconfig.json +++ b/packages/node-loader/tsconfig.json @@ -1,5 +1,3 @@ { - "extends": "../../tsconfig.json", - "include": ["**/*.cjs", "**/*.js", "**/*.jsx"], - "exclude": ["coverage/", "node_modules/"] + "extends": "../../tsconfig.json" } diff --git a/packages/preact/package.json b/packages/preact/package.json index 85f8afeb9..fc42c0098 100644 --- a/packages/preact/package.json +++ b/packages/preact/package.json @@ -53,11 +53,9 @@ "preact-render-to-string": "^6.0.0" }, "scripts": { - "prepack": "npm run build", - "build": "tsc --build --clean && tsc --build && type-coverage", "test-api": "node --no-warnings --experimental-loader=../../script/jsx-loader.js test/test.jsx", "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", - "test": "npm run build && npm run test-coverage" + "test": "npm run test-coverage" }, "xo": { "overrides": [ diff --git a/packages/preact/test/test.jsx b/packages/preact/test/test.jsx index 5b3c96946..8ef7f2196 100644 --- a/packages/preact/test/test.jsx +++ b/packages/preact/test/test.jsx @@ -2,7 +2,8 @@ // * @jsx h // * @jsxFrag Fragment -// Note: this is unused by otherwise `xo` or so seems to fail? +// Note: this is unused but otherwise `xo` or so seems to fail? +// To do: can this be removed? import assert from 'node:assert/strict' import {test} from 'node:test' import {h} from 'preact' @@ -21,9 +22,7 @@ test('should support `components` with `MDXProvider`', async () => { render( } }} @@ -45,7 +44,6 @@ test('should support `wrapper` in `components`', async () => { render( } */ props) { return
} @@ -68,23 +66,17 @@ test('should combine components in nested `MDXProvider`s', async () => { render( }, - // @ts-expect-error: preact + react conflict. h2(props) { - // @ts-expect-error: Something wrong with Preact + React maybe? return

} }} > } }} @@ -107,23 +99,17 @@ test('should support components as a function', async () => { render( }, - // @ts-expect-error: preact + react conflict. h2(props) { - // @ts-expect-error: Something wrong with Preact + React maybe? return

} }} > ({ h2(props) { - // @ts-expect-error: Something wrong with Preact + React maybe? return

} })} @@ -146,9 +132,7 @@ test('should support a `disableParentContext` prop (sandbox)', async () => { render( } }} @@ -172,19 +156,15 @@ test('should support a `disableParentContext` *and* `components as a function', render( } }} > ({ h2(props) { - // @ts-expect-error: Something wrong with Preact + React maybe? return

} })} @@ -213,18 +193,14 @@ test('should support `withComponents`', async () => { render( } }} > } }} diff --git a/packages/preact/tsconfig.json b/packages/preact/tsconfig.json index 027bb5b04..4082f16a5 100644 --- a/packages/preact/tsconfig.json +++ b/packages/preact/tsconfig.json @@ -1,9 +1,3 @@ { - "extends": "../../tsconfig.json", - "include": ["**/*.cjs", "**/*.js", "**/*.jsx"], - "exclude": ["coverage/", "node_modules/"], - "compilerOptions": { - "jsx": "react-jsx", - "jsxImportSource": "preact" - } + "extends": "../../tsconfig.json" } diff --git a/packages/react/package.json b/packages/react/package.json index 6fd8ae474..fae97aea6 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -55,11 +55,9 @@ "react-dom": "^18.0.0" }, "scripts": { - "prepack": "npm run build", - "build": "tsc --build --clean && tsc --build && type-coverage", "test-api": "node --no-warnings --experimental-loader=../../script/jsx-loader.js test/test.jsx", "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", - "test": "npm run build && npm run test-coverage" + "test": "npm run test-coverage" }, "xo": { "overrides": [ diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json index 159a2649d..4082f16a5 100644 --- a/packages/react/tsconfig.json +++ b/packages/react/tsconfig.json @@ -1,8 +1,3 @@ { - "extends": "../../tsconfig.json", - "include": ["**/*.cjs", "**/*.js", "**/*.jsx"], - "exclude": ["coverage/", "node_modules/"], - "compilerOptions": { - "jsx": "preserve" - } + "extends": "../../tsconfig.json" } diff --git a/packages/register/index.cjs b/packages/register/index.cjs index 06aaebd75..72b567ab3 100644 --- a/packages/register/index.cjs +++ b/packages/register/index.cjs @@ -3,4 +3,5 @@ const runtime = require('react/jsx-runtime') const register = require('./lib/index.cjs') +// @ts-expect-error: JSX runtime is untyped. register({...runtime}) diff --git a/packages/register/lib/index.cjs b/packages/register/lib/index.cjs index a3d81dc7b..68dfa6968 100644 --- a/packages/register/lib/index.cjs +++ b/packages/register/lib/index.cjs @@ -1,18 +1,37 @@ +/** + * @typedef {import('node:module').Module} Module + */ + +// @ts-expect-error: type imports do work. +/** @typedef {import('@mdx-js/mdx').EvaluateOptions} EvaluateOptions */ +// @ts-expect-error: type imports do work. +/** @typedef {import('@mdx-js/mdx/lib/run.js')} RunMod */ +// @ts-expect-error: type imports do work. +/** @typedef {import('@mdx-js/mdx/lib/util/create-format-aware-processors.js')} CreateProcessorMod */ +// @ts-expect-error: type imports do work. +/** @typedef {import('@mdx-js/mdx/lib/util/resolve-evaluate-options.js')} ResolveEvaluateMod */ + 'use strict' const fs = require('fs') const deasync = require('deasync') +/** @type {RunMod} */ const {runSync} = deasync(load)('@mdx-js/mdx/lib/run.js') +/** @type {CreateProcessorMod} */ const {createFormatAwareProcessors} = deasync(load)( '@mdx-js/mdx/lib/util/create-format-aware-processors.js' ) +/** @type {ResolveEvaluateMod} */ const {resolveEvaluateOptions} = deasync(load)( '@mdx-js/mdx/lib/util/resolve-evaluate-options.js' ) module.exports = register +/** + * @param {EvaluateOptions} options + */ function register(options) { const {compiletime, runtime} = resolveEvaluateOptions(options) const {extnames, processSync} = createFormatAwareProcessors(compiletime) @@ -23,6 +42,11 @@ function register(options) { require.extensions[extnames[index]] = mdx } + /** + * @param {Module} module + * @param {string} path + * @returns {undefined} + */ function mdx(module, path) { const file = processSync(fs.readFileSync(path)) const result = runSync(file, runtime) @@ -31,7 +55,15 @@ function register(options) { } } +/** + * + * @param {string} filePath + * @param {(error: Error | null, result?: any) => void} callback + * Note: `void` needed, `deasync` types don’t accept `undefined`. + * @returns {undefined} + */ function load(filePath, callback) { + /** @type {boolean} */ let called // Sometimes, the import hangs (see error message for reasons). @@ -54,6 +86,12 @@ function load(filePath, callback) { done(null, module) }, done) + /** + * + * @param {Error | null} error + * @param {unknown} [result] + * @returns {undefined} + */ function done(error, result) { /* Something is going wrong in Node/V8 if this happens. */ /* c8 ignore next */ diff --git a/packages/register/package.json b/packages/register/package.json index 77ad800b6..832f0fa38 100644 --- a/packages/register/package.json +++ b/packages/register/package.json @@ -35,7 +35,8 @@ "index.cjs" ], "dependencies": { - "@mdx-js/mdx": "^2.0.0" + "@mdx-js/mdx": "^2.0.0", + "@types/deasync": "^0.1.0" }, "optionalDependencies": { "deasync": "^0.1.0" @@ -47,9 +48,6 @@ "react-dom": "^18.0.0" }, "scripts": { - "#prepack": "npm run build", - "#1": "to do when TS supports CJS: `build: rimraf \"lib/**/*.d.ts\" \"test/**/*.d.ts\" \"*.d.ts\" && tsc && type-coverage`", - "#2": "to do: re-enable when `deasync` is built on Node 17", "test-api": "node -r ./index.cjs test/index.cjs", "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", "test": "npm run test-coverage" diff --git a/packages/register/test/index.cjs b/packages/register/test/index.cjs index afbabd017..8817010cf 100644 --- a/packages/register/test/index.cjs +++ b/packages/register/test/index.cjs @@ -19,9 +19,10 @@ test('@mdx-js/register', async () => { 'export const Message = () => <>World!\n\n# Hello, ' ) - // OMG, it works! const Content = /** @type {MDXContent} */ ( - require('./register.mdx') // type-coverage:ignore-line + /** @type {unknown} */ ( + require('./register.mdx') // type-coverage:ignore-line + ) ) assert.equal( diff --git a/packages/register/tsconfig.json b/packages/register/tsconfig.json index 6cac7d0aa..4082f16a5 100644 --- a/packages/register/tsconfig.json +++ b/packages/register/tsconfig.json @@ -1,5 +1,3 @@ { - "extends": "../../tsconfig.json", - "include": ["**/*.cjs", "**/*.js", "**/*.jsx"], - "exclude": ["coverage/", "node_modules/"] + "extends": "../../tsconfig.json" } diff --git a/packages/remark-mdx/package.json b/packages/remark-mdx/package.json index 5aa49a5ba..3836118ac 100644 --- a/packages/remark-mdx/package.json +++ b/packages/remark-mdx/package.json @@ -52,11 +52,9 @@ "unist-util-visit": "^5.0.0" }, "scripts": { - "prepack": "npm run build", - "build": "tsc --build --clean && tsc --build && type-coverage", "test-api": "node test/index.js", "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", - "test": "npm run build && npm run test-coverage" + "test": "npm run test-coverage" }, "xo": { "prettier": true, diff --git a/packages/remark-mdx/tsconfig.json b/packages/remark-mdx/tsconfig.json index 6cac7d0aa..4082f16a5 100644 --- a/packages/remark-mdx/tsconfig.json +++ b/packages/remark-mdx/tsconfig.json @@ -1,5 +1,3 @@ { - "extends": "../../tsconfig.json", - "include": ["**/*.cjs", "**/*.js", "**/*.jsx"], - "exclude": ["coverage/", "node_modules/"] + "extends": "../../tsconfig.json" } diff --git a/packages/rollup/package.json b/packages/rollup/package.json index 29a05ee7f..5c7755854 100644 --- a/packages/rollup/package.json +++ b/packages/rollup/package.json @@ -54,11 +54,9 @@ "rollup": "^4.0.0" }, "scripts": { - "prepack": "npm run build", - "build": "tsc --build --clean && tsc --build && type-coverage", "test-api": "node test/index.js", "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", - "test": "npm run build && npm run test-coverage" + "test": "npm run test-coverage" }, "xo": { "prettier": true, diff --git a/packages/rollup/tsconfig.json b/packages/rollup/tsconfig.json index 6cac7d0aa..4082f16a5 100644 --- a/packages/rollup/tsconfig.json +++ b/packages/rollup/tsconfig.json @@ -1,5 +1,3 @@ { - "extends": "../../tsconfig.json", - "include": ["**/*.cjs", "**/*.js", "**/*.jsx"], - "exclude": ["coverage/", "node_modules/"] + "extends": "../../tsconfig.json" } diff --git a/packages/vue/package.json b/packages/vue/package.json index 41e884d35..9af9b5461 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -50,11 +50,9 @@ "vue": "^3.0.0" }, "scripts": { - "prepack": "npm run build", - "build": "tsc --build --clean && tsc --build && type-coverage", "test-api": "node test/index.js", "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", - "test": "npm run build && npm run test-coverage" + "test": "npm run test-coverage" }, "typeCoverage": { "atLeast": 100, diff --git a/packages/vue/test/index.js b/packages/vue/test/index.js index f4c97b878..fbbfc0829 100644 --- a/packages/vue/test/index.js +++ b/packages/vue/test/index.js @@ -1,5 +1,4 @@ /** - * @typedef {import('mdx/types.js').MDXContent} MDXContent * @typedef {import('mdx/types.js').MDXModule} MDXModule * @typedef {import('vue').Component} AnyComponent */ @@ -10,9 +9,13 @@ import * as babel from '@babel/core' import {compile} from '@mdx-js/mdx' import {run} from '@mdx-js/mdx/lib/run.js' import * as vue from 'vue' -import serverRenderer from '@vue/server-renderer' import {useMDXComponents, MDXProvider} from '../index.js' +// Note: a regular import would be nice but that completely messes up the JSX types. +const name = '@vue/server-renderer' +/** @type {{default: {renderToString: (node: unknown) => string}}} */ +const {default: serverRenderer} = await import(name) + /** * @param {string} value * @returns {Promise} diff --git a/packages/vue/tsconfig.json b/packages/vue/tsconfig.json index 6cac7d0aa..4082f16a5 100644 --- a/packages/vue/tsconfig.json +++ b/packages/vue/tsconfig.json @@ -1,5 +1,3 @@ { - "extends": "../../tsconfig.json", - "include": ["**/*.cjs", "**/*.js", "**/*.jsx"], - "exclude": ["coverage/", "node_modules/"] + "extends": "../../tsconfig.json" } diff --git a/tsconfig.json b/tsconfig.json index d495b8bc3..ae6f02dfc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,16 @@ { "compilerOptions": { "checkJs": true, + "customConditions": ["development"], "declaration": true, "emitDeclarationOnly": true, "exactOptionalPropertyTypes": true, - "forceConsistentCasingInFileNames": true, + "jsx": "preserve", "lib": ["es2021"], "module": "node16", - "newLine": "lf", - "skipLibCheck": true, "strict": true, - "target": "es2021", - "jsx": "preserve" - } + "target": "es2020" + }, + "exclude": ["**/coverage/", "**/node_modules/", "**/public/"], + "include": ["**/*.cjs", "**/*.js", "**/*.jsx"] } diff --git a/website/generate.js b/website/generate.js index 90464d6a7..dddb6911a 100644 --- a/website/generate.js +++ b/website/generate.js @@ -2,6 +2,24 @@ /** * @typedef {import('hast').Properties} Properties * @typedef {import('hast').Root} Root + * @typedef {import('mdx/types.js').MDXContent} MDXContent + * @typedef {Exclude} Meta + * @typedef {Exclude} Matter + * @typedef {import('../docs/_component/sort.js').Item} Item + */ + +/** + * @typedef Author + * @property {string | undefined} [github] + * @property {string} name + * @property {string | undefined} [twitter] + * @property {string | undefined} [url] + * + * @typedef Info + * @property {Array | Author | undefined} [author] + * @property {string | undefined} [authorTwitter] + * @property {Date | undefined} [published] + * @property {Date | undefined} [modified] */ import assert from 'assert' @@ -30,7 +48,6 @@ import {Layout} from '../docs/_component/layout.jsx' import {config} from '../docs/_config.js' import {schema} from './schema-description.js' -/** @type {{format(items: Array): string}} */ const listFormat = new Intl.ListFormat('en') main().catch((error) => { @@ -56,7 +73,9 @@ async function main() { config.ghBlob ) - const {default: Content, info, ...data} = await import(url.href) + /** @type {{default: MDXContent, info?: Info, matter: Matter, meta: Meta, navSortSelf?: number | undefined, navExclude?: boolean | undefined}} */ + const mod = await import(url.href) + const {default: Content, info, ...data} = mod // Handle `author` differently. const {author, ...restInfo} = info || {} const authors = Array.isArray(author) ? author : author ? [author] : [] @@ -71,16 +90,22 @@ async function main() { ? [...authorNames.slice(0, 2), 'others'] : authorNames - if (abbreviatedAuthors.length > 0) { - restInfo.author = listFormat.format(abbreviatedAuthors) + data.meta = { + ...restInfo, + // @ts-expect-error: to do: type authors. + authors, + author: + abbreviatedAuthors.length > 0 + ? listFormat.format(abbreviatedAuthors) + : undefined, + ...data.meta } - data.meta = {authors, ...restInfo, ...data.meta} - // Sanitize the hast description: - if (data.meta.descriptionHast) { + if (data.meta && data.meta.descriptionHast) { data.meta.descriptionHast = unified() .use(rehypeSanitize, schema) + // @ts-expect-error: element is fine. .runSync(data.meta.descriptionHast) } @@ -89,7 +114,8 @@ async function main() { {concurrency: 6} ) - const navTree = {name: '/', data: undefined, children: []} + /** @type {Item} */ + const navTree = {name: '/', data: {}, children: []} let index = -1 while (++index < allInfo.length) { @@ -105,7 +131,7 @@ async function main() { let contextItem = context.children.find((d) => d.name === name) if (!contextItem) { - contextItem = {name, data: undefined, children: []} + contextItem = {name, data: {}, children: []} context.children.push(contextItem) } @@ -132,6 +158,7 @@ async function main() { index = -1 + // To do: remove swallowing? const {error} = console // Swallow some errors that react warns about for client components, diff --git a/website/mdx-config.js b/website/mdx-config.js index 52ba3c1a6..4f0766dea 100644 --- a/website/mdx-config.js +++ b/website/mdx-config.js @@ -1,7 +1,16 @@ /** * @typedef {import('@wooorm/starry-night').Grammar} Grammar + * @typedef {import('estree').Program} Program * @typedef {import('hast').ElementContent} ElementContent * @typedef {import('hast').Root} Root + * @typedef {import('vfile').VFile} VFile + * @typedef {import('@mdx-js/mdx').CompileOptions} CompileOptions + */ + +/** + * @typedef MetaOptions + * @property {Array | null | undefined} [include] + * @property {Array | null | undefined} [exclude] */ import path from 'path' @@ -42,6 +51,7 @@ const reactUrl = pathToFileURL( path.resolve(process.cwd(), 'node_modules', 'react') ) +/** @type {CompileOptions} */ const options = { remarkPlugins: [ remarkGfm, @@ -50,6 +60,7 @@ const options = { remarkFrontmatter, remarkStripBadges, remarkSqueezeParagraphs, + // @ts-expect-error: to do: fix types. [remarkMdxFrontmatter, {name: 'matter'}], [ remarkToc, @@ -117,11 +128,19 @@ function link() { ) } +/** + * @returns + * Transform. + */ function unifiedInferRemoteMeta() { + /** + * @param {Root} _ + * @param {VFile} file + * @returns {undefined} + * Nothing. + */ return (_, file) => { - const meta = /** @type {Record} */ ( - file.data.meta || (file.data.meta = {}) - ) + const meta = file.data.meta || (file.data.meta = {}) const fileUrl = pathToFileURL(file.path) const parts = fileUrl.href.slice(config.git.href.length - 1).split('/') @@ -149,8 +168,25 @@ function unifiedInferRemoteMeta() { } } -function recmaInjectMeta(options = {}) { - const {include, exclude} = options +/** + * @returns + * Transform. + */ + +/** + * @param {MetaOptions | null | undefined} [options] + * Configuration (optional). + * @returns + * Transform. + */ +function recmaInjectMeta(options) { + const {include, exclude} = options || {} + /** + * @param {Program} tree + * @param {VFile} file + * @returns {undefined} + * Nothing. + */ return (tree, file) => { // Find everything that’s defined in the top-level scope. const topScope = analyze(tree).scope.declarations @@ -196,6 +232,7 @@ function recmaInjectMeta(options = {}) { function rehypePrettyCodeBlocks() { const re = /\b([-\w]+)(?:=(?:"([^"]*)"|'([^']*)'|([^"'\s]+)))?/g + /** @type {Record} */ const languageNames = { diff: 'Diff', html: 'HTML', @@ -209,10 +246,13 @@ function rehypePrettyCodeBlocks() { tsx: 'TypeScript' } - /** @param {import('hast').Root} tree */ + /** + * @param {Root} tree + * @returns {undefined} + */ return (tree) => { visit(tree, 'element', (node, index, parent) => { - if (node.tagName !== 'pre') { + if (node.tagName !== 'pre' || !parent || index === undefined) { return } @@ -229,12 +269,15 @@ function rehypePrettyCodeBlocks() { /** @type {Record} */ const metaProps = {} + /** @type {string | undefined} */ + // @ts-expect-error: added by `mdast-util-to-hast` on `code` elements. + const meta = code.data?.meta - if (code.data && code.data.meta) { + if (meta) { let match re.lastIndex = 0 // Reset regex. - while ((match = re.exec(code.data.meta))) { + while ((match = re.exec(meta))) { metaProps[match[1]] = match[2] || match[3] || match[4] || '' } } @@ -244,12 +287,20 @@ function rehypePrettyCodeBlocks() { } const textContent = toText(node) + /** @type {Array} */ const children = [node] - const className = (code.properties && code.properties.className) || [] - const lang = className.find((value) => value.slice(0, 9) === 'language-') + const className = Array.isArray(code.properties.className) + ? code.properties.className + : [] + const lang = className.find( + (value) => String(value).slice(0, 9) === 'language-' + ) + /** @type {Array} */ const footer = [] + /** @type {Array} */ const header = [] - const language = metaProps.language || (lang ? lang.slice(9) : undefined) + const language = + metaProps.language || (lang ? String(lang).slice(9) : undefined) // Not giant. if (textContent.length < 8192 && metaProps.copy !== 'no') { @@ -284,11 +335,11 @@ function rehypePrettyCodeBlocks() { ) } - if (header) { + if (header && header.length > 0) { children.unshift(h('.frame-tab-bar.frame-tab-bar-scroll', header)) } - if (footer) { + if (footer && footer.length > 0) { children.push(...footer) } @@ -332,7 +383,7 @@ function rehypeStarryNight(options) { const starryNight = await starryNightPromise visit(tree, 'element', function (node, index, parent) { - if (!parent || index === null || node.tagName !== 'pre') { + if (!parent || typeof index !== 'number' || node.tagName !== 'pre') { return } diff --git a/website/post.js b/website/post.js index 99b2d8b32..90f4adbb0 100644 --- a/website/post.js +++ b/website/post.js @@ -82,12 +82,14 @@ async function main() { const buf = await fs.readFile(new URL('index.html', url)) const file = await unified() .use(rehypeParse) - .use(() => (tree) => { - const node = select('.body', tree) - assert(node) - return { - type: 'root', - children: node.children + .use(() => { + /** + * @param {import('hast').Root} tree + */ + return (tree) => { + const node = select('.body', tree) + assert(node) + return {type: 'root', children: node.children} } }) .use(rehypeSanitize, { @@ -159,7 +161,8 @@ async function main() { try { stats = await fs.stat(output) } catch (error) { - if (error.code !== 'ENOENT') throw error + const cause = /** @type {NodeJS.ErrnoException} */ (error) + if (cause.code !== 'ENOENT') throw cause } // Don’t regenerate to improve performance. @@ -167,7 +170,9 @@ async function main() { const processor = unified().use(rehypeStringify) const file = new VFile({path: url}) - const tree = await processor.run( + + // To do: use hast instead of unified? + file.value = processor.stringify( u('root', [ // To do: remove `name`. u('doctype', {name: 'html'}), @@ -321,12 +326,9 @@ async function main() { ]) ]) ]) - ]), - file + ]) ) - file.value = processor.stringify(tree) - try { await fs.unlink(output) } catch {} diff --git a/website/prep.js b/website/prep.js index b779b70db..245f30a96 100644 --- a/website/prep.js +++ b/website/prep.js @@ -1,4 +1,8 @@ #!/usr/bin/env node +/** + * @typedef {import('hast').Root} Root + */ + import {promises as fs} from 'fs' import {fileURLToPath} from 'url' import pAll from 'p-all' @@ -55,7 +59,9 @@ async function main() { .use(rehypeMinifyUrl, {from: canonical}) .use(rehypeStringify) const file = new VFile({path: new URL('.' + from, config.output)}) - const tree = await processor.run(buildRedirect(to), file) + const tree = /** @type {Root} */ ( + await processor.run(buildRedirect(to), file) + ) file.value = processor.stringify(tree) if (file.dirname) await fs.mkdir(file.dirname, {recursive: true}) await fs.writeFile(file.path, String(file))