Repository: jsx-eslint/eslint-plugin-react
Pull request #3611 (2023-07-23 14:15:04)

fix: revert single template literal expression which might be intended usage
This reverts https://github.com/jsx-eslint/eslint-plugin-react/pull/3538, while keeping the test case there for explanation and future breakage prevention.

The previous commit broke for intended type casting usage: https://github.com/jsx-eslint/eslint-plugin-react/issues/3607

Sorry for adding the change, did not think enough before making it, apparently this is definitely legit use case for casting other type to string, we might be able to keep this rule and limit it to string single template literal with typechecker, but just a bit overkill at this moment.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d8b95aa6..ba18b5de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,9 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
 
 ### Fixed
 * [`require-default-props`]: fix config schema ([#3605][] @controversial)
+* [`jsx-curly-brace-presence`]: Revert [#3538][] due to issues with intended string type casting usage ([#3611][] @taozhou-glean)
 
+[#3611]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3611
 [#3605]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3605
 
 ## [7.33.0] - 2023.07.19
diff --git a/lib/rules/jsx-curly-brace-presence.js b/lib/rules/jsx-curly-brace-presence.js
index 28b72e86..c7b3e55d 100755
--- a/lib/rules/jsx-curly-brace-presence.js
+++ b/lib/rules/jsx-curly-brace-presence.js
@@ -131,10 +131,6 @@ 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 = '<HTML_ENTITY>';
       const withCurlyBraces = text.split(HTML_ENTITY_REGEX()).map((word) => (
@@ -181,9 +177,6 @@ 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;
@@ -286,9 +279,6 @@ module.exports = {
         && !containsQuoteCharacters(expression.quasis[0].value.cooked)
       ) {
         reportUnnecessaryCurly(JSXExpressionNode);
-      } else if (
-        isSingleExpressionTemplateLiteral(expression)) {
-        reportUnnecessaryCurly(JSXExpressionNode);
       } else if (jsxUtil.isJSX(expression)) {
         reportUnnecessaryCurly(JSXExpressionNode);
       }


Test patch:
diff --git a/tests/lib/rules/jsx-curly-brace-presence.js b/tests/lib/rules/jsx-curly-brace-presence.js
index 284d008b..e234bd9c 100755
--- a/tests/lib/rules/jsx-curly-brace-presence.js
+++ b/tests/lib/rules/jsx-curly-brace-presence.js
@@ -469,13 +469,14 @@ ruleTester.run('jsx-curly-brace-presence', rule, {
       features: ['no-ts'],
       options: ['never'],
     },
+    // legit as this single template literal might be used for stringifying
     {
-      code: '<App label={`${label}${suffix}`} />',
-      options: [{ props: 'never' }],
+      code: '<App label={`${label}`} />',
+      options: ['never'],
     },
     {
-      code: '<App>{`${label}${suffix}`}</App>',
-      options: [{ children: 'never' }],
+      code: '<App>{`${label}`}</App>',
+      options: ['never'],
     }
   )),
 
@@ -939,18 +940,6 @@ ruleTester.run('jsx-curly-brace-presence', rule, {
       errors: [{ messageId: 'unnecessaryCurly' }],
       options: [{ props: 'never', children: 'never', propElementValues: 'never' }],
       features: ['no-ts'],
-    },
-    {
-      code: '<App label={`${label}`} />',
-      output: '<App label={label} />',
-      errors: [{ messageId: 'unnecessaryCurly' }],
-      options: [{ props: 'never', children: 'never', propElementValues: 'never' }],
-    },
-    {
-      code: '<App>{`${label}`}</App>',
-      output: '<App>{label}</App>',
-      errors: [{ messageId: 'unnecessaryCurly' }],
-      options: [{ props: 'never', children: 'never', propElementValues: 'never' }],
     }
   )),
 });