diff --git a/src/babel/transformation/transformers/es3/member-expression-literals.js b/src/babel/transformation/transformers/es3/member-expression-literals.js index be8c207560..9b6b30bff7 100644 --- a/src/babel/transformation/transformers/es3/member-expression-literals.js +++ b/src/babel/transformation/transformers/es3/member-expression-literals.js @@ -2,11 +2,7 @@ import * as t from "../../../types"; export function MemberExpression(node) { var prop = node.property; - if (node.computed && t.isLiteral(prop) && t.isValidIdentifier(prop.value)) { - // foo["bar"] => foo.bar - node.property = t.identifier(prop.value); - node.computed = false; - } else if (!node.computed && t.isIdentifier(prop) && !t.isValidIdentifier(prop.name)) { + if (!node.computed && t.isIdentifier(prop) && !t.isValidIdentifier(prop.name)) { // foo.default -> foo["default"] node.property = t.literal(prop.name); node.computed = true; diff --git a/src/babel/transformation/transformers/es3/property-literals.js b/src/babel/transformation/transformers/es3/property-literals.js index 407b33df78..0c9b26a9cd 100644 --- a/src/babel/transformation/transformers/es3/property-literals.js +++ b/src/babel/transformation/transformers/es3/property-literals.js @@ -2,11 +2,7 @@ import * as t from "../../../types"; export function Property(node) { var key = node.key; - if (t.isLiteral(key) && t.isValidIdentifier(key.value)) { - // "foo": "bar" -> foo: "bar" - node.key = t.identifier(key.value); - node.computed = false; - } else if (!node.computed && t.isIdentifier(key) && !t.isValidIdentifier(key.name)) { + if (!node.computed && t.isIdentifier(key) && !t.isValidIdentifier(key.name)) { // default: "bar" -> "default": "bar" node.key = t.literal(key.name); } diff --git a/src/babel/transformation/transformers/es6/properties.computed.js b/src/babel/transformation/transformers/es6/properties.computed.js index 5c45893c7b..e846e4d2a6 100644 --- a/src/babel/transformation/transformers/es6/properties.computed.js +++ b/src/babel/transformation/transformers/es6/properties.computed.js @@ -16,27 +16,13 @@ function loose(node, body, objId) { function spec(node, body, objId, initProps, file) { var props = node.properties; - var prop, key; - - // normalize key - - for (var i = 0; i < props.length; i++) { - prop = props[i]; - if (prop.kind !== "init") continue; - - key = prop.key; - - if (!prop.computed && t.isIdentifier(key)) { - prop.key = t.literal(key.name); - } - } // add all non-computed properties and `__proto__` properties to the initializer var broken = false; - for (i = 0; i < props.length; i++) { - prop = props[i]; + for (let i = 0; i < props.length; i++) { + let prop = props[i]; if (prop.computed) { broken = true; @@ -51,24 +37,17 @@ function spec(node, body, objId, initProps, file) { // add a simple assignment for all Symbol member expressions due to symbol polyfill limitations // otherwise use Object.defineProperty - for (i = 0; i < props.length; i++) { - prop = props[i]; + for (let i = 0; i < props.length; i++) { + let prop = props[i]; if (!prop) continue; - key = prop.key; - var bodyNode; - - if (prop.computed && t.isMemberExpression(key) && t.isIdentifier(key.object, { name: "Symbol" })) { - // { [Symbol.iterator]: "foo" } - bodyNode = t.assignmentExpression( - "=", - t.memberExpression(objId, key, true), - prop.value - ); - } else { - bodyNode = t.callExpression(file.addHelper("define-property"), [objId, key, prop.value]); + let key = prop.key; + if (t.isIdentifier(key) && !prop.computed) { + key = t.literal(key.name); } + var bodyNode = t.callExpression(file.addHelper("define-property"), [objId, key, prop.value]); + body.push(t.expressionStatement(bodyNode)); } diff --git a/src/babel/transformation/transformers/index.js b/src/babel/transformation/transformers/index.js index 5abdd146f2..3a2f6c7f7f 100644 --- a/src/babel/transformation/transformers/index.js +++ b/src/babel/transformation/transformers/index.js @@ -113,7 +113,10 @@ export default { "utility.inlineEnvironmentVariables": require("./utility/inline-environment-variables"), "utility.inlineExpressions": require("./utility/inline-expressions"), - "utility.deadCodeElimination": require("./utility/dead-code-elimination"), + + "minification.deadCodeElimination": require("./minification/dead-code-elimination"), + "minification.memberExpressionLiterals": require("./minification/member-expression-literals"), + "minification.propertyLiterals": require("./minification/property-literals"), jscript: require("./other/jscript"), flow: require("./other/flow") diff --git a/src/babel/transformation/transformers/minification/member-expression-literals.js b/src/babel/transformation/transformers/minification/member-expression-literals.js new file mode 100644 index 0000000000..2038c70d4b --- /dev/null +++ b/src/babel/transformation/transformers/minification/member-expression-literals.js @@ -0,0 +1,14 @@ +import * as t from "../../../types"; + +export var metadata = { + optional: true +}; + +export function MemberExpression(node) { + var prop = node.property; + if (node.computed && t.isLiteral(prop) && t.isValidIdentifier(prop.value)) { + // foo["bar"] => foo.bar + node.property = t.identifier(prop.value); + node.computed = false; + } +} diff --git a/src/babel/transformation/transformers/minification/property-literals.js b/src/babel/transformation/transformers/minification/property-literals.js new file mode 100644 index 0000000000..84902d2b94 --- /dev/null +++ b/src/babel/transformation/transformers/minification/property-literals.js @@ -0,0 +1,14 @@ +import * as t from "../../../types"; + +export var metadata = { + optional: true +}; + +export function Property(node) { + var key = node.key; + if (t.isLiteral(key) && t.isValidIdentifier(key.value)) { + // "foo": "bar" -> foo: "bar" + node.key = t.identifier(key.value); + node.computed = false; + } +} diff --git a/src/babel/transformation/transformers/utility/dead-code-elimination.js b/src/babel/transformation/transformers/utility/dead-code-elimination.js deleted file mode 100644 index d5c975f6ac..0000000000 --- a/src/babel/transformation/transformers/utility/dead-code-elimination.js +++ /dev/null @@ -1,120 +0,0 @@ -import * as t from "../../../types"; - -function toStatements(node) { - if (t.isBlockStatement(node)) { - var hasBlockScoped = false; - - for (var i = 0; i < node.body.length; i++) { - var bodyNode = node.body[i]; - if (t.isBlockScoped(bodyNode)) hasBlockScoped = true; - } - - if (!hasBlockScoped) { - return node.body; - } - } - - return node; -} - -export var metadata = { - optional: true -}; - -export function Identifier(node, parent, scope) { - if (!this.isReferenced()) return; - - var binding = scope.getBinding(node.name); - if (!binding || binding.references > 1 || !binding.constant) return; - - var replacement = binding.path.node; - if (t.isVariableDeclarator(replacement)) { - replacement = replacement.init; - } - t.toExpression(replacement); - - scope.removeBinding(node.name); - - binding.path.remove(); - return replacement; -} - -export function FunctionDeclaration(node, parent, scope) { - var bindingInfo = scope.getBinding(node.id.name); - if (bindingInfo && !bindingInfo.referenced) { - this.remove(); - } -} - -export { FunctionDeclaration as ClassDeclaration }; - -export function VariableDeclarator(node, parent, scope) { - if (!t.isIdentifier(node.id) || !scope.isPure(node.init)) return; - FunctionDeclaration.apply(this, arguments); -} - -export function ConditionalExpression(node, parent, scope) { - var evaluateTest = this.get("test").evaluateTruthy(); - if (evaluateTest === true) { - return node.consequent; - } else if (evaluateTest === false) { - return node.alternate; - } -} - -export var IfStatement = { - exit(node, parent, scope) { - var consequent = node.consequent; - var alternate = node.alternate; - var test = node.test; - - var evaluateTest = this.get("test").evaluateTruthy(); - - // we can check if a test will be truthy 100% and if so then we can inline - // the consequent and completely ignore the alternate - // - // if (true) { foo; } -> { foo; } - // if ("foo") { foo; } -> { foo; } - // - - if (evaluateTest === true) { - return toStatements(consequent); - } - - // we can check if a test will be falsy 100% and if so we can inline the - // alternate if there is one and completely remove the consequent - // - // if ("") { bar; } else { foo; } -> { foo; } - // if ("") { bar; } -> - // - - if (evaluateTest === false) { - if (alternate) { - return toStatements(alternate); - } else { - return this.remove(); - } - } - - // remove alternate blocks that are empty - // - // if (foo) { foo; } else {} -> if (foo) { foo; } - // - - if (t.isBlockStatement(alternate) && !alternate.body.length) { - alternate = node.alternate = null; - } - - // if the consequent block is empty turn alternate blocks into a consequent - // and flip the test - // - // if (foo) {} else { bar; } -> if (!foo) { bar; } - // - - if (t.isBlockStatement(consequent) && !consequent.body.length && t.isBlockStatement(alternate) && alternate.body.length) { - node.consequent = node.alternate; - node.alternate = null; - node.test = t.unaryExpression("!", test, true); - } - } -}; diff --git a/test/core/fixtures/transformation/es3/member-expression-literals/actual.js b/test/core/fixtures/transformation/es3/member-expression-literals/actual.js index 736db6e46a..f7138bc87d 100644 --- a/test/core/fixtures/transformation/es3/member-expression-literals/actual.js +++ b/test/core/fixtures/transformation/es3/member-expression-literals/actual.js @@ -1,6 +1,4 @@ -obj["x"] = 2; - test.catch; -test.catch["foo"]; +test.catch.foo; test["catch"]; -test["catch"]["foo"]; +test["catch"].foo; diff --git a/test/core/fixtures/transformation/es3/member-expression-literals/expected.js b/test/core/fixtures/transformation/es3/member-expression-literals/expected.js index d8156cf500..fdd217784a 100644 --- a/test/core/fixtures/transformation/es3/member-expression-literals/expected.js +++ b/test/core/fixtures/transformation/es3/member-expression-literals/expected.js @@ -1,7 +1,5 @@ "use strict"; -obj.x = 2; - test["catch"]; test["catch"].foo; test["catch"]; diff --git a/test/core/fixtures/transformation/es3/property-literals/expected.js b/test/core/fixtures/transformation/es3/property-literals/expected.js index 3c68a81f12..05c1218da3 100644 --- a/test/core/fixtures/transformation/es3/property-literals/expected.js +++ b/test/core/fixtures/transformation/es3/property-literals/expected.js @@ -1,7 +1,7 @@ "use strict"; var obj = { - test: "foob", + "test": "foob", "!@#$": "foob", "33rd": "foob", fooBar: "foob" diff --git a/test/core/fixtures/transformation/es6.properties.computed-loose/two/expected.js b/test/core/fixtures/transformation/es6.properties.computed-loose/two/expected.js index 349f1e881e..4c96e99ac6 100644 --- a/test/core/fixtures/transformation/es6.properties.computed-loose/two/expected.js +++ b/test/core/fixtures/transformation/es6.properties.computed-loose/two/expected.js @@ -2,4 +2,4 @@ var _obj; -var obj = (_obj = {}, _obj.first = "first", _obj.second = "second", _obj); +var obj = (_obj = {}, _obj.first = "first", _obj["second"] = "second", _obj); diff --git a/test/core/fixtures/transformation/es6.properties.computed/ignore-symbol/expected.js b/test/core/fixtures/transformation/es6.properties.computed/ignore-symbol/expected.js index b6290c7e20..683d1d51bf 100644 --- a/test/core/fixtures/transformation/es6.properties.computed/ignore-symbol/expected.js +++ b/test/core/fixtures/transformation/es6.properties.computed/ignore-symbol/expected.js @@ -1,5 +1,3 @@ "use strict"; -var _foo; - -var foo = (_foo = {}, _foo[Symbol.iterator] = "foobar", _foo); +var foo = babelHelpers.defineProperty({}, Symbol.iterator, "foobar"); diff --git a/test/core/fixtures/transformation/minification.member-expression-literals/invalid-identifiers/actual.js b/test/core/fixtures/transformation/minification.member-expression-literals/invalid-identifiers/actual.js new file mode 100644 index 0000000000..235484a7f1 --- /dev/null +++ b/test/core/fixtures/transformation/minification.member-expression-literals/invalid-identifiers/actual.js @@ -0,0 +1,2 @@ +foo["default"]; +foo["import"]; diff --git a/test/core/fixtures/transformation/minification.member-expression-literals/invalid-identifiers/expected.js b/test/core/fixtures/transformation/minification.member-expression-literals/invalid-identifiers/expected.js new file mode 100644 index 0000000000..6e04d07d27 --- /dev/null +++ b/test/core/fixtures/transformation/minification.member-expression-literals/invalid-identifiers/expected.js @@ -0,0 +1,4 @@ +"use strict"; + +foo["default"]; +foo["import"]; diff --git a/test/core/fixtures/transformation/minification.member-expression-literals/options.json b/test/core/fixtures/transformation/minification.member-expression-literals/options.json new file mode 100644 index 0000000000..2396412196 --- /dev/null +++ b/test/core/fixtures/transformation/minification.member-expression-literals/options.json @@ -0,0 +1,3 @@ +{ + "optional": ["minification.memberExpressionLiterals"] +} diff --git a/test/core/fixtures/transformation/minification.member-expression-literals/valid-identifiers/actual.js b/test/core/fixtures/transformation/minification.member-expression-literals/valid-identifiers/actual.js new file mode 100644 index 0000000000..00eedff60a --- /dev/null +++ b/test/core/fixtures/transformation/minification.member-expression-literals/valid-identifiers/actual.js @@ -0,0 +1,4 @@ +foo["bar"]; +foo["foo"]; +foo.bar; +foo.foo; diff --git a/test/core/fixtures/transformation/minification.member-expression-literals/valid-identifiers/expected.js b/test/core/fixtures/transformation/minification.member-expression-literals/valid-identifiers/expected.js new file mode 100644 index 0000000000..baf1f2a692 --- /dev/null +++ b/test/core/fixtures/transformation/minification.member-expression-literals/valid-identifiers/expected.js @@ -0,0 +1,6 @@ +"use strict"; + +foo.bar; +foo.foo; +foo.bar; +foo.foo; diff --git a/test/core/fixtures/transformation/minification.property-literals/invalid-identifiers/actual.js b/test/core/fixtures/transformation/minification.property-literals/invalid-identifiers/actual.js new file mode 100644 index 0000000000..4ba2280c31 --- /dev/null +++ b/test/core/fixtures/transformation/minification.property-literals/invalid-identifiers/actual.js @@ -0,0 +1,4 @@ +({ + "default": null, + "import": null +}); diff --git a/test/core/fixtures/transformation/minification.property-literals/invalid-identifiers/expected.js b/test/core/fixtures/transformation/minification.property-literals/invalid-identifiers/expected.js new file mode 100644 index 0000000000..aef44ca1d0 --- /dev/null +++ b/test/core/fixtures/transformation/minification.property-literals/invalid-identifiers/expected.js @@ -0,0 +1,6 @@ +"use strict"; + +({ + "default": null, + "import": null +}); diff --git a/test/core/fixtures/transformation/minification.property-literals/options.json b/test/core/fixtures/transformation/minification.property-literals/options.json new file mode 100644 index 0000000000..4522dd06b8 --- /dev/null +++ b/test/core/fixtures/transformation/minification.property-literals/options.json @@ -0,0 +1,3 @@ +{ + "optional": ["minification.propertyLiterals"] +} diff --git a/test/core/fixtures/transformation/minification.property-literals/valid-identifiers/actual.js b/test/core/fixtures/transformation/minification.property-literals/valid-identifiers/actual.js new file mode 100644 index 0000000000..b683811396 --- /dev/null +++ b/test/core/fixtures/transformation/minification.property-literals/valid-identifiers/actual.js @@ -0,0 +1,4 @@ +var obj = { + foo: "foo", + "bar": "bar" +}; diff --git a/test/core/fixtures/transformation/minification.property-literals/valid-identifiers/expected.js b/test/core/fixtures/transformation/minification.property-literals/valid-identifiers/expected.js new file mode 100644 index 0000000000..6cdd9c3a41 --- /dev/null +++ b/test/core/fixtures/transformation/minification.property-literals/valid-identifiers/expected.js @@ -0,0 +1,6 @@ +"use strict"; + +var obj = { + foo: "foo", + bar: "bar" +};