diff --git a/src/formatter/formatReactFunctionNode.js b/src/formatter/formatReactFunctionNode.js new file mode 100644 index 000000000..67acf1b3b --- /dev/null +++ b/src/formatter/formatReactFunctionNode.js @@ -0,0 +1,32 @@ +/* @flow */ + +import spacer from './spacer'; +import formatTreeNode from './formatTreeNode'; +import type { Options } from './../options'; +import type { ReactFunctionTreeNode } from './../tree'; + +export default ( + node: ReactFunctionTreeNode, + inline: boolean, + lvl: number, + options: Options +): string => { + const { tabStop } = options; + const { type, childrens } = node; + + if (type !== 'ReactFunction') { + throw new Error( + `The "formatReactFunctionNode" function could only format node of type "ReactFunction". Given: ${ + type + }` + ); + } + + const functionRender = formatTreeNode(childrens, false, lvl + 1, options); + + const out = `{() => ( +${spacer(lvl + 1, tabStop)}${functionRender} +${spacer(lvl, tabStop)})}`; + + return `${out}`; +}; diff --git a/src/formatter/formatTreeNode.js b/src/formatter/formatTreeNode.js index 0a24d7909..b8ea40758 100644 --- a/src/formatter/formatTreeNode.js +++ b/src/formatter/formatTreeNode.js @@ -2,6 +2,7 @@ import formatReactElementNode from './formatReactElementNode'; import formatReactFragmentNode from './formatReactFragmentNode'; +import formatReactFunctionNode from './formatReactFunctionNode'; import type { Options } from './../options'; import type { TreeNode } from './../tree'; @@ -54,5 +55,9 @@ export default ( return formatReactFragmentNode(node, inline, lvl, options); } + if (node.type === 'ReactFunction') { + return formatReactFunctionNode(node, inline, lvl, options); + } + throw new TypeError(`Unknow format type "${node.type}"`); }; diff --git a/src/index.spec.js b/src/index.spec.js index 23b57bb81..09430d656 100644 --- a/src/index.spec.js +++ b/src/index.spec.js @@ -897,6 +897,22 @@ describe('reactElementToJSXString(ReactElement)', () => { ); }); + it('reactElementToJSXString(
{() => (
Hello World
)}
)', () => { + expect( + reactElementToJSXString(
{() =>
Hello World
}
, { + showFunctions: true, + }) + ).toEqual( + `
+ {() => ( +
+ Hello World +
+ )} +
` + ); + }); + it('reactElementToJSXString()', () => { expect(reactElementToJSXString()).toEqual( '' diff --git a/src/parser/parseReactElement.js b/src/parser/parseReactElement.js index 7b991bd65..2b3b2fbaa 100644 --- a/src/parser/parseReactElement.js +++ b/src/parser/parseReactElement.js @@ -6,6 +6,7 @@ import { createStringTreeNode, createNumberTreeNode, createReactElementTreeNode, + createReactFunctionTreeNode, createReactFragmentTreeNode, } from './../tree'; import type { TreeNode } from './../tree'; @@ -67,10 +68,20 @@ const parseReactElement = ( } const defaultProps = filterProps(element.type.defaultProps || {}, noChildren); + const childrens = React.Children.toArray(element.props.children) .filter(onlyMeaningfulChildren) .map(child => parseReactElement(child, options)); + if (typeof element.props.children === 'function') { + const functionChildrens = parseReactElement( + element.props.children(), + options, + true + ); + childrens.push(createReactFunctionTreeNode(functionChildrens)); + } + if (supportFragment && element.type === Fragment) { return createReactFragmentTreeNode(key, childrens); } diff --git a/src/parser/parseReactElement.spec.js b/src/parser/parseReactElement.spec.js index a30188849..7267a34e8 100644 --- a/src/parser/parseReactElement.spec.js +++ b/src/parser/parseReactElement.spec.js @@ -21,6 +21,29 @@ describe('parseReactElement', () => { }); }); + it('should parse a react element with a function as children', () => { + expect( + parseReactElement(

{() =>
hello world
}

, options) + ).toEqual({ + childrens: [ + { + childrens: { + childrens: [{ type: 'string', value: 'hello world' }], + defaultProps: {}, + displayName: 'div', + props: {}, + type: 'ReactElement', + }, + type: 'ReactFunction', + }, + ], + defaultProps: {}, + displayName: 'h1', + props: {}, + type: 'ReactElement', + }); + }); + it('should filter empty childrens', () => { expect( parseReactElement( diff --git a/src/tree.js b/src/tree.js index efbf254af..8138e6d9f 100644 --- a/src/tree.js +++ b/src/tree.js @@ -16,6 +16,11 @@ export type NumberTreeNode = {| value: number, |}; +export type ReactFunctionTreeNode = {| + type: 'ReactFunction', + childrens: TreeNode[], +|}; + export type ReactElementTreeNode = {| type: 'ReactElement', displayName: string, @@ -46,6 +51,13 @@ export const createNumberTreeNode = (value: number): NumberTreeNode => ({ value, }); +export const createReactFunctionTreeNode = ( + childrens: TreeNode[] +): ReactFunctionTreeNode => ({ + type: 'ReactFunction', + childrens, +}); + export const createReactElementTreeNode = ( displayName: string, props: PropsType,