[babel 8] Remove useSpread and useBuiltIns jsx options (#12593)

* [babel 8] Remove `useSpread` and `useBuiltIns` jsx options

backport of 8cc8696851fa4bf02d7f6ae591404626d1ca32a3

Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
Co-authored-by: Brian Ng <bng412@gmail.com>

* Update fixtures (Windows)

Co-authored-by: Huáng Jùnliàng <jlhwung@gmail.com>
Co-authored-by: Brian Ng <bng412@gmail.com>
Co-authored-by: Babel Bot <babel-bot@users.noreply.github.com>
This commit is contained in:
Nicolò Ribaudo 2021-01-08 18:16:30 +01:00 committed by GitHub
parent 606c91cd33
commit fce3e7124a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 429 additions and 139 deletions

View File

@ -144,7 +144,11 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
let attribs = openingPath.node.attributes;
if (attribs.length) {
attribs = buildOpeningElementAttributes(attribs, file);
if (process.env.BABEL_8_BREAKING) {
attribs = t.objectExpression(attribs.map(convertAttribute));
} else {
attribs = buildOpeningElementAttributes(attribs, file);
}
} else {
attribs = t.nullLiteral();
}

View File

@ -0,0 +1,10 @@
var x = (
<>
<div>
<div key="1" />
<div key="2" meow="wolf" />
<div key="3" />
<div {...props} key="4" />
</div>
</>
);

View File

@ -0,0 +1,5 @@
{
"BABEL_8_BREAKING": false,
"plugins": [["transform-react-jsx-development", { "runtime": "classic" }]],
"os": ["linux", "darwin"]
}

View File

@ -0,0 +1,45 @@
var _jsxFileName = "<CWD>/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/classic-runtime-babel-7/input.js";
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 3,
columnNumber: 5
}
}, /*#__PURE__*/React.createElement("div", {
key: "1",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 4,
columnNumber: 9
}
}), /*#__PURE__*/React.createElement("div", {
key: "2",
meow: "wolf",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 5,
columnNumber: 9
}
}), /*#__PURE__*/React.createElement("div", {
key: "3",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 6,
columnNumber: 9
}
}), /*#__PURE__*/React.createElement("div", _extends({}, props, {
key: "4",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 7,
columnNumber: 9
}
}))));

View File

@ -1,4 +1,5 @@
{
"BABEL_8_BREAKING": true,
"plugins": [["transform-react-jsx-development", { "runtime": "classic" }]],
"os": ["linux", "darwin"]
}

View File

@ -1,7 +1,4 @@
var _jsxFileName = "<CWD>/packages/babel-plugin-transform-react-jsx-development/test/fixtures/linux/classic-runtime/input.js";
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
__self: this,
__source: {
@ -34,7 +31,7 @@ var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/Reac
lineNumber: 6,
columnNumber: 9
}
}), /*#__PURE__*/React.createElement("div", _extends({}, props, {
}), /*#__PURE__*/React.createElement("div", { ...props,
key: "4",
__self: this,
__source: {
@ -42,4 +39,4 @@ var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/Reac
lineNumber: 7,
columnNumber: 9
}
}))));
})));

View File

@ -0,0 +1,10 @@
var x = (
<>
<div>
<div key="1" />
<div key="2" meow="wolf" />
<div key="3" />
<div {...props} key="4" />
</div>
</>
);

View File

@ -0,0 +1,4 @@
{
"BABEL_8_BREAKING": false,
"plugins": [["transform-react-jsx-development", { "runtime": "classic" }]]
}

View File

@ -0,0 +1,45 @@
var _jsxFileName = "<CWD>\\packages\\babel-plugin-transform-react-jsx-development\\test\\fixtures\\windows\\classic-runtime-windows-babel-7\\input.js";
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 3,
columnNumber: 5
}
}, /*#__PURE__*/React.createElement("div", {
key: "1",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 4,
columnNumber: 7
}
}), /*#__PURE__*/React.createElement("div", {
key: "2",
meow: "wolf",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 5,
columnNumber: 7
}
}), /*#__PURE__*/React.createElement("div", {
key: "3",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 6,
columnNumber: 7
}
}), /*#__PURE__*/React.createElement("div", _extends({}, props, {
key: "4",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 7,
columnNumber: 7
}
}))));

