Skip to content

Commit

Permalink
feat: Improve config error messages (#17385)
Browse files Browse the repository at this point in the history
* feat: Improve config error messages

Includes some keys to catch known eslintrc keys when they appear in flat
config. This throws a specific error that the ESLint CLI can then output
a more helpful message about.

fixes #17370

* Update messages/eslintrc-incompat.js

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>

* Update messages/eslintrc-incompat.js

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>

* Apply feedback

---------

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
  • Loading branch information
nzakas and mdjermanovic committed Jul 19, 2023
1 parent 42faa17 commit cf03104
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 1 deletion.
49 changes: 49 additions & 0 deletions lib/config/flat-config-schema.js
Expand Up @@ -212,6 +212,22 @@ function assertIsObject(value) {
}
}

/**
* The error type when there's an eslintrc-style options in a flat config.
*/
class IncompatibleKeyError extends Error {

/**
* @param {string} key The invalid key.
*/
constructor(key) {
super("This appears to be in eslintrc format rather than flat config format.");
this.messageTemplate = "eslintrc-incompat";
this.messageData = { key };
}
}


//-----------------------------------------------------------------------------
// Low-Level Schemas
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -438,11 +454,44 @@ const sourceTypeSchema = {
}
};

/**
* Creates a schema that always throws an error. Useful for warning
* about eslintrc-style keys.
* @param {string} key The eslintrc key to create a schema for.
* @returns {ObjectPropertySchema} The schema.
*/
function createEslintrcErrorSchema(key) {
return {
merge: "replace",
validate() {
throw new IncompatibleKeyError(key);
}
};
}

const eslintrcKeys = [
"env",
"extends",
"globals",
"ignorePatterns",
"noInlineConfig",
"overrides",
"parser",
"parserOptions",
"reportUnusedDisableDirectives",
"root"
];

//-----------------------------------------------------------------------------
// Full schema
//-----------------------------------------------------------------------------

exports.flatConfigSchema = {

// eslintrc-style keys that should always error
...Object.fromEntries(eslintrcKeys.map(key => [key, createEslintrcErrorSchema(key)])),

// flat config keys
settings: deepObjectAssignSchema,
linterOptions: {
schema: {
Expand Down
98 changes: 98 additions & 0 deletions messages/eslintrc-incompat.js
@@ -0,0 +1,98 @@
"use strict";

/* eslint consistent-return: 0 -- no default case */

const messages = {

env: `
A config object is using the "env" key, which is not supported in flat config system.
Flat config uses "languageOptions.globals" to define global variables for your files.
Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#configuring-language-options
`,

extends: `
A config object is using the "extends" key, which is not supported in flat config system.
Instead of "extends", you can include config objects that you'd like to extend from directly in the flat config array.
Please see the following page for more information:
https://eslint.org/docs/latest/use/configure/migration-guide#predefined-configs
`,

globals: `
A config object is using the "globals" key, which is not supported in flat config system.
Flat config uses "languageOptions.globals" to define global variables for your files.
Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#configuring-language-options
`,

ignorePatterns: `
A config object is using the "ignorePatterns" key, which is not supported in flat config system.
Flat config uses "ignores" to specify files to ignore.
Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files
`,

noInlineConfig: `
A config object is using the "noInlineConfig" key, which is not supported in flat config system.
Flat config uses "linterOptions.noInlineConfig" to specify files to ignore.
Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#linter-options
`,

overrides: `
A config object is using the "overrides" key, which is not supported in flat config system.
Flat config is an array that acts like the eslintrc "overrides" array.
Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#glob-based-configs
`,

parser: `
A config object is using the "parser" key, which is not supported in flat config system.
Flat config uses "languageOptions.parser" to override the default parser.
Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#custom-parsers
`,

parserOptions: `
A config object is using the "parserOptions" key, which is not supported in flat config system.
Flat config uses "languageOptions.parserOptions" to specify parser options.
Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#configuring-language-options
`,

reportUnusedDisableDirectives: `
A config object is using the "reportUnusedDisableDirectives" key, which is not supported in flat config system.
Flat config uses "linterOptions.reportUnusedDisableDirectives" to specify files to ignore.
Please see the following page for information on how to convert your config object into the correct format:
https://eslint.org/docs/latest/use/configure/migration-guide#linter-options
`,

root: `
A config object is using the "root" key, which is not supported in flat config system.
Flat configs always act as if they are the root config file, so this key can be safely removed.
`
};

module.exports = function({ key }) {

return messages[key].trim();
};
28 changes: 28 additions & 0 deletions tests/lib/config/flat-config-array.js
Expand Up @@ -1938,5 +1938,33 @@ describe("FlatConfigArray", () => {

});

describe("Invalid Keys", () => {

[
"env",
"extends",
"globals",
"ignorePatterns",
"noInlineConfig",
"overrides",
"parser",
"parserOptions",
"reportUnusedDisableDirectives",
"root"
].forEach(key => {

it(`should error when a ${key} key is found`, async () => {
await assertInvalidConfig([
{
[key]: "foo"
}
], `Key "${key}": This appears to be in eslintrc format rather than flat config format.`);

});
});


});

});
});
2 changes: 1 addition & 1 deletion tests/lib/rule-tester/flat-rule-tester.js
Expand Up @@ -1336,7 +1336,7 @@ describe("FlatRuleTester", () => {
],
invalid: []
});
}, /Unexpected key "env" found./u);
}, /Key "env": This appears to be in eslintrc format rather than flat config format/u);
});

it("should pass-through the tester config to the rule", () => {
Expand Down

0 comments on commit cf03104

Please sign in to comment.