Skip to content

Commit

Permalink
[New] support new config system
Browse files Browse the repository at this point in the history
  - add configs/ entry points for recommended configs
  - add documentation to readme
  • Loading branch information
jjangga0214 authored and ljharb committed Sep 10, 2022
1 parent 8c9ec8a commit e75bebf
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 196 deletions.
206 changes: 171 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ React specific linting rules for `eslint`
npm install eslint eslint-plugin-react --save-dev
```

It is also possible to install ESLint globally rather than locally (using npm install eslint --global). However, this is not recommended, and any plugins or shareable configs that you use must be installed locally in either case.
It is also possible to install ESLint globally rather than locally (using `npm install -g eslint`). However, this is not recommended, and any plugins or shareable configs that you use must be installed locally in either case.

## Configuration
## Configuration (legacy: `.eslintrc*`)

Use [our preset](#recommended) to get reasonable defaults:

Expand Down Expand Up @@ -109,6 +109,174 @@ Enable the rules that you would like to use.
}
```

### Shareable configs

#### Recommended

This plugin exports a `recommended` configuration that enforces React good practices.

To enable this configuration use the `extends` property in your `.eslintrc` config file:

```json
{
"extends": ["eslint:recommended", "plugin:react/recommended"]
}
```

See [`eslint` documentation](https://eslint.org/docs/user-guide/configuring/configuration-files#extending-configuration-files) for more information about extending configuration files.

#### All

This plugin also exports an `all` configuration that includes every available rule.
This pairs well with the `eslint:all` rule.

```json
{
"plugins": [
"react"
],
"extends": ["eslint:all", "plugin:react/all"]
}
```

**Note**: These configurations will import `eslint-plugin-react` and enable JSX in [parser options](https://eslint.org/docs/user-guide/configuring/language-options#specifying-parser-options).

## Configuration (new: `eslint.config.js`)

From [`v8.21.0`](https://github.com/eslint/eslint/releases/tag/v8.21.0), eslint announced a new config system.
In the new system, `.eslintrc*` is no longer used. `eslint.config.js` would be the default config file name.
In eslint `v8`, the legacy system (`.eslintrc*`) would still be supported, while in eslint `v9`, only the new system would be supported.

And from [`v8.23.0`](https://github.com/eslint/eslint/releases/tag/v8.23.0), eslint CLI starts to look up `eslint.config.js`.
**So, if your eslint is `>=8.23.0`, you're 100% ready to use the new config system.**

You might want to check out the official blog posts,

- <https://eslint.org/blog/2022/08/new-config-system-part-1/>
- <https://eslint.org/blog/2022/08/new-config-system-part-2/>
- <https://eslint.org/blog/2022/08/new-config-system-part-3/>

and the [official docs](https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new).

### Plugin

The default export of `eslint-plugin-react` is a plugin object.

```js
const react = require('eslint-plugin-react');
const globals = require('globals');

module.exports = [
{
files: ['**/*.{js,jsx,mjs,cjs,ts,tsx}'],
plugins: {
react,
},
languageOptions: {
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
globals: {
...globals.browser,
},
},
rules: {
// ... any rules you want
'react/jsx-uses-react': 'error',
'react/jsx-uses-vars': 'error',
},
// ... others are omitted for brevity
},
];
```

### Configuring shared settings

Refer to the [official docs](https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new#configuring-shared-settings).

The schema of the `settings.react` object would be identical to that of what's already described above in the legacy config section.

<!-- markdownlint-disable-next-line no-duplicate-heading -->
### 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).

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.

```js
const reactRecommended = require('eslint-plugin-react/configs/recommended');

module.exports = [
reactRecommended, // This is not a plugin object, but a shareable config object
];
```

You can of course add/override some properties.

**Note**: Our shareable configs does not preconfigure `files` or [`languageOptions.globals`](https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new#configuration-objects).
For most of the cases, you probably want to configure some properties by yourself.

```js
const reactRecommended = require('eslint-plugin-react/configs/recommended');
const globals = require('globals');

module.exports = [
{
files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
...reactRecommended,
languageOptions: {
...reactRecommended.languageOptions,
globals: {
...globals.serviceworker,
...globals.browser;
},
},
},
];
```

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 globals = require('globals');

module.exports = [
{
files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
...reactRecommended,
},
{
files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
languageOptions: {
globals: {
...globals.serviceworker,
...globals.browser,
},
},
},
];
```

## List of supported rules

✔: Enabled in the [`recommended`](#recommended) configuration.\
Expand Down Expand Up @@ -225,44 +393,12 @@ Enable the rules that you would like to use.
| | 🔧 | | [react/jsx-wrap-multilines](docs/rules/jsx-wrap-multilines.md) | Disallow missing parentheses around multiline JSX |
<!-- AUTO-GENERATED-CONTENT:END -->

### Other useful plugins
## Other useful plugins

- Rules of Hooks: [eslint-plugin-react-hooks](https://github.com/facebook/react/tree/master/packages/eslint-plugin-react-hooks)
- JSX accessibility: [eslint-plugin-jsx-a11y](https://github.com/evcohen/eslint-plugin-jsx-a11y)
- React Native: [eslint-plugin-react-native](https://github.com/Intellicode/eslint-plugin-react-native)

## Shareable configurations

### Recommended

This plugin exports a `recommended` configuration that enforces React good practices.

To enable this configuration use the `extends` property in your `.eslintrc` config file:

```json
{
"extends": ["eslint:recommended", "plugin:react/recommended"]
}
```

See [`eslint` documentation](https://eslint.org/docs/user-guide/configuring/configuration-files#extending-configuration-files) for more information about extending configuration files.

### All

This plugin also exports an `all` configuration that includes every available rule.
This pairs well with the `eslint:all` rule.

```json
{
"plugins": [
"react"
],
"extends": ["eslint:all", "plugin:react/all"]
}
```

**Note**: These configurations will import `eslint-plugin-react` and enable JSX in [parser options](https://eslint.org/docs/user-guide/configuring/language-options#specifying-parser-options).

## License

`eslint-plugin-react` is licensed under the [MIT License](https://opensource.org/licenses/mit-license.php).
Expand Down
123 changes: 123 additions & 0 deletions configs/all.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
'use strict';

const react = require('../index');

const plugin = Object.assign({}, react);
delete plugin.configs;

/* 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-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-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 */

module.exports = {
plugins: {
react: plugin,
},
languageOptions: {
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
rules: allRules,
};
15 changes: 15 additions & 0 deletions configs/jsx-runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

const all = require('./all');

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,
},
});
Loading

0 comments on commit e75bebf

Please sign in to comment.