From 84bc1e5edf4f5025e046bceda07caa0d8c19f220 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Fri, 23 Mar 2018 19:24:35 +0100 Subject: [PATCH 1/7] Started rewriting the destructuring-assignment rule --- lib/rules/destructuring-assignment.js | 193 ++++++++----- tests/lib/rules/destructuring-assignment.js | 297 +++++++------------- 2 files changed, 216 insertions(+), 274 deletions(-) diff --git a/lib/rules/destructuring-assignment.js b/lib/rules/destructuring-assignment.js index 93bbaed704..5ba6a596f6 100644 --- a/lib/rules/destructuring-assignment.js +++ b/lib/rules/destructuring-assignment.js @@ -7,6 +7,33 @@ const Components = require('../util/Components'); const docsUrl = require('../util/docsUrl'); const DEFAULT_OPTION = 'always'; +const SCHEMA = { + type: 'string', + enum: [ + 'always', + 'never' + ] +}; + +/** + * Check if the node is in a render method of the component. + * + * @param {Object} node - The node. + * @param {Object} component - The component. + * @returns {Boolean} - Returns whether or not the node is in a render method. + */ +function isInRenderMethod(node, component) { + while (node !== component) { + if (node.type === 'MethodDefinition' || node.type === 'Property') { + // Check if the method is named render and that it's not a static method + return !node.static && node.key.name === 'render'; + } + + node = node.parent; + } + + return false; +} module.exports = { meta: { @@ -17,64 +44,77 @@ module.exports = { url: docsUrl('destructuring-assignment') }, schema: [{ - type: 'string', - enum: [ - 'always', - 'never' - ] + oneOf: [SCHEMA, { + type: 'object', + properties: { + SFC: SCHEMA, + class: SCHEMA, + createClass: SCHEMA + } + }] }] }, create: Components.detect((context, components, utils) => { - const configuration = context.options[0] || DEFAULT_OPTION; - + function getConfiguration(componentType) { + if (typeof context.options[0] === 'object') { + return context.options[0][componentType] || DEFAULT_OPTION; + } - /** - * Checks if a prop is being assigned a value props.bar = 'bar' - * @param {ASTNode} node The AST node being checked. - * @returns {Boolean} - */ - - function isAssignmentToProp(node) { - return ( - node.parent && - node.parent.type === 'AssignmentExpression' && - node.parent.left === node - ); + return context.options[0] || DEFAULT_OPTION; } + /** * @param {ASTNode} node We expect either an ArrowFunctionExpression, * FunctionDeclaration, or FunctionExpression */ function handleStatelessComponent(node) { - const destructuringProps = node.params && node.params[0] && node.params[0].type === 'ObjectPattern'; - const destructuringContext = node.params && node.params[1] && node.params[1].type === 'ObjectPattern'; + const hasProps = node.params && node.params[0]; + const isDestructuringProps = hasProps && node.params[0].type === 'ObjectPattern'; + const hasContext = node.params && node.params[1]; + const isDestructuringContext = hasContext && node.params[1].type === 'ObjectPattern'; - if (destructuringProps && components.get(node) && configuration === 'never') { - context.report({ - node: node, - message: 'Must never use destructuring props assignment in SFC argument' - }); - } else if (destructuringContext && components.get(node) && configuration === 'never') { - context.report({ - node: node, - message: 'Must never use destructuring context assignment in SFC argument' - }); + if (!components.get(node)) { + return; } - } - function handleSFCUsage(node) { - // props.aProp || context.aProp - const isPropUsed = (node.object.name === 'props' || node.object.name === 'context') && !isAssignmentToProp(node); - if (isPropUsed && configuration === 'always') { - context.report({ - node: node, - message: `Must use destructuring ${node.object.name} assignment` - }); + if (getConfiguration('SFC') === 'never') { + if (hasProps && isDestructuringProps) { + context.report({ + node: node, + message: 'Must never use destructuring props assignment in SFC argument' + }); + } + + if (hasContext && isDestructuringContext) { + context.report({ + node: node, + message: 'Must never use destructuring context assignment in SFC argument' + }); + } + } else { + if (hasProps && !isDestructuringProps) { + context.report({ + node: node, + message: 'Must use destructuring props assignment in SFC argument' + }); + } + + if (hasContext && !isDestructuringContext) { + context.report({ + node: node, + message: 'Must use destructuring context assignment in SFC argument' + }); + } } } - function handleClassUsage(node) { + function handleClassUsage(node, component, configuration) { + // Check if we are in a render method + if (!isInRenderMethod(node, component)) { + return; + } + // this.props.Aprop || this.context.aProp || this.state.aState const isPropUsed = ( node.object.type === 'MemberExpression' && node.object.object.type === 'ThisExpression' && @@ -90,49 +130,60 @@ module.exports = { } return { - FunctionDeclaration: handleStatelessComponent, - ArrowFunctionExpression: handleStatelessComponent, - FunctionExpression: handleStatelessComponent, MemberExpression: function(node) { - const SFCComponent = components.get(context.getScope(node).block); - const classComponent = utils.getParentComponent(node); - if (SFCComponent) { - handleSFCUsage(node); + const component = utils.getParentComponent(); + + if (!component) { + return; } - if (classComponent) { - handleClassUsage(node, classComponent); + + if (utils.isES6Component(component)) { + handleClassUsage(node, component, getConfiguration('class')); + } else if (utils.isES5Component(component)) { + handleClassUsage(node, component, getConfiguration('createClass')); + } else { + // TODO: Check if property is being accessed from a rest object } }, VariableDeclarator: function(node) { - const classComponent = utils.getParentComponent(node); - const SFCComponent = components.get(context.getScope(node).block); - - const destructuring = (node.init && node.id && node.id.type === 'ObjectPattern'); - // let {foo} = props; - const destructuringSFC = destructuring && (node.init.name === 'props' || node.init.name === 'context'); - // let {foo} = this.props; - const destructuringClass = destructuring && node.init.object && node.init.object.type === 'ThisExpression' && ( - node.init.property.name === 'props' || node.init.property.name === 'context' || node.init.property.name === 'state' - ); - - if (SFCComponent && destructuringSFC && configuration === 'never') { - context.report({ - node: node, - message: `Must never use destructuring ${node.init.name} assignment` - }); + const component = utils.getParentComponent(node); + const isDestructuring = (node.init && node.id && node.id.type === 'ObjectPattern'); + + if (!isDestructuring || !isDestructuring) { + return; } - if (classComponent && destructuringClass && configuration === 'never') { - context.report({ - node: node, - message: `Must never use destructuring ${node.init.property.name} assignment` - }); + // Checks for class components + if (utils.isES5Component(component) || utils.isES6Component(component)) { + const isDestructuringClassProperties = node.init.object && node.init.object.type === 'ThisExpression' && ( + node.init.property.name === 'props' || node.init.property.name === 'context' || node.init.property.name === 'state' + ); + + if (!isDestructuringClassProperties || !isInRenderMethod(node)) { + return; + } + + if (utils.isES5Component(component) && getConfiguration('createClass') === 'never') { + context.report({ + node: node, + message: `Must never use destructuring ${node.init.property.name} assignment` + }); + } else if (utils.isES6Component(component) && getConfiguration('class') === 'never') { + context.report({ + node: node, + message: `Must never use destructuring ${node.init.property.name} assignment` + }); + } + + return; } + + // TODO: Add checks here for destrucuting props inside functional component } }; }) diff --git a/tests/lib/rules/destructuring-assignment.js b/tests/lib/rules/destructuring-assignment.js index f488239ad6..138d003316 100644 --- a/tests/lib/rules/destructuring-assignment.js +++ b/tests/lib/rules/destructuring-assignment.js @@ -18,227 +18,118 @@ const parserOptions = { }; const ruleTester = new RuleTester({parserOptions}); + ruleTester.run('destructuring-assignment', rule, { valid: [{ - code: `const Foo = class extends React.PureComponent { - render() { - const { foo } = this.props; - return
{foo}
; - } - };`, - options: ['always'], - parser: 'babel-eslint' - }, { - code: `const MyComponent = ({ id, className }) => ( -
- );` - }, { - code: `const MyComponent = (props) => { - const { id, className } = props; - return
- };`, - parser: 'babel-eslint' - }, { - code: `const MyComponent = ({ id, className }) => ( -
- );`, - options: ['always'] - }, { - code: `const MyComponent = (props) => { - const { id, className } = props; - return
- };` - }, { - code: `const MyComponent = (props) => { - const { id, className } = props; - return
- };`, - options: ['always'] - }, { - code: `const MyComponent = (props) => ( -
- );` - }, { - code: `const MyComponent = (props) => ( -
- );`, - options: ['always'] - }, { - code: `const MyComponent = (props, { color }) => ( -
- );` + code: `function Component({ color }) { + return {color}; + }` }, { - code: `const MyComponent = (props, { color }) => ( -
- );`, - options: ['always'] + code: 'const Component = ({ color }) => {color};' }, { - code: `const Foo = class extends React.PureComponent { - render() { - return
{this.props.foo}
; - } - };`, - options: ['never'] - }, { - code: `class Foo extends React.Component { - doStuff() {} - render() { - return
{this.props.foo}
; - } - }`, - options: ['never'] - }, { - code: `const Foo = class extends React.PureComponent { - render() { - const { foo } = this.props; - return
{foo}
; - } - };` + code: 'const Component = ({ color }, { onChange }) => {color};' }, { - code: `const Foo = class extends React.PureComponent { - render() { - const { foo } = this.props; - return
{foo}
; - } - };`, - options: ['always'], - parser: 'babel-eslint' + code: 'const Component = (props) => {props.color};', + options: [{SFC: 'never'}] }, { - code: `const Foo = class extends React.PureComponent { - render() { - const { foo } = this.props; - return
{foo}
; + code: ` + class Component extends React.Component { + render() { + return this.props.children; + } } - };` - }, { - code: `const Foo = class extends React.PureComponent { - render() { - const { foo } = this.props; - return
{foo}
; + `, + options: [{class: 'never'}] + }, { + code: ` + class Component extends React.Component { + componentDidMount() { + this.props.onMount(); + } + + render() { + const { children } = this.props; + return children; + } } - };`, - options: ['always'], - parser: 'babel-eslint' - }, { - code: `const MyComponent = (props) => { - const { h, i } = hi; - return
- };`, - options: ['never'], - parser: 'babel-eslint' + `, + options: [{class: 'always'}] + }, { + code: ` + const Component = createReactClass({ + render() { + return this.props.children; + } + }); + `, + options: [{createClass: 'never'}] }], + invalid: [{ - code: `const MyComponent = (props) => { - return (
) - };`, - errors: [ - {message: 'Must use destructuring props assignment'} - ] - }, { - code: `const MyComponent = ({ id, className }) => ( -
- );`, + code: `function Component({ color }) { + return {color}; + }`, options: ['never'], - errors: [ - {message: 'Must never use destructuring props assignment in SFC argument'} - ] + errors: [{message: 'Must never use destructuring props assignment in SFC argument'}] }, { - code: `const MyComponent = (props, { color }) => ( -
- );`, + code: 'const Component = ({ color }) => {color};', options: ['never'], - errors: [ - {message: 'Must never use destructuring context assignment in SFC argument'} - ] - }, { - code: `const Foo = class extends React.PureComponent { - render() { - return
{this.props.foo}
; - } - };`, - errors: [ - {message: 'Must use destructuring props assignment'} - ] + errors: [{message: 'Must never use destructuring props assignment in SFC argument'}] }, { - code: `const Foo = class extends React.PureComponent { - render() { - return
{this.state.foo}
; - } - };`, - errors: [ - {message: 'Must use destructuring state assignment'} - ] - }, { - code: `const Foo = class extends React.PureComponent { - render() { - return
{this.context.foo}
; - } - };`, - errors: [ - {message: 'Must use destructuring context assignment'} - ] - }, { - code: `class Foo extends React.Component { - render() { return this.foo(); } - foo() { - return this.props.children; - } - }`, - errors: [ - {message: 'Must use destructuring props assignment'} - ] + code: 'const Component = (props, { onChange }) => {props.color};', + options: ['never'], + errors: [{message: 'Must never use destructuring context assignment in SFC argument'}] }, { - code: `var Hello = React.createClass({ - render: function() { - return {this.props.foo}; - } - });`, - errors: [ - {message: 'Must use destructuring props assignment'} - ] + code: 'const Component = (props) => {props.color};', + options: [{SFC: 'always'}], + errors: [{message: 'Must use destructuring props assignment in SFC argument'}] }, { - code: `const Foo = class extends React.PureComponent { - render() { - const foo = this.props.foo; - return
{foo}
; - } - };`, - errors: [ - {message: 'Must use destructuring props assignment'} - ] + code: 'const Component = ({ color }, context) => {color};', + options: [{SFC: 'always'}], + errors: [{message: 'Must use destructuring context assignment in SFC argument'}] }, { - code: `const Foo = class extends React.PureComponent { - render() { - const { foo } = this.props; - return
{foo}
; + code: ` + class Component extends React.Component { + render() { + return this.props.children; + } } - };`, - options: ['never'], - parser: 'babel-eslint', - errors: [ - {message: 'Must never use destructuring props assignment'} - ] - }, { - code: `const MyComponent = (props) => { - const { id, className } = props; - return
- };`, - options: ['never'], - parser: 'babel-eslint', - errors: [ - {message: 'Must never use destructuring props assignment'} - ] - }, { - code: `const Foo = class extends React.PureComponent { - render() { - const { foo } = this.state; - return
{foo}
; + `, + options: [{class: 'always'}], + errors: [{message: 'Must use destructuring props assignment'}] + }, { + code: ` + const Component = createReactClass({ + render() { + return this.props.children; + } + }); + `, + options: [{createClass: 'always'}], + errors: [{message: 'Must use destructuring props assignment'}] + }, { + code: ` + const Component = createReactClass({ + render() { + const { children } = this.props; + + return children; + } + }); + `, + options: [{createClass: 'never'}], + errors: [{message: 'Must never use destructuring props assignment'}] + }, { + code: ` + class Component extends React.Component { + render() { + const { children } = this.props; + + return children; + } } - };`, - options: ['never'], - parser: 'babel-eslint', - errors: [ - {message: 'Must never use destructuring state assignment'} - ] + `, + options: [{class: 'never'}], + errors: [{message: 'Must never use destructuring props assignment'}] }] }); From 63ca391d5870ab35342714c99fb11b4e739403bb Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Fri, 23 Mar 2018 19:51:18 +0100 Subject: [PATCH 2/7] Added checking for destructuring inside functional component body --- lib/rules/destructuring-assignment.js | 22 ++++++++++++++-- tests/lib/rules/destructuring-assignment.js | 28 ++++++++++++++++++--- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/lib/rules/destructuring-assignment.js b/lib/rules/destructuring-assignment.js index 5ba6a596f6..82739e90ec 100644 --- a/lib/rules/destructuring-assignment.js +++ b/lib/rules/destructuring-assignment.js @@ -154,10 +154,12 @@ module.exports = { const component = utils.getParentComponent(node); const isDestructuring = (node.init && node.id && node.id.type === 'ObjectPattern'); - if (!isDestructuring || !isDestructuring) { + if (!isDestructuring || !component) { return; } + console.log(component); + // Checks for class components if (utils.isES5Component(component) || utils.isES6Component(component)) { const isDestructuringClassProperties = node.init.object && node.init.object.type === 'ThisExpression' && ( @@ -183,7 +185,23 @@ module.exports = { return; } - // TODO: Add checks here for destrucuting props inside functional component + if (component.params[0] && component.params[0].name === node.init.name) { + context.report({ + node: node, + message: 'Must never use destructuring props assignment' + }); + + return; + } + + if (component.params[1] && component.params[1].name === node.init.name) { + context.report({ + node: node, + message: 'Must never use destructuring context assignment' + }); + + return; + } } }; }) diff --git a/tests/lib/rules/destructuring-assignment.js b/tests/lib/rules/destructuring-assignment.js index 138d003316..40ef9392fe 100644 --- a/tests/lib/rules/destructuring-assignment.js +++ b/tests/lib/rules/destructuring-assignment.js @@ -46,7 +46,7 @@ ruleTester.run('destructuring-assignment', rule, { componentDidMount() { this.props.onMount(); } - + render() { const { children } = this.props; return children; @@ -90,7 +90,7 @@ ruleTester.run('destructuring-assignment', rule, { }, { code: ` class Component extends React.Component { - render() { + render() { return this.props.children; } } @@ -112,7 +112,7 @@ ruleTester.run('destructuring-assignment', rule, { const Component = createReactClass({ render() { const { children } = this.props; - + return children; } }); @@ -124,12 +124,32 @@ ruleTester.run('destructuring-assignment', rule, { class Component extends React.Component { render() { const { children } = this.props; - + return children; } } `, options: [{class: 'never'}], errors: [{message: 'Must never use destructuring props assignment'}] + }, { + code: ` + function Component(props) { + const { children } = props; + + return
{children}
; + } + `, + options: [{SFC: 'never'}], + errors: [{message: 'Must never use destructuring props assignment'}] + }, { + code: ` + function Component(props, context) { + const { onClick } = context; + + return
+ } + `, + options: [{SFC: 'never'}], + errors: [{message: 'Must never use destructuring context assignment'}] }] }); From 10ab63190137b5db7411a0f049d5f432b98971f7 Mon Sep 17 00:00:00 2001 From: Henri Date: Sat, 24 Mar 2018 19:30:14 +0100 Subject: [PATCH 3/7] Updated Docs Added documentation for the object as the first option --- docs/rules/destructuring-assignment.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/rules/destructuring-assignment.md b/docs/rules/destructuring-assignment.md index def9567bcd..186d0f5247 100644 --- a/docs/rules/destructuring-assignment.md +++ b/docs/rules/destructuring-assignment.md @@ -5,6 +5,16 @@ Rule can be set to either of `always` or `never`; "react/destructuring-assignment": [, 'always'] ``` +It also accepts an object as the first option for more granular control for different component types. + +```js +"react/destructuring-assignment": [, { + SFC: 'always', + class: 'always', + createClass: 'always', +}] +``` + ## Rule Details By default rule is set to `always` enforce destructuring assignment. The following patterns are considered warnings: From c5c399ed4b429f858dc89760e62a1c1cc4bd22f5 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Fri, 30 Mar 2018 17:33:01 +0200 Subject: [PATCH 4/7] Fixed a bug where no props are accessed and the whole object is just passed down but still would require to destruct. --- lib/rules/destructuring-assignment.js | 29 ++++++++++++++------- tests/lib/rules/destructuring-assignment.js | 4 --- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/rules/destructuring-assignment.js b/lib/rules/destructuring-assignment.js index 82739e90ec..5637686b02 100644 --- a/lib/rules/destructuring-assignment.js +++ b/lib/rules/destructuring-assignment.js @@ -74,7 +74,7 @@ module.exports = { const hasContext = node.params && node.params[1]; const isDestructuringContext = hasContext && node.params[1].type === 'ObjectPattern'; - if (!components.get(node)) { + if (!components.get(node) || components.get(node).confidence === 0) { return; } @@ -92,15 +92,26 @@ module.exports = { message: 'Must never use destructuring context assignment in SFC argument' }); } - } else { - if (hasProps && !isDestructuringProps) { + } + } + + function handleStatelessUsage(node, component) { + if (getConfiguration('SFC') === 'always') { + const propsName = component.params[0] ? component.params[0].name : null; + const contextName = component.params[1] ? component.params[1].name : null; + + if (!node.object.type === 'Identifier') { + return; + } + + const objName = node.object.name; + + if (objName === propsName) { context.report({ node: node, message: 'Must use destructuring props assignment in SFC argument' }); - } - - if (hasContext && !isDestructuringContext) { + } else if (objName === contextName) { context.report({ node: node, message: 'Must use destructuring context assignment in SFC argument' @@ -146,7 +157,7 @@ module.exports = { } else if (utils.isES5Component(component)) { handleClassUsage(node, component, getConfiguration('createClass')); } else { - // TODO: Check if property is being accessed from a rest object + handleStatelessUsage(node, component); } }, @@ -158,15 +169,13 @@ module.exports = { return; } - console.log(component); - // Checks for class components if (utils.isES5Component(component) || utils.isES6Component(component)) { const isDestructuringClassProperties = node.init.object && node.init.object.type === 'ThisExpression' && ( node.init.property.name === 'props' || node.init.property.name === 'context' || node.init.property.name === 'state' ); - if (!isDestructuringClassProperties || !isInRenderMethod(node)) { + if (!isDestructuringClassProperties || !isInRenderMethod(node, component)) { return; } diff --git a/tests/lib/rules/destructuring-assignment.js b/tests/lib/rules/destructuring-assignment.js index 40ef9392fe..402489dc72 100644 --- a/tests/lib/rules/destructuring-assignment.js +++ b/tests/lib/rules/destructuring-assignment.js @@ -83,10 +83,6 @@ ruleTester.run('destructuring-assignment', rule, { code: 'const Component = (props) => {props.color};', options: [{SFC: 'always'}], errors: [{message: 'Must use destructuring props assignment in SFC argument'}] - }, { - code: 'const Component = ({ color }, context) => {color};', - options: [{SFC: 'always'}], - errors: [{message: 'Must use destructuring context assignment in SFC argument'}] }, { code: ` class Component extends React.Component { From 4011c7858f39ffe90defe61d936ffe93f842c656 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Tue, 10 Apr 2018 22:55:45 +0200 Subject: [PATCH 5/7] Updated isInRenderMethod to use recursive programming --- lib/rules/destructuring-assignment.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/rules/destructuring-assignment.js b/lib/rules/destructuring-assignment.js index 5637686b02..81626b78c1 100644 --- a/lib/rules/destructuring-assignment.js +++ b/lib/rules/destructuring-assignment.js @@ -23,16 +23,16 @@ const SCHEMA = { * @returns {Boolean} - Returns whether or not the node is in a render method. */ function isInRenderMethod(node, component) { - while (node !== component) { - if (node.type === 'MethodDefinition' || node.type === 'Property') { - // Check if the method is named render and that it's not a static method - return !node.static && node.key.name === 'render'; - } + if (node === component) { + return false; + } - node = node.parent; + if (node.type === 'MethodDefinition' || node.type === 'Property') { + // Check if the method is named render and that it's not a static method + return !node.static && node.key.name === 'render'; } - return false; + return isInRenderMethod(node.parent, component); } module.exports = { From 80149b6b5a7bdd90ef9c437a83ae7b39507db170 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Tue, 10 Apr 2018 22:56:01 +0200 Subject: [PATCH 6/7] Added more tests --- tests/lib/rules/destructuring-assignment.js | 84 ++++++++++++++++++--- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/tests/lib/rules/destructuring-assignment.js b/tests/lib/rules/destructuring-assignment.js index 402489dc72..710fbfaa7c 100644 --- a/tests/lib/rules/destructuring-assignment.js +++ b/tests/lib/rules/destructuring-assignment.js @@ -63,6 +63,32 @@ ruleTester.run('destructuring-assignment', rule, { }); `, options: [{createClass: 'never'}] + }, { + code: ` + const Component = createReactClass({ + render() { + const { children } = this.props; + + return children; + } + }); + `, + options: [{createClass: 'always'}] + }, { + code: ` + const Component = createReactClass({ + componentDidMount() { + this.props.onMount(); + }, + + render() { + const { children } = this.props; + + return children; + } + }); + `, + options: [{createClass: 'always'}] }], invalid: [{ @@ -75,6 +101,14 @@ ruleTester.run('destructuring-assignment', rule, { code: 'const Component = ({ color }) => {color};', options: ['never'], errors: [{message: 'Must never use destructuring props assignment in SFC argument'}] + }, { + code: 'const Component = (props) => {props.color};', + options: [{class: 'never'}], + errors: [{message: 'Must use destructuring props assignment in SFC argument'}] + }, { + code: 'const Component = (props) => {props.color.primary};', + options: ['always'], + errors: [{message: 'Must use destructuring props assignment in SFC argument'}] }, { code: 'const Component = (props, { onChange }) => {props.color};', options: ['never'], @@ -83,6 +117,30 @@ ruleTester.run('destructuring-assignment', rule, { code: 'const Component = (props) => {props.color};', options: [{SFC: 'always'}], errors: [{message: 'Must use destructuring props assignment in SFC argument'}] + }, { + code: 'const Component = (props, context) => {context.color};', + options: [{SFC: 'always'}], + errors: [{message: 'Must use destructuring context assignment in SFC argument'}] + }, { + code: ` + function Component(props, context) { + const { onClick } = context; + + return
+ } + `, + options: [{SFC: 'never'}], + errors: [{message: 'Must never use destructuring context assignment'}] + }, { + code: ` + function Component(props) { + const { children } = props; + + return
{children}
; + } + `, + options: [{SFC: 'never'}], + errors: [{message: 'Must never use destructuring props assignment'}] }, { code: ` class Component extends React.Component { @@ -129,23 +187,25 @@ ruleTester.run('destructuring-assignment', rule, { errors: [{message: 'Must never use destructuring props assignment'}] }, { code: ` - function Component(props) { - const { children } = props; - - return
{children}
; + class Component extends React.Component { + render() { + const { value } = this.state; + + return value; + } } `, - options: [{SFC: 'never'}], - errors: [{message: 'Must never use destructuring props assignment'}] + options: [{class: 'never'}], + errors: [{message: 'Must never use destructuring state assignment'}] }, { code: ` - function Component(props, context) { - const { onClick } = context; - - return
+ class Component extends React.Component { + render() { + return this.state.value; + } } `, - options: [{SFC: 'never'}], - errors: [{message: 'Must never use destructuring context assignment'}] + options: [{class: 'always'}], + errors: [{message: 'Must use destructuring state assignment'}] }] }); From f8042b9de7ae3b00072d9b02f5c42d6ddc02bf84 Mon Sep 17 00:00:00 2001 From: Henri Beck Date: Sat, 30 Jun 2018 00:46:47 +0200 Subject: [PATCH 7/7] Fixed linting Signed-off-by: Henri Beck --- lib/rules/destructuring-assignment.js | 10 ++++++++-- tests/lib/rules/destructuring-assignment.js | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/rules/destructuring-assignment.js b/lib/rules/destructuring-assignment.js index 4adab081cd..3ac57f9770 100644 --- a/lib/rules/destructuring-assignment.js +++ b/lib/rules/destructuring-assignment.js @@ -15,6 +15,14 @@ const SCHEMA = { ] }; +function isAssignmentToProp(node) { + return ( + node.parent && + node.parent.type === 'AssignmentExpression' && + node.parent.left === node + ); +} + /** * Check if the node is in a render method of the component. * @@ -209,8 +217,6 @@ module.exports = { node: node, message: 'Must never use destructuring context assignment' }); - - return; } } }; diff --git a/tests/lib/rules/destructuring-assignment.js b/tests/lib/rules/destructuring-assignment.js index 791e42d593..b3ac1ce0d2 100644 --- a/tests/lib/rules/destructuring-assignment.js +++ b/tests/lib/rules/destructuring-assignment.js @@ -88,7 +88,7 @@ ruleTester.run('destructuring-assignment', rule, { } }); `, - options: [{createClass: 'always'}] + options: [{createClass: 'always'}], parser: 'babel-eslint' }, { code: `const MyComponent = (props) => {