diff --git a/CHANGELOG.md b/CHANGELOG.md index a0f4f100b7..5ff143d196 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Fixed * [`no-array-index-key`]: consider flatMap ([#3530][] @k-yle) +* [`jsx-curly-brace-presence`]: handle single and only expression template literals ([#3538][] @taozhou-glean) +[#3538]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3538 [#3530]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3530 [#3529]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3529 diff --git a/lib/rules/jsx-curly-brace-presence.js b/lib/rules/jsx-curly-brace-presence.js index c7b3e55d2e..28b72e86eb 100755 --- a/lib/rules/jsx-curly-brace-presence.js +++ b/lib/rules/jsx-curly-brace-presence.js @@ -131,6 +131,10 @@ module.exports = { return containsLineTerminators(text) && text.trim() === ''; } + function isSingleExpressionTemplateLiteral(child) { + return child.type === 'TemplateLiteral' && child.expressions.length === 1 && child.quasis.map((quasis) => quasis.value.raw).join('') === ''; + } + function wrapNonHTMLEntities(text) { const HTML_ENTITY = ''; const withCurlyBraces = text.split(HTML_ENTITY_REGEX()).map((word) => ( @@ -177,6 +181,9 @@ module.exports = { if (jsxUtil.isJSX(expression)) { const sourceCode = context.getSourceCode(); textToReplace = sourceCode.getText(expression); + } else if (isSingleExpressionTemplateLiteral(expression)) { + const sourceCode = context.getSourceCode(); + textToReplace = `{${sourceCode.getText(expression.expressions[0])}}`; } else { const expressionType = expression && expression.type; const parentType = JSXExpressionNode.parent.type; @@ -279,6 +286,9 @@ module.exports = { && !containsQuoteCharacters(expression.quasis[0].value.cooked) ) { reportUnnecessaryCurly(JSXExpressionNode); + } else if ( + isSingleExpressionTemplateLiteral(expression)) { + reportUnnecessaryCurly(JSXExpressionNode); } else if (jsxUtil.isJSX(expression)) { reportUnnecessaryCurly(JSXExpressionNode); } diff --git a/tests/lib/rules/jsx-curly-brace-presence.js b/tests/lib/rules/jsx-curly-brace-presence.js index 8c66929233..284d008bfd 100755 --- a/tests/lib/rules/jsx-curly-brace-presence.js +++ b/tests/lib/rules/jsx-curly-brace-presence.js @@ -468,6 +468,14 @@ ruleTester.run('jsx-curly-brace-presence', rule, { `, features: ['no-ts'], options: ['never'], + }, + { + code: '', + options: [{ props: 'never' }], + }, + { + code: '{`${label}${suffix}`}', + options: [{ children: 'never' }], } )), @@ -931,6 +939,18 @@ ruleTester.run('jsx-curly-brace-presence', rule, { errors: [{ messageId: 'unnecessaryCurly' }], options: [{ props: 'never', children: 'never', propElementValues: 'never' }], features: ['no-ts'], + }, + { + code: '', + output: '', + errors: [{ messageId: 'unnecessaryCurly' }], + options: [{ props: 'never', children: 'never', propElementValues: 'never' }], + }, + { + code: '{`${label}`}', + output: '{label}', + errors: [{ messageId: 'unnecessaryCurly' }], + options: [{ props: 'never', children: 'never', propElementValues: 'never' }], } )), });