[Pkg-javascript-commits] [uglifyjs] 01/04: New upstream version 2.7.4

Praveen Arimbrathodiyil praveen at moszumanska.debian.org
Sun Nov 27 08:26:29 UTC 2016


This is an automated email from the git hooks/post-receive script.

praveen pushed a commit to branch master
in repository uglifyjs.

commit ae2e82d0b2da14e4f5a3744621a611d2f7eca946
Author: Praveen Arimbrathodiyil <praveen at debian.org>
Date:   Sun Nov 27 13:23:26 2016 +0530

    New upstream version 2.7.4
---
 README.md                       |  19 +++-
 bin/uglifyjs                    |  55 +++++-----
 lib/compress.js                 |  39 +++++--
 lib/output.js                   |  74 ++++++++++---
 lib/scope.js                    |  18 +--
 package.json                    |   2 +-
 test/compress/asm.js            |   4 +-
 test/compress/assignment.js     | 238 ++++++++++++++++++++++++++++++++++++++++
 test/compress/issue-1275.js     |  49 +++++++++
 test/compress/reduce_vars.js    | 171 +++++++++++++++++++++++++++++
 test/compress/typeof.js         |  22 ++++
 test/compress/wrap_iife.js      |  48 ++++++++
 test/input/comments/filter.js   |   3 +
 test/input/issue-1323/sample.js |   7 ++
 test/mocha/arguments.js         |   8 ++
 test/mocha/cli.js               |  55 +++++++++-
 test/mocha/comment-filter.js    |  20 ++++
 test/mocha/minify.js            |  19 ++++
 tools/node.js                   |  14 ++-
 19 files changed, 788 insertions(+), 77 deletions(-)

diff --git a/README.md b/README.md
index 4f5b21a..789219d 100644
--- a/README.md
+++ b/README.md
@@ -62,6 +62,7 @@ The available options are:
   --source-map-include-sources  Pass this flag if you want to include the
                                 content of source files in the source map as
                                 sourcesContent property.
+  --source-map-inline           Write base64-encoded source map to the end of js output.
   --in-source-map               Input source map, useful if you're compressing
                                 JS that was generated from some other original
                                 code.
@@ -97,8 +98,8 @@ The available options are:
                                 "@preserve". You can optionally pass one of the
                                 following arguments to this flag:
                                 - "all" to keep all comments
-                                - a valid JS regexp (needs to start with a
-                                slash) to keep only comments that match.
+                                - a valid JS RegExp like `/foo/` or `/^!/` to
+                                keep only matching comments.
                                 Note that currently not *all* comments can be
                                 kept when compression is on, because of dead
                                 code removal or cascading statements into
@@ -348,6 +349,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
 - `collapse_vars` -- default `false`. Collapse single-use `var` and `const`
   definitions when possible.
 
+- `reduce_vars` -- default `false`. Improve optimization on variables assigned
+  with and used as constant values.
+
 - `warnings` -- display warnings when dropping unreachable code or unused
   declarations etc.
 
