Skip to content

Commit

Permalink
Merge pull request #1994 from alexlamsl/harmony-v3.0.11
Browse files Browse the repository at this point in the history
Merging from master for 3.0.11
  • Loading branch information
alexlamsl authored May 23, 2017
2 parents 7bcb442 + 37e549f commit 075b648
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 45 deletions.
84 changes: 70 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ a double dash to prevent input files being used as option arguments:
`url` If specified, path to the source map to append in
`//# sourceMappingURL`.
--stats Display operations run time on STDERR.
--toplevel Compress and/or mangle variables in toplevel scope.
--toplevel Compress and/or mangle variables in top level scope.
--verbose Print diagnostic messages.
--warn Print warning messages.
--wrap <name> Embed everything in a big function, making the
Expand Down Expand Up @@ -199,7 +199,7 @@ Example:
To enable the mangler you need to pass `--mangle` (`-m`). The following
(comma-separated) options are supported:

- `toplevel` — mangle names declared in the toplevel scope (disabled by
- `toplevel` — mangle names declared in the top level scope (disabled by
default).

- `eval` — mangle names visible in scopes where `eval` or `with` are used
Expand Down Expand Up @@ -298,24 +298,28 @@ like this:
var UglifyJS = require("uglify-es");
```

There is a single high level minification function, `minify(code, options)`, which will
performs all the steps in a configurable manner.
Example:
There is a single high level function, **`minify(code, options)`**,
which will perform all minification [phases](#minify-options) in a configurable
manner. By default `minify()` will enable the options [`compress`](#compress-options)
and [`mangle`](#mangle-options). Example:
```javascript
var code = "function add(first, second) { return first + second; }";
var result = UglifyJS.minify(code);
console.log(result.error); // runtime error, or `undefined` if no error
console.log(result.code); // minified output: function add(n,d){return n+d}
```

You can also compress multiple files:
You can `minify` more than one JavaScript file at a time by using an object
for the first argument where the keys are file names and the values are source
code:
```javascript
var code = {
"file1.js": "function add(first, second) { return first + second; }",
"file2.js": "console.log(add(1 + 2, 3 + 4));"
};
var result = UglifyJS.minify(code);
console.log(result.code); // function add(d,n){return d+n}console.log(add(3,7));
console.log(result.code);
// function add(d,n){return d+n}console.log(add(3,7));
```

The `toplevel` option:
Expand All @@ -326,7 +330,33 @@ var code = {
};
var options = { toplevel: true };
var result = UglifyJS.minify(code, options);
console.log(result.code); // console.log(function(n,o){return n+o}(3,7));
console.log(result.code);
// console.log(function(n,o){return n+o}(3,7));
```

An example of a combination of `minify()` options:
```javascript
var code = {
"file1.js": "function add(first, second) { return first + second; }",
"file2.js": "console.log(add(1 + 2, 3 + 4));"
};
var options = {
toplevel: true,
compress: {
global_defs: {
"@console.log": "alert"
},
passes: 2
},
output: {
beautify: false,
preamble: "/* uglified */"
}
};
var result = UglifyJS.minify(code, options);
console.log(result.code);
// /* uglified */
// alert(10);"
```

To produce warnings:
Expand All @@ -345,7 +375,7 @@ var result = UglifyJS.minify({"foo.js" : "if (0) else console.log(1);"});
console.log(JSON.stringify(result.error));
// {"message":"Unexpected token: keyword (else)","filename":"foo.js","line":1,"col":7,"pos":7}
```
Note: unlike `[email protected]`, the `3.x` API does not throw errors. To
Note: unlike `[email protected]`, the `3.x` API does not throw errors. To
achieve a similar effect one could do the following:
```javascript
var result = UglifyJS.minify(code, options);
Expand All @@ -354,7 +384,7 @@ if (result.error) throw result.error;

## Minify options

- `warnings` (default `false`) — pass `true` to return compressor warnings
- `warnings` (default `false`) — pass `true` to return compressor warnings
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.

- `parse` (default `{}`) — pass an object if you wish to specify some
Expand Down Expand Up @@ -518,7 +548,7 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
assignments do not count as references unless set to `"keep_assign"`)

