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" }] } ] });