View File

@ -1,3 +1,4 @@
{
"BABEL_8_BREAKING": true,
"plugins": [["transform-react-jsx-development", { "runtime": "classic" }]]
}

View File

@ -1,7 +1,4 @@
var _jsxFileName = "<CWD>\\packages\\babel-plugin-transform-react-jsx-development\\test\\fixtures\\windows\\classic-runtime-windows\\input.js";
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
__self: this,
__source: {
@ -15,7 +12,7 @@ var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/Reac
__source: {
fileName: _jsxFileName,
lineNumber: 4,
columnNumber: 7
columnNumber: 9
}
}), /*#__PURE__*/React.createElement("div", {
key: "2",
@ -24,7 +21,7 @@ var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/Reac
__source: {
fileName: _jsxFileName,
lineNumber: 5,
columnNumber: 7
columnNumber: 9
}
}), /*#__PURE__*/React.createElement("div", {
key: "3",
@ -32,14 +29,14 @@ var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/Reac
__source: {
fileName: _jsxFileName,
lineNumber: 6,
columnNumber: 7
columnNumber: 9
}
}), /*#__PURE__*/React.createElement("div", _extends({}, props, {
}), /*#__PURE__*/React.createElement("div", { ...props,
key: "4",
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 7,
columnNumber: 7
columnNumber: 9
}
}))));
})));

View File

