Skip to content

Commit

Permalink
Enable <></> fragment syntax (#160)
Browse files Browse the repository at this point in the history
Co-authored-by: Troy Alford <[email protected]>
  • Loading branch information
TroyAlford and Troy Alford authored Nov 9, 2020
1 parent f3ffa81 commit 0335343
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 7 deletions.
5 changes: 5 additions & 0 deletions source/components/JsxParser.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,11 @@ describe('JsxParser Component', () => {
expect(console.error).toHaveBeenCalledTimes(1)
expect(console.error.mock.calls[0][0]).toMatch(/unrecognized in this browser/)
})
test('handles fragment shorthand syntax (<></>)', () => {
const jsx = '<><>Test</> <>Test</></>'
const wrapper = shallow(<JsxParser jsx={jsx} renderInWrapper={false} />)
expect(wrapper.html()).toBe('Test Test')
})
test('renders falsy expressions correctly', () => {
const jsx = '<b>{false}{undefined}{0}{null}{[]}</b>'
const wrapper = shallow(<JsxParser jsx={jsx} renderInWrapper={false} />)
Expand Down
23 changes: 17 additions & 6 deletions source/components/JsxParser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export default class JsxParser extends React.Component<TProps> {
if (expression.value === null) return true
return this.#parseExpression(expression.value)
case 'JSXElement':
case 'JSXFragment':
return this.#parseElement(expression)
case 'JSXExpressionContainer':
return this.#parseExpression(expression.expression)
Expand Down Expand Up @@ -201,11 +202,18 @@ export default class JsxParser extends React.Component<TProps> {
return `${this.#parseName(element.object)}.${this.#parseName(element.property)}`
}

#parseElement = (element: AcornJSX.JSXElement): JSX.Element | JSX.Element[] | null => {
#parseElement = (
element: AcornJSX.JSXElement | AcornJSX.JSXFragment,
): JSX.Element | JSX.Element[] | null => {
const { allowUnknownElements, components, componentsOnly, onError } = this.props
const { children: childNodes = [], openingElement } = element
const { attributes = [] } = openingElement
const name = this.#parseName(openingElement.name)
const { children: childNodes = [] } = element
const openingTag = element.type === 'JSXElement'
? element.openingElement
: element.openingFragment
const { attributes = [] } = openingTag
const name = element.type === 'JSXElement'
? this.#parseName(openingTag.name)
: ''

const blacklistedAttrs = (this.props.blacklistedAttrs || [])
.map(attr => (attr instanceof RegExp ? attr : new RegExp(attr, 'i')))
Expand All @@ -221,7 +229,7 @@ export default class JsxParser extends React.Component<TProps> {
return null
}

if (!resolvePath(components, name)) {
if (name !== '' && !resolvePath(components, name)) {
if (componentsOnly) {
onError!(new Error(`The component <${name}> is unrecognized, and will not be rendered.`))
return this.props.renderUnrecognized!(name)
Expand All @@ -234,7 +242,10 @@ export default class JsxParser extends React.Component<TProps> {
}

let children
const component = resolvePath(components, name)
const component = element.type === 'JSXElement'
? resolvePath(components, name)
: Fragment

if (component || canHaveChildren(name)) {
children = childNodes.map(this.#parseExpression)
if (!component && !canHaveWhitespace(name)) {
Expand Down
10 changes: 9 additions & 1 deletion source/types/acorn-jsx.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ declare module 'acorn-jsx' {
argument?: Expression;
}

export interface JSXFragment {
children: JSXElement[],
end: number,
openingFragment: OpeningElement,
start: number,
type: 'JSXFragment',
}

export interface OpeningElement extends JSXElement {
attributes: JSXAttribute[];
}
Expand Down Expand Up @@ -137,7 +145,7 @@ declare module 'acorn-jsx' {

export type Expression =
JSXAttribute | JSXAttributeExpression | JSXElement | JSXExpressionContainer |
JSXSpreadAttribute | JSXText |
JSXSpreadAttribute | JSXFragment | JSXText |
ArrayExpression | BinaryExpression | CallExpression | ConditionalExpression |
ExpressionStatement | Identifier | Literal | LogicalExpression | MemberExpression |
ObjectExpression | TemplateElement | TemplateLiteral | UnaryExpression
Expand Down

0 comments on commit 0335343

Please sign in to comment.