aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--lib/compress.js28
-rw-r--r--test/compress/arguments.js119
-rw-r--r--test/compress/hoist_props.js12
4 files changed, 155 insertions, 7 deletions
diff --git a/README.md b/README.md
index e754e0bc..47fabea1 100644
--- a/README.md
+++ b/README.md
@@ -598,6 +598,9 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
## Compress options
+- `arguments` (default: `true`) -- replace `arguments[index]` with function
+ parameter name whenever possible.
+
- `booleans` (default: `true`) -- various optimizations for boolean context,
for example `!!a ? b : c → a ? b : c`
diff --git a/lib/compress.js b/lib/compress.js
index 97e4c11d..a63a5c66 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -48,6 +48,7 @@ function Compressor(options, false_by_default) {
return new Compressor(options, false_by_default);
TreeTransformer.call(this, this.before, this.after);
this.options = defaults(options, {
+ arguments : !false_by_default,
booleans : !false_by_default,
collapse_vars : !false_by_default,
comparisons : !false_by_default,
@@ -3551,7 +3552,7 @@ merge(Compressor.prototype, {
AST_Scope.DEFMETHOD("make_var_name", function(prefix) {
var var_names = this.var_names();
- prefix = prefix.replace(/[^a-z_$]+/ig, "_");
+ prefix = prefix.replace(/(?:^[^a-z_$]|[^a-z0-9_$])/ig, "_");
var name = prefix;
for (var i = 0; var_names[name]; i++) name = prefix + "$" + i;
var_names[name] = true;
@@ -5954,6 +5955,31 @@ merge(Compressor.prototype, {
});
}
}
+ var fn;
+ if (compressor.option("arguments")
+ && expr instanceof AST_SymbolRef
+ && expr.name == "arguments"
+ && expr.definition().orig.length == 1
+ && (fn = expr.scope) instanceof AST_Lambda
+ && prop instanceof AST_Number) {
+ var index = prop.getValue();
+ var argname = fn.argnames[index];
+ if (!argname && !compressor.option("keep_fargs")) {
+ while (index >= fn.argnames.length) {
+ argname = make_node(AST_SymbolFunarg, fn, {
+ name: fn.make_var_name("argument_" + fn.argnames.length),
+ scope: fn
+ });
+ fn.argnames.push(argname);
+ fn.enclosed.push(fn.def_variable(argname));
+ }
+ }
+ if (argname) {
+ var sym = make_node(AST_SymbolRef, self, argname);
+ sym.reference({});
+ return sym;
+ }
+ }
var ev = self.evaluate(compressor);
if (ev !== self) {
ev = make_node_from_constant(ev, self).optimize(compressor);
diff --git a/test/compress/arguments.js b/test/compress/arguments.js
new file mode 100644
index 00000000..e8cc690f
--- /dev/null
+++ b/test/compress/arguments.js
@@ -0,0 +1,119 @@
+replace_index: {
+ options = {
+ arguments: true,
+ evaluate: true,
+ properties: true,
+ }
+ input: {
+ console.log(arguments && arguments[0]);
+ (function() {
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ (function(a, b) {
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ (function(arguments) {
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ (function() {
+ var arguments;
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ }
+ expect: {
+ console.log(arguments && arguments[0]);
+ (function() {
+ console.log(arguments[1], arguments[1], arguments.foo);
+ })("bar", 42);
+ (function(a, b) {
+ console.log(b, b, arguments.foo);
+ })("bar", 42);
+ (function(arguments) {
+ console.log(arguments[1], arguments[1], arguments.foo);
+ })("bar", 42);
+ (function() {
+ var arguments;
+ console.log(arguments[1], arguments[1], arguments.foo);
+ })("bar", 42);
+ }
+ expect_stdout: [
+ "undefined",
+ "42 42 undefined",
+ "42 42 undefined",
+ "a a undefined",
+ "42 42 undefined",
+ ]
+}
+
+replace_index_keep_fargs: {
+ options = {
+ arguments: true,
+ evaluate: true,
+ keep_fargs: false,
+ properties: true,
+ }
+ input: {
+ console.log(arguments && arguments[0]);
+ (function() {
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ (function(a, b) {
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ (function(arguments) {
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ (function() {
+ var arguments;
+ console.log(arguments[1], arguments["1"], arguments["foo"]);
+ })("bar", 42);
+ }
+ expect: {
+ console.log(arguments && arguments[0]);
+ (function(argument_0, argument_1) {
+ console.log(argument_1, argument_1, arguments.foo);
+ })("bar", 42);
+ (function(a, b) {
+ console.log(b, b, arguments.foo);
+ })("bar", 42);
+ (function(arguments) {
+ console.log(arguments[1], arguments[1], arguments.foo);
+ })("bar", 42);
+ (function() {
+ var arguments;
+ console.log(arguments[1], arguments[1], arguments.foo);
+ })("bar", 42);
+ }
+ expect_stdout: [
+ "undefined",
+ "42 42 undefined",
+ "42 42 undefined",
+ "a a undefined",
+ "42 42 undefined",
+ ]
+}
+
+modified: {
+ options = {
+ arguments: true,
+ }
+ input: {
+ (function(a, b) {
+ var c = arguments[0];
+ var d = arguments[1];
+ a = "foo";
+ b++;
+ console.log(a, b, c, d, arguments[0], arguments[1]);
+ })("bar", 42);
+ }
+ expect: {
+ (function(a, b) {
+ var c = a;
+ var d = b;
+ a = "foo";
+ b++;
+ console.log(a, b, c, d, a, b);
+ })("bar", 42);
+ }
+ expect_stdout: "foo 43 bar 42 foo 43"
+}
diff --git a/test/compress/hoist_props.js b/test/compress/hoist_props.js
index 03867f78..26887af2 100644
--- a/test/compress/hoist_props.js
+++ b/test/compress/hoist_props.js
@@ -239,14 +239,14 @@ name_collision_2: {
input: {
var o = {
p: 1,
- 0: function(x) {
+ "+": function(x) {
return x;
},
- 1: function(x) {
+ "-": function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
- console.log(o.p === o.p, o[0](4), o[1](5), o__$0, o__$1);
+ console.log(o.p === o.p, o["+"](4), o["-"](5), o__$0, o__$1);
}
expect: {
var o_p = 1,
@@ -273,14 +273,14 @@ name_collision_3: {
input: {
var o = {
p: 1,
- 0: function(x) {
+ "+": function(x) {
return x;
},
- 1: function(x) {
+ "-": function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
- console.log(o.p === o.p, o[0](4), o[1](5));
+ console.log(o.p === o.p, o["+"](4), o["-"](5));
}
expect: {
var o_p = 1,