From 9cf017b2ca43f86906595989762346fda2d16075 Mon Sep 17 00:00:00 2001 From: Artem Yavorsky Date: Fri, 3 Nov 2017 17:22:11 +0200 Subject: [PATCH] Fix global reference for use-built-ins plugin (#6478) * Consider instance type for polyfills. * Add test cases for evaluated objects. * preset-env fixtures: babel-polyfill -> @babel/polyfill * Split up fixtures with evaluated variables. --- .../src/use-built-ins-plugin.js | 70 +++++++++---------- .../actual.js | 12 ++++ .../expected.js | 14 ++++ .../options.json | 8 +++ .../actual.js | 8 +++ .../expected.js | 10 +++ .../options.json | 8 +++ 7 files changed, 95 insertions(+), 35 deletions(-) create mode 100644 experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/actual.js create mode 100644 experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/expected.js create mode 100644 experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/options.json create mode 100644 experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/actual.js create mode 100644 experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/expected.js create mode 100644 experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/options.json diff --git a/experimental/babel-preset-env/src/use-built-ins-plugin.js b/experimental/babel-preset-env/src/use-built-ins-plugin.js index 98fd7755c3..a1e9e9eeab 100644 --- a/experimental/babel-preset-env/src/use-built-ins-plugin.js +++ b/experimental/babel-preset-env/src/use-built-ins-plugin.js @@ -24,6 +24,11 @@ function has(obj: Object, key: string): boolean { return Object.prototype.hasOwnProperty.call(obj, key); } +function getType(target: any): string { + if (Array.isArray(target)) return "array"; + return typeof target; +} + // function getObjectString(node: Object): string { // if (node.type === "Identifier") { // return node.name; @@ -176,14 +181,31 @@ export default function({ types: t }: { types: Object }): Plugin { const prop = node.property; if (!t.isReferenced(obj, node)) return; - - // doesn't reference the global - if (path.scope.getBindingIdentifier(obj.name)) return; - - if (has(definitions.staticMethods, obj.name)) { - const staticMethods = definitions.staticMethods[obj.name]; - if (has(staticMethods, prop.name)) { - const builtIn = staticMethods[prop.name]; + let instanceType; + let evaluatedPropType = obj.name; + let propName = prop.name; + if (node.computed) { + if (t.isStringLiteral(prop)) { + propName = prop.value; + } else { + const res = path.get("property").evaluate(); + if (res.confident && res.value) { + propName = res.value; + } + } + } + if (path.scope.getBindingIdentifier(obj.name)) { + const result = path.get("object").evaluate(); + if (result.value) { + instanceType = getType(result.value); + } else if (result.deopt && result.deopt.isIdentifier()) { + evaluatedPropType = result.deopt.node.name; + } + } + if (has(definitions.staticMethods, evaluatedPropType)) { + const staticMethods = definitions.staticMethods[evaluatedPropType]; + if (has(staticMethods, propName)) { + const builtIn = staticMethods[propName]; addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns); // if (obj.name === "Array" && prop.name === "from") { // addImport( @@ -195,35 +217,13 @@ export default function({ types: t }: { types: Object }): Plugin { } } - if ( - !node.computed && - t.isIdentifier(prop) && - has(definitions.instanceMethods, prop.name) - ) { + if (has(definitions.instanceMethods, propName)) { //warnOnInstanceMethod(state, getObjectString(node)); - const builtIn = definitions.instanceMethods[prop.name]; - addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns); - } else if (node.computed) { - if ( - t.isStringLiteral(prop) && - has(definitions.instanceMethods, prop.value) - ) { - const builtIn = definitions.instanceMethods[prop.value]; - //warnOnInstanceMethod(state, `${obj.name}['${prop.value}']`); - addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns); - } else { - const res = path.get("property").evaluate(); - if (res.confident) { - const builtIn = definitions.instanceMethods[res.value]; - //warnOnInstanceMethod(state, `${obj.name}['${res.value}']`); - addUnsupported( - path.get("property"), - state.opts.polyfills, - builtIn, - this.builtIns, - ); - } + let builtIn = definitions.instanceMethods[propName]; + if (instanceType) { + builtIn = builtIn.filter(item => item.includes(instanceType)); } + addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns); } }, diff --git a/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/actual.js b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/actual.js new file mode 100644 index 0000000000..c12f5e3a8a --- /dev/null +++ b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/actual.js @@ -0,0 +1,12 @@ +var objectClass = Object; +var arrayInstance = []; +var assignStr = "assign"; +var entriesStr = "entries"; +var valuesStr = "values"; +var inclidesStr = "includes"; +var findStr = "find"; + +// Allow static methods be assigned to variables only directly in the module. +externalVar[valuesStr]; // don't include +objectClass[assignStr]({}); // include +arrayInstance[entriesStr]({}); // don't include diff --git a/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/expected.js b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/expected.js new file mode 100644 index 0000000000..6d9a2d1d60 --- /dev/null +++ b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/expected.js @@ -0,0 +1,14 @@ +import "@babel/polyfill/lib/core-js/modules/es6.object.assign"; +var objectClass = Object; +var arrayInstance = []; +var assignStr = "assign"; +var entriesStr = "entries"; +var valuesStr = "values"; +var inclidesStr = "includes"; +var findStr = "find"; // Allow static methods be assigned to variables only directly in the module. + +externalVar[valuesStr]; // don't include + +objectClass[assignStr]({}); // include + +arrayInstance[entriesStr]({}); // don't include diff --git a/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/options.json b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/options.json new file mode 100644 index 0000000000..fa0e9434e2 --- /dev/null +++ b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-class-methods/options.json @@ -0,0 +1,8 @@ +{ + "presets": [ + ["../../../../lib", { + "useBuiltIns": "usage", + "modules": false + }] + ] +} diff --git a/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/actual.js b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/actual.js new file mode 100644 index 0000000000..369046bb15 --- /dev/null +++ b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/actual.js @@ -0,0 +1,8 @@ +var arrayInstance = []; +var inclidesStr = "includes"; +var findStr = "find"; + +// Allow instance methods be assigned to variables. +arrayInstance[inclidesStr](); // include +externalVar[findStr]; // include + diff --git a/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/expected.js b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/expected.js new file mode 100644 index 0000000000..d233016daf --- /dev/null +++ b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/expected.js @@ -0,0 +1,10 @@ +import "@babel/polyfill/lib/core-js/modules/es6.array.find"; +import "@babel/polyfill/lib/core-js/modules/es7.array.includes"; +var arrayInstance = []; +var inclidesStr = "includes"; +var findStr = "find"; // Allow instance methods be assigned to variables. + +arrayInstance[inclidesStr](); // include + +externalVar[findStr]; // include + diff --git a/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/options.json b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/options.json new file mode 100644 index 0000000000..fa0e9434e2 --- /dev/null +++ b/experimental/babel-preset-env/test/fixtures/preset-options-add-used-built-ins/builtins-used-evaluated-instance-methods/options.json @@ -0,0 +1,8 @@ +{ + "presets": [ + ["../../../../lib", { + "useBuiltIns": "usage", + "modules": false + }] + ] +}