From 8a4b5add2b998ef8d25852a9656c70d93f25c7d2 Mon Sep 17 00:00:00 2001 From: Michael Gall Date: Sat, 29 Jun 2019 22:04:56 +1000 Subject: [PATCH 1/2] Add rule to stop single element style arrays --- README.md | 2 + docs/rules/no-single-element-style-arrays.md | 12 +++ index.js | 2 + lib/rules/no-single-element-style-arrays.js | 47 +++++++++++ .../rules/no-single-element-style-arrays.js | 80 +++++++++++++++++++ 5 files changed, 143 insertions(+) create mode 100644 docs/rules/no-single-element-style-arrays.md create mode 100644 lib/rules/no-single-element-style-arrays.js create mode 100644 tests/lib/rules/no-single-element-style-arrays.js diff --git a/README.md b/README.md index fb395d4..1c85c65 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ Finally, enable all of the rules that you would like to use. "react-native/no-inline-styles": 2, "react-native/no-color-literals": 2, "react-native/no-raw-text": 2, + "react-native/no-single-element-style-arrays": 2, } } ``` @@ -94,6 +95,7 @@ Finally, enable all of the rules that you would like to use. * [no-inline-styles](docs/rules/no-inline-styles.md): Detect JSX components with inline styles that contain literal values * [no-color-literals](docs/rules/no-color-literals.md): Detect `StyleSheet` rules and inline styles containing color literals instead of variables * [no-raw-text](docs/rules/no-raw-text.md): Detect raw text outside of `Text` component +* [no-single-element-style-arrays](docs/rules/no-raw-text.md): No style arrays that have 1 element only `` [npm-url]: https://npmjs.org/package/eslint-plugin-react-native [npm-image]: http://img.shields.io/npm/v/eslint-plugin-react-native.svg?style=flat-square diff --git a/docs/rules/no-single-element-style-arrays.md b/docs/rules/no-single-element-style-arrays.md new file mode 100644 index 0000000..b8741f5 --- /dev/null +++ b/docs/rules/no-single-element-style-arrays.md @@ -0,0 +1,12 @@ +# No Single Element Style Arrays are allowed + +These cause unnecessary re-renders as each time the array's identity changes. + +## Rule Details + +The following pattern is not allowed: + +```js + +``` + diff --git a/index.js b/index.js index 7d28601..c293ffc 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ const allRules = { 'sort-styles': require('./lib/rules/sort-styles'), 'split-platform-components': require('./lib/rules/split-platform-components'), 'no-raw-text': require('./lib/rules/no-raw-text'), + 'no-single-element-style-arrays': require('./lib/rules/no-single-element-style-arrays'), }; function configureAsError(rules) { @@ -34,6 +35,7 @@ module.exports = { 'sort-styles': 0, 'split-platform-components': 0, 'no-raw-text': 0, + 'no-single-element-style-arrays': 0 }, environments: { 'react-native': { diff --git a/lib/rules/no-single-element-style-arrays.js b/lib/rules/no-single-element-style-arrays.js new file mode 100644 index 0000000..9928070 --- /dev/null +++ b/lib/rules/no-single-element-style-arrays.js @@ -0,0 +1,47 @@ +/** + * @fileoverview Enforce no single element style arrays + * @author Michael Gall + */ + +'use strict'; + +module.exports = { + meta: { + docs: { + description: + 'Disallow single element style arrays. These cause unnecessary re-renders as the identity of the array always changes', + category: 'Stylistic Issues', + recommended: false, + url: '', + }, + fixable: 'code', + }, + + create(context) { + function reportNode(JSXExpressionNode) { + context.report({ + node: JSXExpressionNode, + message: + 'Single element style arrays are not necessary and cause unnecessary re-renders', + fix(fixer) { + const realStyleNode = JSXExpressionNode.value.expression.elements[0]; + const styleSource = context.getSourceCode().getText(realStyleNode); + return fixer.replaceText(JSXExpressionNode.value, `{${styleSource}}`); + }, + }); + } + + // -------------------------------------------------------------------------- + // Public + // -------------------------------------------------------------------------- + return { + JSXAttribute(node) { + if (node.name.name !== 'style') return; + if (node.value.expression.type !== 'ArrayExpression') return; + if (node.value.expression.elements.length === 1) { + reportNode(node); + } + }, + }; + }, +}; diff --git a/tests/lib/rules/no-single-element-style-arrays.js b/tests/lib/rules/no-single-element-style-arrays.js new file mode 100644 index 0000000..2709079 --- /dev/null +++ b/tests/lib/rules/no-single-element-style-arrays.js @@ -0,0 +1,80 @@ +/** + * @fileoverview Enforce no single element style arrays + * @author Michael Gall + */ + +'use strict'; + +/* eslint-disable quotes */ // For better readability on tests involving quotes + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester; +const rule = require('../../../lib/rules/no-single-element-style-arrays'); + +require('babel-eslint'); + +const unnecessaryArrayMessage = 'Single element style arrays are not necessary and cause unnecessary re-renders'; + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ +const config = { + parser: 'babel-eslint', + parserOptions: { + ecmaFeatures: { + classes: true, + jsx: true, + }, + }, + settings: { + 'react-native/style-sheet-object-names': ['StyleSheet', 'OtherStyleSheet'], + }, +}; + +const ruleTester = new RuleTester(config); +ruleTester.run('single-element-style-array', rule, { + valid: [ + { + code: ` + const Hello = React.createClass({ + render: function() { + return foo; + } + }); + `, + }, + { + code: 'foo', + }, + { + code: 'foo', + }, + { + code: 'foo', + }, + { + code: 'foo', + }, + { + code: 'foo', + }, + ], + + invalid: [ + { + code: 'foo', + output: 'foo', + errors: [{ message: unnecessaryArrayMessage }], + }, + { + code: 'foo', + output: 'foo', + errors: [{ message: unnecessaryArrayMessage }], + }, + + ], +}); + From dad2b8489a7fe97e9547f6061c3eba86821c7681 Mon Sep 17 00:00:00 2001 From: Michael Gall Date: Thu, 11 Jul 2019 17:41:12 +1000 Subject: [PATCH 2/2] Replace the whole expression rather than the whole node Co-Authored-By: David Buchan-Swanson --- lib/rules/no-single-element-style-arrays.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/no-single-element-style-arrays.js b/lib/rules/no-single-element-style-arrays.js index 9928070..8acaa4c 100644 --- a/lib/rules/no-single-element-style-arrays.js +++ b/lib/rules/no-single-element-style-arrays.js @@ -26,7 +26,7 @@ module.exports = { fix(fixer) { const realStyleNode = JSXExpressionNode.value.expression.elements[0]; const styleSource = context.getSourceCode().getText(realStyleNode); - return fixer.replaceText(JSXExpressionNode.value, `{${styleSource}}`); + return fixer.replaceText(JSXExpressionNode.value.expression, styleSource); }, }); }