@@ -638,7 +642,9 @@ var result = UglifyJS.minify({"file1.js": "var a = function () {};"}, {
 
 Note that the source map is not saved in a file, it's just returned in
 `result.map`.  The value passed for `outSourceMap` is only used to set the
-`file` attribute in the source map (see [the spec][sm-spec]).
+`file` attribute in the source map (see [the spec][sm-spec]). You can set 
+option `sourceMapInline` to be `true` and source map will be appended to 
+code.
 
 You can also specify sourceRoot property to be included in source map:
 ```javascript
@@ -849,8 +855,11 @@ which we care about here are `source_map` and `comments`.
 #### Keeping comments in the output
 
 In order to keep certain comments in the output you need to pass the
-`comments` option.  Pass a RegExp or a function.  If you pass a RegExp, only
-those comments whose body matches the regexp will be kept.  Note that body
+`comments` option.  Pass a RegExp (as string starting and closing with `/`
+or pass a RegExp object), a boolean or a function.  Stringified options
+`all` and `some` can be passed too, where `some` behaves like it's cli
+equivalent `--comments` without passing a value. If you pass a RegExp,
+only those comments whose body matches the RegExp will be kept.  Note that body
 means without the initial `//` or `/*`.  If you pass a function, it will be
 called for every comment in the tree and will receive two arguments: the
 node that the comment is attached to, and the comment token itself.
diff --git a/bin/uglifyjs b/bin/uglifyjs
index 3f0c825..ce2e941 100755
--- a/bin/uglifyjs
+++ b/bin/uglifyjs
@@ -23,6 +23,7 @@ mangling you need to use `-c` and `-m`.\
     .describe("source-map", "Specify an output file where to generate source map.")
     .describe("source-map-root", "The path to the original source to be included in the source map.")
     .describe("source-map-url", "The path to the source map to be added in //# sourceMappingURL.  Defaults to the value passed with --source-map.")
+    .describe("source-map-inline", "Write base64-encoded source map to the end of js output.  Disabled by default")
     .describe("source-map-include-sources", "Pass this flag if you want to include the content of source files in the source map as sourcesContent property.")
     .describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
     .describe("screw-ie8", "Do not support Internet Explorer 6-8 quirks. This flag is enabled by default.")
@@ -46,7 +47,7 @@ Use -c with no argument to use the default compression options.")
 By default this works like Google Closure, keeping JSDoc-style comments that contain \"@license\" or \"@preserve\". \
 You can optionally pass one of the following arguments to this flag:\n\
 - \"all\" to keep all comments\n\
-- a valid JS regexp (needs to start with a slash) to keep only comments that match.\n\
+- a valid JS RegExp like `/foo/`or `/^!/` to keep only matching comments.\n\
 \
 Note that currently not *all* comments can be kept when compression is on, \
 because of dead code removal or cascading statements into sequences.")
@@ -76,6 +77,7 @@ You need to pass an argument to this option to specify the name that your module
     .describe("name-cache", "File to hold mangled names mappings")
     .describe("pure-funcs", "List of functions that can be safely removed if their return value is not used")
     .describe("dump-spidermonkey-ast", "Dump SpiderMonkey AST to stdout.")
+    .describe("wrap-iife", "Wrap IIFEs in parenthesis. Note: this disables the negate_iife compression option")
 
     .alias("p", "prefix")
     .alias("o", "output")
@@ -112,6 +114,7 @@ You need to pass an argument to this option to specify the name that your module
     .array("pure-funcs")
 
     .boolean("expr")
+    .boolean("source-map-inline")
     .boolean("source-map-include-sources")
     .boolean("screw-ie8")
     .boolean("support-ie8")
@@ -130,6 +133,7 @@ You need to pass an argument to this option to specify the name that your module
     .boolean("bare-returns")
     .boolean("keep-fnames")
     .boolean("reserve-domprops")
+    .boolean("wrap-iife")
 
     .wrap(80)
 
@@ -247,28 +251,18 @@ if (ARGS.keep_fnames) {
     if (MANGLE) MANGLE.keep_fnames = true;
 }
 
+if (ARGS.wrap_iife) {
+    if (COMPRESS) COMPRESS.negate_iife = false;
+    OUTPUT_OPTIONS.wrap_iife = true;
+}
+
 if (BEAUTIFY)
     UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
 
-if (ARGS.comments != null) {
-    if (/^\/.*\/[a-zA-Z]*$/.test(ARGS.comments)) {
-        try {
-            OUTPUT_OPTIONS.comments = extractRegex(ARGS.comments);
-        } catch (e) {
-            print_error("ERROR: Invalid --comments: " + e.message);
-        }
-    } else if (ARGS.comments == "all") {
-        OUTPUT_OPTIONS.comments = true;
-    } else {
-        OUTPUT_OPTIONS.comments = function(node, comment) {
-            var text = comment.value;
-            var type = comment.type;
-            if (type == "comment2") {
-                // multiline comment
-                return /@preserve|@license|@cc_on/i.test(text);
-            }
-        }
-    }
+if (ARGS.comments === "") {
+    OUTPUT_OPTIONS.comments = "some";
+} else {
+    OUTPUT_OPTIONS.comments = ARGS.comments;
 }
 
 var files = ARGS._.slice();
@@ -317,7 +311,7 @@ var TOPLEVEL = null;
 var P_RELATIVE = ARGS.p && ARGS.p == "relative";
 var SOURCES_CONTENT = {};
 
-var SOURCE_MAP = ARGS.source_map ? UglifyJS.SourceMap({
+var SOURCE_MAP = (ARGS.source_map || ARGS.source_map_inline) ? UglifyJS.SourceMap({
     file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE,
     root: ARGS.source_map_root,
     orig: ORIG_MAP,
@@ -482,13 +476,18 @@ async.eachLimit(files, 1, function (file, cb) {
         output = output.get();
 
         if (SOURCE_MAP) {
-            fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
-            var source_map_url = ARGS.source_map_url || (
-                P_RELATIVE
-                    ? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map)
-                    : ARGS.source_map
-            );
-            output += "\n//# sourceMappingURL=" + source_map_url;
+            if (ARGS.source_map_inline) {
+                var base64_string = new Buffer(SOURCE_MAP.toString()).toString('base64');
+                output += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + base64_string;
+            } else {
+                fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
+                var source_map_url = ARGS.source_map_url || (
+                    P_RELATIVE
+                        ? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map)
+                        : ARGS.source_map
+                );
+                output += "\n//# sourceMappingURL=" + source_map_url;
+            }
         }
 
         if (OUTPUT_FILE) {
diff --git a/lib/compress.js b/lib/compress.js
index f8d9d32..1845717 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -67,6 +67,7 @@ function Compressor(options, false_by_default) {
         if_return     : !false_by_default,
         join_vars     : !false_by_default,
         collapse_vars : false,
+        reduce_vars   : false,
         cascade       : !false_by_default,
         side_effects  : !false_by_default,
         pure_getters  : false,
@@ -1107,7 +1108,7 @@ merge(Compressor.prototype, {
             this._evaluating = true;
             try {
                 var d = this.definition();
-                if (d && d.constant && d.init) {
+                if (d && (d.constant || compressor.option("reduce_vars") && !d.modified) && d.init) {
                     return ev(d.init, compressor);
                 }
             } finally {
@@ -2313,6 +2314,12 @@ merge(Compressor.prototype, {
                 // typeof always returns a non-empty string, thus it's
                 // always true in booleans
                 compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
+                if (self.expression.has_side_effects(compressor)) {
+                    return make_node(AST_Seq, self, {
+                        car: self.expression,
+                        cdr: make_node(AST_True, self)
+                    });
+                }
                 return make_node(AST_True, self);
             }
             if (e instanceof AST_Binary && self.operator == "!") {
@@ -2499,8 +2506,8 @@ merge(Compressor.prototype, {
           case "+":
             var ll = self.left.evaluate(compressor);
             var rr = self.right.evaluate(compressor);
-            if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1]) ||
-                (rr.length > 1 && rr[0] instanceof AST_String && rr[1])) {
+            if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1] && !self.right.has_side_effects(compressor)) ||
+                (rr.length > 1 && rr[0] instanceof AST_String && rr[1] && !self.left.has_side_effects(compressor))) {
                 compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
                 return make_node(AST_True, self);
             }
@@ -2655,16 +2662,26 @@ merge(Compressor.prototype, {
     });
 
     var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
+    var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
     OPT(AST_Assign, function(self, compressor){
         self = self.lift_sequences(compressor);
-        if (self.operator == "="
-            && self.left instanceof AST_SymbolRef
-            && self.right instanceof AST_Binary
-            && self.right.left instanceof AST_SymbolRef
-            && self.right.left.name == self.left.name
-            && member(self.right.operator, ASSIGN_OPS)) {
-            self.operator = self.right.operator + "=";
-            self.right = self.right.right;
+        if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
+            // x = expr1 OP expr2
+            if (self.right.left instanceof AST_SymbolRef
+                && self.right.left.name == self.left.name
+                && member(self.right.operator, ASSIGN_OPS)) {
+                // x = x - 2  --->  x -= 2
+                self.operator = self.right.operator + "=";
+                self.right = self.right.right;
+            }
+            else if (self.right.right instanceof AST_SymbolRef
+                && self.right.right.name == self.left.name
+                && member(self.right.operator, ASSIGN_OPS_COMMUTATIVE)
+                && !self.right.left.has_side_effects(compressor)) {
+                // x = 2 & x  --->  x &= 2
+                self.operator = self.right.operator + "=";
+                self.right = self.right.left;
+            }
         }
         return self;
     });
diff --git a/lib/output.js b/lib/output.js
index 801f751..63a78c6 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -67,9 +67,54 @@ function OutputStream(options) {
         screw_ie8        : true,
         preamble         : null,
         quote_style      : 0,
-        keep_quoted_props: false
+        keep_quoted_props: false,
+        wrap_iife        : false,
     }, true);
 
+    // Convert comment option to RegExp if neccessary and set up comments filter
+    if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) {
+        var regex_pos = options.comments.lastIndexOf("/");
+        options.comments = new RegExp(
+            options.comments.substr(1, regex_pos - 1),
+            options.comments.substr(regex_pos + 1)
+        );
+    }
+    if (options.comments instanceof RegExp) {
+        options.comments = (function(f) {
+            return function(comment) {
+                return comment.type == "comment5" || f.test(comment.value);
+            }
+        })(options.comments);
+    }
+    else if (typeof options.comments === "function") {
+        options.comments = (function(f) {
+            return function(comment) {
+                return comment.type == "comment5" || f(this, comment);
+            }
+        })(options.comments);
+    }
+    else if (options.comments === "some") {
+        options.comments = function(comment) {
+            var text = comment.value;
+            var type = comment.type;
+            if (type == "comment2") {
+                // multiline comment
+                return /@preserve|@license|@cc_on/i.test(text);
+            }
+            return type == "comment5";
+        }
+    }
+    else if (options.comments){ // NOTE includes "all" option
+        options.comments = function() {
+            return true;
+        }
+    } else {
+        // Falsy case, so reject all comments, except shebangs
+        options.comments = function(comment) {
+            return comment.type == "comment5";
+        }
+    }
+
     var indentation = 0;
     var current_col = 0;
     var current_line = 1;
@@ -435,7 +480,7 @@ function OutputStream(options) {
 
     AST_Node.DEFMETHOD("add_comments", function(output){
         if (output._readonly) return;
-        var c = output.option("comments"), self = this;
+        var self = this;
         var start = self.start;
         if (start && !start._comments_dumped) {
             start._comments_dumped = true;
@@ -458,19 +503,7 @@ function OutputStream(options) {
                 }));
             }
 
-            if (!c) {
-                comments = comments.filter(function(comment) {
-                    return comment.type == "comment5";
-                });
-            } else if (c.test) {
-                comments = comments.filter(function(comment){
-                    return comment.type == "comment5" || c.test(comment.value);
-                });
-            } else if (typeof c == "function") {
-                comments = comments.filter(function(comment){
-                    return comment.type == "comment5" || c(self, comment);
-                });
-            }
+            comments = comments.filter(output.option("comments"), self);
 
             // Keep single line comments after nlb, after nlb
             if (!output.option("beautify") && comments.length > 0 &&
@@ -521,7 +554,16 @@ function OutputStream(options) {
     // a function expression needs parens around it when it's provably
     // the first token to appear in a statement.
     PARENS(AST_Function, function(output){
-        return first_in_statement(output);
+        if (first_in_statement(output)) {
+            return true;
+        }
+
+        if (output.option('wrap_iife')) {
+            var p = output.parent();
+            return p instanceof AST_Call && p.expression === this;
+        }
+
+        return false;
     });
 
     // same goes for an object literal, because otherwise it would be
diff --git a/lib/scope.js b/lib/scope.js
index 606a5a2..4943b56 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -197,12 +197,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
         }
         if (node instanceof AST_SymbolRef) {
             var name = node.name;
-            if (name == "eval" && tw.parent() instanceof AST_Call) {
+            var parent = tw.parent();
+            if (name == "eval" && parent instanceof AST_Call) {
                 for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
                     s.uses_eval = true;
                 }
             }
             var sym = node.scope.find_variable(name);
+            if (node.scope instanceof AST_Lambda && name == "arguments") {
+                node.scope.uses_arguments = true;
+            }
             if (!sym) {
                 var g;
                 if (globals.has(name)) {
@@ -213,12 +217,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
                     g.global = true;
                     globals.set(name, g);
                 }
-                node.thedef = g;
-                if (func && name == "arguments") {
-                    func.uses_arguments = true;
-                }
-            } else {
-                node.thedef = sym;
+                sym = g;
+            }
+            node.thedef = sym;
+            if (parent instanceof AST_Unary && (parent.operator === '++' || parent.operator === '--')
+             || parent instanceof AST_Assign && parent.left === node) {
+                sym.modified = true;
             }
             node.reference();
             return true;
diff --git a/package.json b/package.json
index 4c3a807..2741f02 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
   "homepage": "http://lisperator.net/uglifyjs",
   "author": "Mihai Bazon <mihai.bazon at gmail.com> (http://lisperator.net/)",
   "license": "BSD-2-Clause",
-  "version": "2.7.3",
+  "version": "2.7.4",
   "engines": {
     "node": ">=0.8.0"
   },
diff --git a/test/compress/asm.js b/test/compress/asm.js
index f392e78..9b22732 100644
--- a/test/compress/asm.js
+++ b/test/compress/asm.js
@@ -90,13 +90,13 @@ asm_mixed: {
         }
         function no_asm_GeometricMean(stdlib, foreign, buffer) {
             function logSum(start, end) {
-                start = 0 | start, end = 0 | end;
+                start |= 0, end |= 0;
                 var sum = 0, p = 0, q = 0;
                 for (p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0) sum += +log(values[p >> 3]);
                 return +sum;
             }
             function geometricMean(start, end) {
-                return start = 0 | start, end = 0 | end, +exp(+logSum(start, end) / +(end - start | 0));
+                return start |= 0, end |= 0, +exp(+logSum(start, end) / +(end - start | 0));
             }
             var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer);
             return { geometricMean: geometricMean };
diff --git a/test/compress/assignment.js b/test/compress/assignment.js
new file mode 100644
index 0000000..903380a
--- /dev/null
+++ b/test/compress/assignment.js
@@ -0,0 +1,238 @@
+op_equals_left_local_var: {
+    options = {
+        evaluate: true,
+    }
+    input: {
+        var x;
+
+        x = x +   3;
+        x = x -   3;
+        x = x /   3;
+        x = x *   3;
+        x = x >>  3;
+        x = x <<  3;
+        x = x >>> 3;
+        x = x |   3;
+        x = x ^   3;
+        x = x %   3;
+        x = x &   3;
+
+        x = x +   g();
+        x = x -   g();
+        x = x /   g();
+        x = x *   g();
+        x = x >>  g();
+        x = x <<  g();
+        x = x >>> g();
+        x = x |   g();
+        x = x ^   g();
+        x = x %   g();
+        x = x &   g();
+    }
+    expect: {
+        var x;
+
+        x   += 3;
+        x   -= 3;
+        x   /= 3;
+        x   *= 3;
+        x  >>= 3;
+        x  <<= 3;
+        x >>>= 3;
+        x   |= 3;
+        x   ^= 3;
+        x   %= 3;
+        x   &= 3;
+
+        x   += g();
+        x   -= g();
+        x   /= g();
+        x   *= g();
+        x  >>= g();
+        x  <<= g();
+        x >>>= g();
+        x   |= g();
+        x   ^= g();
+        x   %= g();
+        x   &= g();
+    }
+}
+
+op_equals_right_local_var: {
+    options = {
+        evaluate: true,
+    }
+    input: {
+        var x;
+
+        x = (x -= 2) ^ x;
+
+        x = 3 +   x;
+        x = 3 -   x;
+        x = 3 /   x;
+        x = 3 *   x;
+        x = 3 >>  x;
+        x = 3 <<  x;
+        x = 3 >>> x;
+        x = 3 |   x;
+        x = 3 ^   x;
+        x = 3 %   x;
+        x = 3 &   x;
+
+        x = g() +   x;
+        x = g() -   x;
+        x = g() /   x;
+        x = g() *   x;
+        x = g() >>  x;
+        x = g() <<  x;
+        x = g() >>> x;
+        x = g() |   x;
+        x = g() ^   x;
+        x = g() %   x;
+        x = g() &   x;
+    }
+    expect: {
+        var x;
+
+        x = (x -= 2) ^ x;
+
+        x = 3 + x;
+        x = 3 - x;
+        x = 3 / x;
+        x *= 3;
+        x = 3 >> x;
+        x = 3 << x;
+        x = 3 >>> x;
+        x |= 3;
+        x ^= 3;
+        x = 3 % x;
+        x &= 3;
+
+        x = g() +   x;
+        x = g() -   x;
+        x = g() /   x;
+        x = g() *   x;
+        x = g() >>  x;
+        x = g() <<  x;
+        x = g() >>> x;
+        x = g() |   x;
+        x = g() ^   x;
+        x = g() %   x;
+        x = g() &   x;
+    }
+}
+op_equals_left_global_var: {
+    options = {
+        evaluate: true,
+    }
+    input: {
+        x = x +   3;
+        x = x -   3;
+        x = x /   3;
+        x = x *   3;
+        x = x >>  3;
+        x = x <<  3;
+        x = x >>> 3;
+        x = x |   3;
+        x = x ^   3;
+        x = x %   3;
+        x = x &   3;
+
+        x = x +   g();
+        x = x -   g();
+        x = x /   g();
+        x = x *   g();
+        x = x >>  g();
+        x = x <<  g();
+        x = x >>> g();
+        x = x |   g();
+        x = x ^   g();
+        x = x %   g();
+        x = x &   g();
+    }
+    expect: {
+        x   += 3;
+        x   -= 3;
+        x   /= 3;
+        x   *= 3;
+        x  >>= 3;
+        x  <<= 3;
+        x >>>= 3;
+        x   |= 3;
+        x   ^= 3;
+        x   %= 3;
+        x   &= 3;
+
+        x   += g();
+        x   -= g();
+        x   /= g();
+        x   *= g();
+        x  >>= g();
+        x  <<= g();
+        x >>>= g();
+        x   |= g();
+        x   ^= g();
+        x   %= g();
+        x   &= g();
+    }
+}
+
+op_equals_right_global_var: {
+    options = {
+        evaluate: true,
+    }
+    input: {
+        x = (x -= 2) ^ x;
+
+        x = 3 +   x;
+        x = 3 -   x;
+        x = 3 /   x;
+        x = 3 *   x;
+        x = 3 >>  x;
+        x = 3 <<  x;
+        x = 3 >>> x;
+        x = 3 |   x;
+        x = 3 ^   x;
+        x = 3 %   x;
+        x = 3 &   x;
+
+        x = g() +   x;
+        x = g() -   x;
+        x = g() /   x;
+        x = g() *   x;
+        x = g() >>  x;
+        x = g() <<  x;
+        x = g() >>> x;
+        x = g() |   x;
+        x = g() ^   x;
+        x = g() %   x;
+        x = g() &   x;
+    }
+    expect: {
+        x = (x -= 2) ^ x;
+
+        x = 3 +   x;
+        x = 3 -   x;
+        x = 3 /   x;
+        x *= 3;
+        x = 3 >>  x;
+        x = 3 <<  x;
+        x = 3 >>> x;
+        x |= 3;
+        x ^= 3;
+        x = 3 %   x;
+        x &= 3;
+
+        x = g() +   x;
+        x = g() -   x;
+        x = g() /   x;
+        x = g() *   x;
+        x = g() >>  x;
+        x = g() <<  x;
+        x = g() >>> x;
+        x = g() |   x;
+        x = g() ^   x;
+        x = g() %   x;
+        x = g() &   x;
+    }
+}
diff --git a/test/compress/issue-1275.js b/test/compress/issue-1275.js
new file mode 100644
index 0000000..e88e284
--- /dev/null
+++ b/test/compress/issue-1275.js
@@ -0,0 +1,49 @@
+string_plus_optimization: {
+    options = {
+        side_effects  : true,
+        evaluate      : true,
+        conditionals  : true,
+        comparisons   : true,
+        dead_code     : true,
+        booleans      : true,
+        unused        : true,
+        if_return     : true,
+        join_vars     : true,
+        cascade       : true,
+        hoist_funs    : true,
+    };
+    input: {
+        function foo(anything) {
+            function throwing_function() {
+                throw "nope";
+            }
+            try {
+                console.log('0' + throwing_function() ? "yes" : "no");
+            } catch (ex) {
+                console.log(ex);
+            }
+            console.log('0' + anything ? "yes" : "no");
+            console.log(anything + '0' ? "Yes" : "No");
+            console.log('' + anything);
+            console.log(anything + '');
+        }
+        foo();
+    }
+    expect: {
+        function foo(anything) {
+            function throwing_function() {
+                throw "nope";
+            }
+            try {
+                console.log('0' + throwing_function() ? "yes" : "no");
+            } catch (ex) {
+                console.log(ex);
+            }
+            console.log("yes");
+            console.log("Yes");
+            console.log('' + anything);
+            console.log(anything + '');
+        }
+        foo();
+    }
+}
diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js
new file mode 100644
index 0000000..a1d0501
--- /dev/null
+++ b/test/compress/reduce_vars.js
@@ -0,0 +1,171 @@
+reduce_vars: {
+    options = {
+        conditionals  : true,
+        evaluate      : true,
+        global_defs   : {
+            C : 0
+        },
+        reduce_vars   : true,
+        unused        : true
+    }
+    input: {
+        var A = 1;
+        (function f0() {
+            var a = 2;
+            console.log(a - 5);
+            console.log(A - 5);
+        })();
+        (function f1() {
+            var a = 2;
+            console.log(a - 5);
+            eval("console.log(a);");
+        })();
+        (function f2(eval) {
+            var a = 2;
+            console.log(a - 5);
+            eval("console.log(a);");
+        })(eval);
+        (function f3() {
+            var b = typeof C !== "undefined";
+            var c = 4;
+            if (b) {
+                return 'yes';
+            } else {
+                return 'no';
+            }
+        })();
+        console.log(A + 1);
+    }
+    expect: {
+        var A = 1;
+        (function() {
+            console.log(-3);
+            console.log(-4);
+        })();
+        (function f1() {
+            var a = 2;
+            console.log(-3);
+            eval("console.log(a);");
+        })();
+        (function f2(eval) {
+            var a = 2;
+            console.log(-3);
+            eval("console.log(a);");
+        })(eval);
+        (function() {
+            return "yes";
+        })();
+        console.log(2);
+    }
+}
+
+modified: {
+    options = {
+        conditionals  : true,
+        evaluate      : true,
+        reduce_vars   : true,
+        unused        : true
+    }
+    input: {
+        function f0() {
+            var a = 1, b = 2;
+            b++;
+            console.log(a + 1);
+            console.log(b + 1);
+        }
+
+        function f1() {
+            var a = 1, b = 2;
+            --b;
+            console.log(a + 1);
+            console.log(b + 1);
+        }
+
+        function f2() {
+            var a = 1, b = 2, c = 3;
+            b = c;
+            console.log(a + b);
+            console.log(b + c);
+            console.log(a + c);
+            console.log(a + b + c);
+        }
+
+        function f3() {
+            var a = 1, b = 2, c = 3;
+            b *= c;
+            console.log(a + b);
+            console.log(b + c);
+            console.log(a + c);
+            console.log(a + b + c);
+        }
+
+        function f4() {
+            var a = 1, b = 2, c = 3;
+            if (a) {
+                b = c;
+            } else {
+                c = b;
+            }
+            console.log(a + b);
+            console.log(b + c);
+            // TODO: as "modified" is determined in "figure_out_scope",
+            // even "passes" wouldn't improve this any further
+            console.log(a + c);
+            console.log(a + b + c);
+        }
+
+        function f5(a) {
+            B = a;
+            console.log(A ? 'yes' : 'no');
+            console.log(B ? 'yes' : 'no');
+        }
+    }
+    expect: {
+        function f0() {
+            var b = 2;
+            b++;
+            console.log(2);
+            console.log(b + 1);
+        }
+
+        function f1() {
+            var b = 2;
+            --b;
+            console.log(2);
+            console.log(b + 1);
+        }
+
+        function f2() {
+            var a = 1, b = 2, c = 3;
+            b = c;
+            console.log(a + b);
+            console.log(b + c);
+            console.log(4);
+            console.log(a + b + c);
+        }
+
+        function f3() {
+            var a = 1, b = 2, c = 3;
+            b *= c;
+            console.log(a + b);
+            console.log(b + c);
+            console.log(4);
+            console.log(a + b + c);
+        }
+
+        function f4() {
+            var a = 1, b = 2, c = 3;
+            b = c;
+            console.log(a + b);
+            console.log(b + c);
+            console.log(a + c);
+            console.log(a + b + c);
+        }
+
+        function f5(a) {
+            B = a;
+            console.log(A ? 'yes' : 'no');
+            console.log(B ? 'yes' : 'no');
+        }
+   }
+}
\ No newline at end of file
diff --git a/test/compress/typeof.js b/test/compress/typeof.js
index cefdd43..fb39157 100644
--- a/test/compress/typeof.js
+++ b/test/compress/typeof.js
@@ -23,3 +23,25 @@ typeof_evaluation: {
         h='undefined';
     }
 }
+
+typeof_in_boolean_context: {
+    options = {
+        booleans     : true,
+        evaluate     : true,
+        conditionals : true,
+    };
+    input: {
+        function f1(x) { return typeof x ? "yes" : "no"; }
+        function f2() { return typeof g()? "Yes" : "No"; }
+        typeof 0 ? foo() : bar();
+        !typeof console.log(1);
+        var a = !typeof console.log(2);
+    }
+    expect: {
+        function f1(x) { return "yes"; }
+        function f2() { return g(), "Yes"; }
+        foo();
+        !(console.log(1), !0);
+        var a = !(console.log(2), !0);
+    }
+}
diff --git a/test/compress/wrap_iife.js b/test/compress/wrap_iife.js
new file mode 100644
index 0000000..5c45853
--- /dev/null
+++ b/test/compress/wrap_iife.js
@@ -0,0 +1,48 @@
+wrap_iife: {
+    options = {
+        negate_iife: false,
+    }
+    beautify = {
+        wrap_iife: true,
+    }
+    input: {
+        (function() {
+            return function() {
+                console.log('test')
+            };
+        })()();
+    }
+    expect_exact: '(function(){return function(){console.log("test")}})()();'
+}
+
+wrap_iife_in_expression: {
+    options = {
+        negate_iife: false,
+    }
+    beautify = {
+        wrap_iife: true,
+    }
+    input: {
+        foo = (function () {
+            return bar();
+        })();
+    }
+    expect_exact: 'foo=(function(){return bar()})();'
+}
+
+wrap_iife_in_return_call: {
+    options = {
+        negate_iife: false,
+    }
+    beautify = {
+        wrap_iife: true,
+    }
+    input: {
+        (function() {
+            return (function() {
+                console.log('test')
+            })();
+        })()();
+    }
+    expect_exact: '(function(){return(function(){console.log("test")})()})()();'
+}
diff --git a/test/input/comments/filter.js b/test/input/comments/filter.js
new file mode 100644
index 0000000..c752080
--- /dev/null
+++ b/test/input/comments/filter.js
@@ -0,0 +1,3 @@
+// foo
+/*@preserve*/
+// bar
diff --git a/test/input/issue-1323/sample.js b/test/input/issue-1323/sample.js
new file mode 100644
index 0000000..ff56acc
--- /dev/null
+++ b/test/input/issue-1323/sample.js
@@ -0,0 +1,7 @@
+var bar = (function () {
+    function foo (bar) {
+        return bar;
+    }
+
+    return foo;
+})();
\ No newline at end of file
diff --git a/test/mocha/arguments.js b/test/mocha/arguments.js
index 089826f..73993a7 100644
--- a/test/mocha/arguments.js
+++ b/test/mocha/arguments.js
@@ -19,4 +19,12 @@ describe("arguments", function() {
             value // Select function as scope
         );
     });
+
+    it("Should recognize when a function uses arguments", function() {
+        var ast = UglifyJS.parse("function a(){function b(){function c(){}; return arguments[0];}}");
+        ast.figure_out_scope();
+        assert.strictEqual(ast.body[0].uses_arguments, false);
+        assert.strictEqual(ast.body[0].body[0].uses_arguments, true);
+        assert.strictEqual(ast.body[0].body[0].body[0].uses_arguments, false);
+    });
 });
\ No newline at end of file
diff --git a/test/mocha/cli.js b/test/mocha/cli.js
index 38b57cd..bebd4d9 100644
--- a/test/mocha/cli.js
+++ b/test/mocha/cli.js
@@ -2,11 +2,11 @@ var assert = require("assert");
 var exec = require("child_process").exec;
 
 describe("bin/uglifyjs", function () {
+    var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
     it("should produce a functional build when using --self", function (done) {
         this.timeout(5000);
 
-        var uglifyjs = '"' + process.argv[0] + '" bin/uglifyjs';
-        var command = uglifyjs + ' --self -cm --wrap WrappedUglifyJS';
+        var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS';
 
         exec(command, function (err, stdout) {
             if (err) throw err;
@@ -19,4 +19,55 @@ describe("bin/uglifyjs", function () {
             done();
         });
     });
+    it("Should be able to filter comments correctly with `--comment all`", function (done) {
+        var command = uglifyjscmd + ' test/input/comments/filter.js --comments all';
+
+        exec(command, function (err, stdout) {
+            if (err) throw err;
+
+            assert.strictEqual(stdout, "// foo\n/*@preserve*/\n// bar\n\n");
+            done();
+        });
+    });
+    it("Should be able to filter comments correctly with `--comment <RegExp>`", function (done) {
+        var command = uglifyjscmd + ' test/input/comments/filter.js --comments /r/';
+
+        exec(command, function (err, stdout) {
+            if (err) throw err;
+
+            assert.strictEqual(stdout, "/*@preserve*/\n// bar\n\n");
+            done();
+        });
+    });
+    it("Should be able to filter comments correctly with just `--comment`", function (done) {
+        var command = uglifyjscmd + ' test/input/comments/filter.js --comments';
+
+        exec(command, function (err, stdout) {
+            if (err) throw err;
+
+            assert.strictEqual(stdout, "/*@preserve*/\n\n");
+            done();
+        });
+    });
+    it("Should append source map to output when using --source-map-inline", function (done) {
+       var command = uglifyjscmd + ' test/input/issue-1323/sample.js --source-map-inline';
+
+       exec(command, function (err, stdout) {
+           if (err) throw err;
+
+           assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" + 
+               "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxHQUFJQSxLQUFNLFdBQ04sUUFBU0MsS0FBS0QsS0FDVixNQUFPQSxLQUdYLE1BQU9DIn0=\n");
+           done();
+       });
+    });
+    it("should not append source map to output when not using --source-map-inline", function (done) {
+        var command = uglifyjscmd + ' test/input/issue-1323/sample.js';
+
+        exec(command, function (err, stdout) {
+            if (err) throw err;
+
+            assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n");
+            done();
+        });
+    });
 });
diff --git a/test/mocha/comment-filter.js b/test/mocha/comment-filter.js
index ea2ec2e..7916275 100644
--- a/test/mocha/comment-filter.js
+++ b/test/mocha/comment-filter.js
@@ -7,6 +7,16 @@ describe("comment filters", function() {
         assert.strictEqual(ast.print_to_string({comments: /^!/}), "/*!test1*/\n//!test3\n//!test6\n//!test8\n");
     });
 
+    it("Should be able to filter comments with the 'all' option", function() {
+        var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\n<!--test5\n<!--!test6\n-->test7\n-->!test8");
+        assert.strictEqual(ast.print_to_string({comments: "all"}), "/*!test1*/\n/*test2*/\n//!test3\n//test4\n//test5\n//!test6\n//test7\n//!test8\n");
+    });
+
+    it("Should be able to filter commments with the 'some' option", function() {
+        var ast = UglifyJS.parse("// foo\n/*@preserve*/\n// bar\n/*@license*/\n//@license with the wrong comment type\n/*@cc_on something*/");
+        assert.strictEqual(ast.print_to_string({comments: "some"}), "/*@preserve*/\n/*@license*/\n/*@cc_on something*/\n");
+    });
+
     it("Should be able to filter comments by passing a function", function() {
         var ast = UglifyJS.parse("/*TEST 123*/\n//An other comment\n//8 chars.");
         var f = function(node, comment) {
@@ -16,6 +26,11 @@ describe("comment filters", function() {
         assert.strictEqual(ast.print_to_string({comments: f}), "/*TEST 123*/\n//8 chars.\n");
     });
 
+    it("Should be able to filter comments by passing regex in string format", function() {
+        var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\n<!--test5\n<!--!test6\n-->test7\n-->!test8");
+        assert.strictEqual(ast.print_to_string({comments: "/^!/"}), "/*!test1*/\n//!test3\n//!test6\n//!test8\n");
+    });
+
     it("Should be able to get the comment and comment type when using a function", function() {
         var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\n<!--test5\n<!--!test6\n-->test7\n-->!test8");
         var f = function(node, comment) {
@@ -42,4 +57,9 @@ describe("comment filters", function() {
 
         assert.strictEqual(ast.print_to_string({comments: f}), "#!Random comment\n//test1\n/*test2*/\n");
     });
+
+    it("Should never be able to filter comment5 when using 'some' as filter", function() {
+        var ast = UglifyJS.parse("#!foo\n//foo\n/*@preserve*/\n/* please hide me */");
+        assert.strictEqual(ast.print_to_string({comments: "some"}), "#!foo\n/*@preserve*/\n");
+    });
 });
diff --git a/test/mocha/minify.js b/test/mocha/minify.js
index 2adbadc..ce5e849 100644
--- a/test/mocha/minify.js
+++ b/test/mocha/minify.js
@@ -75,4 +75,23 @@ describe("minify", function() {
                 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
         });
     });
+
+    describe("sourceMapInline", function() {
+        it("should append source map to output js when sourceMapInline is enabled", function() {
+            var result = Uglify.minify('var a = function(foo) { return foo; };', {
+                fromString: true,
+                sourceMapInline: true
+            });
+            var code = result.code;
+            assert.strictEqual(code, "var a=function(n){return n};\n" +
+                "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIj8iXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsR0FBSUEsR0FBSSxTQUFTQyxHQUFPLE1BQU9BIn0=");
+        });
+        it("should not append source map to output js when sourceMapInline is not enabled", function() {
+            var result = Uglify.minify('var a = function(foo) { return foo; };', {
+                fromString: true
+            });
+            var code = result.code;
+            assert.strictEqual(code, "var a=function(n){return n};");
+        });
+    });
 });
diff --git a/tools/node.js b/tools/node.js
index 6712ccf..a16169b 100644
--- a/tools/node.js
+++ b/tools/node.js
@@ -44,6 +44,7 @@ exports.minify = function(files, options) {
         sourceRoot       : null,
         inSourceMap      : null,
         sourceMapUrl     : null,
+        sourceMapInline  : false,
         fromString       : false,
         warnings         : false,
         mangle           : {},
@@ -117,7 +118,7 @@ exports.minify = function(files, options) {
     if (typeof options.inSourceMap == "string") {
         inMap = JSON.parse(fs.readFileSync(options.inSourceMap, "utf8"));
     }
-    if (options.outSourceMap) {
+    if (options.outSourceMap || options.sourceMapInline) {
         output.source_map = UglifyJS.SourceMap({
             file: options.outSourceMap,
             orig: inMap,
@@ -138,16 +139,19 @@ exports.minify = function(files, options) {
     var stream = UglifyJS.OutputStream(output);
     toplevel.print(stream);
 
-    var mappingUrlPrefix = "\n//# sourceMappingURL=";
-    if (options.outSourceMap && typeof options.outSourceMap === "string" && options.sourceMapUrl !== false) {
-        stream += mappingUrlPrefix + (typeof options.sourceMapUrl === "string" ? options.sourceMapUrl : options.outSourceMap);
-    }
 
     var source_map = output.source_map;
     if (source_map) {
         source_map = source_map + "";
     }
 
+    var mappingUrlPrefix = "\n//# sourceMappingURL=";
+    if (options.sourceMapInline) {
+        stream += mappingUrlPrefix + "data:application/json;charset=utf-8;base64," + new Buffer(source_map).toString("base64");
+    } else if (options.outSourceMap && typeof options.outSourceMap === "string" && options.sourceMapUrl !== false) {
+        stream += mappingUrlPrefix + (typeof options.sourceMapUrl === "string" ? options.sourceMapUrl : options.outSourceMap);
+    }
+
     return {
         code : stream + "",
         map  : source_map

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/uglifyjs.git



More information about the Pkg-javascript-commits mailing list