Skip to content

[Flow] Error parsing intersection on imported proptypes #117

@hramos

Description

@hramos

react-docgen encounters an error when parsing a file that intersects propTypes with those declared in a different file.

Version 2.9.0 and 2.9.1 both run into the following error when parsing this file:

Output:

$ react-docgen ../Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js
Error with path "../Libraries/CustomComponents/NavigationExperimental/NavigationHeader.js": TypeError: Cannot read property 'length' of undefined
TypeError: Cannot read property 'length' of undefined
    at NodePath.each (/usr/local/lib/node_modules/react-docgen/node_modules/recast/node_modules/ast-types/lib/path.js:84:29)
    at flowTypeDocBlockHandler (/usr/local/lib/node_modules/react-docgen/dist/handlers/flowTypeDocBlockHandler.js:30:35)
    at /usr/local/lib/node_modules/react-docgen/dist/parse.js:39:14
    at Array.forEach (native)
    at /usr/local/lib/node_modules/react-docgen/dist/parse.js:38:14
    at Array.map (native)
    at executeHandlers (/usr/local/lib/node_modules/react-docgen/dist/parse.js:36:31)
    at parse (/usr/local/lib/node_modules/react-docgen/dist/parse.js:75:12)
    at Object.defaultParse [as parse] (/usr/local/lib/node_modules/react-docgen/dist/main.js:66:30)
    at parse (/usr/local/lib/node_modules/react-docgen/bin/react-docgen.js:83:17)

Specifically, the issue is encountered while parsing this code block:

import type  {
  NavigationSceneRendererProps,
  NavigationStyleInterpolator,
} from 'NavigationTypeDefinition';

type SubViewProps = NavigationSceneRendererProps & {
  onNavigateBack: ?Function,
};

Note that the NavigationSceneRendererProps propTypes are declared in a different file, in which case react-docgen would not be able to grab the propTypes definition. This, coupled with the use of intersection, seems to be causing the parser to fail.

Expected Results

The expected result is that the tool would generate docs for all other method definitions, instead of failing to parse the file.

This seems to be a special case of the issue raised in #75.

Additional Notes

Note that react-docgen has no trouble parsing other files that use propTypes that are declared in a different file. For example, [this file](https://github.com/facebook/react-native/blob/38979f9c68bd054aca3c6102635b2005914506b1/Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js] imports NavigationSceneRendererProps as well, but it can be parsed successfully:

$ react-docgen ../Libraries/CustomComponents/NavigationExperimental/NavigationCardStack.js --pretty
{
  "description": "A controlled navigation view that renders a stack of cards.\n\n```html\n    +------------+\n  +-|   Header   |\n+-+ |------------|\n| | |            |\n| | |  Focused   |\n| | |   Card     |\n| | |            |\n+-+ |            |\n  +-+            |\n    +------------+\n```\n\n## Example\n\n```js\n\nclass App extends React.Component {\n  constructor(props, context) {\n    this.state = {\n      navigation: {\n        index: 0,\n        routes: [\n          {key: 'page 1'},\n        },\n      },\n    };\n  }\n\n  render() {\n    return (\n      <NavigationCardStack\n        navigationState={this.state.navigation}\n        renderScene={this._renderScene}\n      />\n    );\n  }\n\n  _renderScene: (props) => {\n    return (\n      <View>\n        <Text>{props.scene.route.key}</Text>\n      </View>\n    );\n  };\n```",
  "methods": [
    {
      "name": "_render",
      "docblock": null,
      "modifiers": [],
      "params": [
        {
          "name": "props",
          "type": {
            "name": "NavigationTransitionProps",
            "alias": "NavigationTransitionProps"
          }
        }
      ],
      "returns": {
        "type": {
          "name": "ReactElement",
          "elements": [
            {
              "name": "any"
            }
          ],
          "raw": "ReactElement<any>"
        }
      }
    },
    {
      "name": "_renderScene",
      "docblock": null,
      "modifiers": [],
      "params": [
        {
          "name": "props",
          "type": {
            "name": "NavigationSceneRendererProps",
            "alias": "NavigationSceneRendererProps"
          }
        }
      ],
      "returns": {
        "type": {
          "name": "ReactElement",
          "elements": [
            {
              "name": "any"
            }
          ],
          "raw": "ReactElement<any>"
        }
      }
    }
  ],
  "props": {
    "cardStyle": {
      "type": {
        "name": "custom",
        "raw": "View.propTypes.style"
      },
      "required": false,
      "description": "Custom style applied to the card.",
      "flowType": {
        "name": "any"
      }
    },
    "direction": {
      "type": {
        "name": "enum",
        "value": [
          {
            "value": "Directions.HORIZONTAL",
            "computed": true
          },
          {
            "value": "Directions.VERTICAL",
            "computed": true
          }
        ]
      },
      "required": true,
      "description": "Direction of the cards movement. Value could be `horizontal` or\n`vertical`. Default value is `horizontal`.",
      "flowType": {
        "name": "NavigationGestureDirection"
      },
      "defaultValue": {
        "value": "Directions.HORIZONTAL",
        "computed": true
      }
    },
    "gestureResponseDistance": {
      "type": {
        "name": "number"
      },
      "required": false,
      "description": "The distance from the edge of the card which gesture response can start\nfor. Defaults value is `30`.",
      "flowType": {
        "name": "number",
        "nullable": true
      }
    },
    "navigationState": {
      "type": {
        "name": "custom",
        "raw": "NavigationPropTypes.navigationState.isRequired"
      },
      "required": true,
      "description": "The controlled navigation state. Typically, the navigation state\nlook like this:\n\n```js\nconst navigationState = {\n  index: 0, // the index of the selected route.\n  routes: [ // A list of routes.\n    {key: 'page 1'}, // The 1st route.\n    {key: 'page 2'}, // The second route.\n  ],\n};\n```",
      "flowType": {
        "name": "NavigationState"
      }
    },
    "onNavigateBack": {
      "type": {
        "name": "func"
      },
      "required": false,
      "description": "Callback that is called when the \"back\" action is performed.\nThis happens when the back button is pressed or the back gesture is\nperformed.",
      "flowType": {
        "name": "Function"
      }
    },
    "renderHeader": {
      "type": {
        "name": "func"
      },
      "required": true,
      "description": "Function that renders the header.",
      "flowType": {
        "name": "NavigationSceneRenderer",
        "nullable": true
      }
    },
    "renderScene": {
      "type": {
        "name": "func"
      },
      "required": true,
      "description": "Function that renders the a scene for a route.",
      "flowType": {
        "name": "NavigationSceneRenderer"
      }
    },
    "style": {
      "type": {
        "name": "custom",
        "raw": "View.propTypes.style"
      },
      "required": true,
      "description": "Custom style applied to the cards stack.",
      "flowType": {
        "name": "any"
      }
    }
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions