yeonjuan / html-eslint

ESLint plugin for linting HTML
https://html-eslint.org
MIT License
148 stars 28 forks source link

Plugin doesn't work with Typescript+React project #187

Open Maweypeyyu opened 3 months ago

Maweypeyyu commented 3 months ago

I have the following .eslintrc.cjs file:

module.exports = {
  root: true,
  env: { browser: true, es2020: true },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended-type-checked',
    'plugin:@typescript-eslint/stylistic-type-checked',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:react/jsx-runtime',
    'prettier',
  ],
  ignorePatterns: ['dist', '.eslintrc.cjs'],
  parser: '@typescript-eslint/parser',
  plugins: ['react-refresh', 'prettier', 'html' /* scripts in html */, '@html-eslint' /* actual html */],
  rules: {
    'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
    'prettier/prettier': 'error',
  },
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    project: ['./tsconfig.json', './tsconfig.node.json'],
    tsconfigRootDir: __dirname,
  },
  settings: {
    react: {
      createClass: 'createReactClass', // Regex for Component Factory to use,
      // default to "createReactClass"
      pragma: 'React', // Pragma to use, default to "React"
      fragment: 'Fragment', // Fragment to use (may be a property of <pragma>), default to "Fragment"
      version: 'detect', // React version. "detect" automatically picks the version you have installed.
      // You can also use `16.0`, `16.3`, etc, if you want to override the detected value.
      // It will default to "latest" and warn if missing, and to "detect" in the future
      flowVersion: '0.53', // Flow version
    },
    propWrapperFunctions: [
      // The names of any function used to wrap propTypes, e.g. `forbidExtraProps`. If this isn't set, any propTypes wrapped in a function will be skipped.
      'forbidExtraProps',
      { property: 'freeze', object: 'Object' },
      { property: 'myFavoriteWrapper' },
      // for rules that check exact prop wrappers
      { property: 'forbidExtraProps', exact: true },
    ],
    componentWrapperFunctions: [
      // The name of any function used to wrap components, e.g. Mobx `observer` function. If this isn't set, components wrapped by these functions will be skipped.
      'observer', // `property`
      { property: 'styled' }, // `object` is optional
      { property: 'observer', object: 'Mobx' },
      { property: 'observer', object: '<pragma>' }, // sets `object` to whatever value `settings.react.pragma` is set to
    ],
  },
  overrides: [
    {
      files: ['*.html'],
      parser: '@html-eslint/parser',
      extends: ['plugin:@html-eslint/recommended'],
    },
  ],
  // also tried this, no change:
  // overrides: [
  //   {
  //     files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
  //     parser: '@typescript-eslint/parser',
  //     parserOptions: {
  //       project: ['./tsconfig.json', './tsconfig.node.json'],
  //     },
  //   },
  //   {
  //     files: ['*.html'],
  //     parser: '@html-eslint/parser',
  //     parserOptions: {
  //       project: false, // Disable type information for HTML files
  //     },
  //   },
  // ],
};

With these package versions:

    "@html-eslint/eslint-plugin": "^0.24.1",
    "@html-eslint/parser": "^0.24.1",
    "@types/node": "^20.12.7",
    "@types/react": "^18.2.66",
    "@types/react-dom": "^18.2.22",
    "@typescript-eslint/eslint-plugin": "^7.2.0",
    "@typescript-eslint/parser": "^7.2.0",
    "@vitejs/plugin-react-swc": "^3.5.0",
    "eslint": "^8.57.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-html": "^8.1.0",
    "eslint-plugin-prettier": "^5.1.3",
    "eslint-plugin-react": "^7.34.1",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.6",
    "prettier": "^3.2.5",
    "prettier-eslint": "^16.3.0",
    "typescript": "^5.2.2",
    "vite": "^5.2.0"

As soon as I try to use html-eslint in my project, I get the following error in VSCode from the eslint language server (or via eslint CLI command):

