Skip to content

Commit

Permalink
rename rule option
Browse files Browse the repository at this point in the history
  • Loading branch information
Belco90 committed Apr 25, 2022
1 parent 51068b3 commit ca3ce96
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 47 deletions.
24 changes: 14 additions & 10 deletions docs/rules/jsx-no-leaked-zero.md
Expand Up @@ -8,9 +8,11 @@ The number 0 is a special case for JSX inline conditions, since it's the only fa

This rule aims to prevent potential numerical condition from rendering a 0 value to the DOM. Since the rule doesn't know if the condition is based on numbers or something else due to the lack of types, it will report all sorts of conditionals within a JSX expression.

TODO: add dangerous cases here

This can be avoided by:
- casting the condition to bool
- transforming the binary expression into a ternary expression which returns `null` for falsy values
- casting the condition to bool: `{!!someValue && <Something />}`
- transforming the binary expression into a ternary expression which returns `null` for falsy values: `{someValue ? <Something /> : null}`

This rule is autofixable, check the Options section to read more about the different strategies available.

Expand Down Expand Up @@ -120,17 +122,19 @@ const Component = ({ elements }) => {

The supported options are:

### `validFixStrategies`
An array containing `"cast"`, `"ternary"` or both (default: `["ternary", "cast"]`) - Decide which strategies are valid to consider that a potential leaked zero is prevented (at least 1 is required). This also affects the autofix approach used by the rule. The "cast" option will cast to boolean the condition of the JSX expression. The "ternary" option transforms the binary expression into a ternary expression returning `null` for falsy values. If both options are set, the first one will be used for autofixing the reported occurrences.
### `validStrategies`
An array containing `"cast"`, `"ternary"` or both (default: `["ternary", "cast"]`) - Decide which strategies are considered valid to prevent leaked renders (at least 1 is required). The "cast" option will cast to boolean the condition of the JSX expression. The "ternary" option transforms the binary expression into a ternary expression returning `null` for falsy values. The first option from the array will be used as autofix, so the order of the values matter.

It can be set like:
```js
// ...
"react/jsx-no-leaked-zero": [<enabled>, { "validFixStrategies": ["ternary", "cast"] }]
// ...
```json5
{
// ...
"react/jsx-no-leaked-zero": [<enabled>, { "validStrategies": ["ternary", "cast"] }]
// ...
}
```

Assuming the following options: `{ "validFixStrategies": ["ternary"] }`
Assuming the following options: `{ "validStrategies": ["ternary"] }`

Examples of **incorrect** code for this rule, with the above configuration:
```jsx
Expand All @@ -152,7 +156,7 @@ const Component = ({ count, title }) => {
}
```

Assuming the following options: `{ "validFixStrategies": ["cast"] }`
Assuming the following options: `{ "validStrategies": ["cast"] }`

Examples of **incorrect** code for this rule, with the above configuration:
```jsx
Expand Down
12 changes: 6 additions & 6 deletions lib/rules/jsx-no-leaked-zero.js
Expand Up @@ -19,7 +19,7 @@ const messages = {

const CAST_STRATEGY = 'cast';
const TERNARY_STRATEGY = 'ternary';
const DEFAULT_VALID_FIX_STRATEGIES = [TERNARY_STRATEGY, CAST_STRATEGY];
const DEFAULT_VALID_STRATEGIES = [TERNARY_STRATEGY, CAST_STRATEGY];

/**
* @type {import('eslint').Rule.RuleModule}
Expand All @@ -40,7 +40,7 @@ module.exports = {
{
type: 'object',
properties: {
validFixStrategies: {
validStrategies: {
type: 'array',
items: {
enum: [
Expand All @@ -49,7 +49,7 @@ module.exports = {
],
},
uniqueItems: true,
default: DEFAULT_VALID_FIX_STRATEGIES,
default: DEFAULT_VALID_STRATEGIES,
},
},
additionalProperties: false,
Expand All @@ -59,9 +59,9 @@ module.exports = {

create(context) {
const config = context.options[0] || {};
const validFixStrategies = config.validFixStrategies || DEFAULT_VALID_FIX_STRATEGIES;
const fixStrategy = validFixStrategies[0];
const areBothStrategiesValid = validFixStrategies.length === 2;
const validStrategies = config.validStrategies || DEFAULT_VALID_STRATEGIES;
const fixStrategy = validStrategies[0];
const areBothStrategiesValid = validStrategies.length === 2;

function trimLeftNode(node) {
// Remove double unary expression (boolean cast), so we avoid trimming valid negations
Expand Down
62 changes: 31 additions & 31 deletions tests/lib/rules/jsx-no-leaked-zero.js
Expand Up @@ -93,31 +93,31 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
`,
},
{
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
code: `
const Component = ({ elements, count }) => {
return <div>{count ? <List elements={elements}/> : null}</div>
}
`,
},
{
options: [{ validFixStrategies: ['cast'] }],
options: [{ validStrategies: ['cast'] }],
code: `
const Component = ({ elements, count }) => {
return <div>{!!count && <List elements={elements}/>}</div>
}
`,
},
{
options: [{ validFixStrategies: ['cast', 'ternary'] }],
options: [{ validStrategies: ['cast', 'ternary'] }],
code: `
const Component = ({ elements, count }) => {
return <div>{count ? <List elements={elements}/> : null}</div>
}
`,
},
{
options: [{ validFixStrategies: ['cast', 'ternary'] }],
options: [{ validStrategies: ['cast', 'ternary'] }],
code: `
const Component = ({ elements, count }) => {
return <div>{!!count && <List elements={elements}/>}</div>
Expand Down Expand Up @@ -170,7 +170,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
`,
},

// Invalid tests with both fix strategies (default)
// Invalid tests with both strategies enabled (default)
{
code: `
const Component = ({ count, title }) => {
Expand Down Expand Up @@ -279,7 +279,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{(numberA || numberB) && <Results>{numberA+numberB}</Results>}</div>
}
`,
options: [{ validFixStrategies: ['cast', 'ternary'] }],
options: [{ validStrategies: ['cast', 'ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -292,14 +292,14 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
`,
},

// Invalid tests with "ternary" fix strategy
// Invalid tests only with "ternary" strategy enabled
{
code: `
const Component = ({ count, title }) => {
return <div>{count && title}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -317,7 +317,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{count && <span>There are {count} results</span>}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -335,7 +335,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{elements.length && <List elements={elements}/>}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -353,7 +353,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{nestedCollection.elements.length && <List elements={nestedCollection.elements}/>}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -371,7 +371,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{elements[0] && <List elements={elements}/>}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -389,7 +389,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{(numberA || numberB) && <Results>{numberA+numberB}</Results>}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -402,14 +402,14 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
`,
},

// cases: boolean cast isn't valid if fix strategy is only "ternary"
// cases: boolean cast isn't valid if strategy is only "ternary"
{
code: `
const Component = ({ someCondition, title }) => {
return <div>{!someCondition && title}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -427,7 +427,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{!!count && title}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -445,7 +445,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{count > 0 && title}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -463,7 +463,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{0 != count && title}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -481,7 +481,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{count < total && title}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -499,7 +499,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{!!(count && somethingElse) && title}</div>
}
`,
options: [{ validFixStrategies: ['ternary'] }],
options: [{ validStrategies: ['ternary'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -512,14 +512,14 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
`,
},

// Invalid tests with "cast" fix strategy
// Invalid tests only with "cast" strategy enabled
{
code: `
const Component = ({ count, title }) => {
return <div>{count && title}</div>
}
`,
options: [{ validFixStrategies: ['cast'] }],
options: [{ validStrategies: ['cast'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -537,7 +537,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{count && <span>There are {count} results</span>}</div>
}
`,
options: [{ validFixStrategies: ['cast'] }],
options: [{ validStrategies: ['cast'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -555,7 +555,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{elements.length && <List elements={elements}/>}</div>
}
`,
options: [{ validFixStrategies: ['cast'] }],
options: [{ validStrategies: ['cast'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -573,7 +573,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{nestedCollection.elements.length && <List elements={nestedCollection.elements}/>}</div>
}
`,
options: [{ validFixStrategies: ['cast'] }],
options: [{ validStrategies: ['cast'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -591,7 +591,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{elements[0] && <List elements={elements}/>}</div>
}
`,
options: [{ validFixStrategies: ['cast'] }],
options: [{ validStrategies: ['cast'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -609,7 +609,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{(numberA || numberB) && <Results>{numberA+numberB}</Results>}</div>
}
`,
options: [{ validFixStrategies: ['cast'] }],
options: [{ validStrategies: ['cast'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -622,14 +622,14 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
`,
},

// cases: ternary isn't valid if fix strategy is only "cast"
// cases: ternary isn't valid if strategy is only "cast"
{
code: `
const Component = ({ count, title }) => {
return <div>{count ? title : null}</div>
}
`,
options: [{ validFixStrategies: ['cast'] }],
options: [{ validStrategies: ['cast'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -647,7 +647,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{!count ? title : null}</div>
}
`,
options: [{ validFixStrategies: ['cast'] }],
options: [{ validStrategies: ['cast'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand All @@ -665,7 +665,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, {
return <div>{count && somethingElse ? title : null}</div>
}
`,
options: [{ validFixStrategies: ['cast'] }],
options: [{ validStrategies: ['cast'] }],
errors: [{
message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`',
line: 3,
Expand Down

0 comments on commit ca3ce96

Please sign in to comment.