split up es3.xLiterals transformers - fixes #1415

This commit is contained in:
Sebastian McKenzie
2015-05-01 23:13:30 +01:00
parent c28415c38a
commit 90a1c81d30
22 changed files with 90 additions and 172 deletions

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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));
}

View File

@@ -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")

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
};