eslint-plugin-markdown icon indicating copy to clipboard operation
eslint-plugin-markdown copied to clipboard

Change Request: Support MDX linting

Open nzakas opened this issue 10 months ago • 3 comments

Environment

ESLint version: HEAD @eslint/markdown version: HEAD Node version: n/a npm version: n/a Operating System: n/a

What problem do you want to solve?

Currently, the Markdown plugin does not formally parse MDX (it just becomes text but doesn't throw an error). Ideally, we could provide smart parsing for MDX so it can be linted just like anything else.

I investigated using https://github.com/syntax-tree/mdast-util-mdx, but it outputs an AST that is difficult to work with. Any JavaScript code produces a Program node (it uses Acorn under the hood), and there can be multiple Program nodes in a single document. This makes the AST difficult to navigate and make sense of.

Further, because actual JavaScript code can be embedded inside of MDX, we'd need to recreate all of the JavaScript-specific rules just to work in MDX. That seems like wasted effort. I don't think the out-of-the-box approach to MDX from mdast works for our case.

What do you think is the correct solution?

I think ultimately what we want is a way to run existing JavaScript rules on an MDX file in addition to MDX-specific rules. The only way I can think to do that using something like a prelint plugin to extract the JavaScript into a separate virtual file to be linted.

In order to do that, I think we'll need to create a custom mdast plugin that extracts the JavaScript code without creating an AST, basically treating it like a code block.

Participation

  • [x] I am willing to submit a pull request for this change.

Additional comments

I'm just documenting this for now as I have other, higher-priority work to complete. I'd like to consider this on the roadmap for this plugin.

nzakas avatar Jan 31 '25 17:01 nzakas

Does it aim to replace https://github.com/mdx-js/eslint-mdx?

JounQin avatar Feb 10 '25 07:02 JounQin

I haven’t really looked into eslint-plugin-mdx, but I am involved with MDX in other places, including the language server. I also haven’t been involved in ESLint plugin development for a while, but I think it just uses ESTree, right?

You can’t treat each Program node as something individual. They interact with each other.

export function someExport() {
  // Undefined variable.
  props
}

{
  // This is fine.
  props.someProp
}

export function someOtherExport() {
  // This is in scope.
  someOther
  // This is also in scope. The compiler adds it.
  MDXContent
}

You have to compile the MDX to some point where the ESM and expressions make sense. In the end it compiles to something where only one Program node exists.

If I would re-implement ESLint MDX support from scratch, I would start investigating if ESLint can work with the AST MDX exposes after compilation. This is just an ESTree, where authored nodes have positional info, but generated nodes do not. If this works, it would also have support for plugins. For example, remark-mdx-frontmatter adds a top-level variable.

---
meta: data
---

{
  // This is fine.
  {frontmatter.meta.data}
}

Another interesting case is rehype-mdx-code-props, which adds support for JSX props on code blocks like this:

```py filename={props.base + '/file.py'}
print('This is a code block')
```

remcohaszing avatar Feb 10 '25 10:02 remcohaszing

You have to compile the MDX to some point where the ESM and expressions make sense. In the end it compiles to something where only one Program node exists.

@remcohaszing thanks, yes, this is what I was implying in my OP. It's what prelint plugins are designed to do: allow you to say "for this file, also consider this virtual file I've created an overlay the results."

nzakas avatar Feb 10 '25 16:02 nzakas

Oops! It looks like we lost track of this issue. What do we want to do here? This issue will auto-close in 7 days without an update.

github-actions[bot] avatar Aug 14 '25 22:08 github-actions[bot]

I guess this is not stale?

karlhorky avatar Aug 17 '25 20:08 karlhorky

Not stale, just getting a nudge from the bot. :smile:

nzakas avatar Aug 26 '25 14:08 nzakas

Oops! It looks like we lost track of this issue. What do we want to do here? This issue will auto-close in 7 days without an update.

github-actions[bot] avatar Sep 25 '25 22:09 github-actions[bot]

Not stale

karlhorky avatar Sep 26 '25 05:09 karlhorky

Oops! It looks like we lost track of this issue. What do we want to do here? This issue will auto-close in 7 days without an update.

github-actions[bot] avatar Oct 27 '25 22:10 github-actions[bot]

Not stale

karlhorky avatar Oct 28 '25 07:10 karlhorky

Oops! It looks like we lost track of this issue. What do we want to do here? This issue will auto-close in 7 days without an update.

github-actions[bot] avatar Nov 28 '25 22:11 github-actions[bot]

Not stale

lishaduck avatar Nov 28 '25 22:11 lishaduck