Skip to content

Commit 7bfa7bf

Browse files
committed
1 parent 00553b5 commit 7bfa7bf

File tree

4 files changed

+178
-84
lines changed

4 files changed

+178
-84
lines changed

lib/rules/no-unused-prop-types.js

+32-58
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,6 @@
1010
var Components = require('../util/Components');
1111
var variable = require('../util/variable');
1212

13-
// ------------------------------------------------------------------------------
14-
// Constants
15-
// ------------------------------------------------------------------------------
16-
17-
var DIRECT_PROPS_REGEX = /^props\s*(\.|\[)/;
18-
1913
// ------------------------------------------------------------------------------
2014
// Rule Definition
2115
// ------------------------------------------------------------------------------
@@ -74,17 +68,15 @@ module.exports = {
7468
}
7569

7670
/**
77-
* Checks if we are using a prop
71+
* Checks if this node is `this.props`.
7872
* @param {ASTNode} node The AST node being checked.
79-
* @returns {Boolean} True if we are using a prop, false if not.
73+
* @returns {Boolean} True if this node is `this.props`, false if not.
8074
*/
81-
function isPropTypesUsage(node) {
82-
var isClassUsage = (
75+
function isPropsMemberExpression(node) {
76+
return (
8377
(utils.getParentES6Component() || utils.getParentES5Component()) &&
8478
node.object.type === 'ThisExpression' && node.property.name === 'props'
8579
);
86-
var isStatelessFunctionUsage = node.object.name === 'props';
87-
return isClassUsage || isStatelessFunctionUsage;
8880
}
8981

9082
/**
@@ -209,15 +201,26 @@ module.exports = {
209201
}
210202

211203
/**
212-
* Checks if a prop init name matches common naming patterns
204+
* Checks if a node is an identifier referring to props
213205
* @param {ASTNode} node The AST node being checked.
214206
* @returns {Boolean} True if the prop name matches
215207
*/
216-
function isPropAttributeName (node) {
208+
function isPropsIdentifier (node) {
217209
return (
218-
node.init.name === 'props' ||
219-
node.init.name === 'nextProps' ||
220-
node.init.name === 'prevProps'
210+
node.type === 'Identifier' && (
211+
node.parent.type === 'MemberExpression' ||
212+
node.parent.type === 'VariableDeclarator'
213+
) && (
214+
(
215+
(isInLifeCycleMethod(node) || utils.getParentStatelessComponent()) &&
216+
node.name === 'props'
217+
) || (
218+
isInLifeCycleMethod(node) && (
219+
node.name === 'nextProps' ||
220+
node.name === 'prevProps'
221+
)
222+
)
223+
)
221224
);
222225
}
223226

@@ -483,41 +486,17 @@ module.exports = {
483486
}
484487
}
485488

486-
/**
487-
* Check if we are in a class constructor
488-
* @return {boolean} true if we are in a class constructor, false if not
489-
*/
490-
function inConstructor() {
491-
var scope = context.getScope();
492-
while (scope) {
493-
if (scope.block && scope.block.parent && scope.block.parent.kind === 'constructor') {
494-
return true;
495-
}
496-
scope = scope.upper;
497-
}
498-
return false;
499-
}
500-
501489
/**
502490
* Retrieve the name of a property node
503491
* @param {ASTNode} node The AST node with the property.
504492
* @return {string} the name of the property or undefined if not found
505493
*/
506494
function getPropertyName(node) {
507-
var isDirectProp = DIRECT_PROPS_REGEX.test(sourceCode.getText(node));
508-
var isInClassComponent = utils.getParentES6Component() || utils.getParentES5Component();
509-
var isNotInConstructor = !inConstructor(node);
510-
if (isDirectProp && isInClassComponent && isNotInConstructor) {
511-
return void 0;
512-
}
513-
if (!isDirectProp) {
514-
node = node.parent;
515-
}
516-
var property = node.property;
495+
var property = node.parent.property;
517496
if (property) {
518497
switch (property.type) {
519498
case 'Identifier':
520-
if (node.computed) {
499+
if (node.parent.computed) {
521500
return '__COMPUTED_PROP__';
522501
}
523502
return property.name;
@@ -530,7 +509,7 @@ module.exports = {
530509
}
531510
// falls through
532511
default:
533-
if (node.computed) {
512+
if (node.parent.computed) {
534513
return '__COMPUTED_PROP__';
535514
}
536515
break;
@@ -550,6 +529,7 @@ module.exports = {
550529
var allNames;
551530
var properties;
552531
switch (node.type) {
532+
case 'Identifier':
553533
case 'MemberExpression':
554534
name = getPropertyName(node);
555535
if (name) {
@@ -582,16 +562,9 @@ module.exports = {
582562
(node.id.properties[i].key.name === 'props' || node.id.properties[i].key.value === 'props') &&
583563
node.id.properties[i].value.type === 'ObjectPattern'
584564
);
585-
// let {firstname} = props
586-
var genericDestructuring = isPropAttributeName(node) && (
587-
utils.getParentStatelessComponent() ||
588-
isInLifeCycleMethod(node)
589-
);
590565

591566
if (thisDestructuring) {
592567
properties = node.id.properties[i].value.properties;
593-
} else if (genericDestructuring) {
594-
properties = node.id.properties;
595568
} else {
596569
continue;
597570
}
@@ -828,13 +801,8 @@ module.exports = {
828801
var destructuring = node.init && node.id && node.id.type === 'ObjectPattern';
829802
// let {props: {firstname}} = this
830803
var thisDestructuring = destructuring && node.init.type === 'ThisExpression';
831-
// let {firstname} = props
832-
var statelessDestructuring = destructuring && isPropAttributeName(node) && (
833-
utils.getParentStatelessComponent() ||
834-
isInLifeCycleMethod(node)
835-
);
836804

837-
if (!thisDestructuring && !statelessDestructuring) {
805+
if (!thisDestructuring) {
838806
return;
839807
}
840808
markPropTypesAsUsed(node);
@@ -848,7 +816,7 @@ module.exports = {
848816

849817
MemberExpression: function(node) {
850818
var type;
851-
if (isPropTypesUsage(node)) {
819+
if (isPropsMemberExpression(node)) {
852820
type = 'usage';
853821
} else if (isPropTypesDeclaration(node.property)) {
854822
type = 'declaration';
@@ -870,6 +838,12 @@ module.exports = {
870838
}
871839
},
872840

841+
Identifier: function(node) {
842+
if (isPropsIdentifier(node)) {
843+
markPropTypesAsUsed(node);
844+
}
845+
},
846+
873847
MethodDefinition: function(node) {
874848
if (!isPropTypesDeclaration(node.key)) {
875849
return;

lib/util/Components.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -347,12 +347,12 @@ function componentRule(rule, context) {
347347
var isFunction = /Function/.test(node.type); // Functions
348348
var isMethod = node.parent && node.parent.type === 'MethodDefinition'; // Classes methods
349349
var isArgument = node.parent && node.parent.type === 'CallExpression'; // Arguments (callback, etc.)
350-
// Stop moving up if we reach a class or an argument (like a callback)
351-
if (isClass || isArgument) {
350+
// Stop moving up if we reach a class
351+
if (isClass) {
352352
return null;
353353
}
354-
// Return the node if it is a function that is not a class method
355-
if (isFunction && !isMethod) {
354+
// Return the node if it is a function that is not a class method and not a callback argument
355+
if (isFunction && !isMethod && !isArgument) {
356356
return node;
357357
}
358358
scope = scope.upper;

0 commit comments

Comments
 (0)