Skip to content

Commit 8ca8b50

Browse files
nzakasmdjermanovicfasttime
authored
feat: Better error message for flat config plugins (#17399)
* feat: Better error message for flat config plugins Refs #17370 * Update docs/src/use/configure/migration-guide.md Co-authored-by: Milos Djermanovic <[email protected]> * Update extended error message * Update docs/src/use/configure/migration-guide.md Co-authored-by: Francesco Trotta <[email protected]> --------- Co-authored-by: Milos Djermanovic <[email protected]> Co-authored-by: Francesco Trotta <[email protected]>
1 parent 6d6dc51 commit 8ca8b50

4 files changed

Lines changed: 93 additions & 5 deletions

File tree

docs/src/use/configure/migration-guide.md

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ In eslintrc files, you configure various language options across the `env`, `glo
211211

212212
In flat config files, the `globals`, and `parserOptions` are consolidated under the `languageOptions` key; the `env` property doesn't exist. Groups of global variables for specific runtimes are imported from the [globals](https://www.npmjs.com/package/globals) npm package and included in the `globals` property. You can use the spread operator (`...`) to import multiple globals at once.
213213

214-
For example, here's a eslintrc file with language options:
214+
For example, here's an eslintrc file with language options:
215215

216216
```javascript
217217
// .eslintrc.js
@@ -314,14 +314,14 @@ export default [
314314
];
315315
```
316316

317-
### Predefined Configs
317+
### Predefined and Shareable Configs
318318

319-
In eslintrc files, use the `extends` property to use predefined configs. ESLint comes with two predefined configs that you can access as strings:
319+
In eslintrc files, use the `extends` property to use predefined and shareable configs. ESLint comes with two predefined configs that you can access as strings:
320320

321321
* `"eslint:recommended"`: the rules recommended by ESLint
322322
* `"eslint:all"`: all rules shipped with ESLint
323323

324-
You can also use the `extends` property to extend a custom config. Custom configs can either be paths to local config files or npm package names.
324+
You can also use the `extends` property to extend a shareable config. Shareable configs can either be paths to local config files or npm package names.
325325

326326
In flat config files, predefined configs are imported from separate modules into flat config files. The `recommended` and `all` rules configs are located in the [`@eslint/js`](https://www.npmjs.com/package/@eslint/js) package. You must import this package to use these configs:
327327

@@ -346,7 +346,7 @@ module.exports = {
346346
}
347347
```
348348

349-
This eslintrc file uses built-in config, local custom config, and custom config from an npm package:
349+
This eslintrc file uses built-in config, local custom config, and shareable config from an npm package:
350350

351351
```javascript
352352
// .eslintrc.js
@@ -400,6 +400,40 @@ export default [
400400
];
401401
```
402402

403+
#### Using eslintrc Configs in Flat Config
404+
405+
You may find that there's a shareable config you rely on that hasn't yet been updated to flat config format. In that case, you can use the `FlatCompat` utility to translate the eslintrc format into flat config format. First, install the `@eslint/eslintrc` package:
406+
407+
```shell
408+
npm install @eslint/eslintrc --save-dev
409+
```
410+
411+
Then, import `FlatCompat` and create a new instance to convert an existing eslintrc config. For example, if the npm package `eslint-config-my-config` is in eslintrc format, you can write this:
412+
413+
```js
414+
import { FlatCompat } from "@eslint/eslintrc";
415+
import path from "path";
416+
import { fileURLToPath } from "url";
417+
418+
// mimic CommonJS variables -- not needed if using CommonJS
419+
const __filename = fileURLToPath(import.meta.url);
420+
const __dirname = path.dirname(__filename);
421+
422+
const compat = new FlatCompat({
423+
baseDirectory: __dirname
424+
});
425+
426+
export default [
427+
428+
// mimic ESLintRC-style extends
429+
...compat.extends("eslint-config-my-config"),
430+
];
431+
```
432+
433+
This example uses the `FlatCompat#extends()` method to insert the `eslint-config-my-config` into the flat config array.
434+
435+
For more information about the `FlatCompat` class, please see the [package README](https://github.com/eslint/eslintrc#usage).
436+
403437
### Ignoring Files
404438
405439
With eslintrc, you can make ESLint ignore files by creating a separate `.eslintignore` file in the root of your project. The `.eslintignore` file uses the same glob pattern syntax as `.gitignore` files. Alternatively, you can use an `ignorePatterns` property in your eslintrc file.

lib/config/flat-config-schema.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,22 @@ class IncompatibleKeyError extends Error {
227227
}
228228
}
229229

230+
/**
231+
* The error type when there's an eslintrc-style plugins array found.
232+
*/
233+
class IncompatiblePluginsError extends Error {
234+
235+
/**
236+
* Creates a new instance.
237+
* @param {Array<string>} plugins The plugins array.
238+
*/
239+
constructor(plugins) {
240+
super("This appears to be in eslintrc format (array of strings) rather than flat config format (object).");
241+
this.messageTemplate = "eslintrc-plugins";
242+
this.messageData = { plugins };
243+
}
244+
}
245+
230246

231247
//-----------------------------------------------------------------------------
232248
// Low-Level Schemas
@@ -319,6 +335,11 @@ const pluginsSchema = {
319335
throw new TypeError("Expected an object.");
320336
}
321337

338+
// make sure it's not an array, which would mean eslintrc-style is used
339+
if (Array.isArray(value)) {
340+
throw new IncompatiblePluginsError(value);
341+
}
342+
322343
// second check the keys to make sure they are objects
323344
for (const key of Object.keys(value)) {
324345

messages/eslintrc-plugins.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"use strict";
2+
3+
module.exports = function({ plugins }) {
4+
5+
const isArrayOfStrings = typeof plugins[0] === "string";
6+
7+
return `
8+
A config object has a "plugins" key defined as an array${isArrayOfStrings ? " of strings" : ""}.
9+
10+
Flat config requires "plugins" to be an object in this form:
11+
12+
{
13+
plugins: {
14+
${isArrayOfStrings && plugins[0] ? plugins[0] : "namespace"}: pluginObject
15+
}
16+
}
17+
18+
Please see the following page for information on how to convert your config object into the correct format:
19+
https://eslint.org/docs/latest/use/configure/migration-guide#importing-plugins-and-custom-parsers
20+
21+
If you're using a shareable config that you cannot rewrite in flat config format, then use the compatibility utility:
22+
https://eslint.org/docs/latest/use/configure/migration-guide#using-eslintrc-configs-in-flat-config
23+
`;
24+
};

tests/lib/config/flat-config-array.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1963,6 +1963,15 @@ describe("FlatConfigArray", () => {
19631963
});
19641964
});
19651965

1966+
it("should error when plugins is an array", async () => {
1967+
await assertInvalidConfig([
1968+
{
1969+
plugins: ["foo"]
1970+
}
1971+
], "Key \"plugins\": This appears to be in eslintrc format (array of strings) rather than flat config format (object).");
1972+
1973+
});
1974+
19661975

19671976
});
19681977

0 commit comments

Comments
 (0)