Skip to content

Commit

Permalink
refactor(mdx-loader): streamline typescript usage for remark plugin t…
Browse files Browse the repository at this point in the history
…ypes (#10651)
  • Loading branch information
lebalz authored Nov 7, 2024
1 parent e32aa60 commit bdf55ed
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 92 deletions.
33 changes: 13 additions & 20 deletions packages/docusaurus-mdx-loader/src/remark/admonitions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down Expand Up @@ -85,42 +79,41 @@ 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) => {
const {visit} = await import('unist-util-visit');

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
Expand All @@ -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);
}
}
});
Expand Down
32 changes: 13 additions & 19 deletions packages/docusaurus-mdx-loader/src/remark/contentTitle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -41,35 +34,36 @@ 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;

return async (root, vfile) => {
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;
}
}
Expand Down
7 changes: 3 additions & 4 deletions packages/docusaurus-mdx-loader/src/remark/details/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}
Expand Down
7 changes: 3 additions & 4 deletions packages/docusaurus-mdx-loader/src/remark/head/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}
Expand Down
14 changes: 8 additions & 6 deletions packages/docusaurus-mdx-loader/src/remark/headings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -77,4 +77,6 @@ export default function plugin({
properties.id = id;
});
};
}
};

export default plugin;
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand All @@ -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 || {};
Expand All @@ -31,4 +31,6 @@ export default function codeCompatPlugin(this: Processor): Transformer {
node.data.hProperties.live = node.meta?.split(' ').includes('live');
});
};
}
};

export default plugin;
6 changes: 3 additions & 3 deletions packages/docusaurus-mdx-loader/src/remark/mermaid/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
/**
Expand All @@ -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 {
Expand All @@ -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');
Expand Down
10 changes: 7 additions & 3 deletions packages/docusaurus-mdx-loader/src/remark/toc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -184,4 +186,6 @@ export default function plugin(options: PluginOptions = {}): Transformer<Root> {
}),
);
};
}
};

export default plugin;
17 changes: 12 additions & 5 deletions packages/docusaurus-mdx-loader/src/remark/transformImage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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');

Expand All @@ -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;
Loading

0 comments on commit bdf55ed

Please sign in to comment.