diff --git a/lib/rules/jsx-curly-brace-presence.js b/lib/rules/jsx-curly-brace-presence.js
index 5bddc5b98f..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;
}
@@ -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 && jsxUtil.isWhiteSpaces(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/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
};
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',