From 345654d1d7f5c5f51a97fbc518f46f22b02ab512 Mon Sep 17 00:00:00 2001 From: ivandevp Date: Thu, 17 Oct 2019 23:30:26 -0500 Subject: [PATCH 1/6] [transform-react-jsx] Add useSpread option to transform JSX --- .../src/index.js | 26 ++++++++++++++----- .../assignment-invalid-option/input.js | 1 + .../assignment-invalid-option/options.json | 4 +++ .../fixtures/useSpread/assignment/input.js | 1 + .../fixtures/useSpread/assignment/output.js | 3 +++ .../test/fixtures/useSpread/options.json | 3 +++ 6 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-invalid-option/input.js create mode 100644 packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-invalid-option/options.json create mode 100644 packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment/input.js create mode 100644 packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment/output.js create mode 100644 packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/options.json diff --git a/packages/babel-helper-builder-react-jsx/src/index.js b/packages/babel-helper-builder-react-jsx/src/index.js index 3602ecb8496e..07cb1f0e4381 100644 --- a/packages/babel-helper-builder-react-jsx/src/index.js +++ b/packages/babel-helper-builder-react-jsx/src/index.js @@ -172,6 +172,14 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, let _props = []; const objs = []; + const useSpread = file.opts.useSpread || false; + 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( @@ -185,6 +193,9 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, if (t.isJSXSpreadAttribute(prop)) { _props = pushProps(_props, objs); objs.push(prop.argument); + if (useSpread) { + _props.push(t.spreadElement(prop.argument)); + } } else { _props.push(convertAttribute(prop)); } @@ -201,12 +212,15 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, objs.unshift(t.objectExpression([])); } - const helper = useBuiltIns - ? t.memberExpression(t.identifier("Object"), t.identifier("assign")) - : file.addHelper("extends"); - - // spread it - attribs = t.callExpression(helper, objs); + if (useSpread) { + attribs = t.objectExpression(_props); + } else { + const helper = useBuiltIns + ? t.memberExpression(t.identifier("Object"), t.identifier("assign")) + : file.addHelper("extends"); + // spread it + attribs = t.callExpression(helper, objs); + } } return attribs; 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 000000000000..4caacb6aa17d --- /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 000000000000..99eacc111d9f --- /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": "invalidOption" }]], + "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/input.js b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment/input.js new file mode 100644 index 000000000000..4caacb6aa17d --- /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 000000000000..6d3c49132173 --- /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 000000000000..7e0d5fcba0f3 --- /dev/null +++ b/packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["transform-react-jsx", { "useSpread": true }]] +} From 60aad23dabf68da5ae382f983e65979cbe96f5c4 Mon Sep 17 00:00:00 2001 From: ivandevp Date: Wed, 23 Oct 2019 22:41:03 -0500 Subject: [PATCH 2/6] Add validation for default option --- packages/babel-helper-builder-react-jsx/src/index.js | 12 ++++++++++-- .../useSpread/assignment-invalid-option/options.json | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/babel-helper-builder-react-jsx/src/index.js b/packages/babel-helper-builder-react-jsx/src/index.js index 07cb1f0e4381..ca39688df26e 100644 --- a/packages/babel-helper-builder-react-jsx/src/index.js +++ b/packages/babel-helper-builder-react-jsx/src/index.js @@ -161,6 +161,14 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, return []; } + function setDefaultValue(option, defaultValue) { + if (typeof option === "undefined") { + return defaultValue; + } + + return option; + } + /** * The logic for this is quite terse. It's because we need to * support spread elements. We loop over all attributes, @@ -172,7 +180,7 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, let _props = []; const objs = []; - const useSpread = file.opts.useSpread || false; + const useSpread = setDefaultValue(file.opts.useSpread, false); if (typeof useSpread !== "boolean") { throw new Error( "transform-react-jsx currently only accepts a boolean option for " + @@ -180,7 +188,7 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, ); } - const useBuiltIns = file.opts.useBuiltIns || false; + const useBuiltIns = setDefaultValue(file.opts.useBuiltIns, false); if (typeof useBuiltIns !== "boolean") { throw new Error( "transform-react-jsx currently only accepts a boolean option for " + 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 index 99eacc111d9f..ff6406c9a4e2 100644 --- 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 @@ -1,4 +1,4 @@ { - "plugins": [["transform-react-jsx", { "useSpread": "invalidOption" }]], + "plugins": [["transform-react-jsx", { "useSpread": 0 }]], "throws": "transform-react-jsx currently only accepts a boolean option for useSpread (defaults to false)" } From 617dd72d8a890f260ac84893dfee38c5b9687e84 Mon Sep 17 00:00:00 2001 From: ivandevp Date: Sun, 27 Oct 2019 08:52:00 -0600 Subject: [PATCH 3/6] Add error when using useSpread and useBuiltIns at the same time --- .../src/index.js | 19 +++++++++---------- .../useSpread/assignment-use-builtin/input.js | 1 + .../assignment-use-builtin/options.json | 6 ++++++ 3 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-use-builtin/input.js create mode 100644 packages/babel-plugin-transform-react-jsx/test/fixtures/useSpread/assignment-use-builtin/options.json diff --git a/packages/babel-helper-builder-react-jsx/src/index.js b/packages/babel-helper-builder-react-jsx/src/index.js index ca39688df26e..6d7eb705da2e 100644 --- a/packages/babel-helper-builder-react-jsx/src/index.js +++ b/packages/babel-helper-builder-react-jsx/src/index.js @@ -161,14 +161,6 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, return []; } - function setDefaultValue(option, defaultValue) { - if (typeof option === "undefined") { - return defaultValue; - } - - return option; - } - /** * The logic for this is quite terse. It's because we need to * support spread elements. We loop over all attributes, @@ -180,7 +172,7 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, let _props = []; const objs = []; - const useSpread = setDefaultValue(file.opts.useSpread, false); + const { useSpread = false } = file.opts; if (typeof useSpread !== "boolean") { throw new Error( "transform-react-jsx currently only accepts a boolean option for " + @@ -188,7 +180,7 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, ); } - const useBuiltIns = setDefaultValue(file.opts.useBuiltIns, false); + const useBuiltIns = file.opts.useBuiltIns || false; if (typeof useBuiltIns !== "boolean") { throw new Error( "transform-react-jsx currently only accepts a boolean option for " + @@ -196,6 +188,13 @@ 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", + ); + } + while (attribs.length) { const prop = attribs.shift(); if (t.isJSXSpreadAttribute(prop)) { 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 000000000000..4caacb6aa17d --- /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 000000000000..eab6051daa03 --- /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" +} From 3e32a4e1c41c7b6e20f9b552c22170b6d321f413 Mon Sep 17 00:00:00 2001 From: ivandevp Date: Sun, 27 Oct 2019 18:13:28 -0600 Subject: [PATCH 4/6] Move useSpread to convertAttribute helper function --- .../src/index.js | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/babel-helper-builder-react-jsx/src/index.js b/packages/babel-helper-builder-react-jsx/src/index.js index 6d7eb705da2e..b09b61e577fa 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, " "); @@ -195,14 +199,16 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, ); } + if (useSpread) { + const props = attribs.map(convertAttribute); + return t.objectExpression(props); + } + while (attribs.length) { const prop = attribs.shift(); if (t.isJSXSpreadAttribute(prop)) { _props = pushProps(_props, objs); objs.push(prop.argument); - if (useSpread) { - _props.push(t.spreadElement(prop.argument)); - } } else { _props.push(convertAttribute(prop)); } @@ -219,15 +225,12 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`, objs.unshift(t.objectExpression([])); } - if (useSpread) { - attribs = t.objectExpression(_props); - } else { - const helper = useBuiltIns - ? t.memberExpression(t.identifier("Object"), t.identifier("assign")) - : file.addHelper("extends"); - // spread it - attribs = t.callExpression(helper, objs); - } + const helper = useBuiltIns + ? t.memberExpression(t.identifier("Object"), t.identifier("assign")) + : file.addHelper("extends"); + + // spread it + attribs = t.callExpression(helper, objs); } return attribs; From 7b0f8312d38bdf5833e201fe71ab669629e155c7 Mon Sep 17 00:00:00 2001 From: ivandevp Date: Mon, 28 Oct 2019 20:07:16 -0600 Subject: [PATCH 5/6] Add useSpread option to presect-react --- packages/babel-preset-react/src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/babel-preset-react/src/index.js b/packages/babel-preset-react/src/index.js index f99fe36e0b1c..91201b345bf2 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.useSpread; 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, From 35ec82bc6b0a4c89a420dc24f2cb59d866424bd4 Mon Sep 17 00:00:00 2001 From: Ivan Medina Date: Tue, 29 Oct 2019 09:23:22 -0600 Subject: [PATCH 6/6] Remove casting useSpread to boolean in preset-react option. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Nicolò Ribaudo --- packages/babel-preset-react/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/babel-preset-react/src/index.js b/packages/babel-preset-react/src/index.js index 91201b345bf2..aaf358ea5979 100644 --- a/packages/babel-preset-react/src/index.js +++ b/packages/babel-preset-react/src/index.js @@ -13,7 +13,7 @@ export default declare((api, opts) => { opts.throwIfNamespace === undefined ? true : !!opts.throwIfNamespace; const development = !!opts.development; const useBuiltIns = !!opts.useBuiltIns; - const useSpread = !!opts.useSpread; + const { useSpread } = opts; if (typeof development !== "boolean") { throw new Error(