Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
557b3e412f | ||
|
|
8d74f34373 | ||
|
|
266ddd9639 | ||
|
|
e51c6ba380 | ||
|
|
6389e52305 | ||
|
|
e05510f3bc | ||
|
|
fc9804b909 | ||
|
|
4761d07e0b | ||
|
|
0111497fc9 | ||
|
|
7d8dea3b26 | ||
|
|
25fc02743a | ||
|
|
0bd8053524 | ||
|
|
1a78bbcd23 | ||
|
|
8430123e9d | ||
|
|
614db97cca | ||
|
|
d854523783 |
19
README.md
19
README.md
@@ -62,6 +62,7 @@ The available options are:
|
|||||||
--source-map-include-sources Pass this flag if you want to include the
|
--source-map-include-sources Pass this flag if you want to include the
|
||||||
content of source files in the source map as
|
content of source files in the source map as
|
||||||
sourcesContent property.
|
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
|
--in-source-map Input source map, useful if you're compressing
|
||||||
JS that was generated from some other original
|
JS that was generated from some other original
|
||||||
code.
|
code.
|
||||||
@@ -97,8 +98,8 @@ The available options are:
|
|||||||
"@preserve". You can optionally pass one of the
|
"@preserve". You can optionally pass one of the
|
||||||
following arguments to this flag:
|
following arguments to this flag:
|
||||||
- "all" to keep all comments
|
- "all" to keep all comments
|
||||||
- a valid JS regexp (needs to start with a
|
- a valid JS RegExp like `/foo/` or `/^!/` to
|
||||||
slash) to keep only comments that match.
|
keep only matching comments.
|
||||||
Note that currently not *all* comments can be
|
Note that currently not *all* comments can be
|
||||||
kept when compression is on, because of dead
|
kept when compression is on, because of dead
|
||||||
code removal or cascading statements into
|
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`
|
- `collapse_vars` -- default `false`. Collapse single-use `var` and `const`
|
||||||
definitions when possible.
|
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
|
- `warnings` -- display warnings when dropping unreachable code or unused
|
||||||
declarations etc.
|
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
|
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
|
`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:
|
You can also specify sourceRoot property to be included in source map:
|
||||||
```javascript
|
```javascript
|
||||||
@@ -849,8 +855,11 @@ which we care about here are `source_map` and `comments`.
|
|||||||
#### Keeping comments in the output
|
#### Keeping comments in the output
|
||||||
|
|
||||||
In order to keep certain comments in the output you need to pass the
|
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
|
`comments` option. Pass a RegExp (as string starting and closing with `/`
|
||||||
those comments whose body matches the regexp will be kept. Note that body
|
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
|
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
|
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.
|
node that the comment is attached to, and the comment token itself.
|
||||||
|
|||||||
55
bin/uglifyjs
55
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", "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-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-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("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("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.")
|
.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\". \
|
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\
|
You can optionally pass one of the following arguments to this flag:\n\
|
||||||
- \"all\" to keep all comments\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, \
|
Note that currently not *all* comments can be kept when compression is on, \
|
||||||
because of dead code removal or cascading statements into sequences.")
|
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("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("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("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("p", "prefix")
|
||||||
.alias("o", "output")
|
.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")
|
.array("pure-funcs")
|
||||||
|
|
||||||
.boolean("expr")
|
.boolean("expr")
|
||||||
|
.boolean("source-map-inline")
|
||||||
.boolean("source-map-include-sources")
|
.boolean("source-map-include-sources")
|
||||||
.boolean("screw-ie8")
|
.boolean("screw-ie8")
|
||||||
.boolean("support-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("bare-returns")
|
||||||
.boolean("keep-fnames")
|
.boolean("keep-fnames")
|
||||||
.boolean("reserve-domprops")
|
.boolean("reserve-domprops")
|
||||||
|
.boolean("wrap-iife")
|
||||||
|
|
||||||
.wrap(80)
|
.wrap(80)
|
||||||
|
|
||||||
@@ -247,28 +251,18 @@ if (ARGS.keep_fnames) {
|
|||||||
if (MANGLE) MANGLE.keep_fnames = true;
|
if (MANGLE) MANGLE.keep_fnames = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ARGS.wrap_iife) {
|
||||||
|
if (COMPRESS) COMPRESS.negate_iife = false;
|
||||||
|
OUTPUT_OPTIONS.wrap_iife = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (BEAUTIFY)
|
if (BEAUTIFY)
|
||||||
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
|
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
|
||||||
|
|
||||||
if (ARGS.comments != null) {
|
if (ARGS.comments === "") {
|
||||||
if (/^\/.*\/[a-zA-Z]*$/.test(ARGS.comments)) {
|
OUTPUT_OPTIONS.comments = "some";
|
||||||
try {
|
} else {
|
||||||
OUTPUT_OPTIONS.comments = extractRegex(ARGS.comments);
|
OUTPUT_OPTIONS.comments = 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var files = ARGS._.slice();
|
var files = ARGS._.slice();
|
||||||
@@ -317,7 +311,7 @@ var TOPLEVEL = null;
|
|||||||
var P_RELATIVE = ARGS.p && ARGS.p == "relative";
|
var P_RELATIVE = ARGS.p && ARGS.p == "relative";
|
||||||
var SOURCES_CONTENT = {};
|
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,
|
file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE,
|
||||||
root: ARGS.source_map_root,
|
root: ARGS.source_map_root,
|
||||||
orig: ORIG_MAP,
|
orig: ORIG_MAP,
|
||||||
@@ -482,13 +476,18 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
output = output.get();
|
output = output.get();
|
||||||
|
|
||||||
if (SOURCE_MAP) {
|
if (SOURCE_MAP) {
|
||||||
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
|
if (ARGS.source_map_inline) {
|
||||||
var source_map_url = ARGS.source_map_url || (
|
var base64_string = new Buffer(SOURCE_MAP.toString()).toString('base64');
|
||||||
P_RELATIVE
|
output += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + base64_string;
|
||||||
? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map)
|
} else {
|
||||||
: ARGS.source_map
|
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
|
||||||
);
|
var source_map_url = ARGS.source_map_url || (
|
||||||
output += "\n//# sourceMappingURL=" + 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) {
|
if (OUTPUT_FILE) {
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ function Compressor(options, false_by_default) {
|
|||||||
if_return : !false_by_default,
|
if_return : !false_by_default,
|
||||||
join_vars : !false_by_default,
|
join_vars : !false_by_default,
|
||||||
collapse_vars : false,
|
collapse_vars : false,
|
||||||
|
reduce_vars : false,
|
||||||
cascade : !false_by_default,
|
cascade : !false_by_default,
|
||||||
side_effects : !false_by_default,
|
side_effects : !false_by_default,
|
||||||
pure_getters : false,
|
pure_getters : false,
|
||||||
@@ -831,6 +832,13 @@ merge(Compressor.prototype, {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function negate_iifes(statements, compressor) {
|
function negate_iifes(statements, compressor) {
|
||||||
|
function is_iife_call(node) {
|
||||||
|
if (node instanceof AST_Call) {
|
||||||
|
return node.expression instanceof AST_Function || is_iife_call(node.expression);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
statements.forEach(function(stat){
|
statements.forEach(function(stat){
|
||||||
if (stat instanceof AST_SimpleStatement) {
|
if (stat instanceof AST_SimpleStatement) {
|
||||||
stat.body = (function transform(thing) {
|
stat.body = (function transform(thing) {
|
||||||
@@ -838,7 +846,7 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_New) {
|
if (node instanceof AST_New) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Call && node.expression instanceof AST_Function) {
|
if (is_iife_call(node)) {
|
||||||
return make_node(AST_UnaryPrefix, node, {
|
return make_node(AST_UnaryPrefix, node, {
|
||||||
operator: "!",
|
operator: "!",
|
||||||
expression: node
|
expression: node
|
||||||
@@ -1100,7 +1108,7 @@ merge(Compressor.prototype, {
|
|||||||
this._evaluating = true;
|
this._evaluating = true;
|
||||||
try {
|
try {
|
||||||
var d = this.definition();
|
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);
|
return ev(d.init, compressor);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -2306,6 +2314,12 @@ merge(Compressor.prototype, {
|
|||||||
// typeof always returns a non-empty string, thus it's
|
// typeof always returns a non-empty string, thus it's
|
||||||
// always true in booleans
|
// always true in booleans
|
||||||
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
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);
|
return make_node(AST_True, self);
|
||||||
}
|
}
|
||||||
if (e instanceof AST_Binary && self.operator == "!") {
|
if (e instanceof AST_Binary && self.operator == "!") {
|
||||||
@@ -2492,8 +2506,8 @@ merge(Compressor.prototype, {
|
|||||||
case "+":
|
case "+":
|
||||||
var ll = self.left.evaluate(compressor);
|
var ll = self.left.evaluate(compressor);
|
||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if ((ll.length > 1 && ll[0] instanceof AST_String && ll[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])) {
|
(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);
|
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_True, self);
|
return make_node(AST_True, self);
|
||||||
}
|
}
|
||||||
@@ -2648,16 +2662,26 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
||||||
|
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
|
||||||
OPT(AST_Assign, function(self, compressor){
|
OPT(AST_Assign, function(self, compressor){
|
||||||
self = self.lift_sequences(compressor);
|
self = self.lift_sequences(compressor);
|
||||||
if (self.operator == "="
|
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
|
||||||
&& self.left instanceof AST_SymbolRef
|
// x = expr1 OP expr2
|
||||||
&& self.right instanceof AST_Binary
|
if (self.right.left instanceof AST_SymbolRef
|
||||||
&& self.right.left instanceof AST_SymbolRef
|
&& self.right.left.name == self.left.name
|
||||||
&& self.right.left.name == self.left.name
|
&& member(self.right.operator, ASSIGN_OPS)) {
|
||||||
&& member(self.right.operator, ASSIGN_OPS)) {
|
// x = x - 2 ---> x -= 2
|
||||||
self.operator = self.right.operator + "=";
|
self.operator = self.right.operator + "=";
|
||||||
self.right = self.right.right;
|
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;
|
return self;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -67,9 +67,54 @@ function OutputStream(options) {
|
|||||||
screw_ie8 : true,
|
screw_ie8 : true,
|
||||||
preamble : null,
|
preamble : null,
|
||||||
quote_style : 0,
|
quote_style : 0,
|
||||||
keep_quoted_props: false
|
keep_quoted_props: false,
|
||||||
|
wrap_iife : false,
|
||||||
}, true);
|
}, 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 indentation = 0;
|
||||||
var current_col = 0;
|
var current_col = 0;
|
||||||
var current_line = 1;
|
var current_line = 1;
|
||||||
@@ -435,7 +480,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
AST_Node.DEFMETHOD("add_comments", function(output){
|
AST_Node.DEFMETHOD("add_comments", function(output){
|
||||||
if (output._readonly) return;
|
if (output._readonly) return;
|
||||||
var c = output.option("comments"), self = this;
|
var self = this;
|
||||||
var start = self.start;
|
var start = self.start;
|
||||||
if (start && !start._comments_dumped) {
|
if (start && !start._comments_dumped) {
|
||||||
start._comments_dumped = true;
|
start._comments_dumped = true;
|
||||||
@@ -458,19 +503,7 @@ function OutputStream(options) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c) {
|
comments = comments.filter(output.option("comments"), self);
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep single line comments after nlb, after nlb
|
// Keep single line comments after nlb, after nlb
|
||||||
if (!output.option("beautify") && comments.length > 0 &&
|
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
|
// a function expression needs parens around it when it's provably
|
||||||
// the first token to appear in a statement.
|
// the first token to appear in a statement.
|
||||||
PARENS(AST_Function, function(output){
|
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
|
// same goes for an object literal, because otherwise it would be
|
||||||
|
|||||||
18
lib/scope.js
18
lib/scope.js
@@ -197,12 +197,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var name = node.name;
|
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) {
|
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
|
||||||
s.uses_eval = true;
|
s.uses_eval = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var sym = node.scope.find_variable(name);
|
var sym = node.scope.find_variable(name);
|
||||||
|
if (node.scope instanceof AST_Lambda && name == "arguments") {
|
||||||
|
node.scope.uses_arguments = true;
|
||||||
|
}
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
var g;
|
var g;
|
||||||
if (globals.has(name)) {
|
if (globals.has(name)) {
|
||||||
@@ -213,12 +217,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
g.global = true;
|
g.global = true;
|
||||||
globals.set(name, g);
|
globals.set(name, g);
|
||||||
}
|
}
|
||||||
node.thedef = g;
|
sym = g;
|
||||||
if (func && name == "arguments") {
|
}
|
||||||
func.uses_arguments = true;
|
node.thedef = sym;
|
||||||
}
|
if (parent instanceof AST_Unary && (parent.operator === '++' || parent.operator === '--')
|
||||||
} else {
|
|| parent instanceof AST_Assign && parent.left === node) {
|
||||||
node.thedef = sym;
|
sym.modified = true;
|
||||||
}
|
}
|
||||||
node.reference();
|
node.reference();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "2.7.1",
|
"version": "2.7.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -90,13 +90,13 @@ asm_mixed: {
|
|||||||
}
|
}
|
||||||
function no_asm_GeometricMean(stdlib, foreign, buffer) {
|
function no_asm_GeometricMean(stdlib, foreign, buffer) {
|
||||||
function logSum(start, end) {
|
function logSum(start, end) {
|
||||||
start = 0 | start, end = 0 | end;
|
start |= 0, end |= 0;
|
||||||
var sum = 0, p = 0, q = 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]);
|
for (p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0) sum += +log(values[p >> 3]);
|
||||||
return +sum;
|
return +sum;
|
||||||
}
|
}
|
||||||
function geometricMean(start, end) {
|
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);
|
var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer);
|
||||||
return { geometricMean: geometricMean };
|
return { geometricMean: geometricMean };
|
||||||
|
|||||||
238
test/compress/assignment.js
Normal file
238
test/compress/assignment.js
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
49
test/compress/issue-1275.js
Normal file
49
test/compress/issue-1275.js
Normal file
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -130,3 +130,45 @@ negate_iife_issue_1073: {
|
|||||||
}(7))();
|
}(7))();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_1254_negate_iife_false: {
|
||||||
|
options = {
|
||||||
|
negate_iife: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
return function() {
|
||||||
|
console.log('test')
|
||||||
|
};
|
||||||
|
})()();
|
||||||
|
}
|
||||||
|
expect_exact: '(function(){return function(){console.log("test")}})()();'
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1254_negate_iife_true: {
|
||||||
|
options = {
|
||||||
|
negate_iife: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
return function() {
|
||||||
|
console.log('test')
|
||||||
|
};
|
||||||
|
})()();
|
||||||
|
}
|
||||||
|
expect_exact: '!function(){return function(){console.log("test")}}()();'
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1254_negate_iife_nested: {
|
||||||
|
options = {
|
||||||
|
negate_iife: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
return function() {
|
||||||
|
console.log('test')
|
||||||
|
};
|
||||||
|
})()()()()();
|
||||||
|
}
|
||||||
|
expect_exact: '!function(){return function(){console.log("test")}}()()()()();'
|
||||||
|
}
|
||||||
|
|||||||
@@ -75,3 +75,10 @@ call_with_unary_arguments: {
|
|||||||
}
|
}
|
||||||
expect_exact: "x();x(-1);x(-1,-2);x(void 1,+2,-3,~4,!5,--a,++b,c--,d++,typeof e,delete f);(-1)();(-1)(-2);"
|
expect_exact: "x();x(-1);x(-1,-2);x(void 1,+2,-3,~4,!5,--a,++b,c--,d++,typeof e,delete f);(-1)();(-1)(-2);"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_with_unary_prefix: {
|
||||||
|
input: {
|
||||||
|
var bar = (+new Date()).toString(32);
|
||||||
|
}
|
||||||
|
expect_exact: 'var bar=(+new Date).toString(32);';
|
||||||
|
}
|
||||||
|
|||||||
171
test/compress/reduce_vars.js
Normal file
171
test/compress/reduce_vars.js
Normal file
@@ -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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,3 +23,25 @@ typeof_evaluation: {
|
|||||||
h='undefined';
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
48
test/compress/wrap_iife.js
Normal file
48
test/compress/wrap_iife.js
Normal file
@@ -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")})()})()();'
|
||||||
|
}
|
||||||
3
test/input/comments/filter.js
Normal file
3
test/input/comments/filter.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// foo
|
||||||
|
/*@preserve*/
|
||||||
|
// bar
|
||||||
7
test/input/issue-1323/sample.js
Normal file
7
test/input/issue-1323/sample.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
var bar = (function () {
|
||||||
|
function foo (bar) {
|
||||||
|
return bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
return foo;
|
||||||
|
})();
|
||||||
@@ -19,4 +19,12 @@ describe("arguments", function() {
|
|||||||
value // Select function as scope
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -2,11 +2,11 @@ var assert = require("assert");
|
|||||||
var exec = require("child_process").exec;
|
var exec = require("child_process").exec;
|
||||||
|
|
||||||
describe("bin/uglifyjs", function () {
|
describe("bin/uglifyjs", function () {
|
||||||
|
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
|
||||||
it("should produce a functional build when using --self", function (done) {
|
it("should produce a functional build when using --self", function (done) {
|
||||||
this.timeout(5000);
|
this.timeout(5000);
|
||||||
|
|
||||||
var uglifyjs = '"' + process.argv[0] + '" bin/uglifyjs';
|
var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS';
|
||||||
var command = uglifyjs + ' --self -cm --wrap WrappedUglifyJS';
|
|
||||||
|
|
||||||
exec(command, function (err, stdout) {
|
exec(command, function (err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
@@ -19,4 +19,55 @@ describe("bin/uglifyjs", function () {
|
|||||||
done();
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,16 @@ describe("comment filters", function() {
|
|||||||
assert.strictEqual(ast.print_to_string({comments: /^!/}), "/*!test1*/\n//!test3\n//!test6\n//!test8\n");
|
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() {
|
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 ast = UglifyJS.parse("/*TEST 123*/\n//An other comment\n//8 chars.");
|
||||||
var f = function(node, comment) {
|
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");
|
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() {
|
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 ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\n<!--test5\n<!--!test6\n-->test7\n-->!test8");
|
||||||
var f = function(node, comment) {
|
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");
|
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");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -75,4 +75,23 @@ describe("minify", function() {
|
|||||||
'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
|
'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};");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ exports.minify = function(files, options) {
|
|||||||
sourceRoot : null,
|
sourceRoot : null,
|
||||||
inSourceMap : null,
|
inSourceMap : null,
|
||||||
sourceMapUrl : null,
|
sourceMapUrl : null,
|
||||||
|
sourceMapInline : false,
|
||||||
fromString : false,
|
fromString : false,
|
||||||
warnings : false,
|
warnings : false,
|
||||||
mangle : {},
|
mangle : {},
|
||||||
@@ -117,7 +118,7 @@ exports.minify = function(files, options) {
|
|||||||
if (typeof options.inSourceMap == "string") {
|
if (typeof options.inSourceMap == "string") {
|
||||||
inMap = JSON.parse(fs.readFileSync(options.inSourceMap, "utf8"));
|
inMap = JSON.parse(fs.readFileSync(options.inSourceMap, "utf8"));
|
||||||
}
|
}
|
||||||
if (options.outSourceMap) {
|
if (options.outSourceMap || options.sourceMapInline) {
|
||||||
output.source_map = UglifyJS.SourceMap({
|
output.source_map = UglifyJS.SourceMap({
|
||||||
file: options.outSourceMap,
|
file: options.outSourceMap,
|
||||||
orig: inMap,
|
orig: inMap,
|
||||||
@@ -138,16 +139,19 @@ exports.minify = function(files, options) {
|
|||||||
var stream = UglifyJS.OutputStream(output);
|
var stream = UglifyJS.OutputStream(output);
|
||||||
toplevel.print(stream);
|
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;
|
var source_map = output.source_map;
|
||||||
if (source_map) {
|
if (source_map) {
|
||||||
source_map = 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 {
|
return {
|
||||||
code : stream + "",
|
code : stream + "",
|
||||||
map : source_map
|
map : source_map
|
||||||
|
|||||||
Reference in New Issue
Block a user