Skip to content
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

A total redesign for easier configuration of type-aware rules #48

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 75 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,54 +22,106 @@ npm add --dev @vue/eslint-config-typescript @rushstack/eslint-patch

## Usage

This package comes with 2 rulesets.

### `@vue/eslint-config-typescript`

This ruleset is the base configuration for Vue-TypeScript projects.
Besides setting the parser and plugin options, it also turns off several conflicting rules in the `eslint:recommended` ruleset.
So when used alongside other sharable configs, this config should be placed at the end of the `extends` array.
This plugin provides some predefined configs. You can use the following configs by adding them to extends.

- `@vue/eslint-config-typescript`: Aliased to the `recommended` config below.
- `@vue/eslint-config-typescript/base`: Settings and rules to enable correct ESLint parsing for Vue-TypeScript projects.
- `@vue/eslint-config-typescript/eslint-recommended`: `base` + `eslint:recommended` + turns off several conflicting rules in the `eslint:recommended` ruleset.
- `@vue/eslint-config-typescript/recommended`: The recommended rules for Vue-TypeScript projects, extended from `plugin:@typescript-eslint/recommended`.
- Additional configs that can be used *alongside* the abovementioned configs:
- Additional recommended rules that require type information (does not support `no-unsafe-*` rules, though):
- `@vue/eslint-config-typescript/recommended-requiring-type-checking`
- Additional strict rules that can also catch bugs but are more opinionated than recommended rules (with experimental support for `no-unsafe-*` rules; note this config does not conform to semver, meaning breaking changes may be introduced during minor releases):
- `@vue/eslint-config-typescript/strict`
- Additional configs to allow `<script>` langs other than `lang="ts"` (NOT recommended):
- `@vue/eslint-config-typescript/allow-js-in-vue`, allows plain `<script>` tags in `.vue` files.
- `@vue/eslint-config-typescript/allow-tsx-in-vue`, allows `<script lang="tsx">` in `.vue` files; conflicts with `recommended-requiring-type-checking`.
- `@vue/eslint-config-typescript/allow-jsx-in-vue`, allows plain `<script>`, `<script lang="jsx">`, and `<script lang="tsx">` tags in `.vue` files; conflicts with `recommended-requiring-type-checking`.

An example `.eslintrc.cjs`:

```js
/* eslint-env node */
require("@rushstack/eslint-patch/modern-module-resolution")

module.exports = {
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential',
'@vue/eslint-config-typescript'
'@vue/eslint-config-typescript/recommended-requiring-type-checking'
]
}
```

### `@vue/eslint-config-typescript/recommended`
## Migrating from v11.x

This is extended from the `@typescript-eslint/recommended` ruleset, which is an **_opinionated_** ruleset.
See the [original documentation](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin/src/configs#recommended) for more information.
- If you extended from `@vue/eslint-config-typescript` in v11.x, you should now extend from `['@vue/eslint-config-typescript/eslint-recommended', '@vue/eslint-config-typescript/allow-jsx-in-vue']` instead.
- If you extended from `@vue/eslint-config-typescript/recommended` in v11.x, you should now extend from `['@vue/eslint-config-typescript', '@vue/eslint-config-typescript/allow-jsx-in-vue']` instead.
- But if you don't have any plain `<script>`, `<script lang="tsx">`, or `<script lang="jsx">` in your `.vue` files, you can omit `@vue/eslint-config-typescript/allow-jsx-in-vue` from the extends array.

Some of its rules, however, might conflict with `prettier`.
So when used alongside other sharable configs, this config should be placed after all other configs except for the one from `@vue/eslint-config-prettier` or `eslint-plugin-prettier` in the `extends` array.
## TypeScript Support for Other Community Style Guides

An example `.eslintrc.cjs`:
If you are following the [`standard`](https://standardjs.com/) or [`airbnb`](https://github.com/airbnb/javascript/) style guides, don't manually extend from this package. Please use [`@vue/eslint-config-standard-with-typescript`](https://www.npmjs.com/package/@vue/eslint-config-standard-with-typescript) or [`@vue/eslint-config-airbnb-with-typescript`](https://www.npmjs.com/package/@vue/eslint-config-airbnb-with-typescript) instead.

## Non-Conventional TSConfig Locations

By default, this ruleset searches for TSConfig files matching `**/tsconfig.json` and `**/tsconfig.*.json` from the current working directory.
This should cover most use cases.

However, if your TSConfig file is located somewhere else (e.g., in an ancestor directory), or doesn't follow the conventional naming (e.g., named as `my-custom-tsconfig.json`), you need to specify the location in your `.eslintrc.cjs` manually:

```js
/* eslint-env node */
require("@rushstack/eslint-patch/modern-module-resolution")
const createAliasSetting = require('@vue/eslint-config-typescript/createAliasSetting')

module.exports = {
extends: [
root: true,
extens: [
'plugin:vue/vue3-essential',
'@vue/eslint-config-typescript/recommended',
'@vue/eslint-config-prettier'
]
'@vue/eslint-config-typescript'
],
parserOptions: {
project: ['/path/to/my-custom-tsconfig.json']
},
settings: {
...createAliasSetting(['/path/to/my-custom-tsconfig.json'])
}
}
```

### With Other Community Configs
## `Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.`

If you are using this config in an existing project, you may encounter this error:

```text
Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: foo.js.
The file must be included in at least one of the projects provided
```

It is likely because your existing `tsconfig.json` does not include all of the files you would like to lint.

(This doesn't usually happen in projects created by [`create-vue`](https://github.com/vuejs/create-vue) because it creates projects with [solution-style `tsconfig.json` files](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#support-for-solution-style-tsconfigjson-files) that cover every file in the project.)

A workaround is to create a separate `tsconfig.eslint.json` as follows:

```json
{
// Extend your base config so you don't have to redefine your compilerOptions
"extends": "./tsconfig.json",
"include": [
// Include all files in the project
"./**/*",
// By default the `include` glob pattern doesn't match `.vue` files, so we add it explicitly
"./**/*.vue"
],
"compilerOptions": {
// Include `.js` & `.jsx` extensions
"allowJs": true
}
}
```

Work-In-Progress.
## Further Improvements

~~If you are following the [`standard`](https://standardjs.com/) or [`airbnb`](https://github.com/airbnb/javascript/) style guides, don't manually extend from this package. Please use `@vue/eslint-config-standard-with-typescript` or `@vue/eslint-config-airbnb-with-typescript` instead.~~
- Support [ESLint Flag Config](https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new).
- Keep an eye on [`@volar-plugins/eslint`](https://github.com/johnsoncodehk/volar/discussions/2204) for potentially better TypeScript integrations.
10 changes: 10 additions & 0 deletions utils/rules-requiring-type-checking.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const allRules = require('@typescript-eslint/eslint-plugin').rules

module.exports = Object.entries(allRules)
.filter(([name, rule]) => rule.meta?.docs?.requiresTypeChecking)
.map(([name]) => name)
// This rule does not require type information, but as its source code requires the parserService,
// it seems to be encountering undefined behavior in `.vue` files
// https://github.com/typescript-eslint/typescript-eslint/issues/4755#issuecomment-1080961338
.concat('prefer-optional-chain')
.map(name => `@typescript-eslint/${name}`)
Loading