From ca3ce96a6924a0078d74408be5b5c9b07522894e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Mon, 25 Apr 2022 12:27:59 +0200 Subject: [PATCH] rename rule option --- docs/rules/jsx-no-leaked-zero.md | 24 ++++++----- lib/rules/jsx-no-leaked-zero.js | 12 +++--- tests/lib/rules/jsx-no-leaked-zero.js | 62 +++++++++++++-------------- 3 files changed, 51 insertions(+), 47 deletions(-) diff --git a/docs/rules/jsx-no-leaked-zero.md b/docs/rules/jsx-no-leaked-zero.md index 5cc4a2f203..8c8a734fbe 100644 --- a/docs/rules/jsx-no-leaked-zero.md +++ b/docs/rules/jsx-no-leaked-zero.md @@ -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 && }` +- transforming the binary expression into a ternary expression which returns `null` for falsy values: `{someValue ? : null}` This rule is autofixable, check the Options section to read more about the different strategies available. @@ -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": [, { "validFixStrategies": ["ternary", "cast"] }] -// ... +```json5 +{ + // ... + "react/jsx-no-leaked-zero": [, { "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 @@ -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 diff --git a/lib/rules/jsx-no-leaked-zero.js b/lib/rules/jsx-no-leaked-zero.js index 288ff86893..911dc3a711 100644 --- a/lib/rules/jsx-no-leaked-zero.js +++ b/lib/rules/jsx-no-leaked-zero.js @@ -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} @@ -40,7 +40,7 @@ module.exports = { { type: 'object', properties: { - validFixStrategies: { + validStrategies: { type: 'array', items: { enum: [ @@ -49,7 +49,7 @@ module.exports = { ], }, uniqueItems: true, - default: DEFAULT_VALID_FIX_STRATEGIES, + default: DEFAULT_VALID_STRATEGIES, }, }, additionalProperties: false, @@ -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 diff --git a/tests/lib/rules/jsx-no-leaked-zero.js b/tests/lib/rules/jsx-no-leaked-zero.js index d05ea152d3..c860ebbbaa 100644 --- a/tests/lib/rules/jsx-no-leaked-zero.js +++ b/tests/lib/rules/jsx-no-leaked-zero.js @@ -93,7 +93,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { `, }, { - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], code: ` const Component = ({ elements, count }) => { return
{count ? : null}
@@ -101,7 +101,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { `, }, { - options: [{ validFixStrategies: ['cast'] }], + options: [{ validStrategies: ['cast'] }], code: ` const Component = ({ elements, count }) => { return
{!!count && }
@@ -109,7 +109,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { `, }, { - options: [{ validFixStrategies: ['cast', 'ternary'] }], + options: [{ validStrategies: ['cast', 'ternary'] }], code: ` const Component = ({ elements, count }) => { return
{count ? : null}
@@ -117,7 +117,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { `, }, { - options: [{ validFixStrategies: ['cast', 'ternary'] }], + options: [{ validStrategies: ['cast', 'ternary'] }], code: ` const Component = ({ elements, count }) => { return
{!!count && }
@@ -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 }) => { @@ -279,7 +279,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{(numberA || numberB) && {numberA+numberB}}
} `, - options: [{ validFixStrategies: ['cast', 'ternary'] }], + options: [{ validStrategies: ['cast', 'ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -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
{count && title}
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -317,7 +317,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{count && There are {count} results}
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -335,7 +335,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{elements.length && }
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -353,7 +353,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{nestedCollection.elements.length && }
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -371,7 +371,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{elements[0] && }
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -389,7 +389,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{(numberA || numberB) && {numberA+numberB}}
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -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
{!someCondition && title}
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -427,7 +427,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{!!count && title}
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -445,7 +445,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{count > 0 && title}
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -463,7 +463,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{0 != count && title}
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -481,7 +481,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{count < total && title}
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -499,7 +499,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{!!(count && somethingElse) && title}
} `, - options: [{ validFixStrategies: ['ternary'] }], + options: [{ validStrategies: ['ternary'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -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
{count && title}
} `, - options: [{ validFixStrategies: ['cast'] }], + options: [{ validStrategies: ['cast'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -537,7 +537,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{count && There are {count} results}
} `, - options: [{ validFixStrategies: ['cast'] }], + options: [{ validStrategies: ['cast'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -555,7 +555,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{elements.length && }
} `, - options: [{ validFixStrategies: ['cast'] }], + options: [{ validStrategies: ['cast'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -573,7 +573,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{nestedCollection.elements.length && }
} `, - options: [{ validFixStrategies: ['cast'] }], + options: [{ validStrategies: ['cast'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -591,7 +591,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{elements[0] && }
} `, - options: [{ validFixStrategies: ['cast'] }], + options: [{ validStrategies: ['cast'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -609,7 +609,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{(numberA || numberB) && {numberA+numberB}}
} `, - options: [{ validFixStrategies: ['cast'] }], + options: [{ validStrategies: ['cast'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -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
{count ? title : null}
} `, - options: [{ validFixStrategies: ['cast'] }], + options: [{ validStrategies: ['cast'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -647,7 +647,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{!count ? title : null}
} `, - options: [{ validFixStrategies: ['cast'] }], + options: [{ validStrategies: ['cast'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3, @@ -665,7 +665,7 @@ ruleTester.run('jsx-no-leaked-zero', rule, { return
{count && somethingElse ? title : null}
} `, - options: [{ validFixStrategies: ['cast'] }], + options: [{ validStrategies: ['cast'] }], errors: [{ message: 'Potential numeric evaluation resulting in an unintentionally rendered `0`', line: 3,