diff --git a/src/formatter/formatReactFunctionNode.js b/src/formatter/formatReactFunctionNode.js new file mode 100644 index 000000000..2a4bbbbd4 --- /dev/null +++ b/src/formatter/formatReactFunctionNode.js @@ -0,0 +1,34 @@ +/* @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 = Array.isArray(childrens) + ? childrens + .map(children => formatTreeNode(children, false, lvl + 1, options)) + .join('\n') + : 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 20b66234a..6a43915e9 100644 --- a/src/index.spec.js +++ b/src/index.spec.js @@ -898,6 +898,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..152be1d58 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'; @@ -71,6 +72,14 @@ const parseReactElement = ( .filter(onlyMeaningfulChildren) .map(child => parseReactElement(child, options)); + if (typeof element.props.children === 'function') { + const functionChildrens = parseReactElement( + element.props.children(), + options + ); + 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..329554b15 100644 --- a/src/parser/parseReactElement.spec.js +++ b/src/parser/parseReactElement.spec.js @@ -21,6 +21,31 @@ 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..a4c12e5ee 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, @@ -34,7 +39,8 @@ export type TreeNode = | StringTreeNode | NumberTreeNode | ReactElementTreeNode - | ReactFragmentTreeNode; + | ReactFragmentTreeNode + | ReactFunctionTreeNode; export const createStringTreeNode = (value: string): StringTreeNode => ({ type: 'string', @@ -46,6 +52,13 @@ export const createNumberTreeNode = (value: number): NumberTreeNode => ({ value, }); +export const createReactFunctionTreeNode = ( + childrens: TreeNode[] +): ReactFunctionTreeNode => ({ + type: 'ReactFunction', + childrens, +}); + export const createReactElementTreeNode = ( displayName: string, props: PropsType,