From c02f95275fe8da0209653c1ab6bc5d414e62b22d Mon Sep 17 00:00:00 2001 From: Yannick Croissant Date: Sun, 28 Jun 2015 17:02:16 +0000 Subject: [PATCH] Add support for props destructuring directly on the this keyword --- lib/rules/prop-types.js | 68 +++++++++++++++++++++++++---------- tests/lib/rules/prop-types.js | 26 ++++++++++++++ 2 files changed, 75 insertions(+), 19 deletions(-) diff --git a/lib/rules/prop-types.js b/lib/rules/prop-types.js index 9fffaa562a..4d898a81fb 100644 --- a/lib/rules/prop-types.js +++ b/lib/rules/prop-types.js @@ -360,22 +360,46 @@ module.exports = function(context) { function markPropTypesAsUsed(node, parentNames) { parentNames = parentNames || []; var type; - var name = getPropertyName(node.parent); + var name; var allNames; - if (name) { - allNames = parentNames.concat(name); - if (node.parent.type === 'MemberExpression') { - markPropTypesAsUsed(node.parent, allNames); - } - // Do not mark computed props as used. - type = name !== '__COMPUTED_PROP__' ? 'direct' : null; - } else if ( - node.parent.parent.declarations && - node.parent.parent.declarations[0].id.properties && - getKeyValue(node.parent.parent.declarations[0].id.properties[0]) - ) { - type = 'destructuring'; + var properties; + switch (node.type) { + case 'MemberExpression': + name = getPropertyName(node.parent); + if (name) { + allNames = parentNames.concat(name); + if (node.parent.type === 'MemberExpression') { + markPropTypesAsUsed(node.parent, allNames); + } + // Do not mark computed props as used. + type = name !== '__COMPUTED_PROP__' ? 'direct' : null; + } else if ( + node.parent.parent.declarations && + node.parent.parent.declarations[0].id.properties && + getKeyValue(node.parent.parent.declarations[0].id.properties[0]) + ) { + type = 'destructuring'; + properties = node.parent.parent.declarations[0].id.properties; + } + break; + case 'VariableDeclarator': + type = 'destructuring'; + + for (var i = 0, j = node.id.properties.length; i < j; i++) { + if ( + (node.id.properties[i].key.name !== 'props' && node.id.properties[i].key.value !== 'props') || + node.id.properties[i].value.type !== 'ObjectPattern' + ) { + continue; + } + properties = node.id.properties[i].value.properties; + break; + } + break; + default: + throw new Error(node.type + ' ASTNodes are not handled by markPropTypesAsUsed'); } + var component = componentList.getByNode(context, node); var usedPropTypes = component && component.usedPropTypes || []; @@ -392,17 +416,16 @@ module.exports = function(context) { }); break; case 'destructuring': - var properties = node.parent.parent.declarations[0].id.properties; - for (var i = 0, j = properties.length; i < j; i++) { - if (hasSpreadOperator(properties[i])) { + for (var k = 0, l = properties.length; k < l; k++) { + if (hasSpreadOperator(properties[k])) { continue; } - var propName = getKeyValue(properties[i]); + var propName = getKeyValue(properties[k]); if (propName) { usedPropTypes.push({ name: propName, allNames: [propName], - node: properties[i] + node: properties[k] }); } } @@ -509,6 +532,13 @@ module.exports = function(context) { markPropTypesAsDeclared(node, node.value); }, + VariableDeclarator: function(node) { + if (node.init.type !== 'ThisExpression' || node.id.type !== 'ObjectPattern') { + return; + } + markPropTypesAsUsed(node); + }, + MemberExpression: function(node) { var type; if (isPropTypesUsage(node)) { diff --git a/tests/lib/rules/prop-types.js b/tests/lib/rules/prop-types.js index 01bc4b86d3..ce510b46f2 100644 --- a/tests/lib/rules/prop-types.js +++ b/tests/lib/rules/prop-types.js @@ -890,6 +890,32 @@ eslintTester.addRuleTest('lib/rules/prop-types', { errors: [ {message: '\'arr[].some.value\' is missing in props validation for Hello'} ] + }, { + code: [ + 'class Hello extends React.Component {', + ' render() {', + ' let {props: {firstname}} = this;', + ' return
Hello {firstname}
;', + ' }', + '}' + ].join('\n'), + parser: 'babel-eslint', + errors: [ + {message: '\'firstname\' is missing in props validation for Hello'} + ] + }, { + code: [ + 'class Hello extends React.Component {', + ' render() {', + ' var {\'props\': {firstname}} = this;', + ' return
Hello {firstname}
;', + ' }', + '}' + ].join('\n'), + parser: 'babel-eslint', + errors: [ + {message: '\'firstname\' is missing in props validation for Hello'} + ] } ] });