wooorm / xdm

Just a *really* good MDX compiler. No runtime. With esbuild, Rollup, and webpack plugins
http://wooorm.com/xdm/
MIT License
595 stars 18 forks source link

Adding a mdxJsxAttributeValueExpression to a JSX Node has no effect #99

Closed CyriacBr closed 2 years ago

CyriacBr commented 2 years ago

:wave: I am trying to add an evaluated prop to an existing Node but can't figure out the right way to do it. I tried to add a mdxJsxAttributeValueExpression attribute, but it does not appear once XDM compiles.

Reproduction:

import { compile } from 'xdm';
import { Processor } from 'xdm/lib/core';
import { visit } from 'unist-util-visit';

const doc = `

## Test

<MyComp>
  fooBar
</MyComp>
`;

async function main() {
  const compiled = await compile(doc, {
    jsx: true,
    rehypePlugins: [rehypePluginA],
  });
  console.log(String(compiled));
}

main();

function rehypePluginA(this: Processor) {
  return function transform(tree: Node) {
    visit(tree, (node: Node, index: number, parent: Node) => {
      if (node.name === 'MyComp') {
        node.attributes = [
          ...(node.attributes || []),
          {
            type: 'mdxJsxAttribute',
            name: 'prop1',
            value: 'test',
          },
          {
            type: 'mdxJsxAttribute',
            name: 'prop2',
            value: {
              type: 'mdxJsxAttributeValueExpression',
              value: '`test`',
            },
          },
        ];
      }
    });
  };
}

XDM output:

/*@jsxRuntime automatic @jsxImportSource react*/
function MDXContent(props = {}) {
  const {wrapper: MDXLayout} = props.components || ({});
  return MDXLayout ? <MDXLayout {...props}><_createMdxContent /></MDXLayout> : _createMdxContent();
  function _createMdxContent() {
    const _components = Object.assign({
      h2: "h2",
      p: "p"
    }, props.components), {MyComp} = _components;
    if (!MyComp) _missingMdxReference("MyComp", true);
    return <><_components.h2>{"Test"}</_components.h2>{"\n"}<MyComp prop1="test" prop2={}><_components.p>{"fooBar"}</_components.p></MyComp></>;
  }
}
export default MDXContent;
function _missingMdxReference(id, component) {
  throw new Error("Expected " + (component ? "component" : "object") + " `" + id + "` to be defined: you likely forgot to import, pass, or provide it.");
}

As you can see here:

<MyComp prop1="test" prop2={}><_components.p>{"fooBar"}</_components.p></MyComp>

The mdxJsxAttributeValueExpression attribute is not processed.

Any help would be appreciated.

ElMassimo commented 2 years ago

@CyriacBr The value won't be used when stringifying the result to JSX, which relies on the more granular estree definition.

Provide a data.estree in the expression node describing the expression that should be generated (for example, a test literal).

wooorm commented 2 years ago

Yep, as @ElMassimo describes, the string version (value) is ignored when dealing with JavaScript. A subtree node.data.estree is used instead, which is a whole Program node

CyriacBr commented 2 years ago

@ElMassimo Thank you both, that was indeed the missing part.