From 2692c07801348f1d3f5da644955993c84fcd991c Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Thu, 22 Feb 2024 08:36:30 +1030 Subject: [PATCH 1/5] [Fix] export flat configs from plugin root and fix flat config crash --- README.md | 29 +++++++++-------------------- index.js | 13 ++++++++++++- lib/rules/index.js | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 64e57912a1..b6edcf4f23 100644 --- a/README.md +++ b/README.md @@ -203,27 +203,16 @@ Refer to the [official docs](https://eslint.org/docs/latest/user-guide/configuri The schema of the `settings.react` object would be identical to that of what's already described above in the legacy config section. -### Shareable configs - -There're also 3 shareable configs. - -- `eslint-plugin-react/configs/all` -- `eslint-plugin-react/configs/recommended` -- `eslint-plugin-react/configs/jsx-runtime` - -If your eslint.config.js is ESM, include the `.js` extension (e.g. `eslint-plugin-react/recommended.js`). Note that the next semver-major will require omitting the extension for these imports. - -**Note**: These configurations will import `eslint-plugin-react` and enable JSX in [`languageOptions.parserOptions`](https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new#configuration-objects). +### Flat Configs -In the new config system, `plugin:` protocol(e.g. `plugin:react/recommended`) is no longer valid. -As eslint does not automatically import the preset config (shareable config), you explicitly do it by yourself. +The flat configs are available via the root plugin import. They will configure the plugin under the `react/` namespace and enable JSX in [`languageOptions.parserOptions`](https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new#configuration-objects). ```js -const reactRecommended = require('eslint-plugin-react/configs/recommended'); +const reactPlugin = require('eslint-plugin-react'); module.exports = [ … - reactRecommended, // This is not a plugin object, but a shareable config object + reactPlugin.configs['flat/recommended'], // This is not a plugin object, but a shareable config object … ]; ``` @@ -234,16 +223,16 @@ You can of course add/override some properties. For most of the cases, you probably want to configure some properties by yourself. ```js -const reactRecommended = require('eslint-plugin-react/configs/recommended'); +const reactPlugin = require('eslint-plugin-react'); const globals = require('globals'); module.exports = [ … { files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'], - ...reactRecommended, + ...reactPlugin.configs['flat/recommended'], languageOptions: { - ...reactRecommended.languageOptions, + ...reactPlugin.configs['flat/recommended'].languageOptions, globals: { ...globals.serviceworker, ...globals.browser, @@ -257,14 +246,14 @@ module.exports = [ The above example is same as the example below, as the new config system is based on chaining. ```js -const reactRecommended = require('eslint-plugin-react/configs/recommended'); +const reactPlugin = require('eslint-plugin-react'); const globals = require('globals'); module.exports = [ … { files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'], - ...reactRecommended, + ...reactPlugin.configs['flat/recommended'], }, { files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'], diff --git a/index.js b/index.js index 4140c6c881..e6bb51593d 100644 --- a/index.js +++ b/index.js @@ -11,7 +11,7 @@ const plugins = [ 'react', ]; -module.exports = { +const plugin = { deprecatedRules: configAll.plugins.react.deprecatedRules, rules: allRules, configs: { @@ -27,5 +27,16 @@ module.exports = { parserOptions: configRuntime.languageOptions.parserOptions, plugins, }), + + 'flat/recommended': Object.assign({}, configRecommended), + 'flat/all': Object.assign({}, configAll), + 'flat/jsx-runtime': Object.assign({}, configRuntime), }, }; + +// need to ensure the flat configs reference the same plugin identity +plugin.configs['flat/recommended'].plugins.react = plugin; +plugin.configs['flat/all'].plugins.react = plugin; +plugin.configs['flat/recommended'].plugins.react = plugin; + +module.exports = plugin; diff --git a/lib/rules/index.js b/lib/rules/index.js index 784831bba7..c30dc6e609 100644 --- a/lib/rules/index.js +++ b/lib/rules/index.js @@ -2,7 +2,7 @@ /* eslint global-require: 0 */ -/** @type {Record} */ +/** @satisfies {Record} */ module.exports = { 'boolean-prop-naming': require('./boolean-prop-naming'), 'button-has-type': require('./button-has-type'), From 60340f8050ae13c2e8c0e55f6fd3777a9c086c20 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sun, 16 Jun 2024 21:58:48 +0200 Subject: [PATCH 2/5] update docs --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b6edcf4f23..060a3b1275 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,13 @@ The schema of the `settings.react` object would be identical to that of what's a ### Flat Configs -The flat configs are available via the root plugin import. They will configure the plugin under the `react/` namespace and enable JSX in [`languageOptions.parserOptions`](https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new#configuration-objects). +This plugin exports 3 flat configs. + +- `flat/all` +- `flat/recommended` +- `flat/jsx-runtime` + +The flat configs are available via the root plugin import. They will configure the plugin under the `react/` namespace and enable JSX in [`languageOptions.parserOptions`](https://eslint.org/docs/latest/use/configure/language-options#specifying-parser-options). ```js const reactPlugin = require('eslint-plugin-react'); From 4be7f0ebfa9f379c1f53412e094bc7b93436be2e Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sun, 16 Jun 2024 22:38:39 +0200 Subject: [PATCH 3/5] [Fix] use same plugin instance in flat configs --- configs/all.js | 46 ++--------------- configs/jsx-runtime.js | 21 +++----- configs/recommended.js | 37 +++----------- index.js | 109 +++++++++++++++++++++++++++++++++-------- 4 files changed, 109 insertions(+), 104 deletions(-) diff --git a/configs/all.js b/configs/all.js index bcb416e295..1037bc8da1 100644 --- a/configs/all.js +++ b/configs/all.js @@ -1,49 +1,13 @@ 'use strict'; -const fromEntries = require('object.fromentries'); -const entries = require('object.entries'); +const plugin = require('../index'); -const allRules = require('../lib/rules'); - -function filterRules(rules, predicate) { - return fromEntries(entries(rules).filter((entry) => predicate(entry[1]))); -} - -/** - * @param {object} rules - rules object mapping rule name to rule module - * @returns {Record} - */ -function configureAsError(rules) { - return fromEntries(Object.keys(rules).map((key) => [`react/${key}`, 2])); -} - -const activeRules = filterRules(allRules, (rule) => !rule.meta.deprecated); -const activeRulesConfig = configureAsError(activeRules); - -const deprecatedRules = filterRules(allRules, (rule) => rule.meta.deprecated); +const legacyConfig = plugin.configs.all; module.exports = { - plugins: { - /** - * @type {{ - * deprecatedRules: Record, - * rules: Record, - * }} - */ - react: { - deprecatedRules, - rules: allRules, - }, - }, - rules: activeRulesConfig, - languageOptions: { - parserOptions: { - ecmaFeatures: { - jsx: true, - }, - }, - }, + plugins: { react: plugin }, + rules: legacyConfig.rules, + languageOptions: { parserOptions: legacyConfig.parserOptions }, }; -// this is so the `languageOptions` property won't be warned in the new config system Object.defineProperty(module.exports, 'languageOptions', { enumerable: false }); diff --git a/configs/jsx-runtime.js b/configs/jsx-runtime.js index a6302be504..764e7aed43 100644 --- a/configs/jsx-runtime.js +++ b/configs/jsx-runtime.js @@ -1,18 +1,13 @@ 'use strict'; -const all = require('./all'); +const plugin = require('../index'); -module.exports = Object.assign({}, all, { - languageOptions: Object.assign({}, all.languageOptions, { - parserOptions: Object.assign({}, all.languageOptions.parserOptions, { - jsxPragma: null, // for @typescript/eslint-parser - }), - }), - rules: { - 'react/react-in-jsx-scope': 0, - 'react/jsx-uses-react': 0, - }, -}); +const legacyConfig = plugin.configs['jsx-runtime']; + +module.exports = { + plugins: { react: plugin }, + rules: legacyConfig.rules, + languageOptions: { parserOptions: legacyConfig.parserOptions }, +}; -// this is so the `languageOptions` property won't be warned in the new config system Object.defineProperty(module.exports, 'languageOptions', { enumerable: false }); diff --git a/configs/recommended.js b/configs/recommended.js index 0bba09f7bb..3af34bac4a 100644 --- a/configs/recommended.js +++ b/configs/recommended.js @@ -1,34 +1,13 @@ 'use strict'; -const all = require('./all'); +const plugin = require('../index'); -module.exports = Object.assign({}, all, { - languageOptions: all.languageOptions, - rules: { - 'react/display-name': 2, - 'react/jsx-key': 2, - 'react/jsx-no-comment-textnodes': 2, - 'react/jsx-no-duplicate-props': 2, - 'react/jsx-no-target-blank': 2, - 'react/jsx-no-undef': 2, - 'react/jsx-uses-react': 2, - 'react/jsx-uses-vars': 2, - 'react/no-children-prop': 2, - 'react/no-danger-with-children': 2, - 'react/no-deprecated': 2, - 'react/no-direct-mutation-state': 2, - 'react/no-find-dom-node': 2, - 'react/no-is-mounted': 2, - 'react/no-render-return-value': 2, - 'react/no-string-refs': 2, - 'react/no-unescaped-entities': 2, - 'react/no-unknown-property': 2, - 'react/no-unsafe': 0, - 'react/prop-types': 2, - 'react/react-in-jsx-scope': 2, - 'react/require-render-return': 2, - }, -}); +const legacyConfig = plugin.configs.recommended; + +module.exports = { + plugins: { react: plugin }, + rules: legacyConfig.rules, + languageOptions: { parserOptions: legacyConfig.parserOptions }, +}; -// this is so the `languageOptions` property won't be warned in the new config system Object.defineProperty(module.exports, 'languageOptions', { enumerable: false }); diff --git a/index.js b/index.js index e6bb51593d..2a54031aa0 100644 --- a/index.js +++ b/index.js @@ -1,42 +1,109 @@ 'use strict'; -const configAll = require('./configs/all'); -const configRecommended = require('./configs/recommended'); -const configRuntime = require('./configs/jsx-runtime'); +const fromEntries = require('object.fromentries'); +const entries = require('object.entries'); const allRules = require('./lib/rules'); +function filterRules(rules, predicate) { + return fromEntries(entries(rules).filter((entry) => predicate(entry[1]))); +} + +/** + * @param {object} rules - rules object mapping rule name to rule module + * @returns {Record} + */ +function configureAsError(rules) { + return fromEntries(Object.keys(rules).map((key) => [`react/${key}`, 2])); +} + +const activeRules = filterRules(allRules, (rule) => !rule.meta.deprecated); +const activeRulesConfig = configureAsError(activeRules); + +const deprecatedRules = filterRules(allRules, (rule) => rule.meta.deprecated); + // for legacy config system const plugins = [ 'react', ]; const plugin = { - deprecatedRules: configAll.plugins.react.deprecatedRules, + deprecatedRules, rules: allRules, configs: { - recommended: Object.assign({}, configRecommended, { - parserOptions: configRecommended.languageOptions.parserOptions, + recommended: { plugins, - }), - all: Object.assign({}, configAll, { - parserOptions: configAll.languageOptions.parserOptions, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + rules: { + 'react/display-name': 2, + 'react/jsx-key': 2, + 'react/jsx-no-comment-textnodes': 2, + 'react/jsx-no-duplicate-props': 2, + 'react/jsx-no-target-blank': 2, + 'react/jsx-no-undef': 2, + 'react/jsx-uses-react': 2, + 'react/jsx-uses-vars': 2, + 'react/no-children-prop': 2, + 'react/no-danger-with-children': 2, + 'react/no-deprecated': 2, + 'react/no-direct-mutation-state': 2, + 'react/no-find-dom-node': 2, + 'react/no-is-mounted': 2, + 'react/no-render-return-value': 2, + 'react/no-string-refs': 2, + 'react/no-unescaped-entities': 2, + 'react/no-unknown-property': 2, + 'react/no-unsafe': 0, + 'react/prop-types': 2, + 'react/react-in-jsx-scope': 2, + 'react/require-render-return': 2, + }, + }, + all: { plugins, - }), - 'jsx-runtime': Object.assign({}, configRuntime, { - parserOptions: configRuntime.languageOptions.parserOptions, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + rules: activeRulesConfig, + }, + 'jsx-runtime': { plugins, - }), - - 'flat/recommended': Object.assign({}, configRecommended), - 'flat/all': Object.assign({}, configAll), - 'flat/jsx-runtime': Object.assign({}, configRuntime), + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + jsxPragma: null, // for @typescript/eslint-parser + }, + rules: { + 'react/react-in-jsx-scope': 0, + 'react/jsx-uses-react': 0, + }, + }, }, }; -// need to ensure the flat configs reference the same plugin identity -plugin.configs['flat/recommended'].plugins.react = plugin; -plugin.configs['flat/all'].plugins.react = plugin; -plugin.configs['flat/recommended'].plugins.react = plugin; +plugin.configs['flat/recommended'] = { + plugins: { react: plugin }, + rules: plugin.configs.recommended.rules, + languageOptions: { parserOptions: plugin.configs.recommended.parserOptions }, +}; + +plugin.configs['flat/all'] = { + plugins: { react: plugin }, + rules: plugin.configs.all.rules, + languageOptions: { parserOptions: plugin.configs.all.parserOptions }, +}; + +plugin.configs['flat/jsx-runtime'] = { + plugins: { react: plugin }, + rules: plugin.configs['jsx-runtime'].rules, + languageOptions: { parserOptions: plugin.configs['jsx-runtime'].parserOptions }, +}; module.exports = plugin; From a32c0ad69dd77cc268fcc51ea44c671467bb0028 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sun, 16 Jun 2024 23:38:43 +0200 Subject: [PATCH 4/5] [Tests] test plugin in flat configs --- .eslintrc | 1 + package.json | 2 +- .../config-all/eslint.config-deep.js | 11 ++ .../config-all/eslint.config-root.js | 8 ++ .../fixtures/flat-config/config-all/test.jsx | 3 + .../config-jsx-runtime/eslint.config-deep.js | 15 +++ .../config-jsx-runtime/eslint.config-root.js | 11 ++ .../flat-config/config-jsx-runtime/test.jsx | 3 + .../config-recommended/eslint.config-deep.js | 11 ++ .../config-recommended/eslint.config-root.js | 8 ++ .../flat-config/config-recommended/test.jsx | 3 + .../plugin-and-config/eslint.config-deep.js | 18 +++ .../plugin-and-config/eslint.config-root.js | 15 +++ .../flat-config/plugin-and-config/test.jsx | 3 + .../flat-config/plugin/eslint.config.js | 20 +++ tests/fixtures/flat-config/plugin/test.jsx | 3 + tests/flat-config.js | 117 ++++++++++++++++++ 17 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/flat-config/config-all/eslint.config-deep.js create mode 100644 tests/fixtures/flat-config/config-all/eslint.config-root.js create mode 100644 tests/fixtures/flat-config/config-all/test.jsx create mode 100644 tests/fixtures/flat-config/config-jsx-runtime/eslint.config-deep.js create mode 100644 tests/fixtures/flat-config/config-jsx-runtime/eslint.config-root.js create mode 100644 tests/fixtures/flat-config/config-jsx-runtime/test.jsx create mode 100644 tests/fixtures/flat-config/config-recommended/eslint.config-deep.js create mode 100644 tests/fixtures/flat-config/config-recommended/eslint.config-root.js create mode 100644 tests/fixtures/flat-config/config-recommended/test.jsx create mode 100644 tests/fixtures/flat-config/plugin-and-config/eslint.config-deep.js create mode 100644 tests/fixtures/flat-config/plugin-and-config/eslint.config-root.js create mode 100644 tests/fixtures/flat-config/plugin-and-config/test.jsx create mode 100644 tests/fixtures/flat-config/plugin/eslint.config.js create mode 100644 tests/fixtures/flat-config/plugin/test.jsx create mode 100644 tests/flat-config.js diff --git a/.eslintrc b/.eslintrc index d10247d296..225c0678ba 100644 --- a/.eslintrc +++ b/.eslintrc @@ -16,6 +16,7 @@ "ignorePatterns": [ "coverage/", ".nyc_output/", + "tests/fixtures/flat-config/" ], "rules": { "comma-dangle": [2, "always-multiline"], diff --git a/package.json b/package.json index 4f5155c832..0b722b011a 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "test": "npm run unit-test", "posttest": "aud --production", "type-check": "tsc", - "unit-test": "istanbul cover node_modules/mocha/bin/_mocha tests/lib/**/*.js tests/util/**/*.js tests/index.js", + "unit-test": "istanbul cover node_modules/mocha/bin/_mocha tests/lib/**/*.js tests/util/**/*.js tests/index.js tests/flat-config.js", "update:eslint-docs": "eslint-doc-generator" }, "repository": { diff --git a/tests/fixtures/flat-config/config-all/eslint.config-deep.js b/tests/fixtures/flat-config/config-all/eslint.config-deep.js new file mode 100644 index 0000000000..e74b950f50 --- /dev/null +++ b/tests/fixtures/flat-config/config-all/eslint.config-deep.js @@ -0,0 +1,11 @@ +'use strict'; + +const reactAll = require('../../../../configs/all'); + +module.exports = [{ + files: ['**/*.jsx'], + ...reactAll, + languageOptions: { + ...reactAll.languageOptions + } +}]; diff --git a/tests/fixtures/flat-config/config-all/eslint.config-root.js b/tests/fixtures/flat-config/config-all/eslint.config-root.js new file mode 100644 index 0000000000..0caeed41c0 --- /dev/null +++ b/tests/fixtures/flat-config/config-all/eslint.config-root.js @@ -0,0 +1,8 @@ +'use strict'; + +const reactPlugin = require('../../../..'); + +module.exports = [{ + files: ['**/*.jsx'], + ...reactPlugin.configs['flat/all'] +}]; diff --git a/tests/fixtures/flat-config/config-all/test.jsx b/tests/fixtures/flat-config/config-all/test.jsx new file mode 100644 index 0000000000..66e96ef9ed --- /dev/null +++ b/tests/fixtures/flat-config/config-all/test.jsx @@ -0,0 +1,3 @@ +
+ test +
diff --git a/tests/fixtures/flat-config/config-jsx-runtime/eslint.config-deep.js b/tests/fixtures/flat-config/config-jsx-runtime/eslint.config-deep.js new file mode 100644 index 0000000000..053bf08dab --- /dev/null +++ b/tests/fixtures/flat-config/config-jsx-runtime/eslint.config-deep.js @@ -0,0 +1,15 @@ +'use strict'; + +const reactRecommended = require('../../../../configs/recommended'); +const reactJSXRuntime = require('../../../../configs/jsx-runtime'); + +module.exports = [ + { + files: ['**/*.jsx'], + ...reactRecommended, + languageOptions: { + ...reactRecommended.languageOptions + } + }, + reactJSXRuntime +]; diff --git a/tests/fixtures/flat-config/config-jsx-runtime/eslint.config-root.js b/tests/fixtures/flat-config/config-jsx-runtime/eslint.config-root.js new file mode 100644 index 0000000000..f34f321014 --- /dev/null +++ b/tests/fixtures/flat-config/config-jsx-runtime/eslint.config-root.js @@ -0,0 +1,11 @@ +'use strict'; + +const reactPlugin = require('../../../..'); + +module.exports = [ + { + files: ['**/*.jsx'], + ...reactPlugin.configs['flat/recommended'] + }, + reactPlugin.configs['flat/jsx-runtime'] +]; diff --git a/tests/fixtures/flat-config/config-jsx-runtime/test.jsx b/tests/fixtures/flat-config/config-jsx-runtime/test.jsx new file mode 100644 index 0000000000..66e96ef9ed --- /dev/null +++ b/tests/fixtures/flat-config/config-jsx-runtime/test.jsx @@ -0,0 +1,3 @@ +
+ test +
diff --git a/tests/fixtures/flat-config/config-recommended/eslint.config-deep.js b/tests/fixtures/flat-config/config-recommended/eslint.config-deep.js new file mode 100644 index 0000000000..f9471c23e1 --- /dev/null +++ b/tests/fixtures/flat-config/config-recommended/eslint.config-deep.js @@ -0,0 +1,11 @@ +'use strict'; + +const reactRecommended = require('../../../../configs/recommended'); + +module.exports = [{ + files: ['**/*.jsx'], + ...reactRecommended, + languageOptions: { + ...reactRecommended.languageOptions + } +}]; diff --git a/tests/fixtures/flat-config/config-recommended/eslint.config-root.js b/tests/fixtures/flat-config/config-recommended/eslint.config-root.js new file mode 100644 index 0000000000..5b3685beb7 --- /dev/null +++ b/tests/fixtures/flat-config/config-recommended/eslint.config-root.js @@ -0,0 +1,8 @@ +'use strict'; + +const reactPlugin = require('../../../..'); + +module.exports = [{ + files: ['**/*.jsx'], + ...reactPlugin.configs['flat/recommended'] +}]; diff --git a/tests/fixtures/flat-config/config-recommended/test.jsx b/tests/fixtures/flat-config/config-recommended/test.jsx new file mode 100644 index 0000000000..66e96ef9ed --- /dev/null +++ b/tests/fixtures/flat-config/config-recommended/test.jsx @@ -0,0 +1,3 @@ +
+ test +
diff --git a/tests/fixtures/flat-config/plugin-and-config/eslint.config-deep.js b/tests/fixtures/flat-config/plugin-and-config/eslint.config-deep.js new file mode 100644 index 0000000000..ea4882daa1 --- /dev/null +++ b/tests/fixtures/flat-config/plugin-and-config/eslint.config-deep.js @@ -0,0 +1,18 @@ +'use strict'; + +const react = require('../../../..'); +const reactRecommended = require('../../../../configs/recommended'); + +module.exports = [ + { + files: ['**/*.jsx'], + plugins: { react } + }, + { + files: ['**/*.jsx'], + ...reactRecommended, + languageOptions: { + ...reactRecommended.languageOptions + } + } +]; diff --git a/tests/fixtures/flat-config/plugin-and-config/eslint.config-root.js b/tests/fixtures/flat-config/plugin-and-config/eslint.config-root.js new file mode 100644 index 0000000000..c3db2dd691 --- /dev/null +++ b/tests/fixtures/flat-config/plugin-and-config/eslint.config-root.js @@ -0,0 +1,15 @@ +'use strict'; + +const react = require('../../../..'); +const reactRecommended = require('../../../../configs/recommended'); + +module.exports = [ + { + files: ['**/*.jsx'], + plugins: { react } + }, + { + files: ['**/*.jsx'], + ...react.configs['flat/recommended'] + } +]; diff --git a/tests/fixtures/flat-config/plugin-and-config/test.jsx b/tests/fixtures/flat-config/plugin-and-config/test.jsx new file mode 100644 index 0000000000..66e96ef9ed --- /dev/null +++ b/tests/fixtures/flat-config/plugin-and-config/test.jsx @@ -0,0 +1,3 @@ +
+ test +
diff --git a/tests/fixtures/flat-config/plugin/eslint.config.js b/tests/fixtures/flat-config/plugin/eslint.config.js new file mode 100644 index 0000000000..9945a4494e --- /dev/null +++ b/tests/fixtures/flat-config/plugin/eslint.config.js @@ -0,0 +1,20 @@ +'use strict'; + +const react = require('../../../..'); + +module.exports = [{ + files: ['**/*.jsx'], + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + plugins: { + react, + }, + rules: { + 'react/jsx-no-literals': 1, + }, +}]; diff --git a/tests/fixtures/flat-config/plugin/test.jsx b/tests/fixtures/flat-config/plugin/test.jsx new file mode 100644 index 0000000000..66e96ef9ed --- /dev/null +++ b/tests/fixtures/flat-config/plugin/test.jsx @@ -0,0 +1,3 @@ +
+ test +
diff --git a/tests/flat-config.js b/tests/flat-config.js new file mode 100644 index 0000000000..43b8faa24c --- /dev/null +++ b/tests/flat-config.js @@ -0,0 +1,117 @@ +/* eslint-env mocha */ + +'use strict'; + +const semver = require('semver'); +const eslintPkg = require('eslint/package.json'); + +if (!semver.satisfies(eslintPkg.version, '>= 8.57.0')) { + return; +} + +const ESLint = semver.major(eslintPkg.version) < 9 + ? require('eslint/use-at-your-own-risk').FlatESLint // eslint-disable-line import/no-unresolved -- false positive + : require('eslint').ESLint; + +const path = require('path'); +const assert = require('assert'); + +describe('eslint-plugin-react in flat config', () => { + const fixturesdDir = path.resolve(__dirname, 'fixtures', 'flat-config'); + + it('should work when the plugin is used directly', () => { + const eslint = new ESLint({ + cwd: path.resolve(fixturesdDir, 'plugin'), + }); + + return eslint.lintFiles(['test.jsx']).then((results) => { + const result = results[0]; + + assert.strictEqual(result.messages.length, 1); + assert.strictEqual(result.messages[0].severity, 1); + assert.strictEqual(result.messages[0].ruleId, 'react/jsx-no-literals'); + assert.strictEqual(result.messages[0].messageId, 'literalNotInJSXExpression'); + }); + }); + + ['root', 'deep'].forEach((configAccess) => { + const overrideConfigFile = `eslint.config-${configAccess}.js`; + + it(`should work when the plugin is used with "all" config (${configAccess})`, () => { + const eslint = new ESLint({ + cwd: path.resolve(fixturesdDir, 'config-all'), + overrideConfigFile, + }); + + return eslint.lintFiles(['test.jsx']).then((results) => { + const result = results[0]; + + assert.strictEqual(result.messages.length, 3); + assert.strictEqual(result.messages[0].severity, 2); + assert.strictEqual(result.messages[0].ruleId, 'react/react-in-jsx-scope'); + assert.strictEqual(result.messages[0].messageId, 'notInScope'); + assert.strictEqual(result.messages[1].severity, 2); + assert.strictEqual(result.messages[1].ruleId, 'react/no-unknown-property'); + assert.strictEqual(result.messages[1].messageId, 'unknownProp'); + assert.strictEqual(result.messages[2].severity, 2); + assert.strictEqual(result.messages[2].ruleId, 'react/jsx-no-literals'); + assert.strictEqual(result.messages[2].messageId, 'literalNotInJSXExpression'); + }); + }); + + it(`should work when the plugin is used with "recommended" config (${configAccess})`, () => { + const eslint = new ESLint({ + cwd: path.resolve(fixturesdDir, 'config-recommended'), + overrideConfigFile, + }); + + return eslint.lintFiles(['test.jsx']).then((results) => { + const result = results[0]; + + assert.strictEqual(result.messages.length, 2); + assert.strictEqual(result.messages[0].severity, 2); + assert.strictEqual(result.messages[0].ruleId, 'react/react-in-jsx-scope'); + assert.strictEqual(result.messages[0].messageId, 'notInScope'); + assert.strictEqual(result.messages[1].severity, 2); + assert.strictEqual(result.messages[1].ruleId, 'react/no-unknown-property'); + assert.strictEqual(result.messages[1].messageId, 'unknownProp'); + }); + }); + + it(`should work when the plugin is used with "recommended" and "jsx-runtime" configs (${configAccess})`, () => { + const eslint = new ESLint({ + cwd: path.resolve(fixturesdDir, 'config-jsx-runtime'), + overrideConfigFile, + }); + + return eslint.lintFiles(['test.jsx']).then((results) => { + const result = results[0]; + + assert.strictEqual(result.messages.length, 1); + assert.strictEqual(result.messages[0].severity, 2); + assert.strictEqual(result.messages[0].ruleId, 'react/no-unknown-property'); + assert.strictEqual(result.messages[0].messageId, 'unknownProp'); + }); + }); + + // https://github.com/jsx-eslint/eslint-plugin-react/issues/3693 + it(`should work when the plugin is used directly and with "recommended" config (${configAccess})`, () => { + const eslint = new ESLint({ + cwd: path.resolve(fixturesdDir, 'plugin-and-config'), + overrideConfigFile, + }); + + return eslint.lintFiles(['test.jsx']).then((results) => { + const result = results[0]; + + assert.strictEqual(result.messages.length, 2); + assert.strictEqual(result.messages[0].severity, 2); + assert.strictEqual(result.messages[0].ruleId, 'react/react-in-jsx-scope'); + assert.strictEqual(result.messages[0].messageId, 'notInScope'); + assert.strictEqual(result.messages[1].severity, 2); + assert.strictEqual(result.messages[1].ruleId, 'react/no-unknown-property'); + assert.strictEqual(result.messages[1].messageId, 'unknownProp'); + }); + }); + }); +}); From a44e0256211816306c8092f2ece532f6cdd242e6 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Sun, 16 Jun 2024 23:51:32 +0200 Subject: [PATCH 5/5] ignore flat configs in doc generator --- .eslint-doc-generatorrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslint-doc-generatorrc.js b/.eslint-doc-generatorrc.js index 1e6d1717f3..f42a39e130 100644 --- a/.eslint-doc-generatorrc.js +++ b/.eslint-doc-generatorrc.js @@ -4,7 +4,7 @@ const config = { ['jsx-runtime', '🏃'], ['recommended', '☑️'], ], - ignoreConfig: ['all'], + ignoreConfig: ['all', 'flat/all', 'flat/recommended', `flat/jsx-runtime`], urlConfigs: 'https://github.com/jsx-eslint/eslint-plugin-react/#shareable-configs', };