Skip to content

Custom eslint rules

Matt Bierner edited this page Oct 15, 2025 · 7 revisions

VS Code use a set of custom ESLint to enforce repo specific coding rules and styles. These custom rules are run in addition to many standard ESLine 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

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 apple 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:

{
    // 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:

    /*---------------------------------------------------------------------------------------------
    *  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 needed to target the nodes you are interested in. Use the TypeScript ESLint playground 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:

    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 amek 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 fix typically work at the AST level, say they are 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 for an example. The ESLint docs also have details on adding fixes and the fixer api

The fixes can be run using npx eslint --fix in the VS Code repo

Clone this wiki locally