eslint / eslint-plugin-markdown

Lint JavaScript code blocks in Markdown documents

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

eslint-plugin-markdown v2 conflict with prettier

bmish opened this issue · comments

After upgrading to eslint-plugin-markdown v2, I'm seeing a crash that seems to be related to prettier. The crash appears to only happen with code blocks marked as having js syntax in documentation files, and not with javascript syntax code blocks (I thought these names were equivalent...why is the behavior different?).

Here is my minimal reproduction:

.eslintrc.js

'use strict';

module.exports = {
  root: true,
  extends: ['plugin:prettier/recommended', 'plugin:markdown/recommended'],
};

package.json

{
    "devDependencies": {
        "eslint": "^7.20.0",
        "eslint-config-prettier": "^8.1.0",
        "eslint-plugin-markdown": "^2.0.0",
        "eslint-plugin-prettier": "^3.3.1",
        "prettier": "^2.1.1"
    }
}

foo.md

# Title

```js
var x = 123;
```fake-name-to-avoid-breaking-rendering-of-this-block
my-package:0 yarn eslint foo.md 
yarn run v1.22.10
$ my-package/node_modules/.bin/eslint foo.md

Oops! Something went wrong! :(

ESLint: 7.20.0

Error: ENOTDIR: not a directory, stat 'my-package/foo.md/0_0.js'
Occurred while linting my-package/foo.md/0_0.js:1
    at Object.statSync (node:fs:1127:3)
    at isTypeSync (my-package/node_modules/prettier/third-party.js:9748:46)
    at getDirectorySync (my-package/node_modules/prettier/third-party.js:9802:62)
    at ExplorerSync.searchSync (my-package/node_modules/prettier/third-party.js:9950:66)
    at _resolveConfig (my-package/node_modules/prettier/index.js:25592:50)
    at Function.resolveConfig.sync (my-package/node_modules/prettier/index.js:25621:42)
    at Program (my-package/node_modules/eslint-plugin-prettier/eslint-plugin-prettier.js:167:40)
    at my-package/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (my-package/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

When processors extract code from non-JS files, they create virtual filenames for each code block. In your example, the extracted source code var x = 123; gets the virtual filename my-package/foo.md/0_0.js that you see in the stack trace. If I had to guess, the Prettier plugin is trying to load my-package/foo.md/0_0.js as if it were a real file, which obviously isn't going to go well. Could you configure Prettier to ignore files with **/*.md/** in the file path?

That's also likely why code blocks tagged with javascript instead of js are different: it's looking for a .js extension but the code block's virtual filename is my-package/foo.md/0_0.javascript.

Thanks for the explanation!

I filed a separate bug because I noticed eslint-plugin-markdown v2 isn't linting my javascript code samples at all: #176

As for disabling prettier as you suggested, I tried doing so with the below override, but it results in prettier no longer linting my JS code samples at all. One of the primary reasons I use eslint-plugin-markdown is so that I can have prettier apply to my documentation code samples, so turning prettier off like this is a non-starter for me, and I imagine many others are using eslint-plugin-markdown and prettier together as well. I also hope that the solution to this new issue in v2 will not involve exposing internal implementation details like virtual filenames to consumers.

// .eslintrc.js
...
overrides: [
    {
        files: ['**/*.md/**'],
        rules: {
            'prettier/prettier': 'off',
        },
    },
],

All right, after some debugging, this is happening because the Prettier plugin isn't handling the virtual filenames that ESLint generates for code blocks from processors. I've opened prettier/eslint-plugin-prettier#393 over there to see what they think. It's possible that the fix there may be blocked on something like eslint/eslint#11989, though some plugins have come up with solutions that don't require that.

I'm closing this issue because there's nothing that can be done here, but I'll be monitoring those other discussions.