Skip to content

Parsing fails on scriptless Vue files with typescript-eslint parser #125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MatthiasKunnen opened this issue Sep 3, 2021 · 12 comments · Fixed by #126
Closed

Parsing fails on scriptless Vue files with typescript-eslint parser #125

MatthiasKunnen opened this issue Sep 3, 2021 · 12 comments · Fixed by #126

Comments

@MatthiasKunnen
Copy link

When using an eslint config that specifies parserOptions.parser.ts, eslint errors while parsing files that do not have at least an empty <script lang="ts"></script>.

The eslint error is:

Error: Error while loading rule '@typescript-eslint/await-thenable': 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.
Occurred while linting /src/error.vue
    at Object.getParserServices (/node_modules/@typescript-eslint/experimental-utils/dist/eslint-utils/getParserServices.js:16:15)
    at create (/node_modules/@typescript-eslint/eslint-plugin/dist/rules/await-thenable.js:41:37)
    at Object.create (/node_modules/@typescript-eslint/experimental-utils/dist/eslint-utils/RuleCreator.js:13:24)
    at createRuleListeners (/node_modules/eslint/lib/linter/linter.js:761:21)
    at /node_modules/eslint/lib/linter/linter.js:931:31
    at Array.forEach (<anonymous>)
    at runRules (/node_modules/eslint/lib/linter/linter.js:876:34)
    at Linter._verifyWithoutProcessors (/node_modules/eslint/lib/linter/linter.js:1175:31)
    at Linter._verifyWithConfigArray (/node_modules/eslint/lib/linter/linter.js:1273:21)
    at Linter.verify (/node_modules/eslint/lib/linter/linter.js:1228:25)

Config:

module.exports = {
    env: {
        es6: true,
        browser: true,
        node: true,
    },
    overrides: [
        {
            files: [
                '*.vue',
            ],
            plugins: [
                'vue', // With or without this, the error occurs
                '@typescript-eslint',
            ],
            parser: 'vue-eslint-parser',
            parserOptions: {
                parser: {
                    '<template>': 'espree',
                    ts: '@typescript-eslint/parser',
                },
                project: ['./tsconfig.json'],
                extraFileExtensions: ['.vue'],
            },
            rules: {
                '@typescript-eslint/await-thenable': 'error',
            },
        },
    ],
}

Reproduction: https://github.com/MatthiasKunnen/eslint-plugin-vue-ts-script.

@ota-meshi
Copy link
Member

If you do not write <script lang="ts">, the js parser will be selected. The default parser espree (JavaScript parser) is used because you haven't specified js parser.

If you want to enable a rule that uses type checking in all vue files, I think you'll need to specify @typescript-eslint/parser for all files without selecting a separate parser for lang="...".

e.g.

{
    "parserOptions": {
        "parser": "@typescript-eslint/parser"
    }
}

https://github.com/vuejs/vue-eslint-parser#parseroptionsparser

@MatthiasKunnen
Copy link
Author

MatthiasKunnen commented Sep 3, 2021

If you do not write <script lang="ts">, the js parser will be selected.

Why would this matter for a Vue file without a script tag? Is this this some kind of limitation? If so, where would this be addressed, eslint, this repository, ...?

@ota-meshi
Copy link
Member

As described in this parser documentation, your way of specifying is to determine the parser by lang="...". If lang="..." is missing, the js parser will be used.

https://github.com/vuejs/vue-eslint-parser#parseroptionsparser

@MatthiasKunnen
Copy link
Author

The documentation says:

You can use parserOptions.parser property to specify a custom parser to parse <script> tags.

            // Script parser for `<script>`
            "js": "espree",

             // Script parser for `<script lang="ts">`
            "ts": "@typescript-eslint/parser",

yet there is no <script> so why would any parser be selected?

@LinusBorg
Copy link
Member

When you don't provide a script tag, the vue compiler will generate a basic component object for you. so it's like writing:

<script>
  export default {}
</script>

... because components need a base object.

Since that code doesn't have lang="ts" defined, it falls back to the default, which is JS, and it will be parsed with espree according to your settings - which that @typescript-eslint rule can't work with, because this rule requires type information that espree won't provide.

You will likely have the same problem with a plain .js file.

Is there a specific reason why you want to use a different parser for JS? the TS parser can handle both just fine

@MatthiasKunnen
Copy link
Author

The reason for using espree for <template> is speed. Regarding js, this problem also occurs when setting the js parser to @typescript-eslint/parser as such:

parser: {
    '<template>': 'espree',
    js: '@typescript-eslint/parser',
    ts: '@typescript-eslint/parser',
},

@LinusBorg
Copy link
Member

Interesting. I haven't used type-enhanced eslint rules so far, so maybe that's why stuff worked for me ...

We'll need to take a deeper look. you have a workaround for now, I think.

@MatthiasKunnen
Copy link
Author

The workaround allows successful linting indeed. The reproduction repo can be used if you want to debug the issue.

If no solution is found this workaround could benefit from documenting.

The workaround: add this to all your vue files

<script lang="ts">
    export default {}
</script>

@ota-meshi
Copy link
Member

The reason for using espree for <template> is speed. Regarding js, this problem also occurs when setting the js parser to @typescript-eslint/parser as such:

parser: {
    '<template>': 'espree',
    js: '@typescript-eslint/parser',
    ts: '@typescript-eslint/parser',
}

I think this is a bug. I would like to modify it so that parser.js is used.

@MatthiasKunnen
Copy link
Author

@ota-meshi, thank you for addressing this issue!

One note: with the latest parser version, 7.11.0,, when the js parser option is not specified or set to espree, scriptless vue files still cause the same error. While this is not a problem for me as I set js: '@typescript-eslint/parser', I thought I'd let you know since this might not have been your intention.

@LinusBorg
Copy link
Member

When you say "the same error", are you referring to the error about the typescript-eslint rule?

That would be expected. A JS parser like spree can't provide type informaiton to a type-aware rule. Using typescript-eslint - at the very least when using type-aware rules - will always require the typescript-eslint parser to be set.

@MatthiasKunnen
Copy link
Author

A JS parser like spree can't provide type informaiton to a type-aware rule.

I'm well aware. I was just remarking that a .vue file without <script> is currently parsed with a JS/TS parser while it would not need to be. While this is not a problem for me as I set js: '@typescript-eslint/parser', it might catch people off-guard as they could expect a file without script to not perform script parsing. Now I understand that due to ESLint limitations, selecting a JS/TS parser could be required. However, documenting the need for js: '@typescript-eslint/parser' would be beneficial for users that make the same assumption I did.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants