Skip to content
Permalink
Browse files
Update: add enforceForJSX option to no-unused-expressions rule (#14012)
* Update: no-unused-expression flags unused JSX

React's createElement call is side-effect free, as are most JSX pragmas.
An unused JSX element indicates a logic error in the same way any unused, side-effect free expression is.
This extension the no-unused-expression rule flags unused JSX elements unless the (new) allowJsx configuration option is set

* fixup! Update: no-unused-expression flags unused JSX

React's createElement call is side-effect free, as are most JSX pragmas.
An unused JSX element indicates a logic error in the same way any unused, side-effect free expression is.
This extension the no-unused-expression rule flags unused JSX elements when the (new) ignoreJSX configuration option is set

* fixup! Update: no-unused-expression flags unused JSX

* fixup! Update: no-unused-expression flags unused JSX

* fixup! Update: no-unused-expression flags unused JSX

* fixup! Update: no-unused-expression flags unused JSX

* fixup! Update: no-unused-expression flags unused JSX

* fixup! Update: no-unused-expression flags unused JSX

* fixup! Update: no-unused-expression flags unused JSX

* fixup! Update: no-unused-expression flags unused JSX

* fixup! Update: no-unused-expression flags unused JSX

Apply suggestions from code review

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
  • Loading branch information
duncanbeevers and mdjermanovic committed Feb 10, 2021
1 parent d6c84af commit ad9076183bc2c2029525edfc4596e403999348d1
Showing with 75 additions and 1 deletion.
  1. +25 −0 docs/rules/no-unused-expressions.md
  2. +12 −1 lib/rules/no-unused-expressions.js
  3. +38 −0 tests/lib/rules/no-unused-expressions.js
@@ -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 }]*/
<MyComponent />;
<></>;
```

Examples of **correct** code for the `{ "enforceForJSX": true }` option:

```jsx
/*eslint no-unused-expressions: ["error", { "enforceForJSX": true }]*/
var myComponentPartial = <MyComponent />;
var myFragment = <></>;
```
@@ -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) {
@@ -82,6 +82,30 @@ ruleTester.run("no-unused-expressions", rule, {
{
code: "obj?.foo(\"bar\")",
parserOptions: { ecmaVersion: 11 }
},

// JSX
{
code: "<div />",
parserOptions: { ecmaFeatures: { jsx: true } }
},
{
code: "<></>",
parserOptions: { ecmaFeatures: { jsx: true } }
},
{
code: "var partial = <div />",
parserOptions: { ecmaFeatures: { jsx: true } }
},
{
code: "var partial = <div />",
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: "<div />",
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" }]
}
]
});

0 comments on commit ad90761

Please sign in to comment.