Skip to content

ESLint Config

ESLint Config (hereinafter the “Application”) is an npm package containing our highly customised set of ESLint rules. Every rule has been explicitly set - there are no default configurations loaded.

1. User Documentation

This section is for those interacting with a live instance of the Application.

1.1. Installation

To use this linter configuration in your own project, you must be using Node.js. Install the package and the necessary dependency:

Terminal window
npm install -D eslint @nhcarrigan/eslint-config

1.2. Usage

To begin using this package, you’ll need to create an eslint.config.js file in the root of your project. To load our configuration exactly as is with no changes, you can copy-paste this snippet:

import NaomisConfig from "@nhcarrigan/eslint-config";
export default [...NaomisConfig];

Then, to run it, you’ll likely want to define a package.json script that covers your files. Our configuration can run against:

  • src/**/*.ts
  • src/**/*.tsx
  • e2e/**/*.spec.ts (These should be Playwright tests)
  • test/**/*.spec.ts (These should be Vitest tests)

An example script for all of these might be:

{
"lint": "eslint src e2e test --max-warnings 0"
}

1.3. Overriding Rules

You may need to tweak some of the rules to fit your needs. It is highly recommended that you only adjust rules on a per-file basis. You can extend the configuration by adding your rules after you spread our config:

import NaomisConfig from "@nhcarrigan/eslint-config";
export default [
...NaomisConfig,
{
files: ["test/**/*.spec.ts"],
rules: {
"import/no-extraneous-dependencies": "off",
"max-nested-callbacks": "off",
"@typescript-eslint/consistent-type-assertions": "off",
"max-lines-per-function": "off",
},
},
];

Note that the files key allows you to specify which files receive the rules updates. If omitted, the rule changes will apply to all of your files (including those that our configuration might not check!).

2. Technical Documentation

This section is for those interested in running their own instance of the Application.

This section is not applicable to this project.

This section is for expansions to our legal policies specific to the Application.

This section is not applicable to this project.

4. Contributing Documentation

This section is for documentation related to contributing to the Application’s codebase.

4.1. Adding or Updating Rules

When adding new rules to an existing plugin, or changing existing rules, you should find the appropriate file for that plugin within the src/rules directory. Each plugin has its own file.

Most of these should be self-explanatory, but there are a couple of caveats:

  • The eslint.ts file has a disabledEslintRules object. This is the only place where rules are explicitly turned off, and these are the rules that conflict with an enabled @typescript-eslint rule. If you are adding a new @typescript-eslint rule that has a documented conflict, be sure to add the relevant eslint rule here.
  • The typescriptEslint.ts file has a typescriptEslintRulesWithTypes object. Certain @typescript-eslint rules require type definitions to be generated. However, our project structure excludes tests from being compiled (because they are not production code), so those do not get type definitions. As such, rules that need type definitions must go in this object so that they can be run only on src/**/*.ts.

4.2. Adding Plugins

Adding a new plugin is a much more ambitious change. First, ensure that you are using pnpm and you install the plugin as a pinned dependency:

Terminal window
pnpm install --save-exact <plugin>

Additionally, if the plugin relies on another tool (such as Vitest), add that to the peer dependencies restricted to greater than the current major version.

Once your plugin is installed, you will need to create the rules file in src/rules for that plugin. Define a rules object named <plugin name>Rules, annotate it as Linter.RulesRecord, and export it. This is where your rules will go. HOWEVER:

Before you start adding rules, navigate to the src/index.ts file. Import your new rules object, and import the newly installed plugin.

Find the appropriate region for the type of files your plugin should run on (e.g. TypeScript, Playwright). The plugin will need to be added to the plugins property of that object, and here’s the catch:

Add your rules to the rules property of the same config object you added the plugin to.

If your new plugin should run on multiple file-sets, you’ll need to add it to each of the objects for that file set.

4.3. Error or Warn?

As a general principle, we want:

  • “Error” for rules that should not be violated even in development for temporary testing
  • “Warn” for rules that are safe to ignore while working on the code, but should not be checked in to main.

There are a couple of caveats:

  • Stylistic rules should always be “warn”.
  • Test rules should always be “warn”.

With the exception of the disabledEslintRules object mentioned earlier, no rule should be set to off. We do not load any default configurations, so every rule is off by default.

4.4. Adding Tests

If you have not added a new plugin, the tests should be flexible enough to continue passing as is. If you HAVE added a new plugin:

  • If it is a plugin that falls under the “all rules are warn” category, you’ll need to create a <plugin>.spec.ts file and assert that all rules are set to “warn”. You can refer to playwright.spec.ts for an example of this.
  • If it is a plugin that runs on all file sets, an assertion for it will need to be added to the baseProperties function in config.spec.ts.
  • If it is a plugin that runs on a subset of files, an assertion for it will need to be added to the appropriate it block for the file subset configs.

In any case, you will likely need to update the number of assertions and the length of the plugins objects.

4.5. Testing Changes

Your very first step is to confirm that pnpm lint works. This will start by compiling the TypeScript so it can load the updated configuration.

It will then run the new linter configuration against the linter project. If your configuration works, you should either see a successful run, or a failed run with specific linter issues.

If you instead see a failed run with ESlint errors (not linter errors, but package errors), your configuration has failed to parse and will need to be adjusted.

Once that has passed successfully (including resolving any linter flags), you can proceed to running pnpm test to ensure the existing unit tests pass (and any tests you added to cover new plugins).

As always, feel free to reach out to us in Discord if you have any questions!~