Skip to content

Commit 1a13d7d

Browse files
authored
feat: Support custom parser options in programmatic API (#327)
Add logicalAssignment to the default plugins. BREAKING CHANGE: Removed cli arguments `--legacy-decorators` and `--decorators-before-export`. Instead use a babel configuration file with the correct options for the transforms. BREAKING CHANGE: Removed api options `legacyDecorators` and `decoratorsBeforeExport`. Instead use a babel configuration file or supply `parserOptions` and enable the plugins with the correct options.
1 parent 5c01cd7 commit 1a13d7d

File tree

7 files changed

+102
-66
lines changed

7 files changed

+102
-66
lines changed

.flowconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ src/
99
[libs]
1010

1111
[options]
12+
13+
suppress_comment= \\(.\\|\n\\)*\\$FlowIssue

README.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ Options:
4444
-i, --ignore Folders to ignore. Default: [node_modules,__tests__,__mocks__]
4545
--resolver RESOLVER Resolver name (findAllComponentDefinitions, findExportedComponentDefinition) or
4646
path to a module that exports a resolver. [findExportedComponentDefinition]
47-
--legacy-decorators Switch parsing to support only the legacy decorators syntax
4847
4948
Extract meta information from React components.
5049
If a directory is passed, it is recursively traversed.
@@ -60,6 +59,9 @@ resolvers](#resolver).
6059
Have a look at `example/` for an example of how to use the result to generate a
6160
markdown version of the documentation.
6261

62+
`react-docgen` will look for a babel configuration and use it if available. If no config file is found
63+
it will fallback to a default configuration, enabling all [syntax extension](https://babeljs.io/docs/en/babel-parser#plugins) of the babel-parser.
64+
6365
## API
6466

6567
The tool can be used programmatically to extract component information and customize the extraction process:
@@ -83,7 +85,31 @@ As with the CLI, this will look for the exported component created through `Reac
8385
| source | string | The source text |
8486
| 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. |
8587
| 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`. |
86-
| options | Object | Pass options to react-docgen. Supported option is `legacyDecorators` which is a boolean |
88+
| options | Object | Pass options to react-docgen, see below. |
89+
90+
#### options
91+
92+
##### ∙ filename
93+
94+
Type: `string`
95+
96+
The absolute path to the file associated with the code currently being parsed, if there is one. This is used to search for the correct babel config.
97+
98+
This option is optional, but it is highly recommended to set it when integrating `react-docgen`.
99+
100+
##### ∙ cwd
101+
102+
Type: `string`
103+
Default: `process.cwd()`
104+
105+
The working directory that babel configurations will be searched in.
106+
107+
##### ∙ parserOptions
108+
109+
Type: `BabelParserOptions`
110+
111+
This options will be directly supplied to `@babel/parser`. To see a list of
112+
supported options head over to the [babel website](https://babeljs.io/docs/en/babel-parser#options) and have a look.
87113

88114
#### resolver
89115

bin/react-docgen.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,6 @@ argv
4141
collect,
4242
[]
4343
)
44-
.option(
45-
'--legacy-decorators',
46-
'Enable parsing of legacy decorators proposal. By default only the new decorators syntax will be parsable.'
47-
)
48-
.option(
49-
'--decorators-before-export',
50-
'Switches the decorators proposal to allow decorators before the export statement. By default this is false.'
51-
)
5244
.option(
5345
'-i, --ignore <path>',
5446
'Folders to ignore. Default: ' + JSON.stringify(defaultIgnore),
@@ -115,8 +107,6 @@ if (argv.resolver) {
115107
function parse(source, filename) {
116108
return parser.parse(source, resolver, null, {
117109
filename,
118-
legacyDecorators: argv.legacyDecorators,
119-
decoratorsBeforeExport: argv.decoratorsBeforeExport,
120110
});
121111
}
122112

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"eslint": "^5.7.0",
6161
"eslint-config-prettier": "^3.1.0",
6262
"eslint-plugin-prettier": "^3.0.0",
63-
"flow-bin": "^0.87.0",
63+
"flow-bin": "^0.93.0",
6464
"jest": "^23.6.0",
6565
"jest-diff": "^23.6.0",
6666
"jest-matcher-utils": "^23.6.0",

src/__tests__/parse-test.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ describe('parse', () => {
5252
expect(resolver).toBeCalled();
5353
});
5454

55-
it.only('uses local babelrc', () => {
55+
it('uses local babelrc', () => {
5656
const dir = temp.mkdirSync();
5757

5858
try {
@@ -72,4 +72,17 @@ describe('parse', () => {
7272
fs.rmdirSync(dir);
7373
}
7474
});
75+
76+
it('supports custom parserOptions', () => {
77+
expect(() =>
78+
parse('const chained: Type = 1;', () => {}, null, {
79+
parserOptions: {
80+
plugins: [
81+
// no flow
82+
'jsx',
83+
],
84+
},
85+
}),
86+
).toThrowError(/.*Unexpected token \(1:13\).*/);
87+
});
7588
});

src/babelParser.js

Lines changed: 53 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -12,71 +12,76 @@
1212

1313
const babel = require('@babel/core');
1414

15-
const babelParserOptions = {
16-
sourceType: 'module',
17-
strictMode: false,
18-
tokens: true,
19-
plugins: [
20-
'jsx',
21-
'flow',
22-
'estree',
23-
'doExpressions',
24-
'objectRestSpread',
25-
'classProperties',
26-
'classPrivateProperties',
27-
'classPrivateMethods',
28-
'exportDefaultFrom',
29-
'exportNamespaceFrom',
30-
'asyncGenerators',
31-
'functionBind',
32-
'functionSent',
33-
'dynamicImport',
34-
'numericSeparator',
35-
'optionalChaining',
36-
'importMeta',
37-
'bigInt',
38-
'optionalCatchBinding',
39-
'throwExpressions',
40-
['pipelineOperator', { proposal: 'minimal' }],
41-
'nullishCoalescingOperator',
42-
],
15+
const defaultPlugins = [
16+
'jsx',
17+
'flow',
18+
'asyncGenerators',
19+
'bigInt',
20+
'classProperties',
21+
'classPrivateProperties',
22+
'classPrivateMethods',
23+
['decorators', { decoratorsBeforeExport: false }],
24+
'doExpressions',
25+
'dynamicImport',
26+
'exportDefaultFrom',
27+
'exportNamespaceFrom',
28+
'functionBind',
29+
'functionSent',
30+
'importMeta',
31+
'logicalAssignment',
32+
'nullishCoalescingOperator',
33+
'numericSeparator',
34+
'objectRestSpread',
35+
'optionalCatchBinding',
36+
'optionalChaining',
37+
['pipelineOperator', { proposal: 'minimal' }],
38+
'throwExpressions',
39+
];
40+
41+
type ParserOptions = {
42+
plugins?: Array<string | [string, {}]>,
43+
tokens?: boolean,
4344
};
4445

4546
export type Options = {
4647
cwd?: string,
4748
filename?: string,
48-
legacyDecorators?: boolean,
49-
decoratorsBeforeExport?: boolean,
49+
parserOptions?: ParserOptions,
5050
};
5151

52-
function buildOptions(options: Options) {
53-
const parserOptions = {
54-
strictMode: false,
55-
tokens: true,
52+
function buildOptions({
53+
cwd,
54+
filename,
55+
parserOptions,
56+
}: Options): ParserOptions {
57+
let options = {
5658
plugins: [],
5759
};
5860

59-
if (options.legacyDecorators) {
60-
parserOptions.plugins.push('decorators-legacy');
61+
if (parserOptions) {
62+
options = {
63+
...parserOptions,
64+
plugins: parserOptions.plugins ? [...parserOptions.plugins] : [],
65+
};
6166
}
6267

6368
const partialConfig = babel.loadPartialConfig({
64-
cwd: options.cwd,
65-
filename: options.filename,
69+
cwd,
70+
filename,
6671
});
6772

68-
if (!partialConfig.hasFilesystemConfig()) {
69-
parserOptions.plugins = [...babelParserOptions.plugins];
70-
71-
if (!options.legacyDecorators) {
72-
parserOptions.plugins.push([
73-
'decorators',
74-
{ decoratorsBeforeExport: options.decoratorsBeforeExport || false },
75-
]);
76-
}
73+
if (!partialConfig.hasFilesystemConfig() && options.plugins.length === 0) {
74+
options.plugins = [...defaultPlugins];
7775
}
7876

79-
return parserOptions;
77+
// Recast needs tokens to be in the tree
78+
// $FlowIssue tokens is clearly in the Options
79+
options.tokens = true;
80+
// Ensure we always have estree plugin enabled, if we add it a second time
81+
// here it does not matter
82+
options.plugins.push('estree');
83+
84+
return options;
8085
}
8186

8287
export default function buildParse(options?: Options = {}) {

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,10 +1984,10 @@ flat-cache@^1.2.1:
19841984
graceful-fs "^4.1.2"
19851985
write "^0.2.1"
19861986

1987-
flow-bin@^0.87.0:
1988-
version "0.87.0"
1989-
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.87.0.tgz#fab7f984d8cc767e93fa9eb01cf7d57ed744f19d"
1990-
integrity sha512-mnvBXXZkUp4y6A96bR5BHa3q1ioIIN2L10w5osxJqagAakTXFYZwjl0t9cT3y2aCEf1wnK6n91xgYypQS/Dqbw==
1987+
flow-bin@^0.93.0:
1988+
version "0.93.0"
1989+
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.93.0.tgz#9192a08d88db2a8da0ff55e42420f44539791430"
1990+
integrity sha512-p8yq4ocOlpyJgOEBEj0v0GzCP25c9WP0ilFQ8hXSbrTR7RPKuR+Whr+OitlVyp8ocdX0j1MrIwQ8x28dacy1pg==
19911991

19921992
for-in@^1.0.1, for-in@^1.0.2:
19931993
version "1.0.2"

0 commit comments

Comments
 (0)