@@ -36,6 +36,9 @@ module.exports = {
3636 } ,
3737
3838 create : Components . detect ( ( context , components , utils ) => {
39+ let propTypesPackageName = null ;
40+ let reactPackageName = null ;
41+
3942 function checkValidPropTypeQualfier ( node ) {
4043 if ( node . name !== 'isRequired' ) {
4144 context . report ( {
@@ -54,38 +57,66 @@ module.exports = {
5457 }
5558 }
5659
60+ function isPropTypesPackage ( node ) {
61+ return (
62+ node . type === 'Identifier' &&
63+ node . name === propTypesPackageName
64+ ) || (
65+ node . type === 'MemberExpression' &&
66+ node . property . name === 'PropTypes' &&
67+ node . object . name === reactPackageName
68+ ) ;
69+ }
70+
5771 /* eslint-disable no-use-before-define */
72+
73+ function checkValidCallExpression ( node ) {
74+ const callee = node . callee ;
75+ if ( callee . type === 'MemberExpression' && callee . property . name === 'shape' ) {
76+ checkValidPropObject ( node . arguments [ 0 ] ) ;
77+ } else if ( callee . type === 'MemberExpression' && callee . property . name === 'oneOfType' ) {
78+ const args = node . arguments [ 0 ] ;
79+ if ( args && args . type === 'ArrayExpression' ) {
80+ args . elements . forEach ( el => {
81+ checkValidProp ( el ) ;
82+ } ) ;
83+ }
84+ }
85+ }
86+
5887 function checkValidProp ( node ) {
59- if ( node && node . type === 'MemberExpression' && node . object . type === 'MemberExpression' ) {
60- checkValidPropType ( node . object . property ) ;
61- checkValidPropTypeQualfier ( node . property ) ;
62- } else if ( node && node . type === 'MemberExpression' && node . object . type === 'Identifier' && node . property . name !== 'isRequired' ) {
63- checkValidPropType ( node . property ) ;
64- } else if ( node && (
65- node . type === 'MemberExpression' && node . object . type === 'CallExpression' || node . type === 'CallExpression'
66- ) ) {
67- if ( node . type === 'MemberExpression' ) {
88+ if ( ( ! propTypesPackageName && ! reactPackageName ) || ! node ) {
89+ return ;
90+ }
91+
92+ if ( node . type === 'MemberExpression' ) {
93+ if (
94+ node . object . type === 'MemberExpression' &&
95+ isPropTypesPackage ( node . object . object )
96+ ) { // PropTypes.myProp.isRequired
97+ checkValidPropType ( node . object . property ) ;
6898 checkValidPropTypeQualfier ( node . property ) ;
69- node = node . object ;
70- }
71- const callee = node . callee ;
72- if ( callee . type === 'MemberExpression' && callee . property . name === 'shape' ) {
73- checkValidPropObject ( node . arguments [ 0 ] ) ;
74- } else if ( callee . type === 'MemberExpression' && callee . property . name === 'oneOfType' ) {
75- const args = node . arguments [ 0 ] ;
76- if ( args && args . type === 'ArrayExpression' ) {
77- args . elements . forEach ( el => checkValidProp ( el ) ) ;
78- }
99+ } else if (
100+ isPropTypesPackage ( node . object ) &&
101+ node . property . name !== 'isRequired'
102+ ) { // PropTypes.myProp
103+ checkValidPropType ( node . property ) ;
104+ } else if ( node . object . type === 'CallExpression' ) {
105+ checkValidPropTypeQualfier ( node . property ) ;
106+ checkValidCallExpression ( node . object ) ;
79107 }
108+ } else if ( node . type === 'CallExpression' ) {
109+ checkValidCallExpression ( node ) ;
80110 }
81111 }
82112
113+ /* eslint-enable no-use-before-define */
114+
83115 function checkValidPropObject ( node ) {
84116 if ( node && node . type === 'ObjectExpression' ) {
85117 node . properties . forEach ( prop => checkValidProp ( prop . value ) ) ;
86118 }
87119 }
88- /* eslint-enable no-use-before-define */
89120
90121 function reportErrorIfClassPropertyCasingTypo ( node , propertyName ) {
91122 if ( propertyName === 'propTypes' || propertyName === 'contextTypes' || propertyName === 'childContextTypes' ) {
@@ -114,6 +145,23 @@ module.exports = {
114145 }
115146
116147 return {
148+ ImportDeclaration : function ( node ) {
149+ if ( node . source && node . source . value === 'prop-types' ) { // import PropType from "prop-types"
150+ propTypesPackageName = node . specifiers [ 0 ] . local . name ;
151+ } else if ( node . source && node . source . value === 'react' ) { // import { PropTypes } from "react"
152+ reactPackageName = node . specifiers [ 0 ] . local . name ;
153+
154+ if ( node . specifiers . length >= 1 ) {
155+ const propTypesSpecifier = node . specifiers . find ( specifier => (
156+ specifier . imported && specifier . imported . name === 'PropTypes'
157+ ) ) ;
158+ if ( propTypesSpecifier ) {
159+ propTypesPackageName = propTypesSpecifier . local . name ;
160+ }
161+ }
162+ }
163+ } ,
164+
117165 ClassProperty : function ( node ) {
118166 if ( ! node . static || ! utils . isES6Component ( node . parent . parent ) ) {
119167 return ;
0 commit comments