Skip to content

Commit 516fa5e

Browse files
khankuandanez
authored andcommitted
Support cloneElement calls (#138)
1 parent e036dc2 commit 516fa5e

File tree

3 files changed

+69
-3
lines changed

3 files changed

+69
-3
lines changed

src/utils/__tests__/isStatelessComponent-test.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,34 @@ describe('isStatelessComponent', () => {
7171
});
7272
});
7373

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(`
86+
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+
});
100+
});
101+
74102
describe('Stateless Function Components inside module pattern', () => {
75103
it('', () => {
76104
var def = parse(`
@@ -79,19 +107,22 @@ describe('isStatelessComponent', () => {
79107
Bar() { return <div />; },
80108
Baz: function() { return React.createElement('div'); },
81109
['hello']: function() { return React.createElement('div'); },
82-
render() { return 7; }
110+
render() { return 7; },
111+
world: function({ children }) { return React.cloneElement(children, {}); },
83112
}
84113
`).get('body', 1).get('declarations', 0).get('init');
85114

86115
var bar = def.get('properties', 0);
87116
var baz = def.get('properties', 1);
88117
var hello = def.get('properties', 2);
89118
var render = def.get('properties', 3);
119+
var world = def.get('properties', 4);
90120

91121
expect(isStatelessComponent(bar)).toBe(true);
92122
expect(isStatelessComponent(baz)).toBe(true);
93123
expect(isStatelessComponent(hello)).toBe(true);
94124
expect(isStatelessComponent(render)).toBe(false);
125+
expect(isStatelessComponent(world)).toBe(true);
95126
});
96127
});
97128

@@ -250,4 +281,3 @@ describe('isStatelessComponent', () => {
250281
`);
251282
});
252283
});
253-

src/utils/isReactCloneElementCall.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
* @flow
10+
*
11+
*/
12+
13+
import isReactModuleName from './isReactModuleName';
14+
import match from './match';
15+
import recast from 'recast';
16+
import resolveToModule from './resolveToModule';
17+
18+
var {types: {namedTypes: types}} = recast;
19+
20+
/**
21+
* Returns true if the expression is a function call of the form
22+
* `React.createElement(...)`.
23+
*/
24+
export default function isReactCloneElementCall(path: NodePath): boolean {
25+
if (types.ExpressionStatement.check(path.node)) {
26+
path = path.get('expression');
27+
}
28+
29+
if (!match(path.node, {callee: {property: {name: 'cloneElement'}}})) {
30+
return false;
31+
}
32+
var module = resolveToModule(path.get('callee', 'object'));
33+
return Boolean(module && isReactModuleName(module));
34+
}

src/utils/isStatelessComponent.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import getPropertyValuePath from './getPropertyValuePath';
1313
import isReactComponentClass from './isReactComponentClass';
1414
import isReactCreateClassCall from './isReactCreateClassCall';
1515
import isReactCreateElementCall from './isReactCreateElementCall';
16+
import isReactCloneElementCall from './isReactCloneElementCall';
1617
import recast from 'recast';
1718
import resolveToValue from './resolveToValue';
1819

@@ -30,7 +31,8 @@ const validPossibleStatelessComponentTypes = [
3031
function isJSXElementOrReactCreateElement(path) {
3132
return (
3233
path.node.type === 'JSXElement' ||
33-
(path.node.type === 'CallExpression' && isReactCreateElementCall(path))
34+
(path.node.type === 'CallExpression' && isReactCreateElementCall(path)) ||
35+
(path.node.type === 'CallExpression' && isReactCloneElementCall(path))
3436
);
3537
}
3638

0 commit comments

Comments
 (0)