@ -30,10 +30,6 @@ export default function createPlugin({ name, development }) {
// TODO (Babel 8): It should throw if this option is used with the automatic runtime
filter,
// TODO (Babel 8): Remove `useBuiltIns` & `useSpread`
useSpread = false,
useBuiltIns = false,
runtime: RUNTIME_DEFAULT = development ? "automatic" : "classic",
importSource: IMPORT_SOURCE_DEFAULT = DEFAULT.importSource,
@ -41,27 +37,52 @@ export default function createPlugin({ name, development }) {
pragmaFrag: PRAGMA_FRAG_DEFAULT = DEFAULT.pragmaFrag,
} = options;
// TOOD(Babel 8): If the runtime is 'automatic', we should throw when useSpread/useBuiltIns are set
if (RUNTIME_DEFAULT === "classic") {
if (typeof useSpread !== "boolean") {
if (process.env.BABEL_8_BREAKING) {
if ("useSpread" in options) {
throw new Error(
"transform-react-jsx currently only accepts a boolean option for " +
"useSpread (defaults to false)",
'@babel/plugin-transform-react-jsx: Since Babel 8, an inline object with spread elements is always used, and the "useSpread" option is no longer available. Please remove it from your config.',
);
}
if (typeof useBuiltIns !== "boolean") {
if ("useBuiltIns" in options) {
const useBuiltInsFormatted = JSON.stringify(options.useBuiltIns);
throw new Error(
"transform-react-jsx currently only accepts a boolean option for " +
"useBuiltIns (defaults to false)",
`@babel/plugin-transform-react-jsx: Since "useBuiltIns" is removed in Babel 8, you can remove it from the config.
- Babel 8 now transforms JSX spread to object spread. If you need to transpile object spread with
\`useBuiltIns: ${useBuiltInsFormatted}\`, you can use the following config
{
"plugins": [
"@babel/plugin-transform-react-jsx"
["@babel/plugin-proposal-object-rest-spread", { "loose": true, "useBuiltIns": ${useBuiltInsFormatted} }]
]
}`,
);
}
} else {
// eslint-disable-next-line no-var
var { useSpread = false, useBuiltIns = false } = options;
if (useSpread && useBuiltIns) {
throw new Error(
"transform-react-jsx currently only accepts useBuiltIns or useSpread " +
"but not both",
);
if (RUNTIME_DEFAULT === "classic") {
if (typeof useSpread !== "boolean") {
throw new Error(
"transform-react-jsx currently only accepts a boolean option for " +
"useSpread (defaults to false)",
);
}
if (typeof useBuiltIns !== "boolean") {
throw new Error(
"transform-react-jsx currently only accepts a boolean option for " +
"useBuiltIns (defaults to false)",
);
}
if (useSpread && useBuiltIns) {
throw new Error(
"transform-react-jsx currently only accepts useBuiltIns or useSpread " +
"but not both",
);
}
}
}
@ -519,72 +540,78 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
* all prior attributes to an array for later processing.
*/
function buildCreateElementOpeningElementAttributes(file, path, attribs) {
// TODO (Babel 8): Only leave this branch of the code and remove the rest
if (
RUNTIME_DEFAULT === "automatic" ||
get(file, "runtime") === "automatic"
) {
const props = [];
const found = Object.create(null);
const runtime = get(file, "runtime");
if (!process.env.BABEL_8_BREAKING) {
if (runtime !== "automatic") {
const objs = [];
const props = attribs.reduce(accumulateAttribute, []);
for (const attr of attribs) {
const name =
t.isJSXAttribute(attr) &&
t.isJSXIdentifier(attr.name) &&
attr.name.name;
if (name === "__source" || name === "__self") {
if (found[name]) throw sourceSelfError(path, name);
found[name] = true;
}
accumulateAttribute(props, attr);
}
return props.length > 0 ? t.objectExpression(props) : t.nullLiteral();
}
const objs = [];
const props = attribs.reduce(accumulateAttribute, []);
if (!useSpread) {
// Convert syntax to use multiple objects instead of spread
let start = 0;
props.forEach((prop, i) => {
if (t.isSpreadElement(prop)) {
if (i > start) {
objs.push(t.objectExpression(props.slice(start, i)));
if (!useSpread) {
// Convert syntax to use multiple objects instead of spread
let start = 0;
props.forEach((prop, i) => {
if (t.isSpreadElement(prop)) {
if (i > start) {
objs.push(t.objectExpression(props.slice(start, i)));
}
objs.push(prop.argument);
start = i + 1;
}
});
if (props.length > start) {
objs.push(t.objectExpression(props.slice(start)));
}
objs.push(prop.argument);
start = i + 1;
} else if (props.length) {
objs.push(t.objectExpression(props));
}
});
if (props.length > start) {
objs.push(t.objectExpression(props.slice(start)));
if (!objs.length) {
return t.nullLiteral();
}
if (objs.length === 1) {
return objs[0];
}
// looks like we have multiple objects
if (!t.isObjectExpression(objs[0])) {
objs.unshift(t.objectExpression([]));
}
const helper = useBuiltIns
? t.memberExpression(t.identifier("Object"), t.identifier("assign"))
: file.addHelper("extends");
// spread it
return t.callExpression(helper, objs);
}
} else if (props.length) {
objs.push(t.objectExpression(props));
}
if (!objs.length) {
return t.nullLiteral();
const props = [];
const found = Object.create(null);
for (const attr of attribs) {
const name =
t.isJSXAttribute(attr) &&
t.isJSXIdentifier(attr.name) &&
attr.name.name;
if (
runtime === "automatic" &&
(name === "__source" || name === "__self")
) {
if (found[name]) throw sourceSelfError(path, name);
found[name] = true;
}
accumulateAttribute(props, attr);
}
if (objs.length === 1) {
return objs[0];
}
// looks like we have multiple objects
if (!t.isObjectExpression(objs[0])) {
objs.unshift(t.objectExpression([]));
}
const helper = useBuiltIns
? t.memberExpression(t.identifier("Object"), t.identifier("assign"))
: file.addHelper("extends");
// spread it
return t.callExpression(helper, objs);
return props.length === 1 && t.isSpreadElement(props[0])
? props[0].argument
: props.length > 0
? t.objectExpression(props)
: t.nullLiteral();
}
});

View File

@ -0,0 +1,3 @@
<Component
{...props}
sound="moo" />

View File

@ -0,0 +1,4 @@
/*#__PURE__*/
React.createElement(Component, babelHelpers.extends({}, props, {
sound: "moo"
}));

View File

@ -1,4 +1,4 @@
/*#__PURE__*/
React.createElement(Component, babelHelpers.extends({}, props, {
React.createElement(Component, { ...props,
sound: "moo"
}));
});

View File

@ -0,0 +1,3 @@
{
"BABEL_8_BREAKING": false
}

View File

@ -0,0 +1,3 @@
var div = /*#__PURE__*/React.createElement(Component, babelHelpers.extends({}, props, {
foo: "bar"
}));

View File

@ -0,0 +1,3 @@
{
"BABEL_8_BREAKING": true
}

View File

@ -1,3 +1,3 @@
var div = /*#__PURE__*/React.createElement(Component, babelHelpers.extends({}, props, {
var div = /*#__PURE__*/React.createElement(Component, { ...props,
foo: "bar"
}));
});

View File

@ -0,0 +1,3 @@
{
"BABEL_8_BREAKING": false
}

View File

@ -0,0 +1,10 @@
var x = (
<>
<div>
<div key="1" />
<div key="2" meow="wolf" />
<div key="3" />
<div {...props} key="4" />
</div>
</>
);

View File

@ -0,0 +1,3 @@
{
"BABEL_8_BREAKING": false
}

View File

@ -0,0 +1,10 @@
var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
key: "1"
}), /*#__PURE__*/React.createElement("div", {
key: "2",
meow: "wolf"
}), /*#__PURE__*/React.createElement("div", {
key: "3"
}), /*#__PURE__*/React.createElement("div", babelHelpers.extends({}, props, {
key: "4"
}))));

View File

@ -0,0 +1,3 @@
{
"BABEL_8_BREAKING": true
}

View File

@ -5,6 +5,6 @@ var x = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/Reac
meow: "wolf"
}), /*#__PURE__*/React.createElement("div", {
key: "3"
}), /*#__PURE__*/React.createElement("div", babelHelpers.extends({}, props, {
}), /*#__PURE__*/React.createElement("div", { ...props,
key: "4"
}))));
})));

View File

@ -0,0 +1,5 @@
/*#__PURE__*/
React.createElement(Component, babelHelpers.extends({}, x, {
y: 2,
z: true
}));

View File

@ -1,5 +1,5 @@
/*#__PURE__*/
React.createElement(Component, babelHelpers.extends({}, x, {
React.createElement(Component, { ...x,
y: 2,
z: true
}));
});

View File

@ -0,0 +1,5 @@
/*#__PURE__*/
React.createElement(Component, babelHelpers.extends({
y: 2,
z: true
}, x));

View File

@ -1,5 +1,6 @@
/*#__PURE__*/
React.createElement(Component, babelHelpers.extends({
React.createElement(Component, {
y: 2,
z: true
}, x));
z: true,
...x
});

View File

@ -0,0 +1,6 @@
/*#__PURE__*/
React.createElement(Component, babelHelpers.extends({
y: 2
}, x, {
z: true
}));

View File

@ -1,6 +1,6 @@
/*#__PURE__*/
React.createElement(Component, babelHelpers.extends({
y: 2
}, x, {
React.createElement(Component, {
y: 2,
...x,
z: true
}));
});

View File

@ -0,0 +1,5 @@
{
"BABEL_8_BREAKING": true,
"plugins": [["transform-react-jsx", { "useBuiltIns": false }]],
"throws": "@babel/plugin-transform-react-jsx: Since \"useBuiltIns\" is removed in Babel 8, you can remove it from the config."
}

View File

@ -0,0 +1,5 @@
{
"BABEL_8_BREAKING": true,
"plugins": [["transform-react-jsx", { "useBuiltIns": true }]],
"throws": "@babel/plugin-transform-react-jsx: Since \"useBuiltIns\" is removed in Babel 8, you can remove it from the config."
}

View File

@ -0,0 +1,5 @@
{
"BABEL_8_BREAKING": true,
"plugins": [["transform-react-jsx", { "useSpread": false }]],
"throws": "transform-react-jsx: Since Babel 8, an inline object with spread elements is always used, and the \"useSpread\" option is no longer available. Please remove it from your config."
}

View File

