Skip to content

Commit c67267d

Browse files
committed
Merge pull request #48 from researchgate/add-flow-type-support
Support for flow types
2 parents 817f2e6 + 8bf5237 commit c67267d

22 files changed

+1293
-56
lines changed

README.md

Lines changed: 141 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
It uses [recast][] and [babylon][] to parse the source into an AST and provides methods to process this AST to extract the desired information. The output / return value is a JSON blob / JavaScript object.
66

7-
It provides a default implementation for React components defined via
8-
`React.createClass`, [ES2015 class definitions][classes] or functions
9-
(stateless components). These component definitions must follow certain
7+
It provides a default implementation for React components defined via
8+
`React.createClass`, [ES2015 class definitions][classes] or functions
9+
(stateless components). These component definitions must follow certain
1010
guidelines in order to be analyzable (see below for more info).
1111

1212
## Install
@@ -41,11 +41,11 @@ Extract meta information from React components.
4141
If a directory is passed, it is recursively traversed.
4242
```
4343

44-
By default, `react-docgen` will look for the exported component created through
45-
`React.createClass`, a class definition or a function (stateless component) in
46-
each file. You can change that behavior with the `--resolver` option, which
47-
either expects the name of a built-in resolver or a path to JavaScript module
48-
exporting a resolver function. Have a look below for [more information about
44+
By default, `react-docgen` will look for the exported component created through
45+
`React.createClass`, a class definition or a function (stateless component) in
46+
each file. You can change that behavior with the `--resolver` option, which
47+
either expects the name of a built-in resolver or a path to JavaScript module
48+
exporting a resolver function. Have a look below for [more information about
4949
resolvers](#resolver).
5050

5151
Have a look at `example/` for an example of how to use the result to generate a
@@ -111,7 +111,9 @@ For example, while the `propTypesHandler` expects the prop types definition to b
111111
- `propTypes` must be an object literal or resolve to an object literal in the same file.
112112
- The `return` statement in `getDefaultProps` must contain an object literal.
113113

114-
## Example
114+
## PropTypes
115+
116+
### Example
115117

116118
For the following component
117119

@@ -156,7 +158,7 @@ module.exports = Component;
156158

157159
we are getting this output:
158160

159-
```
161+
```json
160162
{
161163
"props": {
162164
"foo": {
@@ -201,6 +203,131 @@ we are getting this output:
201203
}
202204
```
203205

