Skip to content

Commit f20470b

Browse files
jquensedanez
authored andcommitted
feat: support all the config resolving related babel options (#334)
1 parent 4eb9812 commit f20470b

File tree

2 files changed

+106
-104
lines changed

2 files changed

+106
-104
lines changed

README.md

Lines changed: 81 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ yarn add react-docgen --dev
2323
npm install --save-dev react-docgen
2424
```
2525

26-
2726
## CLI
2827

2928
Installing the module adds a `react-docgen` executable which allows you to convert
@@ -85,7 +84,7 @@ As with the CLI, this will look for the exported component created through `Reac
8584
| source | string | The source text |
8685
| resolver | function | A function of the form `(ast: ASTNode, recast: Object) => (NodePath|Array<NodePath>)`. Given an AST and a reference to recast, it returns an (array of) NodePath which represents the component definition. |
8786
| handlers | Array\<function\> | An array of functions of the form `(documentation: Documentation, definition: NodePath) => void`. Each function is called with a `Documentation` object and a reference to the component definition as returned by `resolver`. Handlers extract relevant information from the definition and augment `documentation`. |
88-
| options | Object | Pass options to react-docgen, see below. |
87+
| opt
8988

9089
#### options
9190

@@ -104,6 +103,14 @@ Default: `process.cwd()`
104103

105104
The working directory that babel configurations will be searched in.
106105

106+
##### ∙ babelrc, babelrcRoots, root, rootMode, configFile, envName
107+
108+
Type: `boolean`
109+
Default: `true`
110+
111+
These options, will be passed directly to `babel` for locating and resolving a local config or babelrc. To see
112+
documentation for each option consult the [babel website](https://babeljs.io/docs/en/options#config-loading-options).
113+
107114
##### ∙ parserOptions
108115

109116
Type: `BabelParserOptions`
@@ -129,7 +136,7 @@ module.exports = Component;
129136

130137
and returns the ObjectExpression to which `<def>` resolves to, or the class declaration itself.
131138

132-
`findAllComponentDefinitions` works similarly, but finds *all* `React.createClass` calls and class definitions, not only the one that is exported.
139+
`findAllComponentDefinitions` works similarly, but finds _all_ `React.createClass` calls and class definitions, not only the one that is exported.
133140

134141
This makes it easy, together with the utility methods created to analyze the AST, to introduce new or custom resolver methods. For example, a resolver could look for plain ObjectExpressions with a `render` method.
135142

@@ -145,7 +152,7 @@ For example, while the `propTypesHandler` expects the prop types definition to b
145152

146153
- Modules have to export a single component, and only that component is analyzed.
147154
- When using `React.createClass`, the component definition (the value passed to it) must resolve to an object literal.
148-
- When using classes, the class must either `extend React.Component` *or* define a `render()` method.
155+
- When using classes, the class must either `extend React.Component` _or_ define a `render()` method.
149156
- `propTypes` must be an object literal or resolve to an object literal in the same file.
150157
- The `return` statement in `getDefaultProps` must contain an object literal.
151158

@@ -179,14 +186,11 @@ MyComponent.propTypes = {
179186
bar: function(props, propName, componentName) {
180187
// ...
181188
},
182-
baz: PropTypes.oneOfType([
183-
PropTypes.number,
184-
PropTypes.string
185-
]),
189+
baz: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
186190
};
187191

188192
MyComponent.defaultProps = {
189-
bar: 21
193+
bar: 21,
190194
};
191195

192196
export default MyComponent;
@@ -263,7 +267,6 @@ type Props = {
263267
* General component description.
264268
*/
265269
export default class MyComponent extends Component<void, Props, void> {
266-
267270
props: Props;
268271

269272
render(): ?ReactElement {
@@ -276,83 +279,77 @@ we are getting this output:
276279
277280
```json
278281
{
279-
"description":"General component description.",
280-
"props":{
281-
"primitive":{
282-
"flowType":{ "name":"number" },
283-
"required":true,
284-
"description":"Description of prop \"foo\"."
282+
"description": "General component description.",
283+
"props": {
284+
"primitive": {
285+
"flowType": { "name": "number" },
286+
"required": true,
287+
"description": "Description of prop \"foo\"."
285288
},
286-
"literalsAndUnion":{
287-
"flowType":{
288-
"name":"union",
289-
"raw":"'string' | 'otherstring' | number",
290-
"elements":[
291-
{ "name":"literal", "value":"'string'" },
292-
{ "name":"literal", "value":"'otherstring'" },
293-
{ "name":"number" }
289+
"literalsAndUnion": {
290+
"flowType": {
291+
"name": "union",
292+
"raw": "'string' | 'otherstring' | number",
293+
"elements": [
294+
{ "name": "literal", "value": "'string'" },
295+
{ "name": "literal", "value": "'otherstring'" },
296+
{ "name": "number" }
294297
]
295298
},
296-
"required":true,
297-
"description":"Description of prop \"bar\"."
299+
"required": true,
300+
"description": "Description of prop \"bar\"."
298301
},
299-
"arr":{
300-
"flowType":{
301-
"name":"Array",
302-
"elements":[
303-
{ "name":"any" }
304-
],
305-
"raw":"Array<any>"
302+
"arr": {
303+
"flowType": {
304+
"name": "Array",
305+
"elements": [{ "name": "any" }],
306+
"raw": "Array<any>"
306307
},
307-
"required":true
308+
"required": true
308309
},
309-
"func":{
310-
"flowType":{
311-
"name":"signature",
312-
"type":"function",
313-
"raw":"(value: string) => void",
314-
"signature":{
315-
"arguments":[
316-
{ "name":"value", "type":{ "name":"string" } }
317-
],
318-
"return":{ "name":"void" }
310+
"func": {
311+
"flowType": {
312+
"name": "signature",
313+
"type": "function",
314+
"raw": "(value: string) => void",
315+
"signature": {
316+
"arguments": [{ "name": "value", "type": { "name": "string" } }],
317+
"return": { "name": "void" }
319318
}
320319
},
321-
"required":false
320+
"required": false
322321
},
323-
"noParameterName":{
324-
"flowType":{
325-
"name":"signature",
326-
"type":"function",
327-
"raw":"string => void",
328-
"signature":{
329-
"arguments":[
330-
{ "name":"", "type":{ "name":"string" } }
331-
],
332-
"return":{ "name":"void" }
322+
"noParameterName": {
323+
"flowType": {
324+
"name": "signature",
325+
"type": "function",
326+
"raw": "string => void",
327+
"signature": {
328+
"arguments": [{ "name": "", "type": { "name": "string" } }],
329+
"return": { "name": "void" }
333330
}
334331
},
335-
"required":false
332+
"required": false
336333
},
337-
"obj":{
338-
"flowType":{
339-
"name":"signature",
340-
"type":"object",
341-
"raw":"{ subvalue: ?boolean }",
342-
"signature":{
343-
"properties":[
334+
"obj": {
335+
"flowType": {
336+
"name": "signature",
337+
"type": "object",
338+
"raw": "{ subvalue: ?boolean }",
339+
"signature": {
340+
"properties": [
344341
{
345-
"key":"subvalue",
346-
"value":{
347-
"name":"boolean",
348-
"nullable":true,
349-
"required":true
342+
"key": "subvalue",
343+
"value": {
344+
"name": "boolean",
345+
"nullable": true,
346+
"required": true
350347
}
351348
}
352349
]
353350
}
354351
},
355-
"required":false
352+
"required": false
356353
}
357354
}
358355
}
@@ -362,18 +359,18 @@ we are getting this output:
362359
363360
Here is a list of all the available types and its result structure.
364361
365-
Name | Examples | Result
366-
------------- | ------------- | -------------
367-
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>" }```
368-
Literals | ```let x: 'foo';```<br />```let x: 1;```<br />```let x: true;``` | ```{ "name": "literal", "value": "<rawvalue>" }```
369-
Typed Classes | ```let x: Array<foo>;```<br />```let x: Class<foo>;```<br />```let x: MyClass<bar>;``` | ```{ "name": "<type>", "elements": [{ <element-type> }, ...] }```
370-
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> } }, ...] } }```
371-
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> } } }```
372-
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> } } }```
373-
Tuple | ```let x: [foo, "value", number];``` | ```{ "name": "tuple", "raw": "<raw-signature>", "elements": [{ <element-type> }, ...] }```
374-
Union | ```let x: number | string;``` | ```{ "name": "union", "raw": "<raw-signature>", "elements": [{ <element-type> }, ...] }```
375-
Intersect | ```let x: number & string;``` | ```{ "name": "intersect", "raw": "<raw-signature>", "elements": [{ <element-type> }, ...] }```
376-
Nullable modifier | ```let x: ?number;``` | ```{ "name": "number", "nullable": true }```
362+
| Name | Examples | Result |
363+
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
364+
| 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>" }` |
365+
| Literals | `let x: 'foo';`<br />`let x: 1;`<br />`let x: true;` | `{ "name": "literal", "value": "<rawvalue>" }` |
366+
| Typed Classes | `let x: Array<foo>;`<br />`let x: Class<foo>;`<br />`let x: MyClass<bar>;` | `{ "name": "<type>", "elements": [{ <element-type> }, ...] }` |
367+
| 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> } }, ...] } }` |
368+
| 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> } } }` |
369+
| 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> } } }` |
370+
| Tuple | `let x: [foo, "value", number];` | `{ "name": "tuple", "raw": "<raw-signature>", "elements": [{ <element-type> }, ...] }` |
371+
| Union | `let x: number | string;` | `{ "name": "union", "raw": "<raw-signature>", "elements": [{ <element-type> }, ...] }` |
372+
| Intersect | `let x: number & string;` | `{ "name": "intersect", "raw": "<raw-signature>", "elements": [{ <element-type> }, ...] }` |
373+
| Nullable modifier | `let x: ?number;` | `{ "name": "number", "nullable": true }` |
377374

378375
## Result data structure
379376

@@ -402,14 +399,14 @@ The structure of the JSON blob / JavaScript object is as follows:
402399
["composes": <componentNames>]
403400
}
404401
```
402+
405403
(`[...]` means the property may not exist if such information was not found in the component definition)
406404

