Skip to content
Merged
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
8 changes: 8 additions & 0 deletions .changeset/clever-toys-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@incentro-ic/config-typescript": patch
"@incentro-ic/config-prettier": patch
"@incentro-ic/config-cspell": patch
"@incentro-ic/config-eslint": patch
---

Update dependencies.
5 changes: 5 additions & 0 deletions .changeset/fresh-ghosts-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@incentro-ic/config-eslint": minor
---

Disable `unicorn/consistent-function-scoping` for arrow functions.
5 changes: 5 additions & 0 deletions .changeset/green-dancers-tease.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@incentro-ic/config-eslint": minor
---

Disable `@typescript-eslint/no-misused-promises` for void returns.
5 changes: 5 additions & 0 deletions .changeset/nine-paths-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@incentro-ic/config-typescript": minor
---

Add NestJS and React Router configs.
5 changes: 5 additions & 0 deletions .changeset/smart-papers-spend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@incentro-ic/config-eslint": minor
---

Add new NestJS and React Router configs.
5 changes: 5 additions & 0 deletions .changeset/tricky-bats-say.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@incentro-ic/config-eslint": minor
---

Allow unused variables starting with an underscore in `@typescript-eslint/no-unused-vars`.
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v24.11.1
v24.13.0
14 changes: 7 additions & 7 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,21 @@
"dependencies": {
"@heroicons/react": "^2.2.0",
"@icons-pack/react-simple-icons": "^13.8.0",
"next": "^16.0.10",
"nextra": "^4.6.0",
"nextra-theme-docs": "^4.6.0",
"react": "^19.2.0",
"react-dom": "^19.2.0"
"next": "^16.1.6",
"nextra": "^4.6.1",
"nextra-theme-docs": "^4.6.1",
"react": "^19.2.4",
"react-dom": "^19.2.4"
},
"devDependencies": {
"@incentro-ic/config-eslint": "workspace:^",
"@incentro-ic/config-prettier": "workspace:^",
"@incentro-ic/config-typescript": "workspace:^",
"@types/react": "19.2.7",
"@types/react-dom": "^19.2.3",
"eslint": "^9.39.1",
"eslint": "^9.39.2",
"pagefind": "^1.4.0",
"prettier": "^3.6.2",
"prettier": "^3.8.1",
"rimraf": "^6.1.2",
"serve": "^14.2.5",
"typescript": "^5.9.3"
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@
"prepare": "turbo run @incentro-ic/config-cspell#build @incentro-ic/config-eslint#build @incentro-ic/config-prettier#build"
},
"devDependencies": {
"@changesets/cli": "^2.29.6",
"@changesets/cli": "^2.29.8",
"@incentro-ic/config-cspell": "workspace:^",
"@incentro-ic/config-prettier": "workspace:*",
"@svitejs/changesets-changelog-github-compact": "^1.2.0",
"env-cmd": "^11.0.0",
"prettier": "^3.6.2",
"prettier": "^3.8.1",
"rimraf": "^6.1.2",
"turbo": "^2.6.1"
"turbo": "^2.8.0"
},
"packageManager": "pnpm@10.23.0+sha512.21c4e5698002ade97e4efe8b8b4a89a8de3c85a37919f957e7a0f30f38fbc5bbdd05980ffe29179b2fb6e6e691242e098d945d1601772cad0fef5fb6411e2a4b",
"packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264",
"devEngines": {
"runtime": {
"name": "node",
Expand Down
30 changes: 29 additions & 1 deletion packages/cspell/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pnpm add -D @incentro-ic/config-cspell

## 🪛 Usage

Create an CSPell configuration file and re-export this configuration:
Create [a CSpell configuration file](https://cspell.org/docs/Configuration) (e.g. `cspell.config.js`) and re-export this configuration:

```js filename="cspell.config.js"
export { default } from "@incentro-ic/config-cspell";
Expand All @@ -34,3 +34,31 @@ export default {
words: [...config.words, "flubbernator"],
};
```

### 🇳🇱 Accepting Dutch words

By default the configuration will only allow the use of English words, since this is most common on our code bases. However, this will result in warnings when you use Dutch words in strings and other constants. To allow the use of Dutch words you first have to install the Dutch language dictionary:

```bash
pnpm add -D @cspell/dict-nl-nl
```

Then, you have to extend the CSpell config to import the Dutch language dictionary and accept the Dutch language:

```js filename="cspell.config.js"
import config from "@incentro-ic/config-cspell";

export default {
...config,
import: ["@cspell/dict-nl-nl/cspell-ext.json"],
language: "en,nl",
};
```

> [!NOTE]
>
> This will of course also work for other locales besides Dutch. Just make sure you install the right dictionary and the right language codes.

> [!WARNING]
>
> Even though this will allow the use of Dutch words, you should never use Dutch words when naming variables, functions, classes, etc.
6 changes: 3 additions & 3 deletions packages/cspell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@
"lint:typescript": "tsc --noEmit"
},
"dependencies": {
"@cspell/cspell-types": "^9.3.2"
"@cspell/cspell-types": "^9.6.2"
},
"devDependencies": {
"@incentro-ic/config-eslint": "workspace:^",
"@incentro-ic/config-prettier": "workspace:^",
"@incentro-ic/config-typescript": "workspace:^",
"eslint": "^9.39.1",
"prettier": "^3.6.2",
"eslint": "^9.39.2",
"prettier": "^3.8.1",
"rimraf": "^6.1.2",
"typescript": "^5.9.3"
},
Expand Down
36 changes: 36 additions & 0 deletions packages/eslint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ Shared [ESLint](https://eslint.org/) configuration for linting files. It enforce
- [`@vitest/eslint-plugin`](https://github.com/vitest-dev/eslint-plugin-vitest) - Checks around Vitest test files.
- [`@cspell/eslint-plugin`](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell-eslint-plugin) - Checks spelling and grammar.

The following configurations are available:

- [🏠 Base](#-base) - `@incentro-ic/config-eslint/base`
- [🦁 NestJS](#-nestjs) - `@incentro-ic/config-eslint/nest`
- [🔼 Next.js](#-nextjs) - `@incentro-ic/config-eslint/next`
- [⭐ Nextra](#-nextra) - `@incentro-ic/config-eslint/nextra`
- [🔴 React Router](#-react-router) - `@incentro-ic/config-eslint/react-router`

## 💾 Installation

To install the package, use the following command:
Expand Down Expand Up @@ -83,6 +91,20 @@ export default defineConfig([
]);
```

### 🦁 NestJS

This is the ESLint configuration for all [NestJS](https://nestjs.com/) projects. It extends [the base configuration](#-base) and adds rules and exceptions specific to NestJS projects. For example, it allow empty classes if they use decorators, because this is a common pattern in NestJS.

#### 🪛 Usage

```js filename="eslint.config.js"
export { default } from "@incentro-ic/config-eslint/nest";
```

> [!NOTE]
>
> By default, the NestJS ESLint config ignores files in the `dist` and root directory. If you need to extend this list of ignored files, take a look at [the usage example for the base config](#-base) for an example on how to add ignored directories.

### 🔼 Next.js

This is the ESLint configuration for all [Next.js](https://nextjs.org/) projects. It extends [the base configuration](#-base) and adds rules and exceptions specific to Next.js projects. For example, it adds [the Next.js ESLint plugin](https://nextjs.org/docs/app/api-reference/config/eslint) and allows default exports in files named `layout.tsx` and `page.tsx`.
Expand Down Expand Up @@ -110,3 +132,17 @@ export { default } from "@incentro-ic/config-eslint/nextra";
> [!NOTE]
>
> By default, the Nextra ESLint config ignores files in the `dist`, `.next`, and root directory. If you need to extend this list of ignored files, take a look at [the usage example for the base config](#-base) for an example on how to add ignored directories.

### 🔴 React Router

This is the ESLint configuration for all [React Router](https://reactrouter.com/) projects. It extends [the base configuration](#-base) and adds rules and exceptions specific to React Router projects. For example, it allows default exports in files named `root.ts`, `routes.ts`, and other common React Router file names that require default exports. It also allows the "Params" abbreviation because it's commonly used by code generated by React Router.

#### 🪛 Usage

```js filename="eslint.config.js"
export { default } from "@incentro-ic/config-eslint/react-router";
```

> [!NOTE]
>
> By default, the React Router ESLint config ignores files in the `dist`, `.react-router`, and root directory. If you need to extend this list of ignored files, take a look at [the usage example for the base config](#-base) for an example on how to add ignored directories.
26 changes: 17 additions & 9 deletions packages/eslint/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./nest": {
"types": "./dist/nest.d.ts",
"default": "./dist/nest.js"
},
"./next": {
"types": "./dist/next.d.ts",
"default": "./dist/next.js"
},
"./nextra": {
"types": "./dist/nextra.d.ts",
"default": "./dist/nextra.js"
},
"./react-router": {
"types": "./dist/react-router.d.ts",
"default": "./dist/react-router.js"
}
},
"main": "dist/index.js",
Expand All @@ -42,26 +50,26 @@
"lint:typescript": "tsc --noEmit"
},
"dependencies": {
"@cspell/eslint-plugin": "^9.3.2",
"@eslint-community/eslint-plugin-eslint-comments": "^4.5.0",
"@eslint/js": "^9.39.1",
"@next/eslint-plugin-next": "^16.0.3",
"@vitest/eslint-plugin": "^1.4.4",
"@cspell/eslint-plugin": "^9.6.2",
"@eslint-community/eslint-plugin-eslint-comments": "^4.6.0",
"@eslint/js": "^9.39.2",
"@next/eslint-plugin-next": "^16.1.6",
"@vitest/eslint-plugin": "^1.6.6",
"eslint-config-prettier": "^10.1.8",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-unicorn": "^62.0.0",
"typescript-eslint": "^8.47.0"
"typescript-eslint": "^8.54.0"
},
"devDependencies": {
"@incentro-ic/config-prettier": "workspace:^",
"@incentro-ic/config-typescript": "workspace:^",
"@types/node": "^24.10.1",
"eslint": "^9.39.1",
"prettier": "^3.6.2",
"@types/node": "^24.10.9",
"eslint": "^9.39.2",
"prettier": "^3.8.1",
"rimraf": "^6.1.2",
"typescript": "^5.9.3"
},
Expand Down
25 changes: 25 additions & 0 deletions packages/eslint/src/nest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { Linter } from "eslint";
import { globalIgnores } from "eslint/config";
import baseConfigs from "./base.js";

const config: Linter.Config[] = [
...baseConfigs,

{
name: "incentro-ic/nest",
files: ["src/**/*.ts", "src/**/*.tsx"],
rules: {
// In NestJS it's common to define everything using class decorators,
// which often leads to empty class bodies. To accommodate this pattern,
// we allow extraneous classes if they are decorated.
"@typescript-eslint/no-extraneous-class": [
"error",
{ allowWithDecorator: true },
],
},
},

globalIgnores(["dist/**", "*.*"], "incentro-ic/nest/ignore-directories"),
];

export default config;
10 changes: 10 additions & 0 deletions packages/eslint/src/partials/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ export const baseConfigs: Linter.Config[] = [
// We allow the use of expiring TODO comments, but we don't ever want
// CI / CD pipelines to start failing because it's a different day.
"unicorn/expiring-todo-comments": "off",

// We allow arrow functions to only use outer scope, because they are
// often passed as function references to event handlers (.on() / .off())
// and other similar constructs. Requiring them to be moved to the outer
// scope would require you to bind `this` with `.bind(this)`, which
// reduces readability.
"unicorn/consistent-function-scoping": [
"error",
{ checkArrowFunctions: false },
],
},
},
];
46 changes: 38 additions & 8 deletions packages/eslint/src/partials/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,45 @@ export const typescriptConfigs: Linter.Config[] = [
{ ignoreArrowShorthand: true },
],

// Disallowing passing async functions to places that expect
// void-returning can lead to conflicts with other rules. For example,
// when passing an async function to an event handler. To unregister
// these, the function passed to the handler should be the same reference
// to the function as when unsubscribing. Wrapping the function in an
// anonymous function would create a different reference, making it
// impossible to unsubscribe.
"@typescript-eslint/no-misused-promises": [
"error",
{ checksVoidReturn: false },
],

// We emulate the behavior of Typescript's `noUnusedLocals` and
// `noUnusedParameters` compiler options, but with more granularity by
// allowing unused variables and parameters that start with an
// underscore.
"@typescript-eslint/no-unused-vars": [
"error",
{
args: "all",
argsIgnorePattern: "^_",
caughtErrors: "all",
caughtErrorsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_",
varsIgnorePattern: "^_",
ignoreRestSiblings: true,
},
],

// This rule encourages replacing explicit type assertions with non-null
// assertions (`!`). It directly conflicts with @typescript-eslint/no-non-null-assertion,
// which we intentionally keep enabled to avoid introducing subtle runtime
// errors and hard-to-spot null assertion errors. However, there is a reason to
// want to opt-in to non-null assertions in some cases, for example when
// dealing with third-party libraries without proper types or when dealing
// with data structures where the type system cannot easily express the
// nullability. We disable this rule to allow explicit type
// assertions in such cases.
// assertions (`!`). It directly conflicts with
// @typescript-eslint/no-non-null-assertion, which we intentionally keep
// enabled to avoid introducing subtle runtime errors and hard-to-spot
// null assertion errors. However, there is a reason to want to opt-in to
// non-null assertions in some cases, for example when dealing with
// third-party libraries without proper types or when dealing with data
// structures where the type system cannot easily express the
// nullability. We disable this rule to allow explicit type assertions in
// such cases.
"@typescript-eslint/non-nullable-type-assertion-style": "off",
},
},
Expand Down
Loading