From 4446b99fb30f53a38d43abf09c1706b3091973ad Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 29 May 2020 15:15:57 -0700 Subject: [PATCH] fix: don't mutate InputTarget's passed to @babel/helper-compilation-targets If `@babel/helper-compilation-targets` is called directly, as it is in the [Ember-CLI babel](https://github.com/babel/ember-cli-babel/blob/6f76f405b9dd2a48cce394c4826dd50847f74282/index.js#L543-L545) and [Vue CLI](https://github.com/vuejs/vue-cli/blob/c8cecffedbf7b19cf930bb2821b5c352bc716a67/packages/%40vue/babel-preset-app/index.js#L17) integrations, we don't want to mutate the input passed in. At least in Ember CLI, babel could be called multiple times. So, on subsequent passes all `browsers` and `esmodules` info would be lost (and losing the `browsers` info affects the output in negative ways). Copying the object before dropping keys allows callers not have to worry about babel mutating the object they pass in. Switching to a more functional approach makes it easier for babel to not worry about what consumers are passing in. Dropping the `browser` property was introduced in: https://github.com/babel/babel/pull/11500 Dropping the `esmodules` property was introduced in https://github.com/babel/babel/pull/11124 Discussion about dropping the `esmodules` property: https://github.com/babel/babel/pull/11124#discussion_r383051803 --- .../src/index.js | 16 +++++++++------- .../test/targets-parser.spec.js | 12 ++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/babel-helper-compilation-targets/src/index.js b/packages/babel-helper-compilation-targets/src/index.js index 97223e61b2c6..33a534beb14c 100644 --- a/packages/babel-helper-compilation-targets/src/index.js +++ b/packages/babel-helper-compilation-targets/src/index.js @@ -166,24 +166,26 @@ export default function getTargets( options: Object = {}, ): Targets { const targetOpts: Targets = {}; + let { browsers } = inputTargets; // `esmodules` as a target indicates the specific set of browsers supporting ES Modules. // These values OVERRIDE the `browsers` field. if (inputTargets.esmodules) { const supportsESModules = browserModulesData["es6.module"]; - inputTargets.browsers = Object.keys(supportsESModules) + browsers = Object.keys(supportsESModules) .map(browser => `${browser} ${supportsESModules[browser]}`) .join(", "); } - // Remove esmodules after being consumed to fix `hasTargets` below - delete inputTargets.esmodules; - // Parse browsers target via browserslist - const browsersquery = validateBrowsers(inputTargets.browsers); - delete inputTargets.browsers; + const browsersquery = validateBrowsers(browsers); + + // Remove esmodules after being consumed to fix `hasTargets` below + const input = { ...inputTargets }; + delete input.esmodules; + delete input.browsers; - let targets: Targets = validateTargetNames(inputTargets); + let targets: Targets = validateTargetNames(input); const shouldParseBrowsers = !!browsersquery; const hasTargets = shouldParseBrowsers || Object.keys(targets).length > 0; diff --git a/packages/babel-helper-compilation-targets/test/targets-parser.spec.js b/packages/babel-helper-compilation-targets/test/targets-parser.spec.js index 2c4f1335ef22..f44ae0060197 100644 --- a/packages/babel-helper-compilation-targets/test/targets-parser.spec.js +++ b/packages/babel-helper-compilation-targets/test/targets-parser.spec.js @@ -20,6 +20,18 @@ describe("getTargets", () => { }); }); + it("does not mutate the input", () => { + const input = Object.freeze({ browsers: "defaults", esmodules: true }); + const expected = getTargets({ + browsers: browserslist.defaults, + esmodules: true, + }); + const actual = getTargets(input); + expect(actual).toEqual(expected); + expect(input.browsers).toEqual("defaults"); + expect(input.esmodules).toEqual(true); + }); + it("allows 'defaults' query", () => { const browserslistDefaults = browserslist.defaults;