You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: packages-backend/eslint-config-node/migrations/v27.md
+124-2Lines changed: 124 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -142,6 +142,78 @@ The base `mcAppConfig` registers plugins for:
142
142
143
143
If your override mixes rules from different plugins, split into separate config objects matching each plugin's file types (e.g., `react/` rules in `**/*.{js,jsx,tsx}`, `@typescript-eslint/` rules in `**/*.{ts,tsx}`, core rules in `**/*.{js,jsx,ts,tsx}`).
144
144
145
+
#### Common mistake: catch-all file patterns with mixed plugin rules
146
+
147
+
The natural instinct when converting a subdirectory `.eslintrc.cjs` is to put all the rules into a single config object targeting `**/*.{js,jsx,ts,tsx}`. This will fail because not every plugin is registered for every file type.
148
+
149
+
```js
150
+
// WRONG — will error on .ts files because `react` plugin is not registered for them
> **Tip**: When converting an existing `.eslintrc.cjs`, group its rules by which plugin they belong to, then create one config object per plugin group with the correct `files` pattern. Core ESLint rules (no plugin prefix) can target all file types.
182
+
183
+
#### Common mistake: `no-unused-vars` duplication on TypeScript files
184
+
185
+
The base `mcAppConfig` disables core `no-unused-vars` on `.ts`/`.tsx` files and replaces it with `@typescript-eslint/no-unused-vars`. If your subdirectory config re-enables the core `no-unused-vars` for all file types, both rules will fire on TypeScript files, producing duplicate errors.
186
+
187
+
```js
188
+
// WRONG — re-enables core no-unused-vars on .ts/.tsx where @typescript-eslint
Scope core `no-unused-vars` overrides to JavaScript files only:
197
+
198
+
```js
199
+
// CORRECT — only overrides the core rule on files where it applies
200
+
{
201
+
files: ['packages/my-app/src/**/*.{js,jsx}'],
202
+
rules: { 'no-unused-vars':'error' },
203
+
}
204
+
```
205
+
206
+
### Self-linting the config file
207
+
208
+
The root `eslint.config.js` is itself a `.js` file in your project, so ESLint will lint it. Rules like `import/extensions` may error on `.cjs` requires. Add a self-override to avoid this:
209
+
210
+
```js
211
+
{
212
+
files: ['eslint.config.js'],
213
+
rules: { 'import/extensions':'off' },
214
+
},
215
+
```
216
+
145
217
## Step 4: Update `package.json`
146
218
147
219
```diff
@@ -168,6 +240,27 @@ If you maintain custom ESLint rule plugins, update deprecated APIs:
168
240
169
241
Also update the plugin's `peerDependencies` to `"eslint": "9.x"`.
170
242
243
+
### `jest-runner-eslint` compatibility
244
+
245
+
If using `jest-runner-eslint`, note that the `rules` key in `cliOptions` is not supported in flat config mode — move those rule overrides into `eslint.config.js` instead. You may also need a `pnpm.overrides` (or npm `overrides`) entry if the package's peer dependency still specifies ESLint 8:
246
+
247
+
```json
248
+
{
249
+
"pnpm": {
250
+
"overrides": {
251
+
"jest-runner-eslint>eslint": "^9.0.0"
252
+
}
253
+
}
254
+
}
255
+
```
256
+
257
+
If the formatter path uses a bare directory import (e.g., `node_modules/eslint-formatter-pretty`), ESM module resolution will reject it. Change to an explicit file path:
- Delete **all**`.eslintrc.*` files (root and subdirectories)
@@ -187,11 +280,40 @@ Run eslint on at least one file from **each directory that had its own config**.
187
280
188
281
## Troubleshooting
189
282
190
-
**"Definition for rule 'plugin/rule-name' was not found"**: Plugin not registered for that file type. Common case: stale `eslint-disable-next-line` comments for plugins not valid on that file type (e.g., `@typescript-eslint/...` in a `.js` file). **Fix**: remove the stale comment, or register the plugin for that file type.
283
+
**"Definition for rule 'plugin/rule-name' was not found"**: This means a rule is referenced on a file type where its plugin isn't registered. Two common causes:
284
+
285
+
1.**Config rules targeting wrong file types** — your subdirectory config has a catch-all `files` pattern like `**/*.{js,jsx,ts,tsx}` but includes rules from a plugin that isn't registered for all of those types. See "Plugin scoping" above for how to split by plugin.
286
+
2.**Stale inline `eslint-disable` comments** — ESLint 8 silently ignored `eslint-disable` comments referencing rules from unregistered plugins. ESLint 9 treats them as errors. This surfaces pre-existing stale comments that were previously harmless (e.g., `// eslint-disable-next-line testing-library/no-render-in-setup` in a file that isn't matched by the `testing-library` plugin's file pattern, or `@typescript-eslint/...` in a `.js` file). **Fix**: remove the stale disable comment, or if the rule should apply, register the plugin for that file type.
191
287
192
288
**"ReferenceError: module is not defined in ES module scope"**: Config file uses `module.exports` but nearest `package.json` has `"type": "module"`. **Fix**: rename to `.cjs` extension and update imports.
193
289
194
-
**Jest globals (`describe`, `it`, `expect`) not defined**: The base config only injects Jest globals for `**/*.{spec,test}.*`. For other naming conventions (e.g. `*.visualspec.js`), add `languageOptions: { globals: { ...require('globals').jest } }` for those file patterns.
290
+
**Jest globals (`describe`, `it`, `expect`) not defined**: The base config only injects Jest globals for `**/*.{spec,test}.*`. Other files that use Jest APIs need explicit globals. Common patterns that are easy to miss:
291
+
292
+
-`__mocks__/` directories (at any depth)
293
+
-`test-utils/` directories (helper modules used by tests)
294
+
295
+
Add a config block for these:
296
+
297
+
```js
298
+
{
299
+
files: [
300
+
'**/__mocks__/**/*.{js,jsx,ts,tsx}',
301
+
'**/test-utils/**/*.{js,jsx,ts,tsx}',
302
+
],
303
+
languageOptions: {
304
+
globals: {
305
+
jest:'readonly',
306
+
expect:'readonly',
307
+
},
308
+
},
309
+
},
310
+
```
311
+
312
+
> **Note**: Use `**/__mocks__/**` (with leading `**/`), not `__mocks__/**`. The latter only matches a `__mocks__/` directory at the project root. Most projects have `__mocks__/` directories nested inside packages or `src/` directories.
313
+
314
+
**Duplicate `no-unused-vars` errors on `.ts`/`.tsx` files**: The base config sets `@typescript-eslint/no-unused-vars` for TypeScript files and disables the core `no-unused-vars` there. If your subdirectory config re-enables `no-unused-vars` for `**/*.{js,jsx,ts,tsx}`, both rules fire on TypeScript files. **Fix**: scope `no-unused-vars` overrides to `**/*.{js,jsx}` only. See "Common mistake" above.
315
+
316
+
**Lint errors in `eslint.config.js` itself**: The config file is a `.js` file in the project root, so ESLint lints it. Rules like `import/extensions` may error on `.cjs` requires. **Fix**: add a self-override: `{ files: ['eslint.config.js'], rules: { 'import/extensions': 'off' } }`.
195
317
196
318
**"Cannot find module 'some-eslint-plugin'"**: Plugins must be installed as direct dependencies in flat config.
Copy file name to clipboardExpand all lines: packages/eslint-config-mc-app/migrations/v27.md
+124-2Lines changed: 124 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -142,6 +142,78 @@ The base `mcAppConfig` registers plugins for:
142
142
143
143
If your override mixes rules from different plugins, split into separate config objects matching each plugin's file types (e.g., `react/` rules in `**/*.{js,jsx,tsx}`, `@typescript-eslint/` rules in `**/*.{ts,tsx}`, core rules in `**/*.{js,jsx,ts,tsx}`).
144
144
145
+
#### Common mistake: catch-all file patterns with mixed plugin rules
146
+
147
+
The natural instinct when converting a subdirectory `.eslintrc.cjs` is to put all the rules into a single config object targeting `**/*.{js,jsx,ts,tsx}`. This will fail because not every plugin is registered for every file type.
148
+
149
+
```js
150
+
// WRONG — will error on .ts files because `react` plugin is not registered for them
> **Tip**: When converting an existing `.eslintrc.cjs`, group its rules by which plugin they belong to, then create one config object per plugin group with the correct `files` pattern. Core ESLint rules (no plugin prefix) can target all file types.
182
+
183
+
#### Common mistake: `no-unused-vars` duplication on TypeScript files
184
+
185
+
The base `mcAppConfig` disables core `no-unused-vars` on `.ts`/`.tsx` files and replaces it with `@typescript-eslint/no-unused-vars`. If your subdirectory config re-enables the core `no-unused-vars` for all file types, both rules will fire on TypeScript files, producing duplicate errors.
186
+
187
+
```js
188
+
// WRONG — re-enables core no-unused-vars on .ts/.tsx where @typescript-eslint
Scope core `no-unused-vars` overrides to JavaScript files only:
197
+
198
+
```js
199
+
// CORRECT — only overrides the core rule on files where it applies
200
+
{
201
+
files: ['packages/my-app/src/**/*.{js,jsx}'],
202
+
rules: { 'no-unused-vars':'error' },
203
+
}
204
+
```
205
+
206
+
### Self-linting the config file
207
+
208
+
The root `eslint.config.js` is itself a `.js` file in your project, so ESLint will lint it. Rules like `import/extensions` may error on `.cjs` requires. Add a self-override to avoid this:
209
+
210
+
```js
211
+
{
212
+
files: ['eslint.config.js'],
213
+
rules: { 'import/extensions':'off' },
214
+
},
215
+
```
216
+
145
217
## Step 4: Update `package.json`
146
218
147
219
```diff
@@ -168,6 +240,27 @@ If you maintain custom ESLint rule plugins, update deprecated APIs:
168
240
169
241
Also update the plugin's `peerDependencies` to `"eslint": "9.x"`.
170
242
243
+
### `jest-runner-eslint` compatibility
244
+
245
+
If using `jest-runner-eslint`, note that the `rules` key in `cliOptions` is not supported in flat config mode — move those rule overrides into `eslint.config.js` instead. You may also need a `pnpm.overrides` (or npm `overrides`) entry if the package's peer dependency still specifies ESLint 8:
246
+
247
+
```json
248
+
{
249
+
"pnpm": {
250
+
"overrides": {
251
+
"jest-runner-eslint>eslint": "^9.0.0"
252
+
}
253
+
}
254
+
}
255
+
```
256
+
257
+
If the formatter path uses a bare directory import (e.g., `node_modules/eslint-formatter-pretty`), ESM module resolution will reject it. Change to an explicit file path:
- Delete **all**`.eslintrc.*` files (root and subdirectories)
@@ -187,11 +280,40 @@ Run eslint on at least one file from **each directory that had its own config**.
187
280
188
281
## Troubleshooting
189
282
190
-
**"Definition for rule 'plugin/rule-name' was not found"**: Plugin not registered for that file type. Common case: stale `eslint-disable-next-line` comments for plugins not valid on that file type (e.g., `@typescript-eslint/...` in a `.js` file). **Fix**: remove the stale comment, or register the plugin for that file type.
283
+
**"Definition for rule 'plugin/rule-name' was not found"**: This means a rule is referenced on a file type where its plugin isn't registered. Two common causes:
284
+
285
+
1.**Config rules targeting wrong file types** — your subdirectory config has a catch-all `files` pattern like `**/*.{js,jsx,ts,tsx}` but includes rules from a plugin that isn't registered for all of those types. See "Plugin scoping" above for how to split by plugin.
286
+
2.**Stale inline `eslint-disable` comments** — ESLint 8 silently ignored `eslint-disable` comments referencing rules from unregistered plugins. ESLint 9 treats them as errors. This surfaces pre-existing stale comments that were previously harmless (e.g., `// eslint-disable-next-line testing-library/no-render-in-setup` in a file that isn't matched by the `testing-library` plugin's file pattern, or `@typescript-eslint/...` in a `.js` file). **Fix**: remove the stale disable comment, or if the rule should apply, register the plugin for that file type.
191
287
192
288
**"ReferenceError: module is not defined in ES module scope"**: Config file uses `module.exports` but nearest `package.json` has `"type": "module"`. **Fix**: rename to `.cjs` extension and update imports.
193
289
194
-
**Jest globals (`describe`, `it`, `expect`) not defined**: The base config only injects Jest globals for `**/*.{spec,test}.*`. For other naming conventions (e.g. `*.visualspec.js`), add `languageOptions: { globals: { ...require('globals').jest } }` for those file patterns.
290
+
**Jest globals (`describe`, `it`, `expect`) not defined**: The base config only injects Jest globals for `**/*.{spec,test}.*`. Other files that use Jest APIs need explicit globals. Common patterns that are easy to miss:
291
+
292
+
-`__mocks__/` directories (at any depth)
293
+
-`test-utils/` directories (helper modules used by tests)
294
+
295
+
Add a config block for these:
296
+
297
+
```js
298
+
{
299
+
files: [
300
+
'**/__mocks__/**/*.{js,jsx,ts,tsx}',
301
+
'**/test-utils/**/*.{js,jsx,ts,tsx}',
302
+
],
303
+
languageOptions: {
304
+
globals: {
305
+
jest:'readonly',
306
+
expect:'readonly',
307
+
},
308
+
},
309
+
},
310
+
```
311
+
312
+
> **Note**: Use `**/__mocks__/**` (with leading `**/`), not `__mocks__/**`. The latter only matches a `__mocks__/` directory at the project root. Most projects have `__mocks__/` directories nested inside packages or `src/` directories.
313
+
314
+
**Duplicate `no-unused-vars` errors on `.ts`/`.tsx` files**: The base config sets `@typescript-eslint/no-unused-vars` for TypeScript files and disables the core `no-unused-vars` there. If your subdirectory config re-enables `no-unused-vars` for `**/*.{js,jsx,ts,tsx}`, both rules fire on TypeScript files. **Fix**: scope `no-unused-vars` overrides to `**/*.{js,jsx}` only. See "Common mistake" above.
315
+
316
+
**Lint errors in `eslint.config.js` itself**: The config file is a `.js` file in the project root, so ESLint lints it. Rules like `import/extensions` may error on `.cjs` requires. **Fix**: add a self-override: `{ files: ['eslint.config.js'], rules: { 'import/extensions': 'off' } }`.
195
317
196
318
**"Cannot find module 'some-eslint-plugin'"**: Plugins must be installed as direct dependencies in flat config.
0 commit comments