# The Doctor
URL: /docs/cli-usage/doctor
The Doctor is a diagnostic tool that monitor your Sheriff configuration and ensure it stays up-to-date with your project dependencies.
Example usecase [#example-usecase]
Picture this: you kickstart your project and opt for [jest](https://jestjs.io/) as your unit testing solution of choice. You setup Sheriff with the [Scaffolder](/docs/cli-usage/scaffolder) and it automatically enables the `jest` support for your project. All great.
But then, one day, you decide to switch to [vitest](https://vitest.dev/). You update your project dependencies and forget to update your Sheriff configuration.
**Here is where the Doctor comes into picture**: it will catch this mismatch and warn you about it, so you can readily turn off the `jest` support in your Sheriff configuration and turn on the `vitest` support.
All is good again.
How to run it [#how-to-run-it]
To get started, install it in your project:
npm
pnpm
yarn
bun
```bash
npm i -D @sherifforg/cli
```
```bash
pnpm add -D @sherifforg/cli
```
```bash
yarn add --dev @sherifforg/cli
```
```bash
bun add --dev @sherifforg/cli
```
Add the command to your `package.json` scripts:
```json title="package.json"
{
"scripts": {
"sheriff": "sheriff"
}
}
```
And then run it:
```bash
pnpm sheriff
```
It is advised to integrate the Doctor in your **CI pipelines**, but you can also integrate it into pre-commit hooks if that's your preference.
How it works [#how-it-works]
The `sheriff` command will scan your project dependencies and your Sheriff configuration object. If Sheriff finds some dependencies that don't have the corresponding Sheriff options enabled, it will throw an error.
Example [#example]
```json title="package.json"
{
"name": "my-project",
"dependencies": {
"react": "^18.3.1",
}
}
```
```js title="eslint.config.mjs"
import { sheriff } from 'eslint-config-sheriff';
import { defineConfig } from 'eslint/config';
const sheriffOptions = {
react: false, // ❌ this will throw an error // [!code word:false]
};
export default defineConfig(sheriff(sheriffOptions));
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from 'eslint-config-sheriff';
import { defineConfig } from 'eslint/config';
const sheriffOptions: SheriffSettings = {
react: false, // ❌ this will throw an error // [!code word:false]
};
export default defineConfig(sheriff(sheriffOptions));
```
```js title="eslint.config.mjs"
import { sheriff } from 'eslint-config-sheriff';
import { defineConfig } from 'eslint/config';
const sheriffOptions = {
react: true, // ✅ this will pass // [!code word:true]
};
export default defineConfig(sheriff(sheriffOptions));
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from 'eslint-config-sheriff';
import { defineConfig } from 'eslint/config';
const sheriffOptions: SheriffSettings = {
react: true, // ✅ this will pass // [!code word:true]
};
export default defineConfig(sheriff(sheriffOptions));
```
The Doctor will scan the config file trying to find a variable named **exactly** `sheriffOptions`. If your configuration object variable is called in any other way, nothing will work. Make sure the variable is named `sheriffOptions`.
Options [#options]
The Doctor is very flexible and offers a variety of options to customize its behavior. Check out the [API reference](/docs/cli-usage/commands-reference#sherifforgcli) for detailed info on the available options.
You can:
* skip the check for a specific dependency. This is useful in scenarios where the mismatch is intended, meaning that you don't want Sheriff linting support for a specific dependency even if Sheriff support is available
* let the process finish without throwing erros even if problems with the dependencies are found. In this case the Doctor will just signal problems as warnings
# CLI usage
URL: /docs/cli-usage
The Sheriff CLI is composed of 2 packages: The Scaffolder and The Doctor.
# The Scaffolder
URL: /docs/cli-usage/scaffolder
The Scaffolder lets you introduce Sheriff in your project with a single terminal command. Check out the [automatic setup page](/docs/setup/automatic-setup).
Check the [API reference](/docs/cli-usage/commands-reference#@sherifforgcreate-config) for the the full list of available commands.
# Configuration
URL: /docs/configuration
Base options [#base-options]
The `eslint-config-sheriff` package exports a `sheriff` function.
You can configure Sheriff as desired using a simple javascript object as the first input parameter of the `sheriff` function.
Every config option can be set on/off (you just pass them a boolean value). As they are all opt-in, they are all disabled by default. If you bootstrapped the config with the [Scaffolder](/docs/cli-usage/scaffolder) some of these values will be inferred automatically from your project.
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
// Sheriff configuration object
const sheriffOptions = { // [!code highlight]
react: false, // [!code highlight]
next: false, // [!code highlight]
astro: false, // [!code highlight]
lodash: false, // [!code highlight]
remeda: false, // [!code highlight]
playwright: false, // [!code highlight]
storybook: true, // [!code highlight]
jest: false, // [!code highlight]
vitest: false, // [!code highlight]
tsconfigRootDir: import.meta.dirname, // [!code highlight]
}; // [!code highlight]
export default defineConfig(sheriff(sheriffOptions));
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
// Sheriff configuration object
const sheriffOptions: SheriffSettings = { // [!code highlight]
react: false, // [!code highlight]
next: false, // [!code highlight]
astro: false, // [!code highlight]
lodash: false, // [!code highlight]
remeda: false, // [!code highlight]
playwright: false, // [!code highlight]
storybook: true, // [!code highlight]
jest: false, // [!code highlight]
vitest: false, // [!code highlight]
tsconfigRootDir: import.meta.dirname, // [!code highlight]
}; // [!code highlight]
export default defineConfig(sheriff(sheriffOptions));
```
Remodeling [#remodeling]
You can override any Sheriff rule as desired in the `eslint.config.mjs` file.
For example, let's say you want to disable a Sheriff rule, like `import/first`:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions),
{
rules: {
"import/first": 0, // [!code highlight] 'import/first' is now disabled everywhere.
},
},
);
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions: SheriffSettings = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions),
{
rules: {
"import/first": 0, // [!code highlight] 'import/first' is now disabled everywhere.
},
},
);
```
Likewise, let's say you want to enable a new rule:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions),
{
rules: {
"import/first": 2, // [!code highlight] 'import/first' is now enabled everywhere.
},
},
);
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions: SheriffSettings = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions),
{
rules: {
"import/first": 2, // [!code highlight] 'import/first' is now enabled everywhere.
},
},
);
```
This is just the standard behavior of the `FlatConfig` system of ESLint, which is being illustrated here for your convenience. Sheriff doesn't alter this in any way.
For more in-depth information, refer to the [official docs](https://eslint.org/docs/latest/use/configure/configuration-files).
Advanced options [#advanced-options]
The upcoming configuration options are meant to be situational, tailored to serve only a niche group of users and designed to address specific use cases. **Use these only if and when you end up needing them**.
`files` [#files]
This option is primarily meant to be used while introducing Sheriff to an existing project.
Learn more in the [Migration guide](/docs/migration-guide#progressive-adoption-story).
`ignores` [#ignores]
By default, Sheriff will ignore certain filepaths, but you can choose to opt-out of this behavior.
```ts twoslash
ignores: {
recommended: boolean;
inheritedFromGitignore: boolean;
}
```
`ignores.recommended` [#ignoresrecommended]
With this option, Sheriff will ignore a list of commonly ignored folders:
Example:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
ignores: {
recommended: true, // [!code highlight] true by default. False to disable.
},
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions: SheriffSettings = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
ignores: {
recommended: true, // [!code highlight] true by default. False to disable.
},
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
`ignores.inheritedFromGitignore` [#ignoresinheritedfromgitignore]
With this option, Sheriff will ignore the same filepaths specified in your `.gitignore` file.
Example:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
ignores: {
inheritedFromGitignore: true, // [!code highlight] true by default. False to disable.
},
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions: SheriffSettings = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
ignores: {
inheritedFromGitignore: true, // [!code highlight] true by default. False to disable.
},
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
`pathsOverrides` [#pathsoverrides]
As outlined in the [criteria](/docs/core-philosophy/criteria) page, Sheriff comes with sensible defaults. However, as your project grows, your team may come across the need to override some of these defaults. This option lets you do just that.
```ts twoslash
pathsOverrides: {
tests: string[];
}
```
`pathsOverrides.tests` [#pathsoverridestests]
By default, Sheriff will apply Jest or Vitest rules only on specific files.
This setting overrides this default.
It accepts an array of filepaths, dictaced by [minimatch](https://github.com/isaacs/minimatch) syntax.
Example:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
pathsOverrides: {
tests: [ // [!code highlight]
"**/*.mySpecialName.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
"**/mySpecialFolder/**/*.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
"**/__mySpecialFolder__/**/*.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
], // [!code highlight]
},
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions: SheriffSettings = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
pathsOverrides: {
tests: [ // [!code highlight]
"**/*.mySpecialName.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
"**/mySpecialFolder/**/*.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
"**/__mySpecialFolder__/**/*.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
], // [!code highlight]
},
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
`pathsOverrides.playwrightTests` [#pathsoverridesplaywrighttests]
By default, Sheriff will apply Playwright rules only on specific files.
This setting overrides this default.
It accepts an array of filepaths, dictaced by [minimatch](https://github.com/isaacs/minimatch) syntax.
Example:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
pathsOverrides: {
playwrightTests: [ // [!code highlight]
"**/*.mySpecialName.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
"**/mySpecialFolder/**/*.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
"**/__mySpecialFolder__/**/*.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
], // [!code highlight]
},
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions: SheriffSettings = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
pathsOverrides: {
playwrightTests: [ // [!code highlight]
"**/*.mySpecialName.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
"**/mySpecialFolder/**/*.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
"**/__mySpecialFolder__/**/*.{js,mjs,cjs,ts,mts,cts}", // [!code highlight]
], // [!code highlight]
},
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
# Criteria
URL: /docs/core-philosophy/criteria
This library is very opinionated, but it's for the better. A lot of decisions were taken so you don't have to.
You can now quickstart static analysis in all your Typescript projects with ease.
Just type `pnpm create @sherifforg/config` in a CLI and you are good to go.
Easiness of use without compromises is the top priority of Sheriff. The basic principle behind many design decisions of Sheriff is to require as less inputs from the user as possible.
You can think of Sheriff like Prettier or `create-react-app`. It's a tool that comes battery-packed with optimal defaults. It removes configuration decisions from the equation, so you or your team can focus on developing the actual product.
And if you don't like something, you can easily override it, and just as easily you can extend it. See: [configuration](/docs/configuration).
This config is particularly useful for big teams with developers of various skill levels.
Sheriff was made to prevent all kind of mistakes and to align the team on the same playing field. It is battle-tested in real-world scenarios and shines especially in such.
Also, Sheriff target pretty much everybody. Junior developers can learn a lot by using it, and Lead developers can save a lot of time on configuration and maintenance.
Sheriff doesn't have the goal to include every single ESLint plugin in existance. The ESLint plugins that qualify for inclusion in Sheriff are usually the ones that would benefit the community the most and that would be tricky to manually integrate with the rest of the config.
# Core philosophy
URL: /docs/core-philosophy
# Inspired by Style Guides
URL: /docs/core-philosophy/inspiration
Sheriff design was also inspired by the following style guides:
* [JavaScript Red Style Guide](https://github.com/GrosSacASac/JavaScript-Set-Up/tree/master/js/red-javascript-style-guide)
* [TypeScript Style Guide (Mkosir Style Guide)](https://mkosir.github.io/typescript-style-guide/)
* [TypeScript Deep Dive (Basarat Style Guide)](https://basarat.gitbook.io/typescript/styleguide)
# Ruleset design
URL: /docs/core-philosophy/ruleset-design
No complex presets [#no-complex-presets]
Sheriff doesn't offer "recommended" or "strict" presets. This config contains a predefined set of rules meant to act as guidelines for a **functional-light** programming style.
No esoteric Typescript-only features [#no-esoteric-typescript-only-features]
Sheriff tries to be as faithful to Javascript as possible and conceives Typescript as a tool to enhance the capabilities that Javascript already has. Because of this, Sheriff discourages typescript-only features, like enums and overloads (and classes, and decorators by extensions, even though they also landed in Ecmascript).
Minimal formatting opinions [#minimal-formatting-opinions]
Unlike other ESLint configurations, Sheriff tries to be as unopinionated as possible about formatting, to be aligned with the community philosophy on the matter ([1](https://eslint.org/blog/2023/10/deprecating-formatting-rules), [2](https://typescript-eslint.io/blog/deprecating-formatting-rules)).
Sheriff encourage you to [bring your own formatting tool](/docs/prettier-support#other-formatting-options).
The only formatting rules that Sheriff currently enforces are `@stylistic/padding-line-between-statements` and `curly`.
Opinionated but flexible [#opinionated-but-flexible]
If you just don't like some rules you can disable them on a case-by-case basis.
If you want to adopt a more OOP programming style, or if you feel like the config is too strict, you can disable everything that bothers you.
But if you decide to adopt this config, you should trust it and let it do it's thing.
If you end up fighting it all the way, maybe reconsider about whether or not adopting it.
There are some pretty big hot-takes in this config. Learn more in the [Stylistic choices](/docs/core-philosophy/stylistic-choices) explanations section.
Also in the [FAQs](/docs/faq) there are *even more* hot-takes, if you are into that 🌶️.
# Stylistic choices
URL: /docs/core-philosophy/stylistic-choices
No classes [#no-classes]
* [red-javascript-style-guide - why disallow class](https://github.com/GrosSacASac/JavaScript-Set-Up/blob/master/js/red-javascript-style-guide/why-disallow-class.md)
* Sheriff is trying to promote a "light functional" approach. Javascript classes don't fit such design
No reduce [#no-reduce]
* [Is reduce() bad? - HTTP 203](https://www.youtube.com/watch?v=qaGjS7-qWzg)
* [TkDodo - Why i don't like reduce](https://tkdodo.eu/blog/why-i-dont-like-reduce)
Sheriff actually allows using `reduce` for very simple operations like summing up numbers. Complex operations are banned.
No enums [#no-enums]
* [eslint-plugin-typescript-enum - README](https://github.com/shian15810/eslint-plugin-typescript-enum/blob/main/README.md)
* [Enums considered harmful](https://www.youtube.com/watch?v=jjMbPt_H3RQ)
* [How to use TypeScript Enums and why not to, maybe](https://www.youtube.com/watch?v=pWPClHdcvVg)
* [Let's Talk About TypeScript's Worst Feature](https://www.youtube.com/watch?v=Anu8vHXsavo)
* [Effective Typescript book](https://effectivetypescript.com) explicitly warn against this, saying that `enums` belong to a legacy design choice of Typescript.
No overloads [#no-overloads]
* generics supersedes them. Overloads are a legacy feature that was made available in Typescript before generics were a thing. Overloads are mostly a C#/Angular leftover. Simply put: there are no problems that function overloads solve better than generics
* overloads clutter the code and make it more verbose and harder to read, which increase the cognitive overload
* overloads clutter the VScode tooltips
* overloads force you to write non-standard javascript syntax
* overloads are a bad practice. The flexibility that they enable also enable your team to write inconsistent code. Which is exactly the problem that ESLint is designed to solve
* [Effective Typescript book](https://effectivetypescript.com) explicitly warn against this, saying that "conditional types" are preferrable.
# Why
URL: /docs/core-philosophy/why
Managing a complex ESLint configuration takes time and effort. **Sheriff does it for you.**
There are a lot of factors to take into considerations when you want to tackle a complex ESLint configuration.
It requires a lot of expertise into the Javascript engine and the multitude of Javascript libraries, their nuances, and the interlacing between their behaviors.
*And* it's a huge burden to maintain it.
With Sheriff, maintaining the ESLint configuration is as simple as updating Sheriff to the latest version.
# ESLint Plugins
URL: /docs/eslint-plugins
* [@eslint/js](https://www.npmjs.com/package/@eslint/js)
* [@typescript/eslint](https://github.com/typescript-eslint/typescript-eslint)
* [@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic)
* [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react)
* [eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y)
* [eslint-plugin-react-hooks](https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks)
* [eslint-plugin-react-refresh](https://github.com/ArnaudBarre/eslint-plugin-react-refresh)
* [@eslint-react/eslint-plugin](https://github.com/rel1cx/eslint-react)
* [eslint-plugin-react-you-might-not-need-an-effect](https://github.com/NickvanDyke/eslint-plugin-react-you-might-not-need-an-effect)
* [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn)
* [eslint-plugin-regexp](https://github.com/ota-meshi/eslint-plugin-regexp)
* [eslint-plugin-sonarjs](https://github.com/SonarSource/eslint-plugin-sonarjs)
* [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc)
* [eslint-plugin-tsdoc](https://www.npmjs.com/package/eslint-plugin-tsdoc)
* [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest)
* [@vitest/eslint-plugin](https://github.com/vitest-dev/eslint-plugin-vitest)
* [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import) with [eslint-import-resolver-typescript](https://github.com/import-js/eslint-import-resolver-typescript)
* [eslint-plugin-lodash-f](https://github.com/AndreaPontrandolfo/eslint-plugin-lodash) (my fork of [eslint-plugin-lodash](https://github.com/wix/eslint-plugin-lodash))
* [eslint-plugin-remeda](https://github.com/AndreaPontrandolfo/eslint-plugin-remeda)
* [@next/eslint-plugin-next](https://www.npmjs.com/package/@next/eslint-plugin-next)
* [eslint-plugin-playwright](https://github.com/playwright-community/eslint-plugin-playwright)
* [eslint-plugin-storybook](https://github.com/storybookjs/eslint-plugin-storybook)
* [eslint-plugin-astro](https://github.com/ota-meshi/eslint-plugin-astro)
* [eslint-plugin-fsecond](https://github.com/AndreaPontrandolfo/eslint-plugin-fsecond)
* [@regru/eslint-plugin-prefer-early-return](https://github.com/regru/eslint-plugin-prefer-early-return)
* [eslint-plugin-arrow-return-style](https://github.com/u3u/eslint-plugin-arrow-return-style)
* [eslint-plugin-simple-import-sort](https://github.com/lydell/eslint-plugin-simple-import-sort)
# FAQ
URL: /docs/faq
Why you didn’t include ESLint plugins/rules for "X" library? [#why-you-didnt-include-eslint-pluginsrules-for-x-library]
eslint-plugin-cypress [#eslint-plugin-cypress]
[eslint-plugin-cypress](https://github.com/cypress-io/eslint-plugin-cypress).
Don't use [Cypress](https://www.cypress.io/). Use [Playwright](https://playwright.dev/) instead.
eslint-plugin-testing-library [#eslint-plugin-testing-library]
[eslint-plugin-testing-library](https://github.com/testing-library/eslint-plugin-testing-library).
I believe Sheriff should not encourage wrong testing practices. In my opinion [testing library](https://github.com/testing-library) is one of the least efficient ways to test UIs, by principles. In most codebases it does more harm than good. You can use [Storybook](https://github.com/storybookjs/storybook) to test components in isolation and [Playwright](https://playwright.dev/) for any kind of integration and end-to-end tests.
eslint-plugin-unused-imports [#eslint-plugin-unused-imports]
[eslint-plugin-unused-imports](https://github.com/sweepline/eslint-plugin-unused-imports).
Anything this plugin does is done better by [knip](https://github.com/webpro/knip).
import/no-unused-modules [#importno-unused-modules]
[import/no-unused-modules](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unused-modules.md).
This rule is very slow and and has some issues, it is also hard to get working properly in most codebases. Instead, i recommend [knip](https://github.com/webpro/knip).
Is Sheriff compatible with "X"? [#is-sheriff-compatible-with-x]
Generally speaking, everything that is compatible with ESLint, should also be compatible with Sheriff. That being said, in some cases there can be some nuances:
Vite [#vite]
[Vite](https://vitejs.dev/).
Compatible out of the box.
Next.js [#nextjs]
[Next.js](https://github.com/vercel/next.js).
Sheriff has explicit support for Next.js. You can enable it in the Sheriff config options. You shouldn't follow any of the steps provided in the [Next.js website](https://nextjs.org/docs/pages/building-your-application/configuring/eslint). Only follow the Sheriff instructions.
It's also recommended to [disable the nextjs default linting from the build process](https://nextjs.org/docs/pages/api-reference/config/eslint#disabling-linting-during-production-builds), to avoid potential conflicts with Sheriff.
```ts twoslash title="next.config.ts"
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
eslint: {
ignoreDuringBuilds: true,
},
};
export default nextConfig;
```
CRA [#cra]
[CRA](https://create-react-app.dev/).
Compatible. Just add this line to your `.env` file:
```dotenv title=".env"
DISABLE_ESLINT_PLUGIN=true
```
Does Sheriff support vanilla Javascript codebases? [#does-sheriff-support-vanilla-javascript-codebases]
Sheriff is a Typescript-first ESLint configuration. It's focused on Typescript codebases. You can almost consider Sheriff a superset of [@typescript-eslint](https://typescript-eslint.io/).
If your codebase is not written in Typescript, you should worry about that first, before worrying about linting.
For this reason, vanilla Javascript is not supported as of right now, but support may come at a later time.
# Features
URL: /docs/features
Sheriff is a all-in-one solution. You don't need to install or configure separately anything else. Everything is included here
If you know ESLint, you know Sheriff
Sheriff has extended capabilities beyond being a simple ESLint config, but it's **not** a framework. You can extend the `eslint.config.mjs` beyond Sheriff as much as you like, just like you normally would. Or you can disable any rule Sheriff comes with. Sheriff doesn't impose any limitation. See: [configuration](/docs/configuration)
Some other configs bundle linting rules with formatting opinions and impose restrictions on how you should format your code. Sheriff does not. If you want to use Prettier alongside Sheriff, Sheriff provides you with the golden path to do it, if you don't it's ok too!
To setup Sheriff and take off, the only input required from the user is running the [Scaffolder](/docs/cli-usage/scaffolder). It will automatically infer the details of your project and figure out the optimal Sheriff configuration by itself
You can plop Sheriff in your project at any moment. The [Scaffolder](/docs/cli-usage/scaffolder) will configure automatically everything for you and will warn you if you need to take any special precautions. Bottom line: it's never too late to install Sheriff
Sheriff is one of the first attempts in the wild to adhere to the new eslint configuration format, the `FlatConfig`. You can use Sheriff to easily and safely migrate your project to the new config format without effort. See: [migration guide](/docs/migration-guide)
All of the rules that were hand-picked in Sheriff were chosen to counter some problematic real-world scenarios that can occur in production projects and to ensure maximum style consistency. No bloat here. See [criteria](/docs/core-philosophy/criteria)
The Sheriff configuration file can be typesafe! See: [eslint-config-ts](/docs/typescript-support/eslint-config-ts)
Sheriff is fully configurable with its own config object. See: [configuration](/docs/configuration)
Sheriff has opt-in support for a [wide array of libraries](/docs/techs)
Sheriff provides a [diagnostic tool](/docs/cli-usage/doctor) that helps you maintain your Sheriff configuration and spot inconsistencies. It can easily b run on CI.
Sheriff comes with sensible default ignore patterns out-of-the-box, that also incorporate your `.gitignore` file, so you don't have to worry about excluding common build artifacts, dependencies, and generated files from linting
Sheriff [releases](https://github.com/AndreaPontrandolfo/sheriff/releases) follows [Semantic Versioning](https://semver.org/) with [Conventional Commits](https://www.conventionalcommits.org/) standards
# Introduction
URL: /docs/introduction
This is the official website of the open-source library **Sheriff**.
What is Sheriff? [#what-is-sheriff]
Sheriff is a comprehensive ESLint configuration. It supports [various popular technologies](/docs/techs).
Sheriff is a Typescript-first library, and as such, it support only Typescript codebases written with modern ECMAScript standards. Vanilla Javascript codebases are not supported as of now. See [FAQ](/docs/faq#does-sheriff-support-vanilla-javascript-codebases).
Key points [#key-points]
* This library is pioneering in the adoption of the ESLint `FlatConfig`, [introduced in ESLint v8.23.0](https://eslint.org/blog/2022/08/eslint-v8.23.0-released/)
* Sheriff is very easy to get started with and use. It promotes a *"zero overhead approach"*. See: [philosophy](/docs/core-philosophy/criteria)
* Sheriff is a [*"plug & play"*](/docs/setup/automatic-setup) solution but you can customize it as much as you want. See: [features](/docs/features)
Trivia [#trivia]
The name "Sheriff" comes from the idea that it's a tool that watches over your codebase and keep everything in order.
Ok, let's do this [#ok-lets-do-this]
To get started, head over to the [automatic setup guide](/docs/setup/automatic-setup) and follow the instructions.
# Migration Guide
URL: /docs/migration-guide
Step-by-step instructions [#step-by-step-instructions]
If you are setting up Sheriff in an already established codebase, follow these steps:
Start by running the [Scaffolder](/docs/cli-usage/scaffolder) and follow the advices that it prints in the console
Make sure that the only ESLint config file present in any workspace's package is the `eslint.config.mjs`
If you want to keep your existing custom rules on-top of Sheriff, move them to the `eslint.config.mjs`, after the `sheriff` function, so they will override it. Refer to the [configuration instructions](/docs/configuration)
Make sure to uninstall all the packages that Sheriff already incorporates out-of-the-box. [Here](/docs/eslint-plugins) is the list
Progressive adoption story [#progressive-adoption-story]
In massive codebases it can be troublesome to adapt to all these rules all at once. It is preferable to progressively fix the errors at your own pace, possibly with atomic commits and focused PRs.
You can achieve this by leveraging a few techniques:
* open the `eslint.config.mjs` file and add a key `files` in the `sheriffOptions` object. The value accepts an array of filepaths, dictated by [minimatch](https://github.com/isaacs/minimatch) syntax. Only the matching files found in this array will be linted.
See example below:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions = {
files: ["src/**/*"], // Only the files in the src directory will be linted. [!code highlight]
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions: SheriffSettings = {
files: ["src/**/*"], // Only the files in the src directory will be linted. [!code highlight]
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
By default, the [Scaffolder](/docs/cli-usage/scaffolder) will not add the `files` in the object and every js/ts file will be linted. Use this only if you want to specifically lint just a subsection of the codebase.
* use [eslint-interactive](https://github.com/mizdra/eslint-interactive)
* use [ESLint Bulk Suppressions](https://eslint.org/docs/latest/use/suppressions)
# Monorepo Support
URL: /docs/monorepo-support
General guidelines [#general-guidelines]
While Sheriff can technically be used at the *root* of monorepos, it's **not** recommended.
Sheriff works best when applied to individual packages *within* a monorepo.
Examples [#examples]
Recommended ✅ [#recommended-]
Not Recommended ❌ [#not-recommended-]
Usage in VSCode [#usage-in-vscode]
To make use of the [ESLint VScode extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) in monorepos, use the [eslint.workingDirectories](https://github.com/microsoft/vscode-eslint#mono-repository-setup) setting.
Setup with Scaffolder in a monorepo [#setup-with-scaffolder-in-a-monorepo]
If you want to use the [Scaffolder](/docs/cli-usage/scaffolder) to bootstrap Sheriff in one of your workspace's packages, you can actually do so by following the general usage rules of workspaces, Sheriff will try to mimic the behaviour of popular monorepo CLI tools, so it will feel seamless, intuitive and familiar.
Run the Scaffolder from the root of your monorepo, and then filter by the workspace you want to apply Sheriff to. A chain of prompts will start to guide you through the correct process of installation.
Example [#example]
npm
pnpm
yarn
bun
```bash
npm init @sherifforg/config --filter=path/to/my/package
```
```bash
pnpm create @sherifforg/config --filter=path/to/my/package
```
```bash
yarn create @sherifforg/config --filter=path/to/my/package
```
```bash
bunx @sherifforg/create-config --filter path/to/my/package
```
# Performance Tips
URL: /docs/performance-tips
Depending on the device you are operating on, in-editor performance can be a concern with Sheriff.
`@typescript-eslint` can be particularly taxing on the system, so, some performance considerations are in order.
Rules performance benchmarking [#rules-performance-benchmarking]
The currently known slowest rules in Sheriff are the ones of `@typescript-eslint` that [requires type information](https://typescript-eslint.io/getting-started/typed-linting) to work.
[List of types-aware rules](https://typescript-eslint.io/rules/?=typeInformation).
You can benchmark rules performance by yourself by running the following command in the terminal:
npm
pnpm
yarn
bun
```bash
TIMING=1 npx eslint
```
```bash
TIMING=1 pnpm dlx eslint
```
```bash
TIMING=1 yarn dlx eslint
```
```bash
TIMING=1 bun x eslint
```
Learn more in the [ESLint official docs section](https://eslint.org/docs/latest/extend/custom-rules#profile-rule-performance).
Rules performance optimization strategies [#rules-performance-optimization-strategies]
There are a few techniques you can leverage to improve slow linting time.
You can choose which technique to employ or mix-and-match them.
Disable some of the heaviest rules [#disable-some-of-the-heaviest-rules]
As simple as it sounds, you could assess which of the slowest rules you can live without and simply disable them.
Enable some of the heaviest rules only on CI [#enable-some-of-the-heaviest-rules-only-on-ci]
This approach has a little more overhead, but you could try to run the heaviest rules only on CI.
Here is an example on how you can achieve it:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions),
{
rules: {
"@typescript-eslint/no-misused-promises": process.env.CI ? 2 : 0, // [!code highlight]
},
},
);
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions: SheriffSettings = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
};
export default defineConfig(sheriff(sheriffOptions),
{
rules: {
"@typescript-eslint/no-misused-promises": process.env.CI ? 2 : 0, // [!code highlight]
},
},
);
```
This is a tradeoff, as this approach is a DX degradation and could lead to some developer frustration, because perfectly valid code in local environment could instead fail in CI.
{/* Caching doesn't handles dependencies, breaking typescript-eslint and eslint-plugin-import: https://typescript-eslint.io/troubleshooting/faqs/eslint/#can-i-use-eslints---cache-with-typescript-eslint */}
{/* ### Adopt ESLint's cache
ESLint features an internal cache where you can store your previous runs.
This technique has pretty much no downsides and you should employ it in any case, regardless of any other factor.
Read the official docs on ESLint caching here: [command-line-interface#caching](https://eslint.org/docs/latest/use/command-line-interface#caching).
Instead, if your project lives in a monorepo, you can follow [this guide](https://www.shew.dev/monorepos/guardrails/eslint). */}
Review glob patterns [#review-glob-patterns]
ESLint, Typescript and Sheriff use minimatch syntax to handle glob patterns.
Wide glob patterns can lead to performance degradation.
Pay special attention to:
* [ESLint files and ignore patterns](https://eslint.org/docs/latest/use/configure/configuration-files-new#specifying-files-and-ignores)
* [Typescript include and exclude patterns](https://typescript-eslint.io/troubleshooting/typed-linting/performance/#wide-includes-in-your-tsconfig)
* [Sheriff files options](/docs/configuration#files)
* [Sheriff pathsOverrides options](/docs/configuration#pathsoverrides)
* [wide-globs-in-parseroptionsproject](https://typescript-eslint.io/troubleshooting/typed-linting/monorepos/#wide-globs-in-parseroptionsproject)
# Prettier Support
URL: /docs/prettier-support
Sheriff is designed to coexist smoothly with [Prettier](https://prettier.io/), allowing both tools to complement each other effectively.
If you want Prettier support in your project, the following sections will guide you through the setup and usage of it.
Setup [#setup]
The [Scaffolder](/docs/cli-usage/scaffolder) will:
Attempt to spin up for you a default `.prettierrc.json` configuration. You *can* modify it if you need to, but [it is discouraged](https://prettier.io/docs/en/option-philosophy.html). Act with caution. If you already have a Prettier config in your project, the command will not overwrite it, nor will it attempt to modify it.
Attempt to install the `prettier` dependency in your project.
Attempt to create a [`.prettierignore` file](https://prettier.io/docs/en/ignore.html) in your project.
If you don't use the Scaffolder, you will have to do above setup steps manually yourself.
Usage [#usage]
By design, Sheriff **doesn't** incorporate:
* [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier). Its use is discouraged by the Prettier team itself, [as it just slows down your editor](https://prettier.io/docs/en/integrating-with-linters.html#notes). It's better to just let ESLint and Prettier run side-by-side.
* [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier). Starting from ESLint v8.53.0, [ESLint stopped shipping formatting rules](https://eslint.org/blog/2023/10/deprecating-formatting-rules/), and shortly after `@typesript/eslint` followed suit. This change made `eslint-config-prettier` completely irrelevant and now the only formatting rules left in Sheriff are `@stylistic/padding-line-between-statements` and `curly`, which don't conflict with Prettier.
Instead, for your local editing experience, it's recommended to install the [Prettier editor extension](https://prettier.io/docs/en/editors.html).
If you want to enforce Prettier at pre-commit stage, see the [official Prettier docs](https://prettier.io/docs/en/precommit).
To enforce Prettier in CI, see the [Prettier CLI docs](https://prettier.io/docs/en/cli.html).
Other Formatting options [#other-formatting-options]
As Sheriff doesn’t enforce any formatting rules (except for `@stylistic/padding-line-between-statements` and `curly`), you can use any formatting tool you want to go alongside Sheriff. You are not limited to Prettier.
You can use [Biome](https://github.com/biomejs/biome) or [Dprint](https://github.com/dprint/dprint), but the Scaffolder will not provide direct support for them. You will have to integrate them yourself.
# Prior Art
URL: /docs/prior-art
Why yet another Eslint config? [#why-yet-another-eslint-config]
As you might have noticed, there are already a lot of ESLint configurations in the wild (have a look [here](#related-projects) or [here](https://github.com/dustinspecker/awesome-eslint#configs)).
None of these projects share the same set of goals as Sheriff.
Sheriff has a particular vision.
The main reasons that led to it's creation are:
* easy to setup and use (thanks to the [Scaffolder](/docs/cli-usage/scaffolder))
* easy to customize (thanks to the `FlatConfig` format)
* sensible defaults, proven effective in production scenarios
After exploring every possible alternative, i came to the conclusion that none of the other options where close to what i needed for my projects and everyday use. **That’s why i still opted for making Sheriff**.
Related projects [#related-projects]
Simple ESLint configs [#simple-eslint-configs]
* [eslint-config-airbnb](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb) ([comparison](#sheriff-vs-eslint-config-airbnb))
* [@antfu/eslint-config](https://github.com/antfu/eslint-config) ([comparison](#sheriff-vs-antfueslint-config))
* [eslint-config-canonical](https://github.com/gajus/eslint-config-canonical)
* [eslint-config-hardcore](https://github.com/EvgenyOrekhov/eslint-config-hardcore)
ESLint wrappers [#eslint-wrappers]
These tools are not just sharable ESLint configs, but are wrappers for ESLint (and in some cases Prettier too) and also provide their CLI and their Editor integrations.
* [xo](https://github.com/xojs/xo) ([comparison](#sheriff-vs-xo))
* [standard](https://github.com/standard/standard)
* [gts](https://github.com/google/gts)
* [eslint-kit](https://github.com/eslint-kit/eslint-kit)
Why Sheriff is NOT an ESLint wrapper [#why-sheriff-is-not-an-eslint-wrapper]
Sheriff is **NOT** an ESLint wrapper.
Meaning, you can do with Sheriff anything you can do with ESLint. ESLint wrappers instead limits you in the ability to do so. They lock you into their limited ecosystem.
I believe that ESLint wrappers had their place once upon a time when the `FlatConfig` wasn't a thing. But today their usecases are largely obsolete.
If you want a simple all-in-one solution, that only handles basic Javascript and doesn't require any customization, just go with something like [Biome](https://github.com/biomejs/biome), atleast it's fast. Instead, if you want something more advanced, that handle more usecases and offer more granular control to the user, go with something like Sheriff.
In-depth comparisons [#in-depth-comparisons]
The main technical difference between Sheriff and the other projects is that Sheriff is updated to the most recent version of ESLint and supports the new `FlatConfig` instead of relying on weird hacks using the [@rushstack/eslint-patch](https://www.npmjs.com/package/@rushstack/eslint-patch). Because of the technical limitation imposed by this hack, these configs are harder to work with, at multiple levels.
Another key difference is that the design of most of these configs seems to revolve around the idea of stuffing as much rules as possible into the config, regardless of the quality of the experience and the goal of the project.
Sheriff instead was [shaped around solid principles](/docs/core-philosophy/criteria) and only includes the rules that let it achieve its goals.
In addition, Sheriff features a lot of unique goodies and little nicities that other libraries lack.
For a quick glance at the differences between Sheriff and some of the other ESLint configurations mentioned above, have a look at the table below.
Features comparison table [#features-comparison-table]
Sheriff VS `eslint-config-airbnb` [#sheriff-vs-eslint-config-airbnb]
I cannot not mention the fact that [eslint-config-airbnb](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb) is apparently the most popular ESLint config.
However there are a few specific reasons that led to this, and none of them has to do with the quality of the config itself:
* it was one of the first ESLint configs to be created
* the starred repository actually contains a stylistic guide, not just the ESLint config. The endorsements are for the guide, not the ESLint config
* the repository is owned by Airbnb. Many developers through the years starred it just for their enthusiasm for the company, not for the ESLint library in particular
* for many years, it was the deafult ESLint config in many popular boilerplates and React guides/articles
As of today it's frowned upon by many industry professionals. Some of the most glaring issues:
* it's largely outdated and not maintained since quite some time
* It's big, bloated, too strict for most projects
* it doesn't support TypeScript out of the box, to get it you actually have to use a different library, even less maintained and supported than the original one
Sheriff VS `@antfu/eslint-config` [#sheriff-vs-antfueslint-config]
[Antfu config](https://github.com/antfu/eslint-config) shares many similarities with Sheriff, but is less mature and has less features.
Also, it's important to note that it goes for a very opinionated route toward styling, where instead of adopting Prettier, it relies on [eslint-stylistic](https://github.com/eslint-community/eslint-stylistic) for it's formatting needs.
That being said, Antfu is a prominent figure in the Javascript community and Sheriff takes some inpiration from his config.
Ultimately, both Sheriff and Antfu are good choices, but they have different flavors.
Sheriff VS XO [#sheriff-vs-xo]
[XO](https://github.com/xojs/xo) is an interesting project. It uses ESLint and Prettier under the hood, but don't directly expose them to you. Instead of relying on the ESLint CLI and VSCode Extensions, it has it's own CLI and VSCode Extension. On the surface, it can seem like a good thing because it allows them to provide a more integrated experience, but it also means that you are locked into their ecosystem and you cannot freely extend them.
It is very opinionated in their stylistic and formatting choices and doesn't allow for much flexibility.
XO has many issues that ESLint and Prettier don't have.
# Hard requirements
URL: /docs/requirements/hard-requirements
* [Node >=20.10](https://nodejs.org)
* [ESLint >={devDependencies.eslint}](https://eslint.org)
* [TypeScript >= 5.0.0](https://www.typescriptlang.org)
# Recommendations
URL: /docs/requirements/recommendations
* [Node >=22](https://nodejs.org)
* [ESLint >={devDependencies.eslint.slice(1)}](https://eslint.org)
* [Typescript >= 5.0.0](https://www.typescriptlang.org)
* [VScode](https://code.visualstudio.com)
* [VScode eslint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
* [VScode prettier extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
* Either `strict: true` or at least `strictNullChecks: true` in `tsconfig`. Some `@typescript/eslint` rules requires `strictNullChecks` turned on. This shouldn't be a problem because Sheriff is meant to be used with `strict` turned on anyway
# Rules
URL: /docs/rules
# Automatic setup
URL: /docs/setup/automatic-setup
Just run this command in your terminal:
npm
pnpm
yarn
bun
```bash
npm init @sherifforg/config
```
```bash
pnpm create @sherifforg/config
```
```bash
yarn create @sherifforg/config
```
```bash
bunx @sherifforg/create-config
```
Visit the [Scaffolder commands reference](/docs/cli-usage/commands-reference#sherifforgcreate-config) for a detailed look at the available options.
For monorepos, refer to the extra details in the [monorepo support](/docs/monorepo-support#setup-with-npm-init-sherifforgconfig) guide.
[Setup VSCode support](/docs/vscode-support) (*optional*)
...and you are good to go! Happy hacking 🎉
# Setup
URL: /docs/setup
This config is opinionated and complex, so make sure to meet the [hard requirements](/docs/requirements/hard-requirements) in
your project. Then, let the Scaffolder handle the whole setup for you automatically,
or do it yourself manually.
For greenfield projects that lack a ESLint config, the below setup options will be enough.
However, for established codebases that already have a ESLint config setup, you should also follow the instructions
for the [migration path](/docs/migration-guide).
# Manual setup
URL: /docs/setup/manual-setup
Follow these steps:
Install the package from [npm](https://www.npmjs.com/package/eslint-config-sheriff).
npm
pnpm
yarn
bun
```bash
npm install -D eslint eslint-config-sheriff
```
```bash
pnpm add -D eslint eslint-config-sheriff
```
```bash
yarn add --dev eslint eslint-config-sheriff
```
```bash
bun add --dev eslint eslint-config-sheriff
```
Create a `eslint.config.mjs` file at the root of your project and copy/paste the contents of the following snippet of code:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
or, if you already have a `eslint.config.mjs` in your project, just append Sheriff to the configs array, like this:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff"; // [!code ++]
import { defineConfig } from "eslint/config";
// my other imports...
// [!code ++:12]
const sheriffOptions = {
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(
sheriff(sheriffOptions), // [!code ++]
// my other configurations...
);
```
Adopt `eslint.config.ts` (*optional*).
If you want to have a `.ts` configuration file ([learn more](/docs/typescript-support/eslint-config-ts)) instead of the default `.mjs` file, follow these steps:
1. make sure your installed ESLint version is `>=9.9.0` (preferably `>=9.18.0`. [See why](/docs/vscode-support#eslintconfigts-support))
2. install [jiti](https://github.com/unjs/jiti)
npm
pnpm
yarn
bun
```bash
npm install -D jiti
```
```bash
pnpm add -D jiti
```
```bash
yarn add --dev jiti
```
```bash
bun add --dev jiti
```
3. change the extension of `eslint.config.mjs` from `.mjs` to `.ts`
4. define the types of the `sheriffOptions` object:
```ts twoslash title="eslint.config.ts"
import { sheriff } from "eslint-config-sheriff"; // [!code --]
import { sheriff, type SheriffSettings } from "eslint-config-sheriff"; // [!code ++]
import { defineConfig } from "eslint/config";
const sheriffOptions = { // [!code --]
const sheriffOptions: SheriffSettings = { // [!code ++] [!code word:SheriffSettings]
react: false,
next: false,
astro: false,
lodash: false,
remeda: false,
playwright: false,
storybook: true,
jest: false,
vitest: false,
tsconfigRootDir: import.meta.dirname,
};
export default defineConfig(sheriff(sheriffOptions));
```
[Configure Sheriff](/docs/configuration) (*optional*)
[Setup Prettier](/docs/prettier-support#setup) (*optional*)
[Setup VSCode support](/docs/vscode-support) (*optional*)
Sheriff is based on the [new format of ESLint configs](https://eslint.org/docs/latest/user-guide/configuring/configuration-files). You cannot extend Sheriff from an [old config format](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated), it wouldn't work.
# Techs
URL: /docs/techs
* [Eslint](https://eslint.org)
* [Prettier](https://prettier.io)
* [Typescript](https://www.typescriptlang.org) (*out of the box support*)
* [Storybook](https://storybook.js.org) (*opt-out*)
* [Astro](https://astro.build) (*opt-in*)
* [React](https://reactjs.org) (*opt-in*)
* [Next](https://nextjs.org) (*opt-in*)
* [Lodash](https://lodash.com) (*opt-in*)
* [Remeda](https://remedajs.com) (*opt-in*)
* [Playwright](https://playwright.dev) (*opt-in*)
* [Jest](https://jestjs.io) (*opt-in*)
* [Vitest](https://vitest.dev) (*opt-in*)
# Troubleshooting
URL: /docs/troubleshooting
The Scaffolder fails when using yarn [#the-scaffolder-fails-when-using-yarn]
Depending on the context and under specific conditions, the [Scaffolder](/docs/cli-usage/scaffolder) may fail to install the dependencies when using `yarn`.
In this case you can simply install them yourself. The Scaffolder should spit out the correct command prompt for you to do so at the end of the process. If that doesn't happen, refer to the [manual setup instructions](/docs/setup/manual-setup).
Alternatively, consider switching package manager to [pnpm](https://pnpm.io/).
I'm using Nextjs and the Sheriff rules doesn't seem to apply [#im-using-nextjs-and-the-sheriff-rules-doesnt-seem-to-apply]
In a Nextjs project, you shouldn't follow any of Nextjs' ESLint instructions, including the usage of the command `next lint`. Just use the basic ESlint command `eslint`.
Refer to the [Nextjs compatibility documentation](/docs/faq#is-sheriff-compatible-with-x).
I'm getting the error: Parsing error: No tsconfigRootDir was set, and multiple candidate TSConfigRootDirs are present [#im-getting-the-error-parsing-error-no-tsconfigrootdir-was-set-and-multiple-candidate-tsconfigrootdirs-are-present]
If you are getting the error:
```
Parsing error: No tsconfigRootDir was set, and multiple candidate TSConfigRootDirs are present:
...
You'll need to explicitly set tsconfigRootDir in your parser options.
See: https://typescript-eslint.io/packages/parser/#tsconfigrootdireslint
```
It means that the `typescript-eslint` parser is unsure about the location of the `tsconfig.json` file.
Just add this to your ESLint config:
```js title="eslint.config.mjs"
import { sheriff } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions = {
tsconfigRootDir: import.meta.dirname // [!code highlight]
};
export default defineConfig(sheriff(sheriffOptions));
```
```ts twoslash title="eslint.config.ts"
import { sheriff, type SheriffSettings } from "eslint-config-sheriff";
import { defineConfig } from "eslint/config";
const sheriffOptions: SheriffSettings = {
tsconfigRootDir: import.meta.dirname // [!code highlight]
};
export default defineConfig(sheriff(sheriffOptions));
```
My editor feels slow [#my-editor-feels-slow]
Consult the [performance tips](/docs/performance-tips) page.
# eslint.config.ts
URL: /docs/typescript-support/eslint-config-ts
The `eslint.config.ts` file is a Typescript-enabled version of the `eslint.config.js` file.
If you go through the [automatic setup](/docs/setup/automatic-setup) of Sheriff, at some point the wizard will ask you if you want to setup Sheriff with a `eslint.config.ts` file instead of the default `eslint.config.js` file. Choose `yes` if you want to have a typesafe ESLint configuration file.
Instead, if you choose the manual installation, follow the instructions in the [manual setup page](/docs/setup/manual-setup).
Also check the specific docs for the [VSCode integration](/docs/vscode-support#eslintconfigts-support).
For more details, checkout [the official ESLint documentation on the topic](https://eslint.org/docs/latest/use/configure/configuration-files#typescript-configuration-files).
This feature is available only with ESLint version `>=9.9.0`.
# Typescript support
URL: /docs/typescript-support
# TSConfig guidelines
URL: /docs/typescript-support/tsconfig-guidelines
Typescript configuration is a very wide and complex topic. Depending on the environments that you are going to target, setting up correctly a proper `tsconfig.json` can be daunting and time consuming.
In this section I'll try to illustrate a rundown of the choices that you should make when tweaking a `tsconfig.json` in a modern Typescript project that use Sheriff.
If you don't know much about the `tsconfig.json` and you are uncertain, this can be a good starting point. But in the end you must be sure that the chosen settings fit your project.
Resources [#resources]
* in [this project](https://github.com/tsconfig/bases/tree/main) you can find a lot of `TSConfig` examples for different scenarios
* If you are having hard-to-debug issues, consider using [these debugging tools](https://www.typescriptlang.org/tsconfig#Compiler_Diagnostics_6251)
* for any doubt, make sure to check out the official [TSConfigs documentation](https://www.typescriptlang.org/tsconfig)
* [here](https://www.totaltypescript.com/tsconfig-cheat-sheet) you can also find an interesting deep-dive
Sheriff's TSConfig reference [#sheriffs-tsconfig-reference]
```jsonc title="tsconfig.json"
{
"$schema": "https://json.schemastore.org/tsconfig",
"include": ["src"],
"exclude": ["node_modules", "dist", "build", "coverage"], // this is already a good default. Generally you want to put here build artifacts.
"compilerOptions": {
"target": "es6",
"module": "preserve",
"moduleResolution": "bundler",
"noEmit": true,
"allowImportingTsExtensions": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"jsx": "react-jsx",
"composite": false, // you should enable this only for using TS project references. But they are fairly discourages nowadays.
"incremental": true,
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json",
"strict": true, // this is required for Sheriff to perform correctly. [!code highlight]
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"exactOptionalPropertyTypes": false, // this looks nice on paper, but is actually extremely annoying in practice.
"noUnusedLocals": false, // this is already covered by Sheriff.
"noUnusedParameters": false, // this is already covered by Sheriff.
"isolatedModules": true, // this is required for Sheriff to perform correctly. [!code highlight]
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"verbatimModuleSyntax": true, // this is required for Sheriff to perform correctly. [!code highlight]
"erasableSyntaxOnly": true,
"skipLibCheck": true,
"allowJs": false,
"checkJs": false,
"experimentalDecorators": false,
"paths": {}, // define here your paths if you want to use absolute paths in your project, which is highly recommended.
},
}
```
```jsonc title="tsconfig.json"
{
"$schema": "https://json.schemastore.org/tsconfig",
"include": ["src"],
"exclude": ["node_modules", "dist", "build", "coverage"], // this is already a good default. Generally you want to put here build artifacts.
"compilerOptions": {
"target": "es6",
"module": "nodenext",
"moduleResolution": "nodenext",
"noEmit": false,
"allowImportingTsExtensions": false,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"jsx": "react-jsx",
"composite": false, // you should enable this only for using TS project references. But they are fairly discourages nowadays.
"incremental": true,
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json",
"strict": true, // this is required for Sheriff to perform correctly. [!code highlight]
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"exactOptionalPropertyTypes": false, // this looks nice on paper, but is actually extremely annoying in practice.
"noUnusedLocals": false, // this is already covered by Sheriff.
"noUnusedParameters": false, // this is already covered by Sheriff.
"isolatedModules": true, // this is required for Sheriff to perform correctly. [!code highlight]
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"verbatimModuleSyntax": true, // this is required for Sheriff to perform correctly. [!code highlight]
"erasableSyntaxOnly": true,
"skipLibCheck": true,
"allowJs": false,
"checkJs": false,
"experimentalDecorators": false,
"paths": {}, // define here your paths if you want to use absolute paths in your project, which is highly recommended.
},
}
```
# VSCode Support
URL: /docs/vscode-support
To make the [VSCode ESLint Extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) work better with Sheriff it's recommended to checkout a few settings. It's advisable to enable them at the workspace level, meaning in the root of the project in `.vscode/settings.json`.
Enable linting on specific file extensions [#enable-linting-on-specific-file-extensions]
```jsonc title=".vscode/settings.json"
{
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
],
}
```
Astro support [#astro-support]
For [Astro](https://astro.build/) projects, add the astro extension too:
```jsonc title=".vscode/settings.json"
{
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"astro", // [!code ++]
],
}
```
`eslint.config.ts` support [#eslintconfigts-support]
Follow these instructions if you are using the `eslint.config.ts` configuration file.
With ESLint >= 9.18.0 [#with-eslint--9180]
No further action is required. You are good to go!
With ESLint < 9.18.0 [#with-eslint--9180-1]
Add this to your `.vscode/settings.json`:
```jsonc title=".vscode/settings.json"
"eslint.options": {
"flags": ["unstable_ts_config"]
}
```
Avoid "source.organizeImports" [#avoid-sourceorganizeimports]
Sheriff already handles imports sorting, so if you happen to have enabled the VSCode automatic import sorting feature, you should disable it to avoid conflicts:
```jsonc title=".vscode/settings.json"
"editor.codeActionsOnSave": {
"source.organizeImports": "never"
}
```
If you wish, you can automatically fix some ESLint violations on save, including sorting imports:
```jsonc title=".vscode/settings.json"
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
```