- `toplevel` -- drop unreferenced functions (`"funcs"`) and/or variables (`"vars"`)
in the toplevel scope (`false` by default, `true` to drop both unreferenced
in the top level scope (`false` by default, `true` to drop both unreferenced
functions and variables)

- `top_retain` -- prevent specific toplevel functions and variables from `unused`
Expand All @@ -536,7 +566,7 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
and `x = something(), x` into `x = something()`

- `collapse_vars` -- Collapse single-use non-constant variables - side
- `collapse_vars` -- Collapse single-use non-constant variables - side
effects permitting.

- `reduce_vars` -- Improve optimization on variables assigned with and
Expand Down Expand Up @@ -598,7 +628,7 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u

- `reserved` - pass an array of identifiers that should be excluded from mangling

- `toplevel` — mangle names declared in the toplevel scope (disabled by
- `toplevel` — mangle names declared in the top level scope (disabled by
default).

- `eval` — mangle names visible in scopes where eval or with are used
Expand Down Expand Up @@ -783,7 +813,7 @@ You can also use conditional compilation via the programmatic API. With the diff
property name is `global_defs` and is a compressor property:

```javascript
var result = uglifyJS.minify(fs.readFileSync("input.js", "utf8"), {
var result = UglifyJS.minify(fs.readFileSync("input.js", "utf8"), {
compress: {
dead_code: true,
global_defs: {
Expand All @@ -793,6 +823,32 @@ var result = uglifyJS.minify(fs.readFileSync("input.js", "utf8"), {
});
```

To replace an identifier with an arbitrary non-constant expression it is
necessary to prefix the `global_defs` key with `"@"` to instruct UglifyJS
to parse the value as an expression:
```javascript
UglifyJS.minify("alert('hello');", {
compress: {
global_defs: {
"@alert": "console.log"
}
}
}).code;
// returns: 'console.log("hello");'
```

Otherwise it would be replaced as string literal:
```javascript
UglifyJS.minify("alert('hello');", {
compress: {
global_defs: {
"alert": "console.log"
}
}
}).code;
// returns: '"console.log"("hello");'
```

### Using native Uglify AST with `minify()`
```javascript
// example: parse only, produce native Uglify AST
Expand Down
11 changes: 11 additions & 0 deletions lib/compress.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ function Compressor(options, false_by_default) {
unused : !false_by_default,
warnings : false,
}, true);
var global_defs = this.options["global_defs"];
if (typeof global_defs == "object") for (var key in global_defs) {
if (/^@/.test(key) && HOP(global_defs, key)) {
var ast = parse(global_defs[key]);
if (ast.body.length == 1 && ast.body[0] instanceof AST_SimpleStatement) {
global_defs[key.slice(1)] = ast.body[0].body;
} else throw new Error(string_template("Can't handle expression: {value}", {
value: global_defs[key]
}));
}
}
var pure_funcs = this.options["pure_funcs"];
if (typeof pure_funcs == "function") {
this.pure_funcs = pure_funcs;
Expand Down
69 changes: 50 additions & 19 deletions lib/output.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,43 @@ function OutputStream(options) {
var might_need_semicolon = false;
var might_add_newline = 0;
var last = "";
var mapping_token, mapping_name, mappings = options.source_map && [];

var do_add_mapping = mappings ? function() {
mappings.forEach(function(mapping) {
try {
options.source_map.add(
mapping.token.file,
mapping.line, mapping.col,
mapping.token.line, mapping.token.col,
!mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name
);
} catch(ex) {
AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
file: mapping.token.file,
line: mapping.token.line,
col: mapping.token.col,
cline: mapping.line,
ccol: mapping.col,
name: mapping.name || ""
})
}
});
mappings = [];
} : noop;

var ensure_line_len = options.max_line_len ? function() {
if (current_col > options.max_line_len) {
if (might_add_newline) {
var left = OUTPUT.slice(0, might_add_newline);
var right = OUTPUT.slice(might_add_newline);
if (mappings) {
var delta = right.length - current_col;
mappings.forEach(function(mapping) {
mapping.line++;
mapping.col += delta;
});
}
OUTPUT = left + "\n" + right;
current_line++;
current_pos++;
Expand All @@ -227,7 +258,10 @@ function OutputStream(options) {
AST_Node.warn("Output exceeds {max_line_len} characters", options);
}
}
might_add_newline = 0;
if (might_add_newline) {
might_add_newline = 0;
do_add_mapping();
}
} : noop;

var requireSemicolonChars = makePredicate("( [ + * / - , .");
Expand Down Expand Up @@ -287,6 +321,18 @@ function OutputStream(options) {
}
might_need_space = false;
}

if (mapping_token) {
mappings.push({
token: mapping_token,
name: mapping_name,
line: current_line,
col: current_col
});
mapping_token = false;
if (!might_add_newline) do_add_mapping();
}

OUTPUT += str;
current_pos += str.length;
var a = str.split(/\r?\n/), n = a.length - 1;
Expand Down Expand Up @@ -385,24 +431,9 @@ function OutputStream(options) {
space();
};

var add_mapping = options.source_map ? function(token, name) {
try {
if (token) options.source_map.add(
token.file || "?",
current_line, current_col,
token.line, token.col,
(!name && token.type == "name") ? token.value : name
);
} catch(ex) {
AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
file: token.file,
line: token.line,
col: token.col,
cline: current_line,
ccol: current_col,
name: name || ""
})
}
var add_mapping = mappings ? function(token, name) {
mapping_token = token;
mapping_name = name;
} : noop;

function get() {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"author": "Mihai Bazon <[email protected]> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.0.10",
"version": "3.0.11",
"engines": {
"node": ">=0.8.0"
},
Expand Down
14 changes: 14 additions & 0 deletions test/compress/global_defs.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,17 @@ issue_1801: {
console.log(!0);
}
}

issue_1986: {
options = {
global_defs: {
"@alert": "console.log",
},
}
input: {
alert(42);
}
expect: {
console.log(42);
}
}
5 changes: 5 additions & 0 deletions test/input/issue-505/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function test(callback) {
'aaaaaaaaaaaaaaaa';
callback(err, data);
callback(err, data);
}
5 changes: 5 additions & 0 deletions test/input/issue-505/output.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/input/issue-520/output.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions test/mocha/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe("bin/uglifyjs", function () {
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");
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=\n");
done();
});
});
Expand Down Expand Up @@ -175,7 +175,7 @@ describe("bin/uglifyjs", function () {

assert.strictEqual(stdout, [
"var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxHQUFJQSxLQUFNLFdBQ04sUUFBU0MsS0FBS0QsS0FDVixNQUFPQSxLQUdYLE1BQU9DIn0=",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=",
"",
].join("\n"));
assert.strictEqual(stderr, "WARN: inline source map not found\n");
Expand Down Expand Up @@ -529,7 +529,7 @@ describe("bin/uglifyjs", function () {

assert.strictEqual(stdout, [
'"use strict";var foo=function foo(x){return"foo "+x};console.log(foo("bar"));',
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmpzIl0sIm5hbWVzIjpbImZvbyIsIngiLCJjb25zb2xlIiwibG9nIl0sIm1hcHBpbmdzIjoiWUFBQSxJQUFJQSxLQUFNLFFBQU5BLEtBQU1DLEdBQUEsTUFBSyxPQUFTQSxFQUN4QkMsU0FBUUMsSUFBSUgsSUFBSSJ9",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmpzIl0sIm5hbWVzIjpbImZvbyIsIngiLCJjb25zb2xlIiwibG9nIl0sIm1hcHBpbmdzIjoiYUFBQSxJQUFJQSxJQUFNLFNBQU5BLElBQU1DLEdBQUEsTUFBSyxPQUFTQSxHQUN4QkMsUUFBUUMsSUFBSUgsSUFBSSJ9",
""
].join("\n"));
done();
Expand Down
Loading

0 comments on commit 075b648

Please sign in to comment.