[Error - 6:45:39 PM] An unexpected error occurred:
[Error - 6:45:39 PM] Error: Error while loading rule '@typescript-eslint/consistent-type-assertions': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.
Parser: C:\Users\dev\Development\web-ui\node_modules\@html-eslint\parser\lib\index.js
Note: detected a parser other than @typescript-eslint/parser. Make sure the parser is configured to forward "parserOptions.project" to @typescript-eslint/parser.
Occurred while linting C:\Users\dev\Development\web-ui\403.html
    at throwError (C:\Users\dev\Development\web-ui\node_modules\@typescript-eslint\utils\dist\eslint-utils\getParserServices.js:40:11)
    at getParserServices (C:\Users\dev\Development\web-ui\node_modules\@typescript-eslint\utils\dist\eslint-utils\getParserServices.js:20:9)
    at create (C:\Users\dev\Development\web-ui\node_modules\@typescript-eslint\eslint-plugin\dist\rules\consistent-type-assertions.js:88:61)
    at Object.create (C:\Users\dev\Development\web-ui\node_modules\@typescript-eslint\utils\dist\eslint-utils\RuleCreator.js:38:20)
    at createRuleListeners (C:\Users\dev\Development\web-ui\node_modules\eslint\lib\linter\linter.js:895:21)
    at C:\Users\dev\Development\web-ui\node_modules\eslint\lib\linter\linter.js:1066:110
    at Array.forEach (<anonymous>)
    at runRules (C:\Users\dev\Development\web-ui\node_modules\eslint\lib\linter\linter.js:1003:34)
    at Linter._verifyWithoutProcessors (C:\Users\dev\Development\web-ui\node_modules\eslint\lib\linter\linter.js:1355:31)
    at callOriginalVerify (C:\Users\dev\Development\web-ui\node_modules\eslint-plugin-html\src\verifyPatch.js:14:14)

The error occurs in any files I tested: tsx, ts, html.

Do you see anything wrong with my config? Is there a known incompatibility? Is it a version issue? I tried multiple different overrides (see one above), but nothing changed. Any pointers would be greatly appreciated!

yeonjuan commented 3 months ago

hi @Maweypeyyu Try this :)

module.exports = {
  root: true,
  env: { browser: true, es2020: true },
  ignorePatterns: ['dist', '.eslintrc.cjs'],
  plugins: ['react-refresh', 'prettier', 'html', '@html-eslint', '@typescript-eslint'],
  overrides: [
    {
      files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
      parser: '@typescript-eslint/parser',
      extends: [
        'eslint:recommended',
        'plugin:@typescript-eslint/recommended-type-checked',
        'plugin:@typescript-eslint/stylistic-type-checked',
        'plugin:react/recommended',
        'plugin:react-hooks/recommended',
        'plugin:react/jsx-runtime',
        'prettier',
      ],

      parser: '@typescript-eslint/parser',
      rules: {
        'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
        'prettier/prettier': 'error',
      },
      parserOptions: {
        ecmaVersion: 'latest',
        sourceType: 'module',
        project: ['./tsconfig.json', './tsconfig.node.json'],
        tsconfigRootDir: __dirname,
      },
      settings: {
        react: {
          createClass: 'createReactClass', // Regex for Component Factory to use,
          // default to "createReactClass"
          pragma: 'React', // Pragma to use, default to "React"
          fragment: 'Fragment', // Fragment to use (may be a property of <pragma>), default to "Fragment"
          version: 'detect', // React version. "detect" automatically picks the version you have installed.
          // You can also use `16.0`, `16.3`, etc, if you want to override the detected value.
          // It will default to "latest" and warn if missing, and to "detect" in the future
          flowVersion: '0.53', // Flow version
        },
        propWrapperFunctions: [
          // The names of any function used to wrap propTypes, e.g. `forbidExtraProps`. If this isn't set, any propTypes wrapped in a function will be skipped.
          'forbidExtraProps',
          { property: 'freeze', object: 'Object' },
          { property: 'myFavoriteWrapper' },
          // for rules that check exact prop wrappers
          { property: 'forbidExtraProps', exact: true },
        ],
        componentWrapperFunctions: [
          // The name of any function used to wrap components, e.g. Mobx `observer` function. If this isn't set, components wrapped by these functions will be skipped.
          'observer', // `property`
          { property: 'styled' }, // `object` is optional
          { property: 'observer', object: 'Mobx' },
          { property: 'observer', object: '<pragma>' }, // sets `object` to whatever value `settings.react.pragma` is set to
        ],
      },
    },
    {
      files: ['**/*.html'],
      extends: ['plugin:@html-eslint/recommended'],
      parser: '@html-eslint/parser',
      parserOptions: {
        project: false, // Disable type information for HTML files
      },
    },
  ],
};