Compare commits

..

16 Commits

Author SHA1 Message Date
Jordan Harband
34b5bc39f1 [meta] revert changes from d4e39c9b10
Caused by https://github.com/npm/cli/issues/3619
2021-12-25 12:34:37 -08:00
Jordan Harband
d4e39c9b10 v19.0.4 2021-12-25 07:34:29 -08:00
Jordan Harband
baaa5e8d26 [eslint config] v19.0.3 2021-12-24 12:27:19 -08:00
David Petersen
274c8d5701 [eslint config] [patch] set namedComponents option to match style guide
Change the `namedComponents` option to `function-declaration` to match what the style guide requires.

019e0f7e07 (r60060792)
2021-11-10 17:05:21 -06:00
Jordan Harband
38bc026fe4 [eslint config] [base] add disabled prefer-object-has-own rule 2021-12-22 15:12:04 -08:00
Jordan Harband
445322db64 [eslint config] [deps] update eslint-plugin-react 2021-12-22 15:09:25 -08:00
Jordan Harband
152bd5e85a [eslint config] v19.0.2 2021-12-02 10:34:58 -08:00
Jordan Harband
afc2cc3432 [eslint config] [meta] fix "exports" path
Fixes #2524
2021-12-02 10:04:51 -08:00
Jordan Harband
371537f393 [Tests] re-enable tests disabled for the eslint 8 upgrade 2021-11-22 13:44:36 -08:00
Jordan Harband
c05ffb2417 [eslint config] v19.0.1 2021-11-22 13:32:11 -08:00
Jordan Harband
97a3238020 [eslint config] [deps] update eslint-plugin-react 2021-11-22 11:12:36 -08:00
Jordan Harband
e0bb393519 [eslint config] [*] [dev deps] update tape 2021-11-22 11:12:26 -08:00
Jordan Harband
c4000b932a [eslint config] [fix] whitespace: udpate to support eslint 8
Fixes #2517
2021-11-22 11:07:00 -08:00
Jordan Harband
31c6f21878 [eslint config] [base] [refactor] make a single source of truth for whitespace rule names 2021-11-22 11:06:19 -08:00
Yatin
91cab81f69 [readme] operator => parameter syntax 2021-11-17 00:14:08 +05:30
d8cb404da7 [eslint config] [base] remove unneeded eslint version check 2021-11-11 23:45:40 +08:00
15 changed files with 276 additions and 252 deletions

View File

@@ -62,16 +62,12 @@ jobs:
matrix:
node-version: ${{ fromJson(needs.matrix.outputs.latest) }}
eslint:
- 8
- 7
# - 6
# - 5
package:
- eslint-config-airbnb
react-hooks:
- ''
# - 3 # TODO: re-enable these once the react config uses eslint 8
# - 2.3
# - 1.7
- 4
defaults:
run:
@@ -131,16 +127,12 @@ jobs:
fail-fast: false
matrix:
eslint:
- 8
- 7
# - 6
# - 5
package:
- eslint-config-airbnb
react-hooks:
- ''
# - 3 # TODO: re-enable these once the react config uses eslint 8
# - 2.3
# - 1.7
- 4
defaults:
run:

View File

@@ -310,7 +310,7 @@ Other Style Guides
```
<a name="objects--rest-spread"></a>
- [3.8](#objects--rest-spread) Prefer the object spread syntax over [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) to shallow-copy objects. Use the object rest operator to get a new object with certain properties omitted. eslint: [`prefer-object-spread`](https://eslint.org/docs/rules/prefer-object-spread)
- [3.8](#objects--rest-spread) Prefer the object spread syntax over [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) to shallow-copy objects. Use the object rest parameter syntax to get a new object with certain properties omitted. eslint: [`prefer-object-spread`](https://eslint.org/docs/rules/prefer-object-spread)
```javascript
// very bad

View File

@@ -77,7 +77,7 @@
"eslint-plugin-import": "^2.25.3",
"in-publish": "^2.0.1",
"safe-publish-latest": "^2.0.0",
"tape": "^5.3.1"
"tape": "^5.3.2"
},
"peerDependencies": {
"eslint": "^7.32.0 || ^8.2.0",
@@ -89,7 +89,6 @@
"dependencies": {
"confusing-browser-globals": "^1.0.10",
"object.assign": "^4.1.2",
"object.entries": "^1.1.5",
"semver": "^6.3.0"
"object.entries": "^1.1.5"
}
}

