diff --git a/docs/rules/no-unused-expressions.md b/docs/rules/no-unused-expressions.md
index 8a9748d3d06..1557725a193 100644
--- a/docs/rules/no-unused-expressions.md
+++ b/docs/rules/no-unused-expressions.md
@@ -31,6 +31,7 @@ This rule, in its default state, does not require any arguments. If you would li
* `allowShortCircuit` set to `true` will allow you to use short circuit evaluations in your expressions (Default: `false`).
* `allowTernary` set to `true` will enable you to use ternary operators in your expressions similarly to short circuit evaluations (Default: `false`).
* `allowTaggedTemplates` set to `true` will enable you to use tagged template literals in your expressions (Default: `false`).
+* `enforceForJSX` set to `true` will flag unused JSX element expressions (Default: `false`).
These options allow unused expressions *only if all* of the code paths either directly change the state (for example, assignment statement) or could have *side effects* (for example, function call).
@@ -161,3 +162,27 @@ Examples of **correct** code for the `{ "allowTaggedTemplates": true }` option:
tag`some tagged template string`;
```
+
+### enforceForJSX
+
+JSX is most-commonly used in the React ecosystem, where it is compiled to `React.createElement` expressions. Though free from side-effects, these calls are not automatically flagged by the `no-unused-expression` rule. If you're using React, or any other side-effect-free JSX pragma, this option can be enabled to flag these expressions.
+
+Examples of **incorrect** code for the `{ "enforceForJSX": true }` option:
+
+```jsx
+/*eslint no-unused-expressions: ["error", { "enforceForJSX": true }]*/
+
+;
+
+<>>;
+```
+
+Examples of **correct** code for the `{ "enforceForJSX": true }` option:
+
+```jsx
+/*eslint no-unused-expressions: ["error", { "enforceForJSX": true }]*/
+
+var myComponentPartial = ;
+
+var myFragment = <>>;
+```
diff --git a/lib/rules/no-unused-expressions.js b/lib/rules/no-unused-expressions.js
index 882a0fd1c11..58c9b334187 100644
--- a/lib/rules/no-unused-expressions.js
+++ b/lib/rules/no-unused-expressions.js
@@ -50,6 +50,10 @@ module.exports = {
allowTaggedTemplates: {
type: "boolean",
default: false
+ },
+ enforceForJSX: {
+ type: "boolean",
+ default: false
}
},
additionalProperties: false
@@ -65,7 +69,8 @@ module.exports = {
const config = context.options[0] || {},
allowShortCircuit = config.allowShortCircuit || false,
allowTernary = config.allowTernary || false,
- allowTaggedTemplates = config.allowTaggedTemplates || false;
+ allowTaggedTemplates = config.allowTaggedTemplates || false,
+ enforceForJSX = config.enforceForJSX || false;
// eslint-disable-next-line jsdoc/require-description
/**
@@ -140,6 +145,12 @@ module.exports = {
},
FunctionExpression: alwaysTrue,
Identifier: alwaysTrue,
+ JSXElement() {
+ return enforceForJSX;
+ },
+ JSXFragment() {
+ return enforceForJSX;
+ },
Literal: alwaysTrue,
LogicalExpression(node) {
if (allowShortCircuit) {
diff --git a/tests/lib/rules/no-unused-expressions.js b/tests/lib/rules/no-unused-expressions.js
index 1674629c90c..6f49a0a24fb 100644
--- a/tests/lib/rules/no-unused-expressions.js
+++ b/tests/lib/rules/no-unused-expressions.js
@@ -82,6 +82,30 @@ ruleTester.run("no-unused-expressions", rule, {
{
code: "obj?.foo(\"bar\")",
parserOptions: { ecmaVersion: 11 }
+ },
+
+ // JSX
+ {
+ code: "
",
+ parserOptions: { ecmaFeatures: { jsx: true } }
+ },
+ {
+ code: "<>>",
+ parserOptions: { ecmaFeatures: { jsx: true } }
+ },
+ {
+ code: "var partial = ",
+ parserOptions: { ecmaFeatures: { jsx: true } }
+ },
+ {
+ code: "var partial = ",
+ options: [{ enforceForJSX: true }],
+ parserOptions: { ecmaFeatures: { jsx: true } }
+ },
+ {
+ code: "var partial = <>>",
+ options: [{ enforceForJSX: true }],
+ parserOptions: { ecmaFeatures: { jsx: true } }
}
],
invalid: [
@@ -152,6 +176,20 @@ ruleTester.run("no-unused-expressions", rule, {
code: "obj?.foo().bar",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unusedExpression", type: "ExpressionStatement" }]
+ },
+
+ // JSX
+ {
+ code: "",
+ options: [{ enforceForJSX: true }],
+ parserOptions: { ecmaFeatures: { jsx: true } },
+ errors: [{ messageId: "unusedExpression", type: "ExpressionStatement" }]
+ },
+ {
+ code: "<>>",
+ options: [{ enforceForJSX: true }],
+ parserOptions: { ecmaFeatures: { jsx: true } },
+ errors: [{ messageId: "unusedExpression", type: "ExpressionStatement" }]
}
]
});