Skip to content

Commit 623c192

Browse files
committed
Extend support for ES6 import and export declarations
react-docgen now understands the following constructs: ``` import foo from 'Foo'; import {foo} from 'Foo'; import {foo as bar} from 'Foo'; ``` ``` export var Component = React.createClass({}); var Component = React.createClass({}); export {Component}; export {Component as Foo}; export default Component; export default React.createClass({}); ``` However, to "detect" a React component, `React.createClass(...)` must still be present in the source. I'd argue that being explicit about this makes source easier to understand and follow.
1 parent 9e8670c commit 623c192

File tree

5 files changed

+360
-171
lines changed

5 files changed

+360
-171
lines changed

src/resolver/__tests__/findExportedReactCreateClassCall-test.js

Lines changed: 249 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -29,138 +29,257 @@ describe('React documentation parser', () => {
2929
recast = require('recast');
3030
});
3131

32-
it('finds React.createClass', () => {
33-
var source = [
34-
'var React = require("React");',
35-
'var Component = React.createClass({});',
36-
'module.exports = Component;'
37-
].join('\n');
38-
39-
expect(parse(source)).toBeDefined();
32+
describe('CommonJS module exports', () => {
33+
it('finds React.createClass', () => {
34+
var source = [
35+
'var React = require("React");',
36+
'var Component = React.createClass({});',
37+
'module.exports = Component;'
38+
].join('\n');
39+
40+
expect(parse(source)).toBeDefined();
41+
});
42+
43+
it('finds React.createClass, independent of the var name', () => {
44+
var source = [
45+
'var R = require("React");',
46+
'var Component = R.createClass({});',
47+
'module.exports = Component;'
48+
].join('\n');
49+
50+
expect(parse(source)).toBeDefined();
51+
});
52+
53+
it('does not process X.createClass of other modules', () => {
54+
var source = [
55+
'var R = require("NoReact");',
56+
'var Component = R.createClass({});',
57+
'module.exports = Component;'
58+
].join('\n');
59+
60+
expect(parse(source)).toBeUndefined();
61+
});
62+
63+
describe('module.exports = <C>; / exports.foo = <C>;', () => {
64+
65+
it('finds assignments to exports', () => {
66+
var source = [
67+
'var R = require("React");',
68+
'var Component = R.createClass({});',
69+
'exports.foo = 42;',
70+
'exports.Component = Component;'
71+
].join('\n');
72+
73+
expect(parse(source)).toBeDefined();
74+
});
75+
76+
it('errors if multiple components are exported', () => {
77+
var source = [
78+
'var R = require("React");',
79+
'var ComponentA = R.createClass({});',
80+
'var ComponentB = R.createClass({});',
81+
'exports.ComponentA = ComponentA;',
82+
'exports.ComponentB = ComponentB;'
83+
].join('\n');
84+
85+
expect(function() {
86+
parse(source)
87+
}).toThrow();
88+
});
89+
90+
it('accepts multiple definitions if only one is exported', () => {
91+
var source = [
92+
'var R = require("React");',
93+
'var ComponentA = R.createClass({});',
94+
'var ComponentB = R.createClass({});',
95+
'exports.ComponentB = ComponentB;'
96+
].join('\n');
97+
98+
expect(parse(source)).toBeDefined();
99+
100+
source = [
101+
'var R = require("React");',
102+
'var ComponentA = R.createClass({});',
103+
'var ComponentB = R.createClass({});',
104+
'module.exports = ComponentB;'
105+
].join('\n');
106+
107+
expect(parse(source)).toBeDefined();
108+
});
109+
110+
});
40111
});
41112

42-
it('finds React.createClass, independent of the var name', () => {
43-
var source = [
44-
'var R = require("React");',
45-
'var Component = R.createClass({});',
46-
'module.exports = Component;'
47-
].join('\n');
113+
describe('ES6 export declarations', () => {
114+
115+
describe('export default <component>;', () => {
116+
117+
it('finds default export', () => {
118+
var source = [
119+
'var React = require("React");',
120+
'var Component = React.createClass({});',
121+
'export default Component'
122+
].join('\n');
123+
124+
expect(parse(source)).toBeDefined();
125+
126+
source = [
127+
'var React = require("React");',
128+
'export default React.createClass({});'
129+
].join('\n');
130+
131+
expect(parse(source)).toBeDefined();
132+
});
133+
134+
it('errors if multiple components are exported', () => {
135+
var source = [
136+
'import React, { createElement } from "React"',
137+
'export var Component = React.createClass({})',
138+
'export default React.createClass({});'
139+
].join('\n');
140+
expect(() => parse(source)).toThrow();
141+
142+
source = [
143+
'import React, { createElement } from "React"',
144+
'var Component = React.createClass({})',
145+
'export {Component};',
146+
'export default React.createClass({});'
147+
].join('\n');
148+
expect(() => parse(source)).toThrow();
149+
});
150+
151+
it('accepts multiple definitions if only one is exported', () => {
152+
var source = [
153+
'import React, { createElement } from "React"',
154+
'var Component = React.createClass({})',
155+
'export default React.createClass({});'
156+
].join('\n');
157+
158+
expect(parse(source)).toBeDefined();
159+
});
160+
161+
});
162+
163+
describe('export var foo = <C>, ...;', () => {
164+
165+
it('finds named exports', () => {
166+
var source = [
167+
'var React = require("React");',
168+
'export var somethingElse = 42, Component = React.createClass({});'
169+
].join('\n');
170+
expect(parse(source)).toBeDefined();
171+
172+
source = [
173+
'var React = require("React");',
174+
'export let Component = React.createClass({}), somethingElse = 42;'
175+
].join('\n');
176+
expect(parse(source)).toBeDefined();
177+
178+
source = [
179+
'var React = require("React");',
180+
'export const something = 21,',
181+
' Component = React.createClass({}),',
182+
' somethingElse = 42;',
183+
].join('\n');
184+
expect(parse(source)).toBeDefined();
185+
186+
source = [
187+
'var React = require("React");',
188+
'export var somethingElse = function() {};',
189+
'export let Component = React.createClass({});',
190+
].join('\n');
191+
expect(parse(source)).toBeDefined();
192+
});
193+
194+
it('errors if multiple components are exported', () => {
195+
var source = [
196+
'var R = require("React");',
197+
'export var ComponentA = R.createClass({}),',
198+
' ComponentB = R.createClass({});',
199+
].join('\n');
200+
201+
expect(function() {
202+
parse(source)
203+
}).toThrow();
204+
205+
source = [
206+
'var R = require("React");',
207+
'export var ComponentA = R.createClass({}),',
208+
'var ComponentB = R.createClass({});',
209+
'export {ComponentB};',
210+
].join('\n');
211+
212+
expect(function() {
213+
parse(source)
214+
}).toThrow();
215+
});
216+
217+
it('accepts multiple definitions if only one is exported', () => {
218+
var source = [
219+
'var R = require("React");',
220+
'var ComponentA = R.createClass({});',
221+
'export let ComponentB = R.createClass({});',
222+
].join('\n');
223+
224+
expect(parse(source)).toBeDefined();
225+
});
226+
227+
});
228+
229+
describe('export {<C>};', () => {
230+
231+
it('finds exported specifiers', () => {
232+
var source = [
233+
'var React = require("React");',
234+
'var foo = 42;',
235+
'var Component = React.createClass({});',
236+
'export {foo, Component}'
237+
].join('\n');
238+
expect(parse(source)).toBeDefined();
239+
240+
source = [
241+
'import React from "React"',
242+
'var React = require("React");',
243+
'var Component = React.createClass({});',
244+
'export {Component, foo}'
245+
].join('\n');
246+
expect(parse(source)).toBeDefined();
247+
248+
source = [
249+
'import React, { createElement } from "React"',
250+
'var foo = 42;',
251+
'var baz = 21;',
252+
'var Component = React.createClass({});',
253+
'export {foo, Component as bar, baz}'
254+
].join('\n');
255+
expect(parse(source)).toBeDefined();
256+
});
257+
258+
it('errors if multiple components are exported', () => {
259+
var source = [
260+
'var R = require("React");',
261+
'var ComponentA = R.createClass({}),',
262+
'var ComponentB = R.createClass({});',
263+
'export {ComponentA as foo, ComponentB};'
264+
].join('\n');
265+
266+
expect(function() {
267+
parse(source)
268+
}).toThrow();
269+
});
270+
271+
it('accepts multiple definitions if only one is exported', () => {
272+
var source = [
273+
'var R = require("React");',
274+
'var ComponentA = R.createClass({});',
275+
'var ComponentB = R.createClass({});',
276+
'export {ComponentA}',
277+
].join('\n');
278+
279+
expect(parse(source)).toBeDefined();
280+
});
281+
282+
});
48283

49-
expect(parse(source)).toBeDefined();
50284
});
51-
52-
it('does not process X.createClass of other modules', () => {
53-
var source = [
54-
'var R = require("NoReact");',
55-
'var Component = R.createClass({});',
56-
'module.exports = Component;'
57-
].join('\n');
58-
59-
expect(parse(source)).toBeUndefined();
60-
});
61-
62-
it('finds assignments to exports', () => {
63-
var source = [
64-
'var R = require("React");',
65-
'var Component = R.createClass({});',
66-
'exports.foo = 42;',
67-
'exports.Component = Component;'
68-
].join('\n');
69-
70-
expect(parse(source)).toBeDefined();
71-
});
72-
73-
it('errors if multiple components are exported', () => {
74-
var source = [
75-
'var R = require("React");',
76-
'var ComponentA = R.createClass({});',
77-
'var ComponentB = R.createClass({});',
78-
'exports.ComponentA = ComponentA;',
79-
'exports.ComponentB = ComponentB;'
80-
].join('\n');
81-
82-
expect(function() {
83-
parse(source)
84-
}).toThrow();
85-
});
86-
87-
it('accepts multiple definitions if only one is exported', () => {
88-
var source = [
89-
'var R = require("React");',
90-
'var ComponentA = R.createClass({});',
91-
'var ComponentB = R.createClass({});',
92-
'exports.ComponentB = ComponentB;'
93-
].join('\n');
94-
95-
expect(parse(source)).toBeDefined();
96-
97-
source = [
98-
'var R = require("React");',
99-
'var ComponentA = R.createClass({});',
100-
'var ComponentB = R.createClass({});',
101-
'module.exports = ComponentB;'
102-
].join('\n');
103-
104-
expect(parse(source)).toBeDefined();
105-
});
106-
107-
it('finds React.createClass in default exported', () => {
108-
var source = [
109-
'var React = require("React");',
110-
'var Component = React.createClass({});',
111-
'export default Component'
112-
].join('\n');
113-
114-
expect(parse(source)).toBeDefined();
115-
116-
source = [
117-
'var React = require("React");',
118-
'export default React.createClass({});'
119-
].join('\n');
120-
121-
expect(parse(source)).toBeDefined();
122-
});
123-
124-
it('finds React.createClass in variable exported', () => {
125-
var source = [
126-
'var React = require("React");',
127-
'export var Component = React.createClass({});'
128-
].join('\n');
129-
130-
expect(parse(source)).toBeDefined();
131-
});
132-
133-
it('finds React.createClass in default exported and default import', () => {
134-
var source = [
135-
'import React from "React"',
136-
'var Component = React.createClass({});',
137-
'export default React.createClass({});'
138-
].join('\n');
139-
140-
expect(parse(source)).toBeDefined();
141-
142-
source = [
143-
'import React, { createElement } from "React"',
144-
'export default React.createClass({});'
145-
].join('\n');
146-
147-
expect(parse(source)).toBeDefined();
148-
});
149-
150-
it('finds React.createClass in variable exported and default import', () => {
151-
var source = [
152-
'import React from "React"',
153-
'export var Component = React.createClass({});'
154-
].join('\n');
155-
156-
expect(parse(source)).toBeDefined();
157-
158-
source = [
159-
'import React, { createElement } from "React"',
160-
'export var Component = React.createClass({});'
161-
].join('\n');
162-
163-
expect(parse(source)).toBeDefined();
164-
});
165-
166285
});

0 commit comments

Comments
 (0)