diff --git a/packages/babel-helper-builder-react-jsx/src/index.js b/packages/babel-helper-builder-react-jsx/src/index.js index fa68384f1b..64b136923f 100644 --- a/packages/babel-helper-builder-react-jsx/src/index.js +++ b/packages/babel-helper-builder-react-jsx/src/index.js @@ -87,6 +87,10 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, function convertAttribute(node) { const value = convertAttributeValue(node.value || t.booleanLiteral(true)); + if (t.isJSXSpreadAttribute(node)) { + return t.spreadElement(node.argument); + } + if (t.isStringLiteral(value) && !t.isJSXExpressionContainer(node.value)) { value.value = value.value.replace(/\n\s+/g, " "); @@ -170,6 +174,14 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, let _props = []; const objs = []; + const { useSpread = false } = file.opts; + if (typeof useSpread !== "boolean") { + throw new Error( + "transform-react-jsx currently only accepts a boolean option for " + + "useSpread (defaults to false)", + ); + } + const useBuiltIns = file.opts.useBuiltIns || false; if (typeof useBuiltIns !== "boolean") { throw new Error( @@ -178,6 +190,18 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, ); } + if (useSpread && useBuiltIns) { + throw new Error( + "transform-react-jsx currently only accepts useBuiltIns or useSpread " + + "but not both", + ); + } + + if (useSpread) { + const props = attribs.map(convertAttribute); + return t.objectExpression(props); + } + while (attribs.length) { const prop = attribs.shift(); if (t.isJSXSpreadAttribute(prop)) { diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-invalid-option/input.js b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-invalid-option/input.js new file mode 100644 index 0000000000..4caacb6aa1 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-invalid-option/input.js @@ -0,0 +1 @@ +var div = diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-invalid-option/options.json b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-invalid-option/options.json new file mode 100644 index 0000000000..ff6406c9a4 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-invalid-option/options.json @@ -0,0 +1,4 @@ +{ + "plugins": [["transform-react-jsx", { "useSpread": 0 }]], + "throws": "transform-react-jsx currently only accepts a boolean option for useSpread (defaults to false)" +} diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-use-builtin/input.js b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-use-builtin/input.js new file mode 100644 index 0000000000..4caacb6aa1 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-use-builtin/input.js @@ -0,0 +1 @@ +var div = diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-use-builtin/options.json b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-use-builtin/options.json new file mode 100644 index 0000000000..eab6051daa --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-use-builtin/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + ["transform-react-jsx", { "useSpread": true, "useBuiltIns": true }] + ], + "throws": "transform-react-jsx currently only accepts useBuiltIns or useSpread but not both" +} diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment/input.js b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment/input.js new file mode 100644 index 0000000000..4caacb6aa1 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment/input.js @@ -0,0 +1 @@ +var div = diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment/output.js b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment/output.js new file mode 100644 index 0000000000..6d3c491321 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment/output.js @@ -0,0 +1,3 @@ +var div = React.createElement(Component, { ...props, + foo: "bar" +}); diff --git a/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/options.json b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/options.json new file mode 100644 index 0000000000..7e0d5fcba0 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["transform-react-jsx", { "useSpread": true }]] +} diff --git a/packages/babel-preset-react/src/index.js b/packages/babel-preset-react/src/index.js index f99fe36e0b..aaf358ea59 100644 --- a/packages/babel-preset-react/src/index.js +++ b/packages/babel-preset-react/src/index.js @@ -13,6 +13,7 @@ export default declare((api, opts) => { opts.throwIfNamespace === undefined ? true : !!opts.throwIfNamespace; const development = !!opts.development; const useBuiltIns = !!opts.useBuiltIns; + const { useSpread } = opts; if (typeof development !== "boolean") { throw new Error( @@ -24,7 +25,7 @@ export default declare((api, opts) => { plugins: [ [ transformReactJSX, - { pragma, pragmaFrag, throwIfNamespace, useBuiltIns }, + { pragma, pragmaFrag, throwIfNamespace, useBuiltIns, useSpread }, ], transformReactDisplayName,