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