From 9b2db61fd8218fd003c513be9b63a207606e461a Mon Sep 17 00:00:00 2001 From: Veda Date: Thu, 12 Sep 2019 19:29:04 +0530 Subject: [PATCH 1/2] [fix] `jsx-curly-brace-presence`: report unnecessary curly braces with children on next line --- lib/rules/jsx-curly-brace-presence.js | 39 ++++++++-- tests/lib/rules/jsx-curly-brace-presence.js | 86 +++++++++++++++++++++ 2 files changed, 119 insertions(+), 6 deletions(-) diff --git a/lib/rules/jsx-curly-brace-presence.js b/lib/rules/jsx-curly-brace-presence.js index 5bddc5b98f..3865e273f9 100755 --- a/lib/rules/jsx-curly-brace-presence.js +++ b/lib/rules/jsx-curly-brace-presence.js @@ -205,17 +205,44 @@ module.exports = { ); } - function shouldCheckForUnnecessaryCurly(parent, config) { - // If there are more than one JSX child, there is no need to check for - // unnecessary curly braces. - if (jsxUtil.isJSX(parent) && parent.children.length !== 1) { + function isWhiteSpaceLiteral(node) { + return node.type && node.type === 'Literal' && node.value && !(/\S/.test(node.value)); + } + + function getAdjacentSiblings(node, children) { + for (let i = 1; i < children.length - 1; i++) { + const child = children[i]; + if (node === child) { + return [children[i - 1], children[i + 1]]; + } + } + if (node === children[0] && children[1]) { + return [children[1]]; + } + if (node === children[children.length - 1] && children[children.length - 2]) { + return [children[children.length - 2]]; + } + return []; + } + + function hasAdjacentJsxExpressionContainers(node, children) { + const childrenExcludingWhitespaceLiteral = children.filter(child => !isWhiteSpaceLiteral(child)); + const adjSiblings = getAdjacentSiblings(node, childrenExcludingWhitespaceLiteral); + + return adjSiblings.some(x => x.type && x.type === 'JSXExpressionContainer'); + } + + function shouldCheckForUnnecessaryCurly(parent, node, config) { + // If there are adjacent `JsxExpressionContainer` then there is no need, + // to check for unnecessary curly braces. + if (jsxUtil.isJSX(parent) && hasAdjacentJsxExpressionContainers(node, parent.children)) { return false; } if ( parent.children && parent.children.length === 1 && - containsWhitespaceExpression(parent.children[0]) + containsWhitespaceExpression(node) ) { return false; } @@ -241,7 +268,7 @@ module.exports = { return { JSXExpressionContainer: (node) => { - if (shouldCheckForUnnecessaryCurly(node.parent, userConfig)) { + if (shouldCheckForUnnecessaryCurly(node.parent, node, userConfig)) { lintUnnecessaryCurly(node); } }, diff --git a/tests/lib/rules/jsx-curly-brace-presence.js b/tests/lib/rules/jsx-curly-brace-presence.js index 3376e1ac19..baeff71ab4 100755 --- a/tests/lib/rules/jsx-curly-brace-presence.js +++ b/tests/lib/rules/jsx-curly-brace-presence.js @@ -284,6 +284,25 @@ ruleTester.run('jsx-curly-brace-presence', rule, { \`} `, options: ['always'] + }, + { + code: ` + + % + + `, + parser: parsers.BABEL_ESLINT, + options: [{children: 'never'}] + }, + { + code: ` + + foo +
bar
+
+ `, + parser: parsers.BABEL_ESLINT, + options: [{children: 'never'}] } ], @@ -335,6 +354,73 @@ ruleTester.run('jsx-curly-brace-presence', rule, { options: [{props: 'never'}], errors: [{message: unnecessaryCurlyMessage}] }, + { + code: ` + + {'%'} + + `, + output: ` + + % + + `, + parser: parsers.BABEL_ESLINT, + options: [{children: 'never'}], + errors: [{message: unnecessaryCurlyMessage}] + }, + { + code: ` + + {'foo'} +
+ {'bar'} +
+ {'baz'} +
+ `, + output: ` + + foo +
+ bar +
+ baz +
+ `, + parser: parsers.BABEL_ESLINT, + options: [{children: 'never'}], + errors: [ + {message: unnecessaryCurlyMessage}, + {message: unnecessaryCurlyMessage}, + {message: unnecessaryCurlyMessage} + ] + }, + { + code: ` + + {'foo'} +
+ {'bar'} +
+ {'baz'} + {'some-complicated-exp'} +
+ `, + output: ` + + foo +
+ bar +
+ {'baz'} + {'some-complicated-exp'} +
+ `, + parser: parsers.BABEL_ESLINT, + options: [{children: 'never'}], + errors: [{message: unnecessaryCurlyMessage}, {message: unnecessaryCurlyMessage}] + }, { code: `foo`, output: 'foo', From 489ced3e0d53d0523d0dd7265fd618ebca9a3cdf Mon Sep 17 00:00:00 2001 From: Veda Date: Fri, 13 Sep 2019 17:50:36 +0530 Subject: [PATCH 2/2] [refactor] `jsx-curly-braces-presence, jsx-one-expression-per-line, no-danger-with-children`: add `isWhiteSpaces` to `lib/util/jsx` --- lib/rules/jsx-curly-brace-presence.js | 4 ++-- lib/rules/jsx-one-expression-per-line.js | 3 ++- lib/rules/no-danger-with-children.js | 3 ++- lib/util/jsx.js | 12 +++++++++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/rules/jsx-curly-brace-presence.js b/lib/rules/jsx-curly-brace-presence.js index 3865e273f9..490e18bc2c 100755 --- a/lib/rules/jsx-curly-brace-presence.js +++ b/lib/rules/jsx-curly-brace-presence.js @@ -104,7 +104,7 @@ module.exports = { function containsWhitespaceExpression(child) { if (child.type === 'JSXExpressionContainer') { const value = child.expression.value; - return value ? !(/\S/.test(value)) : false; + return value ? jsxUtil.isWhiteSpaces(value) : false; } return false; } @@ -206,7 +206,7 @@ module.exports = { } function isWhiteSpaceLiteral(node) { - return node.type && node.type === 'Literal' && node.value && !(/\S/.test(node.value)); + return node.type && node.type === 'Literal' && node.value && jsxUtil.isWhiteSpaces(node.value); } function getAdjacentSiblings(node, children) { diff --git a/lib/rules/jsx-one-expression-per-line.js b/lib/rules/jsx-one-expression-per-line.js index 4ce00a9063..093969d208 100644 --- a/lib/rules/jsx-one-expression-per-line.js +++ b/lib/rules/jsx-one-expression-per-line.js @@ -6,6 +6,7 @@ 'use strict'; const docsUrl = require('../util/docsUrl'); +const jsxUtil = require('../util/jsx'); // ------------------------------------------------------------------------------ // Rule Definition @@ -89,7 +90,7 @@ module.exports = { let countNewLinesAfterContent = 0; if (child.type === 'Literal' || child.type === 'JSXText') { - if (/^\s*$/.test(child.raw)) { + if (jsxUtil.isWhiteSpaces(child.raw)) { return; } diff --git a/lib/rules/no-danger-with-children.js b/lib/rules/no-danger-with-children.js index ae420581a4..66eb7f70a6 100644 --- a/lib/rules/no-danger-with-children.js +++ b/lib/rules/no-danger-with-children.js @@ -6,6 +6,7 @@ 'use strict'; const variableUtil = require('../util/variable'); +const jsxUtil = require('../util/jsx'); const docsUrl = require('../util/docsUrl'); // ------------------------------------------------------------------------------ @@ -81,7 +82,7 @@ module.exports = { function isLineBreak(node) { const isLiteral = node.type === 'Literal' || node.type === 'JSXText'; const isMultiline = node.loc.start.line !== node.loc.end.line; - const isWhiteSpaces = /^\s*$/.test(node.value); + const isWhiteSpaces = jsxUtil.isWhiteSpaces(node.value); return isLiteral && isMultiline && isWhiteSpaces; } diff --git a/lib/util/jsx.js b/lib/util/jsx.js index 6f8cbfde29..e3bcc23e3a 100644 --- a/lib/util/jsx.js +++ b/lib/util/jsx.js @@ -76,9 +76,19 @@ function isJSXAttributeKey(node) { node.name.name === 'key'; } +/** + * Check if value has only whitespaces + * @param {string} value + * @returns {boolean} + */ +function isWhiteSpaces(value) { + return typeof value === 'string' ? /^\s*$/.test(value) : false; +} + module.exports = { isDOMComponent, isFragment, isJSX, - isJSXAttributeKey + isJSXAttributeKey, + isWhiteSpaces };