Files
vscode/.eslint-plugin-local/README.md
2025-10-16 16:48:02 -07:00

126 lines
5.7 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Custom ESLint rules
We use a set of custom [ESLint](http://eslint.org) to enforce repo specific coding rules and styles. These custom rules are run in addition to many standard ESLint rules we enable in the project. Some example custom rules includes:
- Enforcing proper code layering
- Preventing checking in of `test.only(...)`
- Enforcing conventions in `vscode.d.ts`
Custom rules are mostly used for enforcing or banning certain coding patterns. We tend to leave stylistic choices up to area owners unless there's a good reason to enforce something project wide.
This doc provides a brief overview of how these rules are setup and how you can add a new one.
# Resources
- [ESLint rules](https://eslint.org/docs/latest/extend/custom-rules) — General documentation about writing eslint rules
- [TypeScript ASTs and eslint](https://typescript-eslint.io/blog/asts-and-typescript-eslint/) — Look at how ESLint works with TS programs
- [ESTree selectors](https://eslint.org/docs/latest/extend/selectors) — Info about the selector syntax rules use to target specific nodes in an AST. Works similarly to css selectors.
- [TypeScript ESLint playground](https://typescript-eslint.io/play/#showAST=es) — Useful tool for figuring out the structure of TS programs and debugging custom rule selectors
# Custom Rule Configuration
Custom rules are defined in the `.eslint-plugin-local` folder. Each rule is defined in its own TypeScript file. These follow the naming convention:
- `code-RULE-NAME.ts` General rules that apply to the entire repo.
- `vscode-dts-RULE-NAME.ts` Rules that apply just to `vscode.d.ts`.
These rules are then enabled in the `eslint.config.js` file. This is the main eslint configuration for our repo. It defines a set of file scopes which rules should apply to files in those scopes.
For example, here's a configuration that enables the no `test.only` rule in all `*.test.ts` files in the VS Code repo:
```ts
{
// Define which files these rules apply to
files: [
'**/*.test.ts'
],
languageOptions: { parser: tseslint.parser, },
plugins: {
'local': pluginLocal,
},
rules: {
// Enable the rule from .eslint-plugin-local/code-no-test-only.ts
'local/code-no-test-only': 'error',
}
}
```
# Creating a new custom rule
This walks through the steps to create a new eslint rule:
1. Create a new rule file under `.eslint-plugin-local`. Generally you should call it `code-YOUR-RULE-NAME.ts`, for example, `.eslint-plugin-local/code-no-not-null-assertions-on-undefined-values.ts`
2. In this file, add the rule. Here's a template:
```ts
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
export = new class YourRuleName implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
customMessageName: 'message text shown in errors/warnings',
},
schema: false,
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
[SELECTOR]: (node: any) => {
// Report errors if needed
return context.report({
node,
messageId: 'customMessageName'
});
}
};
}
};
```
- Update the name of the class to match the name of your rule
- Add message entries for any errors you want to report
- Update `SELECTOR` with the [ESTree selector](https://eslint.org/docs/latest/extend/selectors) needed to target the nodes you are interested in. Use the [TypeScript ESLint playground](https://typescript-eslint.io/play/#showAST=es) to figure out which nodes you need and debug selectors
3. Register the rule in `eslint.config.js`
Generally this is just turning on the rule in the rule list like so:
```js
rules: {
// Name should match file name
'local/code-no-not-null-assertions-on-undefined-values': 'warn',
...
}
```
Rules can also take custom arguments. For example, here's how we can pass arguments to a custom rule in the `eslint.config.js`:
```
rules: {
'local/code-no-not-null-assertions-on-undefined-values': ['warn', { testsOk: true }],
...
}
```
In these cases make sure to update the `meta.schema` property on your rule with the JSON schema for the arguments. You can access these arguments using `context.options` in the rule `create` function
## Adding fixes to custom rules
Fixes are a useful way to mechanically fix basic linting issues, such as auto inserting semicolons. These fixes typically work at the AST level, so they are a more reliable way to perform bulk fixes compared to find/replaces.
To add a fix for a custom rule:
1. On the `meta` for your rule, add `fixable: 'code'`
2. When reporting an error in the rule, also include a `fix`. This is a function that takes a `fixer` argument and returns one or more fixes.
See the [Double quoted to single quoted string covert fix](https://github.com/microsoft/vscode/blob/b074375e1884ae01033967bf0bbceeaa4795354a/.eslint-plugin-local/code-no-unexternalized-strings.ts#L128) for an example. The ESLint docs also have [details on adding fixes and the fixer api](https://eslint.org/docs/latest/extend/custom-rules#applying-fixes)
The fixes can be run using `npx eslint --fix` in the VS Code repo