vuejs / vue-eslint-parser

The ESLint custom parser for `.vue` files.
MIT License
435 stars 74 forks source link

vue-eslint-parser and typescript-eslint problems #104

Open yoyo930021 opened 3 years ago

yoyo930021 commented 3 years ago

Reason: https://github.com/typescript-eslint/typescript-eslint/issues/2865#issuecomment-742942987

Hi, I'm using vue-eslint-parser and typescript-eslint in company project. At the same time, I also help to contribute typescript-eslint project for fixing vue problems.

This problems are only happens when using type rules in typescript-eslint. You need to add parserOptions.project in project to enable it. https://github.com/typescript-eslint/typescript-eslint/blob/master/docs/getting-started/linting/TYPED_LINTING.md

There are two main issues:

performance issue

issues: https://github.com/vuejs/vue-eslint-parser/issues/65, https://github.com/typescript-eslint/typescript-eslint/issues/1180

The problem is that vue-eslint-parser is designed with the AST not type information. The vue-eslint-parser will split code frame from template to @typescript-eslint/parser. https://github.com/typescript-eslint/typescript-eslint/issues/1180#issuecomment-552297706 Typescript program need to parse full project for generate type information. When parsing code frame, typescript program will reparse file AST and rebuild type information in project. The vue-eslint-parser will pass more code frames and same file path in single Vue SFC.

Possible solutions:

  1. Ignore parserOptions.project to close get type information when pass code frame.
  2. Try to use ESLint processors, like Svelte. Ref: https://github.com/typescript-eslint/typescript-eslint/issues/1180#issuecomment-553007193

[no-unsafe-*] rules

issues: https://github.com/typescript-eslint/typescript-eslint/issues/2865

Strictly speaking, it isn't a problem with this project. The typescript program can't parse Vue SFC file directly.

You may think it's strange, but why is it working now? Because @typescript-eslint/parser will prioritize the content delivered from ESLint. Typescript program will update by ESLint content not same as typescript program read. But this problem is happens when ESLint not send file content and content from typescript program reading. Example:

// App.vue
import HelloWorld from './components/HelloWorld.vue' // <- typescript program can't parse it. because it will read including template and style.

export default {
  name: 'App',
  components: {
    HelloWorld // <- so type information is `any`
  }
}

This problem will also have in <script setup> RFC.

Possible solutions:

  1. Override HelloWorld.vue content.
  2. Mock a HelloWorld.vue.ts file.

Maybe we need a common project for hacking typescript program.

Thanks for watching. Have a good day!

Stanzilla commented 1 month ago

@Stanzilla try run eslint with env var TSESTREE_SINGLE_RUN=false typescript-eslint/typescript-eslint#4093 typescript-eslint/typescript-eslint#8922

since passing @typescript-eslint specified parserOptions to vue-eslint-parser

languageOptions: {
    parser: vueParser,
    parserOptions: {
        parser: tsParser,
+       allowAutomaticSingleRunInference: false,
+       disallowAutomaticSingleRunInference: true,
    }
}

won't work as it's not going to forward them as parserOptions of the given parserOptions.parser:

https://github.com/vuejs/vue-eslint-parser/blob/b0e0ccc6d302bb40c5cb496528536bd355ee5151/src/common/parser-options.ts#L49-L50

Thanks, that helps a bit!

Stanzilla commented 1 month ago

@Stanzilla try run eslint with env var TSESTREE_SINGLE_RUN=false typescript-eslint/typescript-eslint#4093 typescript-eslint/typescript-eslint#8922

since passing @typescript-eslint specified parserOptions to vue-eslint-parser

languageOptions: {
    parser: vueParser,
    parserOptions: {
        parser: tsParser,
+       allowAutomaticSingleRunInference: false,
+       disallowAutomaticSingleRunInference: true,
    }
}

won't work as it's not going to forward them as parserOptions of the given parserOptions.parser:

https://github.com/vuejs/vue-eslint-parser/blob/b0e0ccc6d302bb40c5cb496528536bd355ee5151/src/common/parser-options.ts#L49-L50

Thanks, that helps a bit!

Stanzilla commented 6 days ago

I have this now which works fairly well:

import pluginVue from "eslint-plugin-vue";
import unocss from "@unocss/eslint-config/flat";
import eslint from "@eslint/js";
import tsEslint from "typescript-eslint";
import tsParser from "@typescript-eslint/parser";
import vueParser from "vue-eslint-parser";

export default [
  eslint.configs.recommended,
  ...tsEslint.configs.recommendedTypeChecked,
  ...pluginVue.configs["flat/recommended"],
  unocss,
  {
    languageOptions: {
      parser: vueParser,
      parserOptions: {
        parser: tsParser,
        sourceType: "module",
        extraFileExtensions: [".vue"],
        project: true,
      },
    },
  },
  {
    ignores: [
      "dist",
      "node_modules",
      "dist_electron",
      "dist-electron",
      "release",
      "index.html",
      "tools/**/*.js",
      "uno.config.ts",
      "vite.config.ts",
      "*.d.ts",
    ],
    rules: {
      "no-console": "off",
      "no-undef": "off",
      "@typescript-eslint/no-explicit-any": "off",
      "@typescript-eslint/no-implicit-any": "off",
      "@typescript-eslint/no-unsafe-call": "off",
      "@typescript-eslint/no-unsafe-return": "off",
      "@typescript-eslint/no-unsafe-member-access": "off",
      "@typescript-eslint/no-unsafe-assignment": "off",
      "@typescript-eslint/no-unsafe-argument": "off",
      "@typescript-eslint/no-floating-promises": "off",
      "@typescript-eslint/no-unnecessary-type-assertion": "off",
      "@typescript-eslint/no-base-to-string": "off",
      "@typescript-eslint/restrict-template-expressions": "off",
      "@typescript-eslint/require-await": "off",
      "vue/multi-word-component-names": "off",
      "vue/component-tags-order": [
        "error",
        {
          order: [["script", "template"], "style"],
        },
      ],
      "vue/html-self-closing": "off",
      "vue/html-indent": "off",
      "vue/html-closing-bracket-newline": "off",
      "vue/singleline-html-element-content-newline": "off",
    },
  },
];
MartinX3 commented 6 days ago

I use a vuetify or quasar starter with typescript and script setup.

It just works.