diff --git a/CHANGELOG.md b/CHANGELOG.md index 73fe1726c9..3ce65c9fb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## Unreleased +### Fixed +* prevent circular dependency in index and "all" config ([#3519][] @ljharb) + +[#3519]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3519 + ## [7.32.0] - 2023.01.10 ### Added diff --git a/configs/all.js b/configs/all.js index 302fbaf88e..c507744ac1 100644 --- a/configs/all.js +++ b/configs/all.js @@ -1,119 +1,31 @@ 'use strict'; -const react = require('../index'); +const fromEntries = require('object.fromentries'); +const entries = require('object.entries'); -const plugin = Object.assign({}, react); -delete plugin.configs; +const allRules = require('../lib/rules'); -/* eslint-disable global-require */ -const allRules = { - 'boolean-prop-naming': require('../lib/rules/boolean-prop-naming'), - 'button-has-type': require('../lib/rules/button-has-type'), - 'default-props-match-prop-types': require('../lib/rules/default-props-match-prop-types'), - 'destructuring-assignment': require('../lib/rules/destructuring-assignment'), - 'display-name': require('../lib/rules/display-name'), - 'forbid-component-props': require('../lib/rules/forbid-component-props'), - 'forbid-dom-props': require('../lib/rules/forbid-dom-props'), - 'forbid-elements': require('../lib/rules/forbid-elements'), - 'forbid-foreign-prop-types': require('../lib/rules/forbid-foreign-prop-types'), - 'forbid-prop-types': require('../lib/rules/forbid-prop-types'), - 'function-component-definition': require('../lib/rules/function-component-definition'), - 'hook-use-state': require('../lib/rules/hook-use-state'), - 'iframe-missing-sandbox': require('../lib/rules/iframe-missing-sandbox'), - 'jsx-boolean-value': require('../lib/rules/jsx-boolean-value'), - 'jsx-child-element-spacing': require('../lib/rules/jsx-child-element-spacing'), - 'jsx-closing-bracket-location': require('../lib/rules/jsx-closing-bracket-location'), - 'jsx-closing-tag-location': require('../lib/rules/jsx-closing-tag-location'), - 'jsx-curly-spacing': require('../lib/rules/jsx-curly-spacing'), - 'jsx-curly-newline': require('../lib/rules/jsx-curly-newline'), - 'jsx-equals-spacing': require('../lib/rules/jsx-equals-spacing'), - 'jsx-filename-extension': require('../lib/rules/jsx-filename-extension'), - 'jsx-first-prop-new-line': require('../lib/rules/jsx-first-prop-new-line'), - 'jsx-handler-names': require('../lib/rules/jsx-handler-names'), - 'jsx-indent': require('../lib/rules/jsx-indent'), - 'jsx-indent-props': require('../lib/rules/jsx-indent-props'), - 'jsx-key': require('../lib/rules/jsx-key'), - 'jsx-max-depth': require('../lib/rules/jsx-max-depth'), - 'jsx-max-props-per-line': require('../lib/rules/jsx-max-props-per-line'), - 'jsx-newline': require('../lib/rules/jsx-newline'), - 'jsx-no-bind': require('../lib/rules/jsx-no-bind'), - 'jsx-no-comment-textnodes': require('../lib/rules/jsx-no-comment-textnodes'), - 'jsx-no-constructed-context-values': require('../lib/rules/jsx-no-constructed-context-values'), - 'jsx-no-duplicate-props': require('../lib/rules/jsx-no-duplicate-props'), - 'jsx-no-leaked-render': require('../lib/rules/jsx-no-leaked-render'), - 'jsx-no-literals': require('../lib/rules/jsx-no-literals'), - 'jsx-no-script-url': require('../lib/rules/jsx-no-script-url'), - 'jsx-no-target-blank': require('../lib/rules/jsx-no-target-blank'), - 'jsx-no-useless-fragment': require('../lib/rules/jsx-no-useless-fragment'), - 'jsx-one-expression-per-line': require('../lib/rules/jsx-one-expression-per-line'), - 'jsx-no-undef': require('../lib/rules/jsx-no-undef'), - 'jsx-curly-brace-presence': require('../lib/rules/jsx-curly-brace-presence'), - 'jsx-pascal-case': require('../lib/rules/jsx-pascal-case'), - 'jsx-fragments': require('../lib/rules/jsx-fragments'), - 'jsx-props-no-multi-spaces': require('../lib/rules/jsx-props-no-multi-spaces'), - 'jsx-props-no-spreading': require('../lib/rules/jsx-props-no-spreading'), - 'jsx-sort-default-props': require('../lib/rules/jsx-sort-default-props'), - 'jsx-sort-props': require('../lib/rules/jsx-sort-props'), - 'jsx-space-before-closing': require('../lib/rules/jsx-space-before-closing'), - 'jsx-tag-spacing': require('../lib/rules/jsx-tag-spacing'), - 'jsx-uses-react': require('../lib/rules/jsx-uses-react'), - 'jsx-uses-vars': require('../lib/rules/jsx-uses-vars'), - 'jsx-wrap-multilines': require('../lib/rules/jsx-wrap-multilines'), - 'no-invalid-html-attribute': require('../lib/rules/no-invalid-html-attribute'), - 'no-access-state-in-setstate': require('../lib/rules/no-access-state-in-setstate'), - 'no-adjacent-inline-elements': require('../lib/rules/no-adjacent-inline-elements'), - 'no-array-index-key': require('../lib/rules/no-array-index-key'), - 'no-arrow-function-lifecycle': require('../lib/rules/no-arrow-function-lifecycle'), - 'no-children-prop': require('../lib/rules/no-children-prop'), - 'no-danger': require('../lib/rules/no-danger'), - 'no-danger-with-children': require('../lib/rules/no-danger-with-children'), - 'no-deprecated': require('../lib/rules/no-deprecated'), - 'no-did-mount-set-state': require('../lib/rules/no-did-mount-set-state'), - 'no-did-update-set-state': require('../lib/rules/no-did-update-set-state'), - 'no-direct-mutation-state': require('../lib/rules/no-direct-mutation-state'), - 'no-find-dom-node': require('../lib/rules/no-find-dom-node'), - 'no-is-mounted': require('../lib/rules/no-is-mounted'), - 'no-multi-comp': require('../lib/rules/no-multi-comp'), - 'no-namespace': require('../lib/rules/no-namespace'), - 'no-set-state': require('../lib/rules/no-set-state'), - 'no-string-refs': require('../lib/rules/no-string-refs'), - 'no-redundant-should-component-update': require('../lib/rules/no-redundant-should-component-update'), - 'no-render-return-value': require('../lib/rules/no-render-return-value'), - 'no-this-in-sfc': require('../lib/rules/no-this-in-sfc'), - 'no-typos': require('../lib/rules/no-typos'), - 'no-unescaped-entities': require('../lib/rules/no-unescaped-entities'), - 'no-unknown-property': require('../lib/rules/no-unknown-property'), - 'no-unsafe': require('../lib/rules/no-unsafe'), - 'no-unstable-nested-components': require('../lib/rules/no-unstable-nested-components'), - 'no-unused-class-component-methods': require('../lib/rules/no-unused-class-component-methods'), - 'no-unused-prop-types': require('../lib/rules/no-unused-prop-types'), - 'no-unused-state': require('../lib/rules/no-unused-state'), - 'no-object-type-as-default-prop': require('../lib/rules/no-object-type-as-default-prop'), - 'no-will-update-set-state': require('../lib/rules/no-will-update-set-state'), - 'prefer-es6-class': require('../lib/rules/prefer-es6-class'), - 'prefer-exact-props': require('../lib/rules/prefer-exact-props'), - 'prefer-read-only-props': require('../lib/rules/prefer-read-only-props'), - 'prefer-stateless-function': require('../lib/rules/prefer-stateless-function'), - 'prop-types': require('../lib/rules/prop-types'), - 'react-in-jsx-scope': require('../lib/rules/react-in-jsx-scope'), - 'require-default-props': require('../lib/rules/require-default-props'), - 'require-optimization': require('../lib/rules/require-optimization'), - 'require-render-return': require('../lib/rules/require-render-return'), - 'self-closing-comp': require('../lib/rules/self-closing-comp'), - 'sort-comp': require('../lib/rules/sort-comp'), - 'sort-default-props': require('../lib/rules/sort-default-props'), - 'sort-prop-types': require('../lib/rules/sort-prop-types'), - 'state-in-constructor': require('../lib/rules/state-in-constructor'), - 'static-property-placement': require('../lib/rules/static-property-placement'), - 'style-prop-object': require('../lib/rules/style-prop-object'), - 'void-dom-elements-no-children': require('../lib/rules/void-dom-elements-no-children'), -}; -/* eslint-enable global-require */ +function filterRules(rules, predicate) { + return fromEntries(entries(rules).filter((entry) => predicate(entry[1]))); +} + +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); module.exports = { plugins: { - react: plugin, + react: { + deprecatedRules, + rules: allRules, + }, }, + rules: activeRulesConfig, languageOptions: { parserOptions: { ecmaFeatures: { @@ -121,7 +33,6 @@ module.exports = { }, }, }, - rules: allRules, }; // this is so the `languageOptions` property won't be warned in the new config system diff --git a/index.js b/index.js index e9f2802e91..2c47ef6bec 100644 --- a/index.js +++ b/index.js @@ -1,44 +1,28 @@ 'use strict'; -const fromEntries = require('object.fromentries'); -const entries = require('object.entries'); - const configAll = require('./configs/all'); const configRecommended = require('./configs/recommended'); const configRuntime = require('./configs/jsx-runtime'); -const allRules = configAll.rules; - -function filterRules(rules, predicate) { - return fromEntries(entries(rules).filter((entry) => predicate(entry[1]))); -} - -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 allRules = require('./lib/rules'); -const eslintrcPlugins = [ +// for legacy config system +const plugins = [ 'react', ]; module.exports = { - deprecatedRules, + deprecatedRules: configAll.plugins.react.deprecatedRules, rules: allRules, configs: { recommended: Object.assign({}, configRecommended, { - plugins: eslintrcPlugins, + plugins, }), all: Object.assign({}, configAll, { - plugins: eslintrcPlugins, - rules: activeRulesConfig, + plugins, }), 'jsx-runtime': Object.assign({}, configRuntime, { - plugins: eslintrcPlugins, + plugins, }), }, }; diff --git a/lib/rules/index.js b/lib/rules/index.js new file mode 100644 index 0000000000..d7142ed9b4 --- /dev/null +++ b/lib/rules/index.js @@ -0,0 +1,106 @@ +'use strict'; + +/* eslint global-require: 0 */ + +module.exports = { + 'boolean-prop-naming': require('./boolean-prop-naming'), + 'button-has-type': require('./button-has-type'), + 'default-props-match-prop-types': require('./default-props-match-prop-types'), + 'destructuring-assignment': require('./destructuring-assignment'), + 'display-name': require('./display-name'), + 'forbid-component-props': require('./forbid-component-props'), + 'forbid-dom-props': require('./forbid-dom-props'), + 'forbid-elements': require('./forbid-elements'), + 'forbid-foreign-prop-types': require('./forbid-foreign-prop-types'), + 'forbid-prop-types': require('./forbid-prop-types'), + 'function-component-definition': require('./function-component-definition'), + 'hook-use-state': require('./hook-use-state'), + 'iframe-missing-sandbox': require('./iframe-missing-sandbox'), + 'jsx-boolean-value': require('./jsx-boolean-value'), + 'jsx-child-element-spacing': require('./jsx-child-element-spacing'), + 'jsx-closing-bracket-location': require('./jsx-closing-bracket-location'), + 'jsx-closing-tag-location': require('./jsx-closing-tag-location'), + 'jsx-curly-spacing': require('./jsx-curly-spacing'), + 'jsx-curly-newline': require('./jsx-curly-newline'), + 'jsx-equals-spacing': require('./jsx-equals-spacing'), + 'jsx-filename-extension': require('./jsx-filename-extension'), + 'jsx-first-prop-new-line': require('./jsx-first-prop-new-line'), + 'jsx-handler-names': require('./jsx-handler-names'), + 'jsx-indent': require('./jsx-indent'), + 'jsx-indent-props': require('./jsx-indent-props'), + 'jsx-key': require('./jsx-key'), + 'jsx-max-depth': require('./jsx-max-depth'), + 'jsx-max-props-per-line': require('./jsx-max-props-per-line'), + 'jsx-newline': require('./jsx-newline'), + 'jsx-no-bind': require('./jsx-no-bind'), + 'jsx-no-comment-textnodes': require('./jsx-no-comment-textnodes'), + 'jsx-no-constructed-context-values': require('./jsx-no-constructed-context-values'), + 'jsx-no-duplicate-props': require('./jsx-no-duplicate-props'), + 'jsx-no-leaked-render': require('./jsx-no-leaked-render'), + 'jsx-no-literals': require('./jsx-no-literals'), + 'jsx-no-script-url': require('./jsx-no-script-url'), + 'jsx-no-target-blank': require('./jsx-no-target-blank'), + 'jsx-no-useless-fragment': require('./jsx-no-useless-fragment'), + 'jsx-one-expression-per-line': require('./jsx-one-expression-per-line'), + 'jsx-no-undef': require('./jsx-no-undef'), + 'jsx-curly-brace-presence': require('./jsx-curly-brace-presence'), + 'jsx-pascal-case': require('./jsx-pascal-case'), + 'jsx-fragments': require('./jsx-fragments'), + 'jsx-props-no-multi-spaces': require('./jsx-props-no-multi-spaces'), + 'jsx-props-no-spreading': require('./jsx-props-no-spreading'), + 'jsx-sort-default-props': require('./jsx-sort-default-props'), + 'jsx-sort-props': require('./jsx-sort-props'), + 'jsx-space-before-closing': require('./jsx-space-before-closing'), + 'jsx-tag-spacing': require('./jsx-tag-spacing'), + 'jsx-uses-react': require('./jsx-uses-react'), + 'jsx-uses-vars': require('./jsx-uses-vars'), + 'jsx-wrap-multilines': require('./jsx-wrap-multilines'), + 'no-invalid-html-attribute': require('./no-invalid-html-attribute'), + 'no-access-state-in-setstate': require('./no-access-state-in-setstate'), + 'no-adjacent-inline-elements': require('./no-adjacent-inline-elements'), + 'no-array-index-key': require('./no-array-index-key'), + 'no-arrow-function-lifecycle': require('./no-arrow-function-lifecycle'), + 'no-children-prop': require('./no-children-prop'), + 'no-danger': require('./no-danger'), + 'no-danger-with-children': require('./no-danger-with-children'), + 'no-deprecated': require('./no-deprecated'), + 'no-did-mount-set-state': require('./no-did-mount-set-state'), + 'no-did-update-set-state': require('./no-did-update-set-state'), + 'no-direct-mutation-state': require('./no-direct-mutation-state'), + 'no-find-dom-node': require('./no-find-dom-node'), + 'no-is-mounted': require('./no-is-mounted'), + 'no-multi-comp': require('./no-multi-comp'), + 'no-namespace': require('./no-namespace'), + 'no-set-state': require('./no-set-state'), + 'no-string-refs': require('./no-string-refs'), + 'no-redundant-should-component-update': require('./no-redundant-should-component-update'), + 'no-render-return-value': require('./no-render-return-value'), + 'no-this-in-sfc': require('./no-this-in-sfc'), + 'no-typos': require('./no-typos'), + 'no-unescaped-entities': require('./no-unescaped-entities'), + 'no-unknown-property': require('./no-unknown-property'), + 'no-unsafe': require('./no-unsafe'), + 'no-unstable-nested-components': require('./no-unstable-nested-components'), + 'no-unused-class-component-methods': require('./no-unused-class-component-methods'), + 'no-unused-prop-types': require('./no-unused-prop-types'), + 'no-unused-state': require('./no-unused-state'), + 'no-object-type-as-default-prop': require('./no-object-type-as-default-prop'), + 'no-will-update-set-state': require('./no-will-update-set-state'), + 'prefer-es6-class': require('./prefer-es6-class'), + 'prefer-exact-props': require('./prefer-exact-props'), + 'prefer-read-only-props': require('./prefer-read-only-props'), + 'prefer-stateless-function': require('./prefer-stateless-function'), + 'prop-types': require('./prop-types'), + 'react-in-jsx-scope': require('./react-in-jsx-scope'), + 'require-default-props': require('./require-default-props'), + 'require-optimization': require('./require-optimization'), + 'require-render-return': require('./require-render-return'), + 'self-closing-comp': require('./self-closing-comp'), + 'sort-comp': require('./sort-comp'), + 'sort-default-props': require('./sort-default-props'), + 'sort-prop-types': require('./sort-prop-types'), + 'state-in-constructor': require('./state-in-constructor'), + 'static-property-placement': require('./static-property-placement'), + 'style-prop-object': require('./style-prop-object'), + 'void-dom-elements-no-children': require('./void-dom-elements-no-children'), +}; diff --git a/tests/index.js b/tests/index.js index c04936fa26..258429517b 100644 --- a/tests/index.js +++ b/tests/index.js @@ -7,9 +7,11 @@ const fs = require('fs'); const path = require('path'); const plugin = require('..'); +const index = require('../lib/rules'); const ruleFiles = fs.readdirSync(path.resolve(__dirname, '../lib/rules/')) - .map((f) => path.basename(f, '.js')); + .map((f) => path.basename(f, '.js')) + .filter((f) => f !== 'index'); describe('all rule files should be exported by the plugin', () => { ruleFiles.forEach((ruleName) => { @@ -19,6 +21,13 @@ describe('all rule files should be exported by the plugin', () => { require(path.join('../lib/rules', ruleName)) // eslint-disable-line global-require, import/no-dynamic-require ); }); + + it(`should export ${ruleName} from lib/rules/index`, () => { + assert.equal( + plugin.rules[ruleName], + index[ruleName] + ); + }); }); }); @@ -74,7 +83,7 @@ describe('configurations', () => { }); }); - it('should export a \'jsx-runtime\' configuration', () => { + it('should export a ‘jsx-runtime’ configuration', () => { const configName = 'jsx-runtime'; assert(plugin.configs[configName]);