Skip to content

Commit

Permalink
[New] jsx-props-no-spreading: add explicitSpread option to allow …
Browse files Browse the repository at this point in the history
…explicit spread of props

Fixes #2439.
  • Loading branch information
pawelnvk authored and ljharb committed Oct 5, 2019
1 parent 03bdefc commit 0877bcd
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 7 deletions.
15 changes: 13 additions & 2 deletions docs/rules/jsx-props-no-spreading.md
Expand Up @@ -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": [<string>]
}]
...
Expand Down Expand Up @@ -65,6 +66,16 @@ The following patterns are still considered warnings:
<img {...props} />
```

### 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
<img {...{ prop1, prop2, prop3 }} />
```

### 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`.
Expand Down
28 changes: 23 additions & 5 deletions lib/rules/jsx-props-no-spreading.js
Expand Up @@ -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
Expand Down Expand Up @@ -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({
Expand Down
38 changes: 38 additions & 0 deletions tests/lib/rules/jsx-props-no-spreading.js
Expand Up @@ -82,6 +82,13 @@ ruleTester.run('jsx-props-no-spreading', rule, {
'</App>'
].join('\n'),
options: [{html: 'ignore'}]
}, {
code: `
<App>
<Foo {...{ prop1, prop2, prop3 }} />
</App>
`,
options: [{explicitSpread: 'ignore'}]
}],

invalid: [{
Expand Down Expand Up @@ -154,5 +161,36 @@ ruleTester.run('jsx-props-no-spreading', rule, {
].join('\n'),
options: [{html: 'ignore'}],
errors: [expectedError]
}, {
code: `
<App>
<Foo {...{ prop1, prop2, prop3 }} />
</App>
`,
errors: [expectedError]
}, {
code: `
<App>
<Foo {...{ prop1, ...rest }} />
</App>
`,
options: [{explicitSpread: 'ignore'}],
errors: [expectedError]
}, {
code: `
<App>
<Foo {...{ ...props }} />
</App>
`,
options: [{explicitSpread: 'ignore'}],
errors: [expectedError]
}, {
code: `
<App>
<Foo {...props } />
</App>
`,
options: [{explicitSpread: 'ignore'}],
errors: [expectedError]
}]
});

0 comments on commit 0877bcd

Please sign in to comment.