View File

@@ -376,6 +376,11 @@ module.exports = {
// https://eslint.org/docs/rules/prefer-named-capture-group
'prefer-named-capture-group': 'off',
// Prefer Object.hasOwn() over Object.prototype.hasOwnProperty.call()
// https://eslint.org/docs/rules/prefer-object-has-own
// TODO: semver-major: enable thus rule, once eslint v8.5.0 is required
'prefer-object-has-own': 'off',
// https://eslint.org/docs/rules/prefer-regex-literals
'prefer-regex-literals': ['error', {
disallowRedundantWrapping: true,

View File

@@ -1,6 +1,3 @@
const semver = require('semver');
const eslintPkg = require('eslint/package.json');
module.exports = {
rules: {
// enforce line breaks after opening and before closing array brackets
@@ -105,7 +102,7 @@ module.exports = {
// require line breaks inside function parentheses if there are line breaks between parameters
// https://eslint.org/docs/rules/function-paren-newline
'function-paren-newline': ['error', semver.satisfies(eslintPkg.version, '>= 6') ? 'multiline-arguments' : 'consistent'],
'function-paren-newline': ['error', 'multiline-arguments'],
// disallow specified identifiers
// https://eslint.org/docs/rules/id-denylist

View File

@@ -5,6 +5,7 @@ const entries = require('object.entries');
const { ESLint } = require('eslint');
const baseConfig = require('.');
const whitespaceRules = require('./whitespaceRules');
const severities = ['off', 'warn', 'error'];
@@ -45,52 +46,4 @@ async function onlyErrorOnRules(rulesToError, config) {
return errorsOnly;
}
onlyErrorOnRules([
'array-bracket-newline',
'array-bracket-spacing',
'array-element-newline',
'arrow-spacing',
'block-spacing',
'comma-spacing',
'computed-property-spacing',
'dot-location',
'eol-last',
'func-call-spacing',
'function-paren-newline',
'generator-star-spacing',
'implicit-arrow-linebreak',
'indent',
'key-spacing',
'keyword-spacing',
'line-comment-position',
'linebreak-style',
'multiline-ternary',
'newline-per-chained-call',
'no-irregular-whitespace',
'no-mixed-spaces-and-tabs',
'no-multi-spaces',
'no-regex-spaces',
'no-spaced-func',
'no-trailing-spaces',
'no-whitespace-before-property',
'nonblock-statement-body-position',
'object-curly-newline',
'object-curly-spacing',
'object-property-newline',
'one-var-declaration-per-line',
'operator-linebreak',
'padded-blocks',
'padding-line-between-statements',
'rest-spread-spacing',
'semi-spacing',
'semi-style',
'space-before-blocks',
'space-before-function-paren',
'space-in-parens',
'space-infix-ops',
'space-unary-ops',
'spaced-comment',
'switch-colon-spacing',
'template-tag-spacing',
'import/newline-after-import',
], baseConfig).then((config) => console.log(JSON.stringify(config)));
onlyErrorOnRules(whitespaceRules, baseConfig).then((config) => console.log(JSON.stringify(config)));

View File

@@ -6,6 +6,7 @@ if (CLIEngine) {
/* eslint no-inner-declarations: 0 */
const assign = require('object.assign');
const entries = require('object.entries');
const whitespaceRules = require('./whitespaceRules');
const baseConfig = require('.');
@@ -45,55 +46,7 @@ if (CLIEngine) {
return errorsOnly;
}
module.exports = onlyErrorOnRules([
'array-bracket-newline',
'array-bracket-spacing',
'array-element-newline',
'arrow-spacing',
'block-spacing',
'comma-spacing',
'computed-property-spacing',
'dot-location',
'eol-last',
'func-call-spacing',
'function-paren-newline',
'generator-star-spacing',
'implicit-arrow-linebreak',
'indent',
'key-spacing',
'keyword-spacing',
'line-comment-position',
'linebreak-style',
'multiline-ternary',
'newline-per-chained-call',
'no-irregular-whitespace',
'no-mixed-spaces-and-tabs',
'no-multi-spaces',
'no-regex-spaces',
'no-spaced-func',
'no-trailing-spaces',
'no-whitespace-before-property',
'nonblock-statement-body-position',
'object-curly-newline',
'object-curly-spacing',
'object-property-newline',
'one-var-declaration-per-line',
'operator-linebreak',
'padded-blocks',
'padding-line-between-statements',
'rest-spread-spacing',
'semi-spacing',
'semi-style',
'space-before-blocks',
'space-before-function-paren',
'space-in-parens',
'space-infix-ops',
'space-unary-ops',
'spaced-comment',
'switch-colon-spacing',
'template-tag-spacing',
'import/newline-after-import',
], baseConfig);
module.exports = onlyErrorOnRules(whitespaceRules, baseConfig);
} else {
const path = require('path');
const { execSync } = require('child_process');

View File

@@ -0,0 +1,49 @@
module.exports = [
'array-bracket-newline',
'array-bracket-spacing',
'array-element-newline',
'arrow-spacing',
'block-spacing',
'comma-spacing',
'computed-property-spacing',
'dot-location',
'eol-last',
'func-call-spacing',
'function-paren-newline',
'generator-star-spacing',
'implicit-arrow-linebreak',
'indent',
'key-spacing',
'keyword-spacing',
'line-comment-position',
'linebreak-style',
'multiline-ternary',
'newline-per-chained-call',
'no-irregular-whitespace',
'no-mixed-spaces-and-tabs',
'no-multi-spaces',
'no-regex-spaces',
'no-spaced-func',
'no-trailing-spaces',
'no-whitespace-before-property',
'nonblock-statement-body-position',
'object-curly-newline',
'object-curly-spacing',
'object-property-newline',
'one-var-declaration-per-line',
'operator-linebreak',
'padded-blocks',
'padding-line-between-statements',
'rest-spread-spacing',
'semi-spacing',
'semi-style',
'space-before-blocks',
'space-before-function-paren',
'space-in-parens',
'space-infix-ops',
'space-unary-ops',
'spaced-comment',
'switch-colon-spacing',
'template-tag-spacing',
'import/newline-after-import'
];

View File

@@ -1,3 +1,23 @@
19.0.4 / 2021-12-25
==================
- republish to fix #2529
19.0.3 / 2021-12-24
==================
- [patch] set `namedComponents` option to match style guide
- [deps] update `eslint-plugin-react`
19.0.2 / 2021-12-02
==================
- [meta] fix "exports" path (#2525)
- [Tests] re-enable tests disabled for the eslint 8 upgrade
19.0.1 / 2021-11-22
==================
- [fix] `whitespace`: update to support eslint 8 (#2517)
- [deps] update `eslint-plugin-react`
- [dev deps] update `tape`
19.0.0 / 2021-11-10
==================
- [breaking] support `eslint` 8; drop `eslint` < 7

View File

@@ -1,6 +1,6 @@
{
"name": "eslint-config-airbnb",
"version": "19.0.0",
"version": "19.0.4",
"description": "Airbnb's ESLint config, following our styleguide",
"main": "index.js",
"exports": {
@@ -11,7 +11,7 @@
"./whitespace": "./whitespace.js",
"./rules/react": "./rules/react.js",
"./rules/react-a11y": "./rules/react-a11y.js",
"./rules/react-hooks": "./rules/react-hook.js",
"./rules/react-hooks": "./rules/react-hooks.js",
"./package.json": "./package.json"
},
"scripts": {
@@ -79,18 +79,18 @@
"eslint-find-rules": "^4.0.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.27.0",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0",
"in-publish": "^2.0.1",
"react": ">= 0.13.0",
"safe-publish-latest": "^2.0.0",
"tape": "^5.3.1"
"tape": "^5.3.2"
},
"peerDependencies": {
"eslint": "^7.32.0 || ^8.2.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.27.0",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.3.0"
},
"engines": {

View File

@@ -524,9 +524,8 @@ module.exports = {
// Enforce a specific function type for function components
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md
// TODO: investigate if setting namedComponents to expression vs declaration is problematic
'react/function-component-definition': ['error', {
namedComponents: 'function-expression',
namedComponents: ['function-declaration', 'function-expression'],
unnamedComponents: 'function-expression',
}],

View File

@@ -4,25 +4,25 @@ import eslintrc from '..';
import reactRules from '../rules/react';
import reactA11yRules from '../rules/react-a11y';
const rules = {
// It is okay to import devDependencies in tests.
'import/no-extraneous-dependencies': [2, { devDependencies: true }],
// this doesn't matter for tests
'lines-between-class-members': 0,
// otherwise we need some junk in our fixture code
'react/no-unused-class-component-methods': 0,
};
const cli = new (CLIEngine || ESLint)({
useEslintrc: false,
baseConfig: eslintrc,
rules: {
// It is okay to import devDependencies in tests.
'import/no-extraneous-dependencies': [2, { devDependencies: true }],
// this doesn't matter for tests
'lines-between-class-members': 0,
// otherwise we need some junk in our fixture code
'react/no-unused-class-component-methods': 0,
},
...(CLIEngine ? { rules } : { overrideConfig: { rules } }),
});
function lint(text) {
async function lint(text) {
// @see https://eslint.org/docs/developer-guide/nodejs-api.html#executeonfiles
// @see https://eslint.org/docs/developer-guide/nodejs-api.html#executeontext
const linter = CLIEngine ? cli.executeOnText(text) : cli.lintText(text);
return linter.results[0];
const linter = CLIEngine ? cli.executeOnText(text) : await cli.lintText(text);
return (CLIEngine ? linter.results : linter)[0];
}
function wrapComponent(body) {
@@ -42,9 +42,8 @@ test('validate react methods order', (t) => {
t.deepEqual(reactA11yRules.plugins, ['jsx-a11y', 'react']);
});
t.test('passes a good component', (t) => {
t.plan(3);
const result = lint(wrapComponent(`
t.test('passes a good component', async (t) => {
const result = await lint(wrapComponent(`
componentDidMount() {}
handleSubmit() {}
onButtonAClick() {}
@@ -61,9 +60,8 @@ test('validate react methods order', (t) => {
t.notOk(result.errorCount, 'no errors');
});
t.test('order: when random method is first', (t) => {
t.plan(2);
const result = lint(wrapComponent(`
t.test('order: when random method is first', async (t) => {
const result = await lint(wrapComponent(`
someMethod() {}
componentDidMount() {}
setFoo() {}
@@ -77,9 +75,8 @@ test('validate react methods order', (t) => {
t.deepEqual(result.messages.map((msg) => msg.ruleId), ['react/sort-comp'], 'fails due to sort');
});
t.test('order: when random method after lifecycle methods', (t) => {
t.plan(2);
const result = lint(wrapComponent(`
t.test('order: when random method after lifecycle methods', async (t) => {
const result = await lint(wrapComponent(`
componentDidMount() {}
someMethod() {}
setFoo() {}
@@ -93,9 +90,8 @@ test('validate react methods order', (t) => {
t.deepEqual(result.messages.map((msg) => msg.ruleId), ['react/sort-comp'], 'fails due to sort');
});
t.test('order: when handler method with `handle` prefix after method with `on` prefix', (t) => {
t.plan(2);
const result = lint(wrapComponent(`
t.test('order: when handler method with `handle` prefix after method with `on` prefix', async (t) => {
const result = await lint(wrapComponent(`
componentDidMount() {}
onButtonAClick() {}
handleSubmit() {}
@@ -108,9 +104,8 @@ test('validate react methods order', (t) => {
t.deepEqual(result.messages.map((msg) => msg.ruleId), ['react/sort-comp'], 'fails due to sort');
});
t.test('order: when lifecycle methods after event handler methods', (t) => {
t.plan(2);
const result = lint(wrapComponent(`
t.test('order: when lifecycle methods after event handler methods', async (t) => {
const result = await lint(wrapComponent(`
handleSubmit() {}
componentDidMount() {}
setFoo() {}
@@ -122,9 +117,8 @@ test('validate react methods order', (t) => {
t.deepEqual(result.messages.map((msg) => msg.ruleId), ['react/sort-comp'], 'fails due to sort');
});
t.test('order: when event handler methods after getters and setters', (t) => {
t.plan(2);
const result = lint(wrapComponent(`
t.test('order: when event handler methods after getters and setters', async (t) => {
const result = await lint(wrapComponent(`
componentDidMount() {}
setFoo() {}
getFoo() {}

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env node
const assign = require('object.assign');
const entries = require('object.entries');
const { ESLint } = require('eslint');
const baseConfig = require('.');
const whitespaceRules = require('./whitespaceRules');
const severities = ['off', 'warn', 'error'];
function getSeverity(ruleConfig) {
if (Array.isArray(ruleConfig)) {
return getSeverity(ruleConfig[0]);
}
if (typeof ruleConfig === 'number') {
return severities[ruleConfig];
}
return ruleConfig;
}
async function onlyErrorOnRules(rulesToError, config) {
const errorsOnly = assign({}, config);
const cli = new ESLint({
useEslintrc: false,
baseConfig: config
});
const baseRules = (await cli.calculateConfigForFile(require.resolve('./'))).rules;
entries(baseRules).forEach((rule) => {
const ruleName = rule[0];
const ruleConfig = rule[1];
const severity = getSeverity(ruleConfig);
if (rulesToError.indexOf(ruleName) === -1 && severity === 'error') {
if (Array.isArray(ruleConfig)) {
errorsOnly.rules[ruleName] = ['warn'].concat(ruleConfig.slice(1));
} else if (typeof ruleConfig === 'number') {
errorsOnly.rules[ruleName] = 1;
} else {
errorsOnly.rules[ruleName] = 'warn';
}
}
});
return errorsOnly;
}
onlyErrorOnRules(whitespaceRules, baseConfig).then((config) => console.log(JSON.stringify(config)));

View File

@@ -1,105 +1,55 @@
const assign = require('object.assign');
const entries = require('object.entries');
/* eslint global-require: 0 */
const { CLIEngine } = require('eslint');
const baseConfig = require('.');
if (CLIEngine) {
/* eslint no-inner-declarations: 0 */
const assign = require('object.assign');
const entries = require('object.entries');
const whitespaceRules = require('./whitespaceRules');
const severities = ['off', 'warn', 'error'];
const baseConfig = require('.');
function getSeverity(ruleConfig) {
if (Array.isArray(ruleConfig)) {
return getSeverity(ruleConfig[0]);
}
if (typeof ruleConfig === 'number') {
return severities[ruleConfig];
}
return ruleConfig;
}
const severities = ['off', 'warn', 'error'];
function onlyErrorOnRules(rulesToError, config) {
const errorsOnly = assign({}, config);
const cli = new CLIEngine({ baseConfig: config, useEslintrc: false });
const baseRules = cli.getConfigForFile(require.resolve('./')).rules;
entries(baseRules).forEach((rule) => {
const ruleName = rule[0];
const ruleConfig = rule[1];
const severity = getSeverity(ruleConfig);
if (rulesToError.indexOf(ruleName) === -1 && severity === 'error') {
if (Array.isArray(ruleConfig)) {
errorsOnly.rules[ruleName] = ['warn'].concat(ruleConfig.slice(1));
} else if (typeof ruleConfig === 'number') {
errorsOnly.rules[ruleName] = 1;
} else {
errorsOnly.rules[ruleName] = 'warn';
}
function getSeverity(ruleConfig) {
if (Array.isArray(ruleConfig)) {
return getSeverity(ruleConfig[0]);
}
});
if (typeof ruleConfig === 'number') {
return severities[ruleConfig];
}
return ruleConfig;
}
return errorsOnly;
function onlyErrorOnRules(rulesToError, config) {
const errorsOnly = assign({}, config);
const cli = new CLIEngine({ baseConfig: config, useEslintrc: false });
const baseRules = cli.getConfigForFile(require.resolve('./')).rules;
entries(baseRules).forEach((rule) => {
const ruleName = rule[0];
const ruleConfig = rule[1];
const severity = getSeverity(ruleConfig);
if (rulesToError.indexOf(ruleName) === -1 && severity === 'error') {
if (Array.isArray(ruleConfig)) {
errorsOnly.rules[ruleName] = ['warn'].concat(ruleConfig.slice(1));
} else if (typeof ruleConfig === 'number') {
errorsOnly.rules[ruleName] = 1;
} else {
errorsOnly.rules[ruleName] = 'warn';
}
}
});
return errorsOnly;
}
module.exports = onlyErrorOnRules(whitespaceRules, baseConfig);
} else {
const path = require('path');
const { execSync } = require('child_process');
module.exports = JSON.parse(String(execSync(path.join(__dirname, 'whitespace-async.js'))));
}
module.exports = onlyErrorOnRules([
'array-bracket-newline',
'array-bracket-spacing',
'array-element-newline',
'arrow-spacing',
'block-spacing',
'comma-spacing',
'computed-property-spacing',
'dot-location',
'eol-last',
'func-call-spacing',
'function-paren-newline',
'generator-star-spacing',
'implicit-arrow-linebreak',
'indent',
'key-spacing',
'keyword-spacing',
'line-comment-position',
'linebreak-style',
'multiline-ternary',
'newline-per-chained-call',
'no-irregular-whitespace',
'no-mixed-spaces-and-tabs',
'no-multi-spaces',
'no-regex-spaces',
'no-spaced-func',
'no-trailing-spaces',
'no-whitespace-before-property',
'nonblock-statement-body-position',
'object-curly-newline',
'object-curly-spacing',
'object-property-newline',
'one-var-declaration-per-line',
'operator-linebreak',
'padded-blocks',
'padding-line-between-statements',
'rest-spread-spacing',
'semi-spacing',
'semi-style',
'space-before-blocks',
'space-before-function-paren',
'space-in-parens',
'space-infix-ops',
'space-unary-ops',
'spaced-comment',
'switch-colon-spacing',
'template-tag-spacing',
'import/newline-after-import',
// eslint-plugin-react rules
'react/jsx-child-element-spacing',
'react/jsx-closing-bracket-location',
'react/jsx-closing-tag-location',
'react/jsx-curly-spacing',
'react/jsx-equals-spacing',
'react/jsx-first-prop-newline',
'react/jsx-indent',
'react/jsx-indent-props',
'react/jsx-max-props-per-line',
'react/jsx-one-expression-per-line',
'react/jsx-space-before-closing',
'react/jsx-tag-spacing',
'react/jsx-wrap-multilines',
], baseConfig);

View File

@@ -0,0 +1,64 @@
module.exports = [
'array-bracket-newline',
'array-bracket-spacing',
'array-element-newline',
'arrow-spacing',
'block-spacing',
'comma-spacing',
'computed-property-spacing',
'dot-location',
'eol-last',
'func-call-spacing',
'function-paren-newline',
'generator-star-spacing',
'implicit-arrow-linebreak',
'indent',
'key-spacing',
'keyword-spacing',
'line-comment-position',
'linebreak-style',
'multiline-ternary',
'newline-per-chained-call',
'no-irregular-whitespace',
'no-mixed-spaces-and-tabs',
'no-multi-spaces',
'no-regex-spaces',
'no-spaced-func',
'no-trailing-spaces',
'no-whitespace-before-property',
'nonblock-statement-body-position',
'object-curly-newline',
'object-curly-spacing',
'object-property-newline',
'one-var-declaration-per-line',
'operator-linebreak',
'padded-blocks',
'padding-line-between-statements',
'rest-spread-spacing',
'semi-spacing',
'semi-style',
'space-before-blocks',
'space-before-function-paren',
'space-in-parens',
'space-infix-ops',
'space-unary-ops',
'spaced-comment',
'switch-colon-spacing',
'template-tag-spacing',
'import/newline-after-import',
// eslint-plugin-react rules
'react/jsx-child-element-spacing',
'react/jsx-closing-bracket-location',
'react/jsx-closing-tag-location',
'react/jsx-curly-spacing',
'react/jsx-equals-spacing',
'react/jsx-first-prop-newline',
'react/jsx-indent',
'react/jsx-indent-props',
'react/jsx-max-props-per-line',
'react/jsx-one-expression-per-line',
'react/jsx-space-before-closing',
'react/jsx-tag-spacing',
'react/jsx-wrap-multilines',
];