Skip to content

Commit 44fa05e

Browse files
author
David B
committed
implement child function
Render a function which render React element is now possible
1 parent bfe9a9f commit 44fa05e

File tree

6 files changed

+99
-0
lines changed

6 files changed

+99
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/* @flow */
2+
3+
import spacer from './spacer';
4+
import formatTreeNode from './formatTreeNode';
5+
import type { Options } from './../options';
6+
import type { ReactFunctionTreeNode } from './../tree';
7+
8+
export default (
9+
node: ReactFunctionTreeNode,
10+
inline: boolean,
11+
lvl: number,
12+
options: Options
13+
): string => {
14+
const { tabStop } = options;
15+
const { type, childrens } = node;
16+
17+
if (type !== 'ReactFunction') {
18+
throw new Error(
19+
`The "formatReactFunctionNode" function could only format node of type "ReactFunction". Given: ${
20+
type
21+
}`
22+
);
23+
}
24+
25+
const functionRender = formatTreeNode(childrens, false, lvl + 1, options);
26+
27+
const out = `{() => (
28+
${spacer(lvl + 1, tabStop)}${functionRender}
29+
${spacer(lvl, tabStop)})}`;
30+
31+
return `${out}`;
32+
};

src/formatter/formatTreeNode.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import formatReactElementNode from './formatReactElementNode';
44
import formatReactFragmentNode from './formatReactFragmentNode';
5+
import formatReactFunctionNode from './formatReactFunctionNode';
56
import type { Options } from './../options';
67
import type { TreeNode } from './../tree';
78

@@ -54,5 +55,9 @@ export default (
5455
return formatReactFragmentNode(node, inline, lvl, options);
5556
}
5657

58+
if (node.type === 'ReactFunction') {
59+
return formatReactFunctionNode(node, inline, lvl, options);
60+
}
61+
5762
throw new TypeError(`Unknow format type "${node.type}"`);
5863
};

src/index.spec.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,22 @@ describe('reactElementToJSXString(ReactElement)', () => {
897897
);
898898
});
899899

900+
it('reactElementToJSXString(<div>{() => (<div>Hello World</div>)}</div>)', () => {
901+
expect(
902+
reactElementToJSXString(<div>{() => <div>Hello World</div>}</div>, {
903+
showFunctions: true,
904+
})
905+
).toEqual(
906+
`<div>
907+
{() => (
908+
<div>
909+
Hello World
910+
</div>
911+
)}
912+
</div>`
913+
);
914+
});
915+
900916
it('reactElementToJSXString(<DisplayNamePrecedence />)', () => {
901917
expect(reactElementToJSXString(<DisplayNamePrecedence />)).toEqual(
902918
'<This should take precedence />'

src/parser/parseReactElement.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
createStringTreeNode,
77
createNumberTreeNode,
88
createReactElementTreeNode,
9+
createReactFunctionTreeNode,
910
createReactFragmentTreeNode,
1011
} from './../tree';
1112
import type { TreeNode } from './../tree';
@@ -67,10 +68,20 @@ const parseReactElement = (
6768
}
6869

6970
const defaultProps = filterProps(element.type.defaultProps || {}, noChildren);
71+
7072
const childrens = React.Children.toArray(element.props.children)
7173
.filter(onlyMeaningfulChildren)
7274
.map(child => parseReactElement(child, options));
7375

76+
if (typeof element.props.children === 'function') {
77+
const functionChildrens = parseReactElement(
78+
element.props.children(),
79+
options,
80+
true
81+
);
82+
childrens.push(createReactFunctionTreeNode(functionChildrens));
83+
}
84+
7485
if (supportFragment && element.type === Fragment) {
7586
return createReactFragmentTreeNode(key, childrens);
7687
}

src/parser/parseReactElement.spec.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,29 @@ describe('parseReactElement', () => {
2121
});
2222
});
2323

24+
it('should parse a react element with a function as children', () => {
25+
expect(
26+
parseReactElement(<h1>{() => <div>hello world</div>}</h1>, options)
27+
).toEqual({
28+
childrens: [
29+
{
30+
childrens: {
31+
childrens: [{ type: 'string', value: 'hello world' }],
32+
defaultProps: {},
33+
displayName: 'div',
34+
props: {},
35+
type: 'ReactElement',
36+
},
37+
type: 'ReactFunction',
38+
},
39+
],
40+
defaultProps: {},
41+
displayName: 'h1',
42+
props: {},
43+
type: 'ReactElement',
44+
});
45+
});
46+
2447
it('should filter empty childrens', () => {
2548
expect(
2649
parseReactElement(

src/tree.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export type NumberTreeNode = {|
1616
value: number,
1717
|};
1818

19+
export type ReactFunctionTreeNode = {|
20+
type: 'ReactFunction',
21+
childrens: TreeNode[],
22+
|};
23+
1924
export type ReactElementTreeNode = {|
2025
type: 'ReactElement',
2126
displayName: string,
@@ -46,6 +51,13 @@ export const createNumberTreeNode = (value: number): NumberTreeNode => ({
4651
value,
4752
});
4853

54+
export const createReactFunctionTreeNode = (
55+
childrens: TreeNode[]
56+
): ReactFunctionTreeNode => ({
57+
type: 'ReactFunction',
58+
childrens,
59+
});
60+
4961
export const createReactElementTreeNode = (
5062
displayName: string,
5163
props: PropsType,

0 commit comments

Comments
 (0)