Skip to content

Commit 743f4e4

Browse files
committed
Merge branch 'master' into v3-dev
# Conflicts: # src/__tests__/__snapshots__/main-test.js.snap # src/__tests__/fixtures/component_11.js
2 parents dace500 + 6a59f3f commit 743f4e4

File tree

7 files changed

+310
-200
lines changed

7 files changed

+310
-200
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
"scripts": {
2020
"build": "rimraf dist/ && babel src/ --out-dir dist/ --ignore __tests__,__mocks__",
2121
"lint": "eslint src/ bin/",
22-
"prepublish": "yarn run build",
23-
"preversion": "yarn run lint",
22+
"prepublish": "yarn build",
23+
"preversion": "yarn lint",
2424
"test": "jest",
2525
"test:ci": "yarn lint && yarn flow && yarn test --runInBand",
2626
"watch": "yarn build --watch"

src/__tests__/__snapshots__/main-test.js.snap

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Object {
3838
"computed": false,
3939
"value": "\\"primary\\"",
4040
},
41+
"required": false,
4142
},
4243
},
4344
}
@@ -294,3 +295,31 @@ Object {
294295
},
295296
}
296297
`;
298+
299+
exports[`main fixtures processes component "component_12.js" without errors 1`] = `
300+
Object {
301+
"description": "",
302+
"displayName": "Foo",
303+
"methods": Array [],
304+
"props": Object {
305+
"prop1": Object {
306+
"description": "",
307+
"flowType": Object {
308+
"name": "string",
309+
},
310+
"required": true,
311+
},
312+
"prop2": Object {
313+
"defaultValue": Object {
314+
"computed": false,
315+
"value": "'bar'",
316+
},
317+
"description": "",
318+
"flowType": Object {
319+
"name": "string",
320+
},
321+
"required": false,
322+
},
323+
},
324+
}
325+
`;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (c) 2015, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
11+
/**
12+
* Test for documentation of React components with Flow annotations for props.
13+
*/
14+
15+
import React from 'react';
16+
17+
type Props = {
18+
prop1: string,
19+
prop2: string,
20+
};
21+
22+
class Foo extends React.Component<Props> {
23+
render() {
24+
return (
25+
<div>
26+
{this.props.prop1}
27+
I am Foo!
28+
{this.props.prop2}
29+
</div>
30+
);
31+
}
32+
}
33+
34+
Foo.defaultProps = {
35+
prop2: 'bar',
36+
};
37+
38+
export default Foo;

src/parse.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212

1313
import Documentation from './Documentation';
14+
import postProcessDocumentation from './utils/postProcessDocumentation';
1415

1516
import babylon from './babylon';
1617
import recast from 'recast';
@@ -21,7 +22,7 @@ function executeHandlers(handlers, componentDefinitions) {
2122
return componentDefinitions.map(componentDefinition => {
2223
var documentation = new Documentation();
2324
handlers.forEach(handler => handler(documentation, componentDefinition));
24-
return documentation.toObject();
25+
return postProcessDocumentation(documentation.toObject());
2526
});
2627
}
2728

src/utils/__tests__/isStatelessComponent-test.js

Lines changed: 116 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -22,109 +22,122 @@ describe('isStatelessComponent', () => {
2222
({statement, parse} = require('../../../tests/utils'));
2323
});
2424

25-
describe('Stateless Function Components with JSX', () => {
26-
it('accepts simple arrow function components', () => {
27-
var def = parse(
28-
'var Foo = () => <div />'
29-
).get('body', 0).get('declarations', [0]).get('init');
30-
expect(isStatelessComponent(def)).toBe(true);
31-
});
32-
33-
it('accepts simple function expressions components', () => {
34-
var def = parse(
35-
'let Foo = function() { return <div />; };'
36-
).get('body', 0).get('declarations', [0]).get('init');
37-
expect(isStatelessComponent(def)).toBe(true);
38-
});
39-
40-
it('accepts simple function declaration components', () => {
41-
var def = parse('function Foo () { return <div /> }').get('body', 0);
42-
expect(isStatelessComponent(def)).toBe(true);
43-
});
44-
});
45-
46-
describe('Stateless Function Components with React.createElement', () => {
47-
it('accepts simple arrow function components', () => {
48-
var def = parse(`
49-
var AlphaBetters = require('react');
50-
var Foo = () => AlphaBetters.createElement("div", null);
51-
`).get('body', 1).get('declarations', [0]).get('init');
52-
53-
expect(isStatelessComponent(def)).toBe(true);
54-
});
55-
56-
it('accepts simple function expressions components', () => {
57-
var def = parse(`
25+
const componentIdentifiers = {
26+
'JSX': '<div />',
27+
'React.createElement': 'React.createElement("div", null)',
28+
'React.cloneElement': 'React.cloneElement(children, null)',
29+
'React.Children.only()': 'React.Children.only(children, null)',
30+
};
31+
32+
const componentStyle = {
33+
'ArrowExpression': [
34+
(name, expr) => `var ${name} = () => (${expr});`,
35+
['declarations', 0, 'init'],
36+
],
37+
'ArrowBlock': [
38+
(name, expr) => `var ${name} = () => { return (${expr}); };`,
39+
['declarations', 0, 'init'],
40+
],
41+
'FunctionExpression': [
42+
(name, expr) => `var ${name} = function () { return (${expr}); }`,
43+
['declarations', 0, 'init'],
44+
],
45+
'FunctionDeclaration': [
46+
(name, expr) => `function ${name} () { return (${expr}); }`,
47+
[],
48+
],
49+
};
50+
51+
const modifiers = {
52+
'default': (expr) => expr,
53+
'conditional consequent': (expr) => `x ? ${expr} : null`,
54+
'conditional alternate': (expr) => `x ? null : ${expr}`,
55+
'OR left': (expr) => `${expr} || null`,
56+
'AND right': (expr) => `x && ${expr}`,
57+
};
58+
59+
const cases = {
60+
'no reference': [
61+
(expr, componentFactory) => `
5862
var React = require('react');
59-
let Foo = function() { return React.createElement("div", null); };
60-
`).get('body', 1).get('declarations', [0]).get('init');
61-
62-
expect(isStatelessComponent(def)).toBe(true);
63-
});
64-
65-
it('accepts simple function declaration components', () => {
66-
var def = parse(`
63+
${componentFactory('Foo', expr)}
64+
`,
65+
['body', 1],
66+
],
67+
'with Identifier reference': [
68+
(expr, componentFactory) => `
6769
var React = require('react');
68-
function Foo () { return React.createElement("div", null); }
69-
`).get('body', 1);
70-
expect(isStatelessComponent(def)).toBe(true);
71-
});
72-
});
73-
74-
describe('Stateless Function Components with React.cloneElement', () => {
75-
it('accepts simple arrow function components', () => {
76-
var def = parse(`
77-
var AlphaBetters = require('react');
78-
var Foo = ({ children }) => AlphaBetters.cloneElement(children, null);
79-
`).get('body', 1).get('declarations', [0]).get('init');
80-
81-
expect(isStatelessComponent(def)).toBe(true);
82-
});
83-
84-
it('accepts simple function expressions components', () => {
85-
var def = parse(`
70+
var jsx = (${expr});
71+
${componentFactory('Foo', 'jsx')}
72+
`,
73+
['body', 2],
74+
],
75+
};
76+
77+
Object.keys(componentStyle).forEach((name) => {
78+
cases[`with ${name} reference`] = [
79+
(expr, componentFactory) => `
8680
var React = require('react');
87-
let Foo = function({ children }) { return React.cloneElement(children, null); };
88-
`).get('body', 1).get('declarations', [0]).get('init');
89-
90-
expect(isStatelessComponent(def)).toBe(true);
91-
});
92-
93-
it('accepts simple function declaration components', () => {
94-
var def = parse(`
95-
var React = require('react');
96-
function Foo ({ children }) { return React.cloneElement(children, null); }
97-
`).get('body', 1);
98-
expect(isStatelessComponent(def)).toBe(true);
99-
});
81+
${componentStyle[name][0]('jsx', expr)}
82+
${componentFactory('Foo', 'jsx()')}
83+
`,
84+
['body', 2],
85+
]
10086
});
10187

102-
describe('Stateless Function Components with React.Children.only', () => {
103-
it('accepts simple arrow function components', () => {
104-
var def = parse(`
105-
var React = require('react');
106-
var Foo = ({ children }) => React.Children.only(children, null);
107-
`).get('body', 1).get('declarations', [0]).get('init');
108-
109-
expect(isStatelessComponent(def)).toBe(true);
88+
const negativeModifiers = {
89+
'nested ArrowExpression': (expr) => `() => ${expr}`,
90+
'nested ArrowBlock': (expr) => `() => { return ${expr} }`,
91+
'nested FunctionExpression': (expr) => `function () { return ${expr} }`,
92+
};
93+
94+
Object.keys(cases).forEach((name) => {
95+
const [caseFactory, caseSelector] = cases[name];
96+
97+
describe(name, () => {
98+
Object.keys(componentIdentifiers).forEach((componentIdentifierName) => {
99+
100+
const returnExpr = componentIdentifiers[componentIdentifierName];
101+
describe(componentIdentifierName, () => {
102+
Object.keys(componentStyle).forEach((componentName) => {
103+
const [componentFactory, componentSelector] = componentStyle[componentName];
104+
describe(componentName, () => {
105+
106+
Object.keys(modifiers).forEach((modifierName) => {
107+
const modifierFactory = modifiers[modifierName];
108+
109+
it(modifierName, () => {
110+
const code = caseFactory(modifierFactory(returnExpr), componentFactory);
111+
const def = parse(code).get(...caseSelector, ...componentSelector);
112+
expect(isStatelessComponent(def)).toBe(true);
113+
});
114+
});
115+
116+
Object.keys(negativeModifiers).forEach((modifierName) => {
117+
const modifierFactory = negativeModifiers[modifierName];
118+
119+
it(modifierName, () => {
120+
const code = caseFactory(modifierFactory(returnExpr), componentFactory);
121+
const def = parse(code).get(...caseSelector, ...componentSelector);
122+
expect(isStatelessComponent(def)).toBe(false);
123+
});
124+
});
125+
});
126+
});
127+
});
128+
});
110129
});
130+
});
111131

112-
it('accepts simple function expressions components', () => {
132+
describe('Stateless Function Components with React.createElement', () => {
133+
it('accepts different name than React', () => {
113134
var def = parse(`
114-
var React = require('react');
115-
let Foo = function({ children }) { return React.Children.only(children, null); };
135+
var AlphaBetters = require('react');
136+
var Foo = () => AlphaBetters.createElement("div", null);
116137
`).get('body', 1).get('declarations', [0]).get('init');
117138

118139
expect(isStatelessComponent(def)).toBe(true);
119140
});
120-
121-
it('accepts simple function declaration components', () => {
122-
var def = parse(`
123-
var React = require('react');
124-
function Foo ({ children }) { return React.Children.only(children, null); }
125-
`).get('body', 1);
126-
expect(isStatelessComponent(def)).toBe(true);
127-
});
128141
});
129142

130143
describe('Stateless Function Components inside module pattern', () => {
@@ -190,21 +203,6 @@ describe('isStatelessComponent', () => {
190203

191204
expect(isStatelessComponent(def)).toBe(false);
192205
});
193-
194-
it('does not mark containing functions as StatelessComponents', () => {
195-
var def = parse(`
196-
var React = require('react');
197-
function Foo (props) {
198-
function Bar() {
199-
return React.createElement("div", props);
200-
}
201-
202-
return {Bar}
203-
}
204-
`).get('body', 1);
205-
206-
expect(isStatelessComponent(def)).toBe(false);
207-
});
208206
});
209207

210208
describe('resolving return values', () => {
@@ -216,6 +214,18 @@ describe('isStatelessComponent', () => {
216214
});
217215
}
218216

217+
it('does not see ifs as separate block', () => {
218+
var def = statement(`
219+
function Foo (props) {
220+
if (x) {
221+
return <div />;
222+
}
223+
}
224+
`);
225+
226+
expect(isStatelessComponent(def)).toBe(true);
227+
});
228+
219229
test('handles simple resolves', `
220230
var React = require('react');
221231
function Foo (props) {
@@ -282,20 +292,6 @@ describe('isStatelessComponent', () => {
282292
}
283293
`);
284294

285-
test('handles external reference member call expression resolves', `
286-
var React = require('react');
287-
function Foo (props) {
288-
var member = () => <div />;
289-
var obj = {
290-
deep: {
291-
member: member
292-
}
293-
};
294-
295-
return obj.deep.member();
296-
}
297-
`);
298-
299295
test('handles all sorts of JavaScript things', `
300296
var React = require('react');
301297
function Foo (props) {

0 commit comments

Comments
 (0)