@ -0,0 +1,5 @@
{
"BABEL_8_BREAKING": true,
"plugins": [["transform-react-jsx", { "useSpread": true }]],
"throws": "transform-react-jsx: Since Babel 8, an inline object with spread elements is always used, and the \"useSpread\" option is no longer available. Please remove it from your config."
}

View File

@ -0,0 +1,3 @@
{
"BABEL_8_BREAKING": true
}

View File

@ -0,0 +1 @@
var div = <Component {...props} foo="bar" />

View File

@ -0,0 +1,6 @@
{
"plugins": ["transform-react-jsx", ["proposal-object-rest-spread", {
"loose": true,
"useBuiltIns": false
}], "external-helpers"]
}

View File

@ -0,0 +1,3 @@
var div = /*#__PURE__*/React.createElement(Component, babelHelpers.extends({}, props, {
foo: "bar"
}));

View File

@ -0,0 +1 @@
var div = <Component {...props} foo="bar" />

View File

@ -0,0 +1,6 @@
{
"plugins": ["transform-react-jsx", ["proposal-object-rest-spread", {
"loose": true,
"useBuiltIns": true
}]]
}

View File

@ -1,4 +0,0 @@
{
"plugins": [["transform-react-jsx", { "useBuiltIns": "invalidOption" }]],
"throws": "transform-react-jsx currently only accepts a boolean option for useBuiltIns (defaults to false)"
}

View File

@ -1,3 +0,0 @@
{
"plugins": [["transform-react-jsx", { "useBuiltIns": true }]]
}

View File

@ -1,4 +0,0 @@
{
"plugins": [["transform-react-jsx", { "useSpread": 0 }]],
"throws": "transform-react-jsx currently only accepts a boolean option for useSpread (defaults to false)"
}

View File

@ -1,6 +0,0 @@
{
"plugins": [
["transform-react-jsx", { "useSpread": true, "useBuiltIns": true }]
],
"throws": "transform-react-jsx currently only accepts useBuiltIns or useSpread but not both"
}

View File

@ -1,3 +0,0 @@
var div = /*#__PURE__*/React.createElement(Component, { ...props,
foo: "bar"
});

View File

@ -1,3 +0,0 @@
{
"plugins": [["transform-react-jsx", { "useSpread": true }]]
}

View File

@ -25,21 +25,58 @@ export default declare((api, opts) => {
// TODO: (Babel 8) Don't cast this option but validate it
const development = !!opts.development;
if (process.env.BABEL_8_BREAKING) {
if ("useSpread" in opts) {
throw new Error(
'@babel/preset-react: Since Babel 8, an inline object with spread elements is always used, and the "useSpread" option is no longer available. Please remove it from your config.',
);
}
if ("useBuiltIns" in opts) {
const useBuiltInsFormatted = JSON.stringify(opts.useBuiltIns);
throw new Error(
`@babel/preset-react: Since "useBuiltIns" is removed in Babel 8, you can remove it from the config.
- Babel 8 now transforms JSX spread to object spread. If you need to transpile object spread with
\`useBuiltIns: ${useBuiltInsFormatted}\`, you can use the following config
{
"plugins": [
["@babel/plugin-proposal-object-rest-spread", { "loose": true, "useBuiltIns": ${useBuiltInsFormatted} }]
],
"presets": ["@babel/preset-react"]
}`,
);
}
}
if (typeof development !== "boolean") {
throw new Error(
"@babel/preset-react 'development' option must be a boolean.",
);
}
return {
plugins: [
[
development ? transformReactJSXDevelopment : transformReactJSX,
{
importSource,
pragma,
pragmaFrag,
runtime,
throwIfNamespace,
pure,
// TODO (Babel 8): Remove `useBuiltIns` & `useSpread`
useBuiltIns: !!opts.useBuiltIns,
useSpread: opts.useSpread,
},
process.env.BABEL_8_BREAKING
? {
importSource,
pragma,
pragmaFrag,
runtime,
throwIfNamespace,
pure,
}
: {
importSource,
pragma,
pragmaFrag,
runtime,
throwIfNamespace,
pure,
useBuiltIns: !!opts.useBuiltIns,
useSpread: opts.useSpread,
},
],
transformReactDisplayName,
pure !== false && transformReactPure,