206+
## Flow Type support
207+
208+
If you are using [flow][flow] then react-docgen can also extract the flow type annotations. As flow has a way more advanced and fine granular type system, the returned types from react-docgen are different in comparison when using `React.PropTypes`.
209+
210+
> **Note**: react-docgen will not be able to grab the type definition if the type is imported or declared in a different file.
211+
212+
### Example
213+
214+
For the following component
215+
216+
```js
217+
import React, { Component } from 'react';
218+
219+
type Props = {
220+
/** Description of prop "foo". */
221+
primitive: number,
222+
/** Description of prop "bar". */
223+
literalsAndUnion: 'string' | 'otherstring' | number,
224+
arr: Array<any>,
225+
func?: (value: string) => void,
226+
obj?: { subvalue: ?boolean },
227+
};
228+
229+
/**
230+
* General component description.
231+
*/
232+
export default class MyComponent extends Component<void, Props, void> {
233+
234+
props: Props;
235+
236+
render(): ?ReactElement {
237+
// ...
238+
}
239+
}
240+
```
241+
242+
we are getting this output:
243+
244+
```json
245+
{
246+
"description":"General component description.",
247+
"props":{
248+
"primitive":{
249+
"flowType":{ "name":"number" },
250+
"required":true,
251+
"description":"Description of prop \"foo\"."
252+
},
253+
"literalsAndUnion":{
254+
"flowType":{
255+
"name":"union",
256+
"raw":"'string' | 'otherstring' | number",
257+
"elements":[
258+
{ "name":"literal", "value":"'string'" },
259+
{ "name":"literal", "value":"'otherstring'" },
260+
{ "name":"number" }
261+
]
262+
},
263+
"required":true,
264+
"description":"Description of prop \"bar\"."
265+
},
266+
"arr":{
267+
"flowType":{
268+
"name":"Array",
269+
"elements":[
270+
{ "name":"any" }
271+
],
272+
"raw":"Array<any>"
273+
},
274+
"required":true
275+
},
276+
"func":{
277+
"flowType":{
278+
"name":"signature",
279+
"type":"function",
280+
"raw":"(value: string) => void",
281+
"signature":{
282+
"arguments":[
283+
{ "name":"value", "type":{ "name":"string" } }
284+
],
285+
"return":{ "name":"void" }
286+
}
287+
},
288+
"required":false
289+
},
290+
"obj":{
291+
"flowType":{
292+
"name":"signature",
293+
"type":"object",
294+
"raw":"{ subvalue: ?boolean }",
295+
"signature":{
296+
"properties":[
297+
{
298+
"key":"subvalue",
299+
"value":{
300+
"name":"boolean",
301+
"nullable":true,
302+
"required":true
303+
}
304+
}
305+
]
306+
}
307+
},
308+
"required":false
309+
}
310+
}
311+
}
312+
```
313+
314+
### Types
315+
316+
Here is a list of all the available types and its result structure.
317+
318+
Name | Examples | Result
319+
------------- | ------------- | -------------
320+
Simple | ```let x: string;```<br />```let x: number;```<br />```let x: boolean;```<br />```let x: any;```<br />```let x: void;```<br />```let x: Object;```<br />```let x: String;```<br />```let x: MyClass;``` | ```{ "name": "<type>" }```
321+
Literals | ```let x: 'foo';```<br />```let x: 1;```<br />```let x: true;``` | ```{ "name": "literal", "value": "<rawvalue>" }```
322+
Typed Classes | ```let x: Array<foo>;```<br />```let x: Class<foo>;```<br />```let x: MyClass<bar>;``` | ```{ "name": "<type>", "elements": [{ <element-type> }, ...] }```
323+
Object Signature | ```let x: { foo: string, bar?: mixed };```<br />```let x: { [key: string]: string, foo: number };``` | ```{ "name": "signature", "type": "object", "raw": "<raw-signature>", "signature": { "properties": [{ "key": "<property-name>"|{ <property-key-type> }, "value": { <property-type>, "required": <true/false> } }, ...] } }```
324+
Function Signature | ```let x: (x: string) => void;``` | ```{ "name": "signature", "type": "function", "raw": "<raw-signature>", "signature": { "arguments": [{ "name": "<argument-name>", "type": { <argument-type> } }, ...], "return": { <return-type> } } }```
325+
Callable-Object/Function-Object Signature | ```let x: { (x: string): void, prop: string };``` | ```{ "name": "signature", "type": "object", "raw": "<raw-signature>", "signature": { "properties": [{ "key": "<property-name>"|{ <property-key-type> }, "value": { <property-type>, "required": <true/false> } }, ...], "constructor": { <function-signature> } } }```
326+
Tuple | ```let x: [foo, "value", number];``` | ```{ "name": "tuple", "raw": "<raw-signature>", "elements": [{ <element-type> }, ...] }```
327+
Union | ```let x: number | string;``` | ```{ "name": "union", "raw": "<raw-signature>", "elements": [{ <element-type> }, ...] }```
328+
Intersect | ```let x: number & string;``` | ```{ "name": "intersect", "raw": "<raw-signature>", "elements": [{ <element-type> }, ...] }```
329+
Nullable modifier | ```let x: ?number;``` | ```{ "name": "number", "nullable": true }```
330+
204331
## Result data structure
205332

