From 0877bcd3085a0cfdb78ce4036faa624f398bbf7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Nowak?= Date: Sat, 5 Oct 2019 18:16:47 +0200 Subject: [PATCH] [New] `jsx-props-no-spreading`: add `explicitSpread` option to allow explicit spread of props Fixes #2439. --- docs/rules/jsx-props-no-spreading.md | 15 +++++++-- lib/rules/jsx-props-no-spreading.js | 28 ++++++++++++++--- tests/lib/rules/jsx-props-no-spreading.js | 38 +++++++++++++++++++++++ 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/docs/rules/jsx-props-no-spreading.md b/docs/rules/jsx-props-no-spreading.md index bc03b32abc..2d0bee711b 100644 --- a/docs/rules/jsx-props-no-spreading.md +++ b/docs/rules/jsx-props-no-spreading.md @@ -27,8 +27,9 @@ const {one_prop, two_prop} = otherProps; ```js ... "react/jsx-props-no-spreading": [{ - "html": "ignore" / "enforce", - "custom": "ignore" / "enforce", + "html": "ignore" | "enforce", + "custom": "ignore" | "enforce", + "explicitSpread": "ignore" | "enforce", "exceptions": [] }] ... @@ -65,6 +66,16 @@ The following patterns are still considered warnings: ``` +### explicitSpread + +`explicitSpread` set to `ignore` will ignore spread operators that are explicilty listing all object properties within that spread. Default is set to `enforce`. + +The following pattern is **not** considered warning when `explicitSpread` is set to `ignore`: + +```jsx + +``` + ### exceptions An "exception" will always flip the resulting html or custom setting for that component - ie, html set to `ignore`, with an exception of `div` will enforce on an `div`; custom set to `enforce` with an exception of `Foo` will ignore `Foo`. diff --git a/lib/rules/jsx-props-no-spreading.js b/lib/rules/jsx-props-no-spreading.js index f5ad8087f5..2a311a0a6f 100644 --- a/lib/rules/jsx-props-no-spreading.js +++ b/lib/rules/jsx-props-no-spreading.js @@ -12,7 +12,12 @@ const docsUrl = require('../util/docsUrl'); // ------------------------------------------------------------------------------ const OPTIONS = {ignore: 'ignore', enforce: 'enforce'}; -const DEFAULTS = {html: OPTIONS.enforce, custom: OPTIONS.enforce, exceptions: []}; +const DEFAULTS = { + html: OPTIONS.enforce, + custom: OPTIONS.enforce, + explicitSpread: OPTIONS.enforce, + exceptions: [] +}; // ------------------------------------------------------------------------------ // Rule Definition @@ -70,21 +75,34 @@ module.exports = { const configuration = context.options[0] || {}; const ignoreHtmlTags = (configuration.html || DEFAULTS.html) === OPTIONS.ignore; const ignoreCustomTags = (configuration.custom || DEFAULTS.custom) === OPTIONS.ignore; + const ignoreExplicitSpread = (configuration.explicitSpread || DEFAULTS.explicitSpread) === OPTIONS.ignore; const exceptions = configuration.exceptions || DEFAULTS.exceptions; const isException = (tag, allExceptions) => allExceptions.indexOf(tag) !== -1; + const isProperty = property => property.type === 'Property'; return { JSXSpreadAttribute(node) { const tagName = node.parent.name.name; const isHTMLTag = tagName && tagName[0] !== tagName[0].toUpperCase(); const isCustomTag = tagName && tagName[0] === tagName[0].toUpperCase(); - if (isHTMLTag && + if ( + isHTMLTag && ((ignoreHtmlTags && !isException(tagName, exceptions)) || - (!ignoreHtmlTags && isException(tagName, exceptions)))) { + (!ignoreHtmlTags && isException(tagName, exceptions))) + ) { return; } - if (isCustomTag && + if ( + isCustomTag && ((ignoreCustomTags && !isException(tagName, exceptions)) || - (!ignoreCustomTags && isException(tagName, exceptions)))) { + (!ignoreCustomTags && isException(tagName, exceptions))) + ) { + return; + } + if ( + ignoreExplicitSpread && + node.argument.type === 'ObjectExpression' && + node.argument.properties.every(isProperty) + ) { return; } context.report({ diff --git a/tests/lib/rules/jsx-props-no-spreading.js b/tests/lib/rules/jsx-props-no-spreading.js index 903ab7fdd8..fbb22504b3 100644 --- a/tests/lib/rules/jsx-props-no-spreading.js +++ b/tests/lib/rules/jsx-props-no-spreading.js @@ -82,6 +82,13 @@ ruleTester.run('jsx-props-no-spreading', rule, { '' ].join('\n'), options: [{html: 'ignore'}] + }, { + code: ` + + + + `, + options: [{explicitSpread: 'ignore'}] }], invalid: [{ @@ -154,5 +161,36 @@ ruleTester.run('jsx-props-no-spreading', rule, { ].join('\n'), options: [{html: 'ignore'}], errors: [expectedError] + }, { + code: ` + + + + `, + errors: [expectedError] + }, { + code: ` + + + + `, + options: [{explicitSpread: 'ignore'}], + errors: [expectedError] + }, { + code: ` + + + + `, + options: [{explicitSpread: 'ignore'}], + errors: [expectedError] + }, { + code: ` + + + + `, + options: [{explicitSpread: 'ignore'}], + errors: [expectedError] }] });