From f71e8fd9488b28b92e6897254b7a54cf51471557 Mon Sep 17 00:00:00 2001 From: kzc Date: Wed, 31 May 2017 09:52:43 -0400 Subject: [PATCH 1/5] reformat mangle options section of README (#2036) --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d9a0162c609..b6b52a46def 100644 --- a/README.md +++ b/README.md @@ -680,17 +680,18 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u ## Mangle options -- `reserved` - pass an array of identifiers that should be excluded from mangling +- `reserved` (default `[]`). Pass an array of identifiers that should be + excluded from mangling. Example: `["foo", "bar"]`. -- `toplevel` — mangle names declared in the top level scope (disabled by -default). +- `toplevel` (default `false`). Pass `true` to mangle names declared in the + top level scope. -- `eval` — mangle names visible in scopes where eval or with are used -(disabled by default). +- `keep_fnames` (default `false`). Pass `true` to not mangle function names. + Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames` + [compress option](#compress-options). -- `keep_fnames` -- default `false`. Pass `true` to not mangle -function names. Useful for code relying on `Function.prototype.name`. -See also: the `keep_fnames` [compress option](#compress-options). +- `eval` (default `false`). Pass `true` to mangle names visible in scopes + where `eval` or `with` are used. Examples: From 17e73121fa641c14fd9f4cdd3310bf3e8ec037d0 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Thu, 1 Jun 2017 00:56:28 +0800 Subject: [PATCH 2/5] enhance `unsafe` `evaluate` (#2037) --- lib/compress.js | 25 +++++++++++++++++++++++++ test/compress/evaluate.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/lib/compress.js b/lib/compress.js index 32a4d603110..a928d7b710d 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1665,6 +1665,26 @@ merge(Compressor.prototype, { } throw def; }); + def(AST_Call, function(compressor){ + var exp = this.expression; + if (compressor.option("unsafe") && exp instanceof AST_PropAccess) { + var key = exp.property; + if (key instanceof AST_Node) { + key = ev(key, compressor); + } + var val = ev(exp.expression, compressor); + var fn = val[key]; + if (typeof fn == "function") { + return fn.apply(val, this.args.map(function(arg) { + return ev(arg, compressor); + })); + } + } + throw def; + }); + def(AST_New, function(compressor){ + throw def; + }); })(function(node, func){ node.DEFMETHOD("_eval", func); }); @@ -3144,6 +3164,11 @@ merge(Compressor.prototype, { && is_iife_call(self)) { return self.negate(compressor, true); } + var ev = self.evaluate(compressor); + if (ev !== self) { + ev = make_node_from_constant(ev, self).optimize(compressor); + return best_of(compressor, ev, self); + } return self; }); diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index a1e3d0be5e2..020d7cf3b1f 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -1037,3 +1037,31 @@ issue_1964_2: { } expect_stdout: "b" } + +array_slice_index: { + options = { + evaluate: true, + unsafe: true, + } + input: { + console.log([1,2,3].slice(1)[1]); + } + expect: { + console.log(3); + } + expect_stdout: "3" +} + +string_charCodeAt: { + options = { + evaluate: true, + unsafe: true, + } + input: { + console.log("foo".charCodeAt("bar".length)); + } + expect: { + console.log(NaN); + } + expect_stdout: "NaN" +} From ec095ed647691b3458ec9e65e89ff92d5151abc4 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Thu, 1 Jun 2017 04:33:05 +0800 Subject: [PATCH 3/5] whitelist `unsafe` `evaluate` candidates (#2039) - all arguments may accept constant values - return constant value - free of side effects - available & identical across locales and runtime environments --- lib/compress.js | 43 ++++++++++++++++++++++++++++++++++++--- test/compress/evaluate.js | 6 ++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index a928d7b710d..71cffceeb0b 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1665,6 +1665,44 @@ merge(Compressor.prototype, { } throw def; }); + var object_fns = [ + 'constructor', + 'toString', + 'valueOf', + ]; + var native_fns = { + Array: makePredicate([ + 'indexOf', + 'join', + 'lastIndexOf', + 'slice', + ].concat(object_fns)), + Boolean: makePredicate(object_fns), + Number: makePredicate([ + 'toExponential', + 'toFixed', + 'toPrecision', + ].concat(object_fns)), + RegExp: makePredicate([ + 'test', + ].concat(object_fns)), + String: makePredicate([ + 'charAt', + 'charCodeAt', + 'concat', + 'indexOf', + 'italics', + 'lastIndexOf', + 'match', + 'replace', + 'search', + 'slice', + 'split', + 'substr', + 'substring', + 'trim', + ].concat(object_fns)), + }; def(AST_Call, function(compressor){ var exp = this.expression; if (compressor.option("unsafe") && exp instanceof AST_PropAccess) { @@ -1673,9 +1711,8 @@ merge(Compressor.prototype, { key = ev(key, compressor); } var val = ev(exp.expression, compressor); - var fn = val[key]; - if (typeof fn == "function") { - return fn.apply(val, this.args.map(function(arg) { + if ((val && native_fns[val.constructor.name] || return_false)(key)) { + return val[key].apply(val, this.args.map(function(arg) { return ev(arg, compressor); })); } diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index 020d7cf3b1f..99245d0d78b 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -780,13 +780,15 @@ unsafe_charAt_noop: { input: { console.log( s.charAt(0), - "string".charAt(x) + "string".charAt(x), + (typeof x).charAt() ); } expect: { console.log( s.charAt(0), - "string".charAt(x) + "string".charAt(x), + (typeof x)[0] ); } } From bac14ba881729fa573effa1fb4afdb76a7c5662e Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Thu, 1 Jun 2017 18:11:16 +0800 Subject: [PATCH 4/5] fix non-identifier getter/setter name (#2041) fixes #2040 --- lib/output.js | 25 ++++++++++++++----------- test/compress/properties.js | 17 +++++++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/lib/output.js b/lib/output.js index e9765f7c564..2fb7441b77d 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1234,9 +1234,8 @@ function OutputStream(options) { }); else output.print("{}"); }); - DEFPRINT(AST_ObjectKeyVal, function(self, output){ - var key = self.key; - var quote = self.quote; + + function print_property_name(key, quote, output) { if (output.option("quote_keys")) { output.print_string(key + ""); } else if ((typeof key == "number" @@ -1253,20 +1252,24 @@ function OutputStream(options) { } else { output.print_string(key, quote); } + } + + DEFPRINT(AST_ObjectKeyVal, function(self, output){ + print_property_name(self.key, self.quote, output); output.colon(); self.value.print(output); }); - DEFPRINT(AST_ObjectSetter, function(self, output){ - output.print("set"); + AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, output) { + output.print(type); output.space(); - self.key.print(output); - self.value._do_print(output, true); + print_property_name(this.key.name, this.quote, output); + this.value._do_print(output, true); + }); + DEFPRINT(AST_ObjectSetter, function(self, output){ + self._print_getter_setter("set", output); }); DEFPRINT(AST_ObjectGetter, function(self, output){ - output.print("get"); - output.space(); - self.key.print(output); - self.value._do_print(output, true); + self._print_getter_setter("get", output); }); DEFPRINT(AST_Symbol, function(self, output){ var def = self.definition(); diff --git a/test/compress/properties.js b/test/compress/properties.js index 3e06dc1e000..d49b9ea47d6 100644 --- a/test/compress/properties.js +++ b/test/compress/properties.js @@ -555,3 +555,20 @@ native_prototype: { "".indexOf.call(e, "bar"); } } + +issue_2040: { + input: { + var a = 1; + var b = { + get "a-b"() { + return a; + }, + set "a-b"(c) { + a = c; + } + }; + console.log(b["a-b"], b["a-b"] = 2, b["a-b"]); + } + expect_exact: 'var a=1;var b={get"a-b"(){return a},set"a-b"(c){a=c}};console.log(b["a-b"],b["a-b"]=2,b["a-b"]);' + expect_stdout: "1 2 2" +} From 4377e932ca2112178b6f2733084ddd668fbf0e51 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Thu, 1 Jun 2017 18:12:38 +0800 Subject: [PATCH 5/5] v3.0.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 253c61d8451..e1d04fdbdac 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "homepage": "http://lisperator.net/uglifyjs", "author": "Mihai Bazon (http://lisperator.net/)", "license": "BSD-2-Clause", - "version": "3.0.14", + "version": "3.0.15", "engines": { "node": ">=0.8.0" },