@@ -359,7 +359,7 @@ module.exports = {
359359 value . callee . object &&
360360 hasCustomValidator ( value . callee . object . name )
361361 ) {
362- return true ;
362+ return { } ;
363363 }
364364
365365 if (
@@ -387,23 +387,20 @@ module.exports = {
387387 switch ( callName ) {
388388 case 'shape' :
389389 if ( skipShapeProps ) {
390- return true ;
390+ return { } ;
391391 }
392392
393393 if ( argument . type !== 'ObjectExpression' ) {
394394 // Invalid proptype or cannot analyse statically
395- return true ;
395+ return { } ;
396396 }
397397 const shapeTypeDefinition = {
398398 type : 'shape' ,
399399 children : [ ]
400400 } ;
401401 iterateProperties ( argument . properties , ( childKey , childValue ) => {
402402 const fullName = [ parentName , childKey ] . join ( '.' ) ;
403- let types = buildReactDeclarationTypes ( childValue , fullName ) ;
404- if ( types === true ) {
405- types = { } ;
406- }
403+ const types = buildReactDeclarationTypes ( childValue , fullName ) ;
407404 types . fullName = fullName ;
408405 types . name = childKey ;
409406 types . node = childValue ;
@@ -413,10 +410,7 @@ module.exports = {
413410 case 'arrayOf' :
414411 case 'objectOf' :
415412 const fullName = [ parentName , '*' ] . join ( '.' ) ;
416- let child = buildReactDeclarationTypes ( argument , fullName ) ;
417- if ( child === true ) {
418- child = { } ;
419- }
413+ const child = buildReactDeclarationTypes ( argument , fullName ) ;
420414 child . fullName = fullName ;
421415 child . name = '__ANY_KEY__' ;
422416 child . node = argument ;
@@ -430,7 +424,7 @@ module.exports = {
430424 ! argument . elements . length
431425 ) {
432426 // Invalid proptype or cannot analyse statically
433- return true ;
427+ return { } ;
434428 }
435429 const unionTypeDefinition = {
436430 type : 'union' ,
@@ -439,7 +433,7 @@ module.exports = {
439433 for ( let i = 0 , j = argument . elements . length ; i < j ; i ++ ) {
440434 const type = buildReactDeclarationTypes ( argument . elements [ i ] , parentName ) ;
441435 // keep only complex type
442- if ( type !== true ) {
436+ if ( Object . keys ( type ) . length > 0 ) {
443437 if ( type . children === true ) {
444438 // every child is accepted for one type, abort type analysis
445439 unionTypeDefinition . children = true ;
@@ -451,7 +445,7 @@ module.exports = {
451445 }
452446 if ( unionTypeDefinition . length === 0 ) {
453447 // no complex type found, simply accept everything
454- return true ;
448+ return { } ;
455449 }
456450 return unionTypeDefinition ;
457451 case 'instanceOf' :
@@ -462,19 +456,19 @@ module.exports = {
462456 } ;
463457 case 'oneOf' :
464458 default :
465- return true ;
459+ return { } ;
466460 }
467461 }
468462 // Unknown property or accepts everything (any, object, ...)
469- return true ;
463+ return { } ;
470464 }
471465
472466 /**
473467 * Creates the representation of the React props type annotation for the component.
474468 * The representation is used to verify nested used properties.
475469 * @param {ASTNode } annotation Type annotation for the props class property.
476470 * @param {String } parentName Name of the parent prop node.
477- * @return {Object|Boolean } The representation of the declaration, true means
471+ * @return {Object } The representation of the declaration, an empty object means
478472 * the property is declared without the need for further analysis.
479473 */
480474 function buildTypeAnnotationDeclarationTypes ( annotation , parentName ) {
@@ -483,21 +477,18 @@ module.exports = {
483477 if ( typeScope ( annotation . id . name ) ) {
484478 return buildTypeAnnotationDeclarationTypes ( typeScope ( annotation . id . name ) , parentName ) ;
485479 }
486- return true ;
480+ return { } ;
487481 case 'ObjectTypeAnnotation' :
488482 if ( skipShapeProps ) {
489- return true ;
483+ return { } ;
490484 }
491485 const shapeTypeDefinition = {
492486 type : 'shape' ,
493487 children : [ ]
494488 } ;
495489 iterateProperties ( annotation . properties , ( childKey , childValue ) => {
496490 const fullName = [ parentName , childKey ] . join ( '.' ) ;
497- let types = buildTypeAnnotationDeclarationTypes ( childValue , fullName ) ;
498- if ( types === true ) {
499- types = { } ;
500- }
491+ const types = buildTypeAnnotationDeclarationTypes ( childValue , fullName ) ;
501492 types . fullName = fullName ;
502493 types . name = childKey ;
503494 types . node = childValue ;
@@ -512,7 +503,7 @@ module.exports = {
512503 for ( let i = 0 , j = annotation . types . length ; i < j ; i ++ ) {
513504 const type = buildTypeAnnotationDeclarationTypes ( annotation . types [ i ] , parentName ) ;
514505 // keep only complex type
515- if ( type !== true ) {
506+ if ( Object . keys ( type ) . length > 0 ) {
516507 if ( type . children === true ) {
517508 // every child is accepted for one type, abort type analysis
518509 unionTypeDefinition . children = true ;
@@ -523,16 +514,13 @@ module.exports = {
523514 unionTypeDefinition . children . push ( type ) ;
524515 }
525516 if ( unionTypeDefinition . children . length === 0 ) {
526- // no complex type found, simply accept everything
527- return true ;
517+ // no complex type found
518+ return { } ;
528519 }
529520 return unionTypeDefinition ;
530521 case 'ArrayTypeAnnotation' :
531522 const fullName = [ parentName , '*' ] . join ( '.' ) ;
532- let child = buildTypeAnnotationDeclarationTypes ( annotation . elementType , fullName ) ;
533- if ( child === true ) {
534- child = { } ;
535- }
523+ const child = buildTypeAnnotationDeclarationTypes ( annotation . elementType , fullName ) ;
536524 child . fullName = fullName ;
537525 child . name = '__ANY_KEY__' ;
538526 child . node = annotation ;
@@ -542,7 +530,7 @@ module.exports = {
542530 } ;
543531 default :
544532 // Unknown or accepts everything.
545- return true ;
533+ return { } ;
546534 }
547535 }
548536
@@ -724,6 +712,60 @@ module.exports = {
724712 } ) ;
725713 }
726714
715+ /**
716+ * Marks all props found inside ObjectTypeAnnotaiton as declared.
717+ *
718+ * Modifies the declaredProperties object
719+ * @param {ASTNode } propTypes
720+ * @param {Object } declaredPropTypes
721+ * @returns {Boolean } True if propTypes should be ignored (e.g. when a type can't be resolved, when it is imported)
722+ */
723+ function declarePropTypesForObjectTypeAnnotation ( propTypes , declaredPropTypes ) {
724+ let ignorePropsValidation = false ;
725+
726+ iterateProperties ( propTypes . properties , ( key , value ) => {
727+ if ( ! value ) {
728+ ignorePropsValidation = true ;
729+ return ;
730+ }
731+
732+ const types = buildTypeAnnotationDeclarationTypes ( value , key ) ;
733+ types . fullName = key ;
734+ types . name = key ;
735+ types . node = value ;
736+ declaredPropTypes . push ( types ) ;
737+ } ) ;
738+
739+ return ignorePropsValidation ;
740+ }
741+
742+ /**
743+ * Marks all props found inside IntersectionTypeAnnotation as declared.
744+ * Since InterSectionTypeAnnotations can be nested, this handles recursively.
745+ *
746+ * Modifies the declaredPropTypes object
747+ * @param {ASTNode } propTypes
748+ * @param {Object } declaredPropTypes
749+ * @returns {Boolean } True if propTypes should be ignored (e.g. when a type can't be resolved, when it is imported)
750+ */
751+ function declarePropTypesForIntersectionTypeAnnotation ( propTypes , declaredPropTypes ) {
752+ return propTypes . types . some ( annotation => {
753+ if ( annotation . type === 'ObjectTypeAnnotation' ) {
754+ return declarePropTypesForObjectTypeAnnotation ( annotation , declaredPropTypes ) ;
755+ }
756+
757+ const typeNode = typeScope ( annotation . id . name ) ;
758+
759+ if ( ! typeNode ) {
760+ return true ;
761+ } else if ( typeNode . type === 'IntersectionTypeAnnotation' ) {
762+ return declarePropTypesForIntersectionTypeAnnotation ( typeNode , declaredPropTypes ) ;
763+ }
764+
765+ return declarePropTypesForObjectTypeAnnotation ( typeNode , declaredPropTypes ) ;
766+ } ) ;
767+ }
768+
727769 /**
728770 * Mark a prop type as declared
729771 * @param {ASTNode } node The AST node being checked.
@@ -736,31 +778,15 @@ module.exports = {
736778
737779 switch ( propTypes && propTypes . type ) {
738780 case 'ObjectTypeAnnotation' :
739- iterateProperties ( propTypes . properties , ( key , value ) => {
740- if ( ! value ) {
741- ignorePropsValidation = true ;
742- return ;
743- }
744- let types = buildTypeAnnotationDeclarationTypes ( value , key ) ;
745- if ( types === true ) {
746- types = { } ;
747- }
748- types . fullName = key ;
749- types . name = key ;
750- types . node = value ;
751- declaredPropTypes . push ( types ) ;
752- } ) ;
781+ ignorePropsValidation = declarePropTypesForObjectTypeAnnotation ( propTypes , declaredPropTypes ) ;
753782 break ;
754783 case 'ObjectExpression' :
755784 iterateProperties ( propTypes . properties , ( key , value ) => {
756785 if ( ! value ) {
757786 ignorePropsValidation = true ;
758787 return ;
759788 }
760- let types = buildReactDeclarationTypes ( value , key ) ;
761- if ( types === true ) {
762- types = { } ;
763- }
789+ const types = buildReactDeclarationTypes ( value , key ) ;
764790 types . fullName = key ;
765791 types . name = key ;
766792 types . node = value ;
@@ -791,24 +817,7 @@ module.exports = {
791817 }
792818 break ;
793819 case 'IntersectionTypeAnnotation' :
794- propTypes . types . forEach ( annotation => {
795- const propsType = typeScope ( annotation . id . name ) ;
796- iterateProperties ( propsType . properties , ( key , value ) => {
797- if ( ! value ) {
798- ignorePropsValidation = true ;
799- return ;
800- }
801-
802- let types = buildTypeAnnotationDeclarationTypes ( value , key ) ;
803- if ( types === true ) {
804- types = { } ;
805- }
806- types . fullName = key ;
807- types . name = key ;
808- types . node = value ;
809- declaredPropTypes . push ( types ) ;
810- } ) ;
811- } ) ;
820+ ignorePropsValidation = declarePropTypesForIntersectionTypeAnnotation ( propTypes , declaredPropTypes ) ;
812821 break ;
813822 case null :
814823 break ;
0 commit comments