-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature(format): support react fragment (#265)
* feature(format): support react fragment `react-element-to-jsx-string` could now render React fragments: ``` reactElementToJSXString( <> <h1>foo</h1> <p>bar</p> </> ) // Output: // <> // <h1>foo</h1> // <p>bar</p> // </> ``` See the React documentation for more informations on this feature: https://reactjs.org/docs/fragments.html * style(typo): Fix a typo in the `syntax` word
- Loading branch information
1 parent
1e50344
commit 768cce0
Showing
13 changed files
with
350 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* @flow */ | ||
|
||
import type { Key } from 'react'; | ||
import formatReactElementNode from './formatReactElementNode'; | ||
import type { Options } from './../options'; | ||
import type { | ||
ReactElementTreeNode, | ||
ReactFragmentTreeNode, | ||
TreeNode, | ||
} from './../tree'; | ||
|
||
const REACT_FRAGMENT_TAG_NAME_SHORT_SYNTAX = ''; | ||
const REACT_FRAGMENT_TAG_NAME_EXPLICIT_SYNTAX = 'React.Fragment'; | ||
|
||
const toReactElementTreeNode = ( | ||
displayName: string, | ||
key: ?Key, | ||
childrens: TreeNode[] | ||
): ReactElementTreeNode => { | ||
let props = {}; | ||
if (key) { | ||
props = { key }; | ||
} | ||
|
||
return { | ||
type: 'ReactElement', | ||
displayName, | ||
props, | ||
defaultProps: {}, | ||
childrens, | ||
}; | ||
}; | ||
|
||
const isKeyedFragment = ({ key }: ReactFragmentTreeNode) => Boolean(key); | ||
const hasNoChildren = ({ childrens }: ReactFragmentTreeNode) => | ||
childrens.length === 0; | ||
|
||
export default ( | ||
node: ReactFragmentTreeNode, | ||
inline: boolean, | ||
lvl: number, | ||
options: Options | ||
): string => { | ||
const { type, key, childrens } = node; | ||
|
||
if (type !== 'ReactFragment') { | ||
throw new Error( | ||
`The "formatReactFragmentNode" function could only format node of type "ReactFragment". Given: ${ | ||
type | ||
}` | ||
); | ||
} | ||
|
||
const { useFragmentShortSyntax } = options; | ||
|
||
let displayName; | ||
if (useFragmentShortSyntax) { | ||
if (hasNoChildren(node) || isKeyedFragment(node)) { | ||
displayName = REACT_FRAGMENT_TAG_NAME_EXPLICIT_SYNTAX; | ||
} else { | ||
displayName = REACT_FRAGMENT_TAG_NAME_SHORT_SYNTAX; | ||
} | ||
} else { | ||
displayName = REACT_FRAGMENT_TAG_NAME_EXPLICIT_SYNTAX; | ||
} | ||
|
||
return formatReactElementNode( | ||
toReactElementTreeNode(displayName, key, childrens), | ||
inline, | ||
lvl, | ||
options | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/* @flow */ | ||
|
||
import formatReactFragmentNode from './formatReactFragmentNode'; | ||
|
||
const defaultOptions = { | ||
filterProps: [], | ||
showDefaultProps: true, | ||
showFunctions: false, | ||
tabStop: 2, | ||
useBooleanShorthandSyntax: true, | ||
useFragmentShortSyntax: true, | ||
sortProps: true, | ||
}; | ||
|
||
describe('formatReactFragmentNode', () => { | ||
it('should format a react fragment with a string as children', () => { | ||
const tree = { | ||
type: 'ReactFragment', | ||
childrens: [ | ||
{ | ||
value: 'Hello world', | ||
type: 'string', | ||
}, | ||
], | ||
}; | ||
|
||
expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual( | ||
`<> | ||
Hello world | ||
</>` | ||
); | ||
}); | ||
|
||
it('should format a react fragment with a key', () => { | ||
const tree = { | ||
type: 'ReactFragment', | ||
key: 'foo', | ||
childrens: [ | ||
{ | ||
value: 'Hello world', | ||
type: 'string', | ||
}, | ||
], | ||
}; | ||
|
||
expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual( | ||
`<React.Fragment key="foo"> | ||
Hello world | ||
</React.Fragment>` | ||
); | ||
}); | ||
|
||
it('should format a react fragment with multiple childrens', () => { | ||
const tree = { | ||
type: 'ReactFragment', | ||
childrens: [ | ||
{ | ||
type: 'ReactElement', | ||
displayName: 'div', | ||
props: { a: 'foo' }, | ||
childrens: [], | ||
}, | ||
{ | ||
type: 'ReactElement', | ||
displayName: 'div', | ||
props: { b: 'bar' }, | ||
childrens: [], | ||
}, | ||
], | ||
}; | ||
|
||
expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual( | ||
`<> | ||
<div a="foo" /> | ||
<div b="bar" /> | ||
</>` | ||
); | ||
}); | ||
|
||
it('should format an empty react fragment', () => { | ||
const tree = { | ||
type: 'ReactFragment', | ||
childrens: [], | ||
}; | ||
|
||
expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual( | ||
'<React.Fragment />' | ||
); | ||
}); | ||
|
||
it('should format an empty react fragment with key', () => { | ||
const tree = { | ||
type: 'ReactFragment', | ||
key: 'foo', | ||
childrens: [], | ||
}; | ||
|
||
expect(formatReactFragmentNode(tree, false, 0, defaultOptions)).toEqual( | ||
'<React.Fragment key="foo" />' | ||
); | ||
}); | ||
|
||
it('should format a react fragment using the explicit syntax', () => { | ||
const tree = { | ||
type: 'ReactFragment', | ||
childrens: [ | ||
{ | ||
value: 'Hello world', | ||
type: 'string', | ||
}, | ||
], | ||
}; | ||
|
||
expect( | ||
formatReactFragmentNode(tree, false, 0, { | ||
...defaultOptions, | ||
...{ useFragmentShortSyntax: false }, | ||
}) | ||
).toEqual( | ||
`<React.Fragment> | ||
Hello world | ||
</React.Fragment>` | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.