refactor(mdx-loader): streamline typescript usage for remark plugin types (#10651)

This commit is contained in:
Balthasar Hofer 2024-11-07 17:42:32 +01:00 committed by GitHub
parent e32aa605ca
commit bdf55eda22
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 92 additions and 92 deletions

View file

@ -5,17 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer, Processor} from 'unified';
import type {Transformer, Plugin} from 'unified';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {ContainerDirective} from 'mdast-util-directive';
import type {Parent} from 'mdast';
// TODO as of April 2023, no way to import/re-export this ESM type easily :/
// This might change soon, likely after TS 5.2
// See https://github.com/microsoft/TypeScript/issues/49721#issuecomment-1517839391
// import type {Plugin} from 'unified';
type Plugin = any; // TODO fix this asap
import type {Parent, Root} from 'mdast';
export type AdmonitionOptions = {
keywords: string[];
@ -85,10 +79,10 @@ function getTextOnlyTitle(directiveLabel: DirectiveLabel): string | undefined {
: undefined;
}
const plugin: Plugin = function plugin(
this: Processor,
optionsInput: Partial<AdmonitionOptions> = {},
): Transformer {
const plugin: Plugin<Partial<AdmonitionOptions>[], Root> = function plugin(
this,
optionsInput = {},
): Transformer<Root> {
const {keywords} = normalizeAdmonitionOptions(optionsInput);
return async (root) => {
@ -96,31 +90,30 @@ const plugin: Plugin = function plugin(
visit(root, (node) => {
if (node.type === 'containerDirective') {
const directive = node as ContainerDirective;
const isAdmonition = keywords.includes(directive.name);
const isAdmonition = keywords.includes(node.name);
if (!isAdmonition) {
return;
}
const {directiveLabel, contentNodes} = parseDirective(directive);
const {directiveLabel, contentNodes} = parseDirective(node);
const textOnlyTitle =
directive.attributes?.title ??
node.attributes?.title ??
(directiveLabel ? getTextOnlyTitle(directiveLabel) : undefined);
// Transform the mdast directive node to a hast admonition node
// See https://github.com/syntax-tree/mdast-util-to-hast#fields-on-nodes
// TODO in MDX v2 we should transform the whole directive to
// mdxJsxFlowElement instead of using hast
directive.data = {
node.data = {
hName: 'admonition',
hProperties: {
...(textOnlyTitle && {title: textOnlyTitle}),
type: directive.name,
type: node.name,
},
};
directive.children = contentNodes;
node.children = contentNodes;
// TODO legacy MDX v1 <mdxAdmonitionTitle> workaround
// v1: not possible to inject complex JSX elements as props
@ -135,7 +128,7 @@ const plugin: Plugin = function plugin(
children: directiveLabel.children,
};
// @ts-expect-error: invented node type
directive.children.unshift(complexTitleNode);
node.children.unshift(complexTitleNode);
}
}
});

View file

@ -4,20 +4,13 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified';
import type {Heading, Parent} from 'mdast';
import type {Transformer, Plugin} from 'unified';
import type {Heading, Parent, Root} from 'mdast';
// @ts-expect-error: ES support...
import type {MdxJsxFlowElement} from 'mdast-util-mdx';
// TODO as of April 2023, no way to import/re-export this ESM type easily :/
// TODO upgrade to TS 5.3
// See https://github.com/microsoft/TypeScript/issues/49721#issuecomment-1517839391
// import type {Plugin} from 'unified';
type Plugin = any; // TODO fix this asap
interface PluginOptions {
removeContentTitle?: boolean;
}
@ -41,9 +34,9 @@ function wrapHeadingInJsxHeader(
* This is exposed as "data.contentTitle" to the processed vfile
* Also gives the ability to strip that content title (used for the blog plugin)
*/
const plugin: Plugin = function plugin(
options: PluginOptions = {},
): Transformer {
const plugin: Plugin<PluginOptions[], Root> = function plugin(
options = {},
): Transformer<Root> {
// content title is
const removeContentTitle = options.removeContentTitle ?? false;
@ -51,25 +44,26 @@ const plugin: Plugin = function plugin(
const {toString} = await import('mdast-util-to-string');
const {visit, EXIT} = await import('unist-util-visit');
visit(root, ['heading', 'thematicBreak'], (node, index, parent) => {
if (!parent || index === undefined) {
return undefined;
}
if (node.type === 'heading') {
const headingNode = node as Heading;
// console.log('headingNode:', headingNode);
if (headingNode.depth === 1) {
vfile.data.contentTitle = toString(headingNode);
if (node.depth === 1) {
vfile.data.contentTitle = toString(node);
if (removeContentTitle) {
// @ts-expect-error: TODO how to fix?
parent!.children.splice(index, 1);
parent.children.splice(index, 1);
} else {
// TODO in the future it might be better to export contentTitle as
// as JSX node to keep this logic a theme concern?
// See https://github.com/facebook/docusaurus/pull/10335#issuecomment-2250187371
wrapHeadingInJsxHeader(headingNode, parent, index!);
wrapHeadingInJsxHeader(node, parent, index);
}
return EXIT; // We only handle the very first heading
}
// We only handle contentTitle if it's the very first heading found
if (headingNode.depth >= 1) {
if (node.depth >= 1) {
return EXIT;
}
}

View file

@ -8,15 +8,14 @@
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified';
// @ts-expect-error: ES support...
import type {MdxJsxFlowElement} from 'mdast-util-mdx';
import type {Root} from 'mdast';
// Transform <details> to <Details>
// MDX 2 doesn't allow to substitute html elements with the provider anymore
export default function plugin(): Transformer {
export default function plugin(): Transformer<Root> {
return async (root) => {
const {visit} = await import('unist-util-visit');
visit(root, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => {
visit(root, 'mdxJsxFlowElement', (node) => {
if (node.name === 'details') {
node.name = 'Details';
}

View file

@ -8,15 +8,14 @@
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {MdxJsxFlowElement} from 'mdast-util-mdx';
import type {Root} from 'mdast';
// Transform <head> to <Head>
// MDX 2 doesn't allow to substitute html elements with the provider anymore
export default function plugin(): Transformer {
export default function plugin(): Transformer<Root> {
return async (root) => {
const {visit} = await import('unist-util-visit');
visit(root, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => {
visit(root, 'mdxJsxFlowElement', (node) => {
if (node.name === 'head') {
node.name = 'Head';
}

View file

@ -9,22 +9,22 @@
import {parseMarkdownHeadingId, createSlugger} from '@docusaurus/utils';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified';
import type {Heading, Text} from 'mdast';
import type {Plugin, Transformer} from 'unified';
import type {Root, Text} from 'mdast';
export interface PluginOptions {
anchorsMaintainCase: boolean;
}
export default function plugin({
const plugin: Plugin<PluginOptions[], Root> = function plugin({
anchorsMaintainCase,
}: PluginOptions): Transformer {
}): Transformer<Root> {
return async (root) => {
const {toString} = await import('mdast-util-to-string');
const {visit} = await import('unist-util-visit');
const slugs = createSlugger();
visit(root, 'heading', (headingNode: Heading) => {
visit(root, 'heading', (headingNode) => {
const data = headingNode.data ?? (headingNode.data = {});
const properties = (data.hProperties || (data.hProperties = {})) as {
id: string;
@ -77,4 +77,6 @@ export default function plugin({
properties.id = id;
});
};
}
};
export default plugin;

View file

@ -6,8 +6,8 @@
*/
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer, Processor} from 'unified';
import type {Code} from 'mdast';
import type {Transformer, Plugin} from 'unified';
import type {Root} from 'mdast';
// Solution inspired by https://github.com/pomber/docusaurus-mdx-2/blob/main/packages/mdx-loader/src/remark/codeCompat/index.ts
// TODO after MDX 2 we probably don't need this - remove soon?
@ -16,11 +16,11 @@ import type {Code} from 'mdast';
// To make theme-classic/src/theme/MDXComponents/Pre work
// we need to fill two properties that mdx v2 doesn't provide anymore
export default function codeCompatPlugin(this: Processor): Transformer {
const plugin: Plugin<unknown[], Root> = function plugin(): Transformer<Root> {
return async (root) => {
const {visit} = await import('unist-util-visit');
visit(root, 'code', (node: Code) => {
visit(root, 'code', (node) => {
node.data = node.data || {};
node.data.hProperties = node.data.hProperties || {};
@ -31,4 +31,6 @@ export default function codeCompatPlugin(this: Processor): Transformer {
node.data.hProperties.live = node.meta?.split(' ').includes('live');
});
};
}
};
export default plugin;

View file

@ -9,17 +9,17 @@ import {transformNode} from '../utils';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified';
import type {Code} from 'mdast';
import type {Root} from 'mdast';
// TODO: this plugin shouldn't be in the core MDX loader
// After we allow plugins to provide Remark/Rehype plugins (see
// https://github.com/facebook/docusaurus/issues/6370), this should be provided
// by theme-mermaid itself
export default function plugin(): Transformer {
export default function plugin(): Transformer<Root> {
return async (root) => {
const {visit} = await import('unist-util-visit');
visit(root, 'code', (node: Code) => {
visit(root, 'code', (node) => {
if (node.lang === 'mermaid') {
// TODO migrate to mdxJsxFlowElement? cf admonitions
transformNode(node, {

View file

@ -12,8 +12,8 @@ import {
} from '@docusaurus/utils';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified';
import type {Definition, Link} from 'mdast';
import type {Plugin, Transformer} from 'unified';
import type {Definition, Link, Root} from 'mdast';
type ResolveMarkdownLinkParams = {
/**
@ -35,12 +35,6 @@ export interface PluginOptions {
resolveMarkdownLink: ResolveMarkdownLink;
}
// TODO as of April 2023, no way to import/re-export this ESM type easily :/
// TODO upgrade to TS 5.3
// See https://github.com/microsoft/TypeScript/issues/49721#issuecomment-1517839391
// import type {Plugin} from 'unified';
type Plugin = any; // TODO fix this asap
const HAS_MARKDOWN_EXTENSION = /\.mdx?$/i;
function parseMarkdownLinkURLPath(link: string): URLPath | null {
@ -64,7 +58,9 @@ function parseMarkdownLinkURLPath(link: string): URLPath | null {
* This is exposed as "data.contentTitle" to the processed vfile
* Also gives the ability to strip that content title (used for the blog plugin)
*/
const plugin: Plugin = function plugin(options: PluginOptions): Transformer {
const plugin: Plugin<PluginOptions[], Root> = function plugin(
options,
): Transformer<Root> {
const {resolveMarkdownLink} = options;
return async (root, file) => {
const {visit} = await import('unist-util-visit');

View file

@ -15,7 +15,7 @@ import {
} from './utils';
import type {Heading, Root} from 'mdast';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified';
import type {Plugin, Transformer} from 'unified';
import type {
MdxjsEsm,
MdxJsxFlowElement,
@ -155,7 +155,9 @@ async function collectTOCItems({
}
}
export default function plugin(options: PluginOptions = {}): Transformer<Root> {
const plugin: Plugin<PluginOptions[], Root> = function plugin(
options = {},
): Transformer<Root> {
const tocExportName = options.name || 'toc';
return async (root) => {
@ -184,4 +186,6 @@ export default function plugin(options: PluginOptions = {}): Transformer<Root> {
}),
);
};
}
};
export default plugin;

View file

@ -21,10 +21,10 @@ import sizeOf from 'image-size';
import logger from '@docusaurus/logger';
import {assetRequireAttributeValue, transformNode} from '../utils';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified';
import type {Plugin, Transformer} from 'unified';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {MdxJsxTextElement} from 'mdast-util-mdx';
import type {Image} from 'mdast';
import type {Image, Root} from 'mdast';
import type {Parent} from 'unist';
type PluginOptions = {
@ -186,7 +186,9 @@ async function processImageNode(target: Target, context: Context) {
await toImageRequireNode(target, imagePath, context);
}
export default function plugin(options: PluginOptions): Transformer {
const plugin: Plugin<PluginOptions[], Root> = function plugin(
options,
): Transformer<Root> {
return async (root, vfile) => {
const {visit} = await import('unist-util-visit');
@ -201,9 +203,14 @@ export default function plugin(options: PluginOptions): Transformer {
};
const promises: Promise<void>[] = [];
visit(root, 'image', (node: Image, index, parent) => {
visit(root, 'image', (node, index, parent) => {
if (!parent || index === undefined) {
return;
}
promises.push(processImageNode([node, index, parent!], context));
});
await Promise.all(promises);
};
}
};
export default plugin;

View file

@ -18,11 +18,11 @@ import {
import escapeHtml from 'escape-html';
import {assetRequireAttributeValue, transformNode} from '../utils';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer} from 'unified';
import type {Plugin, Transformer} from 'unified';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {MdxJsxTextElement} from 'mdast-util-mdx';
import type {Parent} from 'unist';
import type {Link, Literal} from 'mdast';
import type {Link, Literal, Root} from 'mdast';
type PluginOptions = {
staticDirs: string[];
@ -199,7 +199,9 @@ async function processLinkNode(target: Target, context: Context) {
}
}
export default function plugin(options: PluginOptions): Transformer {
const plugin: Plugin<PluginOptions[], Root> = function plugin(
options,
): Transformer<Root> {
return async (root, vfile) => {
const {visit} = await import('unist-util-visit');
@ -214,9 +216,14 @@ export default function plugin(options: PluginOptions): Transformer {
};
const promises: Promise<void>[] = [];
visit(root, 'link', (node: Link, index, parent) => {
promises.push(processLinkNode([node, index, parent!], context));
visit(root, 'link', (node, index, parent) => {
if (!parent || index === undefined) {
return;
}
promises.push(processLinkNode([node, index, parent], context));
});
await Promise.all(promises);
};
}
};
export default plugin;

View file

@ -9,21 +9,16 @@ import process from 'process';
import logger from '@docusaurus/logger';
import {posixPath} from '@docusaurus/utils';
import {transformNode} from '../utils';
import type {Root} from 'mdast';
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
import type {Transformer, Processor, Parent} from 'unified';
import type {Transformer, Processor, Parent, Plugin} from 'unified';
import type {
Directives,
TextDirective,
// @ts-expect-error: TODO see https://github.com/microsoft/TypeScript/issues/49721
} from 'mdast-util-directive';
// TODO as of April 2023, no way to import/re-export this ESM type easily :/
// This might change soon, likely after TS 5.2
// See https://github.com/microsoft/TypeScript/issues/49721#issuecomment-1517839391
// import type {Plugin} from 'unified';
type Plugin = any; // TODO fix this asap
type DirectiveType = Directives['type'];
const directiveTypes: DirectiveType[] = [
@ -130,7 +125,9 @@ function isUnusedDirective(directive: Directives) {
return !directive.data;
}
const plugin: Plugin = function plugin(this: Processor): Transformer {
const plugin: Plugin<unknown[], Root> = function plugin(
this: Processor,
): Transformer<Root> {
return async (tree, file) => {
const {visit} = await import('unist-util-visit');