Repository: facebook/docusaurus
File: packages/docusaurus-mdx-loader/src/remark/admonitions/index.ts (TypeScript)

Code before:
}

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 isAdmonition = keywords.includes(node.name);

        if (!isAdmonition) {
          return;
        }

        const {directiveLabel, contentNodes} = parseDirective(node);

        const textOnlyTitle =
          node.attributes?.title ??
          (directiveLabel ? getTextOnlyTitle(directiveLabel) : undefined);

        // Convert 'class' attribute to 'className' for React compatibility
        const attributes = node.attributes
          ? Object.fromEntries(
              Object.entries(node.attributes).map(([key, value]) => [
                key === 'class' ? 'className' : key,
                value,
              ]),
            )
          : {};
        // 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
        node.data = {
          hName: 'admonition',
          hProperties: {
            ...(textOnlyTitle && {title: textOnlyTitle}),
            ...attributes,
            type: node.name,
          },
        };
        node.children = contentNodes;

        // TODO legacy MDX v1 <mdxAdmonitionTitle> workaround
        // v1: not possible to inject complex JSX elements as props
        // v2: now possible: use a mdxJsxFlowElement element

Review comment (suggestion):
This is likely not the only conversion we would need to do.

I'd prefer if we only support id/className shortcuts for now instead of allowing arbitrary attributes

Code after:
}

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 isAdmonition = keywords.includes(node.name);

        if (!isAdmonition) {
          return;
        }

        const {directiveLabel, contentNodes} = parseDirective(node);

        const textOnlyTitle =
          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
        node.data = {
          hName: 'admonition',
          hProperties: {
            ...(textOnlyTitle && {title: textOnlyTitle}),
            ...(node.attributes?.class && {className: node.attributes.class}),
            ...(node.attributes?.id && {id: node.attributes.id}),
            type: node.name,
          },
        };
        node.children = contentNodes;

        // TODO legacy MDX v1 <mdxAdmonitionTitle> workaround
        // v1: not possible to inject complex JSX elements as props
        // v2: now possible: use a mdxJsxFlowElement element
        if (directiveLabel && !textOnlyTitle) {
          const complexTitleNode = {
            type: 'mdxAdmonitionTitle',
            data: {
              hName: 'mdxAdmonitionTitle',
              hProperties: {},
            },
            children: directiveLabel.children,