206333
The structure of the JSON blob / JavaScript object is as follows:
@@ -215,10 +342,11 @@ The structure of the JSON blob / JavaScript object is as follows:
215342
["value": <typeValue>]
216343
["raw": string]
217344
},
345+
"flowType": <flowType>,
218346
"required": boolean,
219347
"description": string,
220348
["defaultValue": {
221-
"value": number | string,
349+
"value": string,
222350
"computed": boolean
223351
}]
224352
},
@@ -232,9 +360,11 @@ The structure of the JSON blob / JavaScript object is as follows:
232360
- `<propName>`: For each prop that was found, there will be an entry in `props` under the same name.
233361
- `<typeName>`: The name of the type, which is usually corresponds to the function name in `React.PropTypes`. However, for types define with `oneOf`, we use `"enum"` and for `oneOfType` we use `"union"`. If a custom function is provided or the type cannot be resolved to anything of `React.PropTypes`, we use `"custom"`.
234362
- `<typeValue>`: Some types accept parameters which define the type in more detail (such as `arrayOf`, `instanceOf`, `oneOf`, etc). Those are stored in `<typeValue>`. The data type of `<typeValue>` depends on the type definition.
363+
- `<flowType>`: If using flow type this property contains the parsed flow type as can be seen in the table above.
235364

236365

237366
[react]: http://facebook.github.io/react/
367+
[flow]: http://flowtype.org/
238368
[recast]: https://github.com/benjamn/recast
239369
[babylon]: https://github.com/babel/babel/tree/master/packages/babylon
240370
[classes]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

flow/react-docgen.js

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,43 @@
1111
import type Documentation from '../src/Documentation';
1212

1313
type PropTypeDescriptor = {
14-
name: string;
15-
value?: any;
16-
raw?: string;
17-
computed?: boolean;
14+
name: string,
15+
value?: any,
16+
raw?: string,
17+
computed?: boolean,
1818
// These are only needed for shape types.
1919
// Consider consolidating PropTypeDescriptor and PropDescriptor
20-
description?: string;
21-
required?: boolean;
20+
description?: string,
21+
required?: boolean,
22+
};
23+
24+
type flowObjectSignatureType = {
25+
properties: Array<{ key: string | FlowTypeDescriptor, value: FlowTypeDescriptor }>,
26+
constructor?: FlowTypeDescriptor
27+
};
28+
29+
type flowFunctionSignatureType = {
30+
arguments: Array<{ name: string, type: FlowTypeDescriptor }>,
31+
return: FlowTypeDescriptor
32+
};
33+
34+
type FlowTypeDescriptor = {
35+
name: string,
36+
value?: string,
37+
required?: boolean,
38+
nullable?: boolean,
39+
raw?: string,
40+
elements?: Array<FlowTypeDescriptor>,
41+
type?: 'object' | 'function',
42+
signature?: flowObjectSignatureType | flowFunctionSignatureType,
2243
};
2344

2445
type PropDescriptor = {
25-
type?: PropTypeDescriptor;
26-
required?: boolean;
27-
defaultValue?: any;
28-
description?: string;
46+
type?: PropTypeDescriptor,
47+
flowType?: FlowTypeDescriptor,
48+
required?: boolean,
49+
defaultValue?: any,
50+
description?: string,
2951
};
3052

3153
type Handler = (documentation: Documentation, path: NodePath) => void;

flow/recast.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ type ASTNode = Object;
1818

1919
declare class Scope {
2020
lookup(name: string): ?Scope;
21-
getBindings(): {[key: string]: NodePath};
21+
lookupType(name: string): ?Scope;
22+
getBindings(): {[key: string]: Array<NodePath>};
23+
getTypes(): {[key: string]: Array<NodePath>};
2224
node: NodePath;
2325
}
2426

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"babylon": "~5.8.3",
3030
"node-dir": "^0.1.10",
3131
"nomnom": "^1.8.1",
32-
"recast": "^0.10.33"
32+
"recast": "^0.10.41"
3333
},
3434
"devDependencies": {
3535
"babel": "^5.6.23",

0 commit comments

Comments
 (0)