Add JSX Fragment syntax support (#6552)
* Add JSX Fragments to babel-types * Support JSX fragments in the transform-react-jsx plugin * Add tests JSX fragments * Update helper-builder and transform plugin documentations for jsx fragment * Add generator for jsx fragments * Add test for jsx fragment generator * Split jsx transform example into normal and fragment examples * Remove unnecessary fields from ElementState in babel-helper-builder-react-jsx * inline [skip ci]
This commit is contained in:
@@ -8,8 +8,6 @@ type ElementState = {
|
||||
tagName: string; // raw string tag name
|
||||
args: Array<Object>; // array of call arguments
|
||||
call?: Object; // optional call property that can be set to override the call expression returned
|
||||
pre?: Function; // function called with (state: ElementState) before building attribs
|
||||
post?: Function; // function called with (state: ElementState) after building attribs
|
||||
};
|
||||
|
||||
require("@babel/helper-builder-react-jsx")({
|
||||
@@ -18,11 +16,13 @@ require("@babel/helper-builder-react-jsx")({
|
||||
},
|
||||
|
||||
pre: function (state: ElementState) {
|
||||
// called before building the element
|
||||
// function called with (state: ElementState) before building attribs
|
||||
},
|
||||
|
||||
post: function (state: ElementState) {
|
||||
// called after building the element
|
||||
}
|
||||
// function called with (state: ElementState) after building attribs
|
||||
},
|
||||
|
||||
compat?: boolean // true if React is in compat mode
|
||||
});
|
||||
```
|
||||
|
||||
@@ -3,11 +3,9 @@ import * as t from "@babel/types";
|
||||
|
||||
type ElementState = {
|
||||
tagExpr: Object, // tag node
|
||||
tagName: string, // raw string tag name
|
||||
tagName: ?string, // raw string tag name
|
||||
args: Array<Object>, // array of call arguments
|
||||
call?: Object, // optional call property that can be set to override the call expression returned
|
||||
pre?: Function, // function called with (state: ElementState) before building attribs
|
||||
post?: Function, // function called with (state: ElementState) after building attribs
|
||||
};
|
||||
|
||||
export default function(opts) {
|
||||
@@ -30,6 +28,20 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
|
||||
},
|
||||
};
|
||||
|
||||
visitor.JSXFragment = {
|
||||
exit(path, file) {
|
||||
if (opts.compat) {
|
||||
throw path.buildCodeFrameError(
|
||||
"Fragment tags are only supported in React 16 and up.",
|
||||
);
|
||||
}
|
||||
const callExpr = buildFragmentCall(path, file);
|
||||
if (callExpr) {
|
||||
path.replaceWith(t.inherits(callExpr, path.node));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return visitor;
|
||||
|
||||
function convertJSXIdentifier(node, parent) {
|
||||
@@ -188,4 +200,35 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
|
||||
|
||||
return attribs;
|
||||
}
|
||||
|
||||
function buildFragmentCall(path, file) {
|
||||
if (opts.filter && !opts.filter(path.node, file)) return;
|
||||
|
||||
const openingPath = path.get("openingElement");
|
||||
openingPath.parent.children = t.react.buildChildren(openingPath.parent);
|
||||
|
||||
const args = [];
|
||||
const tagName = null;
|
||||
const tagExpr = file.get("jsxFragIdentifier")();
|
||||
|
||||
const state: ElementState = {
|
||||
tagExpr: tagExpr,
|
||||
tagName: tagName,
|
||||
args: args,
|
||||
};
|
||||
|
||||
if (opts.pre) {
|
||||
opts.pre(state, file);
|
||||
}
|
||||
|
||||
// no attributes are allowed with <> syntax
|
||||
args.push(t.nullLiteral(), ...path.node.children);
|
||||
|
||||
if (opts.post) {
|
||||
opts.post(state, file);
|
||||
}
|
||||
|
||||
file.set("usedFragment", true);
|
||||
return state.call || t.callExpression(state.callee, args);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user