407-
- `<propName>`: For each prop that was found, there will be an entry in `props` under the same name.
408-
- `<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"`.
405+
- `<propName>`: For each prop that was found, there will be an entry in `props` under the same name.
406+
- `<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"`.
409407
- `<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.
410408
- `<flowType>`: If using flow type this property contains the parsed flow type as can be seen in the table above.
411409

412-
413410
[react]: http://facebook.github.io/react/
414411
[flow]: http://flowtype.org/
415412
[recast]: https://github.com/benjamn/recast

src/babelParser.js

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,56 +43,61 @@ type ParserOptions = {
4343
tokens?: boolean,
4444
};
4545

46-
export type Options = {
46+
type BabelOptions = {
4747
cwd?: string,
4848
filename?: string,
49+
envName?: string,
50+
babelrc?: boolean,
51+
root?: string,
52+
rootMode?: string,
53+
configFile?: string | false,
54+
babelrcRoots?: true | string | string[],
55+
};
56+
57+
export type Options = BabelOptions & {
4958
parserOptions?: ParserOptions,
5059
};
5160

52-
function buildOptions({
53-
cwd,
54-
filename,
55-
parserOptions,
56-
}: Options): ParserOptions {
57-
let options = {
61+
function buildOptions(
62+
parserOptions: ?ParserOptions,
63+
babelOptions: BabelOptions,
64+
): ParserOptions {
65+
let parserOpts = {
5866
plugins: [],
5967
};
6068

6169
if (parserOptions) {
62-
options = {
70+
parserOpts = {
6371
...parserOptions,
6472
plugins: parserOptions.plugins ? [...parserOptions.plugins] : [],
6573
};
6674
}
6775

68-
const partialConfig = babel.loadPartialConfig({
69-
cwd,
70-
filename,
71-
});
76+
const partialConfig = babel.loadPartialConfig(babelOptions);
7277

73-
if (!partialConfig.hasFilesystemConfig() && options.plugins.length === 0) {
74-
options.plugins = [...defaultPlugins];
78+
if (!partialConfig.hasFilesystemConfig() && parserOpts.plugins.length === 0) {
79+
parserOpts.plugins = [...defaultPlugins];
7580
}
7681

7782
// Recast needs tokens to be in the tree
7883
// $FlowIssue tokens is clearly in the Options
79-
options.tokens = true;
84+
parserOpts.tokens = true;
8085
// Ensure we always have estree plugin enabled, if we add it a second time
8186
// here it does not matter
82-
options.plugins.push('estree');
87+
parserOpts.plugins.push('estree');
8388

84-
return options;
89+
return parserOpts;
8590
}
8691

8792
export default function buildParse(options?: Options = {}) {
88-
const parserOpts = buildOptions(options);
93+
const { parserOptions, ...babelOptions } = options;
94+
const parserOpts = buildOptions(parserOptions, babelOptions);
8995

9096
return {
9197
parse(src: string) {
9298
return babel.parseSync(src, {
9399
parserOpts,
94-
cwd: options.cwd,
95-
filename: options.filename,
100+
...babelOptions,
96101
});
97102
},
98103
};

0 commit comments

Comments
 (0)