@@ -144,13 +144,13 @@ module.exports = function(context) {
144
144
/**
145
145
* Checks if the prop is declared
146
146
* @param {Object } component The component to process
147
- * @param {String } name Dot separated name of the prop to check.
147
+ * @param {String[] } names List of names of the prop to check.
148
148
* @returns {Boolean } True if the prop is declared, false if not.
149
149
*/
150
- function isDeclaredInComponent ( component , name ) {
150
+ function isDeclaredInComponent ( component , names ) {
151
151
return _isDeclaredInComponent (
152
152
component . declaredPropTypes || { } ,
153
- name . split ( '.' )
153
+ names
154
154
) ;
155
155
}
156
156
@@ -164,14 +164,14 @@ module.exports = function(context) {
164
164
return tokens . length && tokens [ 0 ] . value === '...' ;
165
165
}
166
166
167
+ /**
168
+ * Retrieve the name of a key node
169
+ * @param {ASTNode } node The AST node with the key.
170
+ * @return {string } the name of the key
171
+ */
167
172
function getKeyValue ( node ) {
168
173
var key = node . key ;
169
- if ( key ) {
170
- if ( key . type === 'Identifier' ) {
171
- return key . name ;
172
- }
173
- return key . value ;
174
- }
174
+ return key . type === 'Identifier' ? key . name : key . value ;
175
175
}
176
176
177
177
/**
@@ -321,22 +321,51 @@ module.exports = function(context) {
321
321
return true ;
322
322
}
323
323
324
+ /**
325
+ * Retrieve the name of a property node
326
+ * @param {ASTNode } node The AST node with the property.
327
+ * @return {string } the name of the property or undefined if not found
328
+ */
329
+ function getPropertyName ( node ) {
330
+ var property = node . property ;
331
+ if ( property ) {
332
+ switch ( property . type ) {
333
+ case 'Identifier' :
334
+ if ( node . computed ) {
335
+ return '__COMPUTED_PROP__' ;
336
+ }
337
+ return property . name ;
338
+ case 'Literal' :
339
+ // Accept computed properties that are literal strings
340
+ if ( typeof property . value === 'string' ) {
341
+ return property . value ;
342
+ }
343
+ // falls through
344
+ default :
345
+ if ( node . computed ) {
346
+ return '__COMPUTED_PROP__' ;
347
+ }
348
+ break ;
349
+ }
350
+ }
351
+ }
352
+
324
353
/**
325
354
* Mark a prop type as used
326
355
* @param {ASTNode } node The AST node being marked.
327
356
*/
328
- function markPropTypesAsUsed ( node , parentName ) {
357
+ function markPropTypesAsUsed ( node , parentNames ) {
358
+ parentNames = parentNames || [ ] ;
329
359
var type ;
330
- var name = node . parent . computed ?
331
- '__COMPUTED_PROP__'
332
- : node . parent . property && node . parent . property . name ;
333
- var fullName = parentName ? parentName + '.' + name : name ;
334
-
335
- if ( node . parent . type === 'MemberExpression' ) {
336
- markPropTypesAsUsed ( node . parent , fullName ) ;
337
- }
338
- if ( name && ! node . parent . computed ) {
339
- type = 'direct' ;
360
+ var name = getPropertyName ( node . parent ) ;
361
+ var allNames ;
362
+ if ( name ) {
363
+ allNames = parentNames . concat ( name ) ;
364
+ if ( node . parent . type === 'MemberExpression' ) {
365
+ markPropTypesAsUsed ( node . parent , allNames ) ;
366
+ }
367
+ // Do not mark computed props as used.
368
+ type = name !== '__COMPUTED_PROP__' ? 'direct' : null ;
340
369
} else if (
341
370
node . parent . parent . declarations &&
342
371
node . parent . parent . declarations [ 0 ] . id . properties &&
@@ -354,7 +383,8 @@ module.exports = function(context) {
354
383
break ;
355
384
}
356
385
usedPropTypes . push ( {
357
- name : fullName ,
386
+ name : name ,
387
+ allNames : allNames ,
358
388
node : node . parent . property
359
389
} ) ;
360
390
break ;
@@ -368,6 +398,7 @@ module.exports = function(context) {
368
398
if ( propName ) {
369
399
usedPropTypes . push ( {
370
400
name : propName ,
401
+ allNames : [ propName ] ,
371
402
node : properties [ i ]
372
403
} ) ;
373
404
}
@@ -441,19 +472,20 @@ module.exports = function(context) {
441
472
* @param {Object } component The component to process
442
473
*/
443
474
function reportUndeclaredPropTypes ( component ) {
444
- var name ;
475
+ var allNames , name ;
445
476
for ( var i = 0 , j = component . usedPropTypes . length ; i < j ; i ++ ) {
446
477
name = component . usedPropTypes [ i ] . name ;
478
+ allNames = component . usedPropTypes [ i ] . allNames ;
447
479
if (
448
- isIgnored ( name . split ( '.' ) . pop ( ) ) ||
449
- isDeclaredInComponent ( component , name )
480
+ isIgnored ( name ) ||
481
+ isDeclaredInComponent ( component , allNames )
450
482
) {
451
483
continue ;
452
484
}
453
485
context . report (
454
486
component . usedPropTypes [ i ] . node ,
455
487
component . name === componentUtil . DEFAULT_COMPONENT_NAME ? MISSING_MESSAGE : MISSING_MESSAGE_NAMED_COMP , {
456
- name : name . replace ( / \. _ _ C O M P U T E D _ P R O P _ _ / g, '[]' ) ,
488
+ name : allNames . join ( '.' ) . replace ( / \. _ _ C O M P U T E D _ P R O P _ _ / g, '[]' ) ,
457
489
component : component . name
458
490
}
459
491
) ;
0 commit comments