Compare commits

...

20 Commits

Author SHA1 Message Date
Alex Lam S.L
f81ff10a9b v3.0.28 2017-08-20 00:27:01 +08:00
Erik Desjardins
16d40915b4 don't escape null characters as \0 when followed by any digit (#2273)
fixes #2272
2017-08-14 12:30:08 +08:00
Alex Lam S.L
e7c21e87e3 fix ie8 mangling of top-level AST_SymbolCatch (#2263)
fixes #2254
2017-08-01 02:38:32 +08:00
Alex Lam S.L
c4c2ef44d0 v3.0.27 2017-07-30 01:50:42 +08:00
Alex Lam S.L
a845897758 improve mangle.properties (#2261)
- include dead code when `keep_quoted`
- unify `keep_quoted` & `reserved`
- make `test/run-tests.js` consistent with `minify()`

fixes #2256
2017-07-29 23:02:04 +08:00
kzc
32ea2c5530 issue template: describe acceptable JS input (#2255) 2017-07-27 21:38:36 +08:00
Alex Lam S.L
bc61deeca9 v3.0.26 2017-07-23 12:39:36 +08:00
Alex Lam S.L
6a5e74b44e unescape surrogate pairs only (#2246)
fixes #2242
2017-07-23 12:38:21 +08:00
Alex Lam S.L
54446341ee update dependencies (#2241)
- acorn@5.1.1
- commander@2.11.0
- mocha@3.4.2
2017-07-16 16:20:40 +08:00
Alex Lam S.L
4e12a6f740 v3.0.25 2017-07-16 11:05:53 +08:00
Alex Lam S.L
b35dfc2599 reject malformed CLI parameters (#2239)
fixes #2237
2017-07-15 23:50:27 +08:00
Alex Lam S.L
9e1da9235e ensure ie8 works with mangled properties (#2238)
fixes #2234
2017-07-15 22:50:59 +08:00
Alex Lam S.L
a5ffe2c23f drop unused builtin globals under unsafe (#2236)
fixes #2233
2017-07-15 15:16:11 +08:00
Alex Lam S.L
9282e7b0c6 fix unsafe evaluate of Object static methods (#2232)
fixes #2231
2017-07-14 19:52:01 +08:00
Alex Lam S.L
5229cb2b1b drop unused compound assignments (#2230)
fixes #2226
2017-07-14 00:39:34 +08:00
Alex Lam S.L
458e3e15f0 enhance passes (#2229)
- remove hardcoded upper limit
- continue based on node count reduction
- emit verbose statistics

fixes #2226
2017-07-13 02:18:59 +08:00
Alex Lam S.L
c615a1e80a fix gzip stream in test/benchmark.js (#2228) 2017-07-12 02:55:57 +08:00
Alex Lam S.L
10a938cb79 enhance source mapping on IIFEs (#2224)
fixes #2213
2017-07-11 02:34:28 +08:00
Alex Lam S.L
4956ad311b benchmark gzipped output (#2220) 2017-07-09 01:44:59 +08:00
kzc
145874e504 docs: update benchmarks using node 8, add babili (#2218) 2017-07-09 01:06:15 +08:00
29 changed files with 759 additions and 289 deletions

View File

@@ -8,7 +8,14 @@
**Uglify version (`uglifyjs -V`)** **Uglify version (`uglifyjs -V`)**
**JavaScript input** <!-- ideally as small as possible --> **JavaScript input**
<!--
A complete parsable JS program exhibiting the issue with
UglifyJS alone - without third party tools or libraries.
Ideally the input should be as small as possible.
Post a link to a gist if necessary.
-->
**The `uglifyjs` CLI command executed or `minify()` options used.** **The `uglifyjs` CLI command executed or `minify()` options used.**

View File

@@ -721,7 +721,7 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
compressor from discarding function names. Useful for code relying on compressor from discarding function names. Useful for code relying on
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle). `Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
- `passes` -- default `1`. Number of times to run compress with a maximum of 3. - `passes` -- default `1`. The maximum number of times to run compress.
In some cases more than one pass leads to further compressed code. Keep in In some cases more than one pass leads to further compressed code. Keep in
mind more passes will take more time. mind more passes will take more time.
@@ -1032,8 +1032,8 @@ in total it's a bit more than just using UglifyJS's own parser.
### Uglify Fast Minify Mode ### Uglify Fast Minify Mode
It's not well known, but variable and function name mangling accounts for It's not well known, but whitespace removal and symbol mangling accounts
95% of the size reduction in minified code for most javascript - not for 95% of the size reduction in minified code for most javascript - not
elaborate code transforms. One can simply disable `compress` to speed up elaborate code transforms. One can simply disable `compress` to speed up
Uglify builds by 3 to 4 times. In this fast `mangle`-only mode Uglify has Uglify builds by 3 to 4 times. In this fast `mangle`-only mode Uglify has
comparable minify speeds and gzip sizes to comparable minify speeds and gzip sizes to
@@ -1042,10 +1042,11 @@ comparable minify speeds and gzip sizes to
| d3.js | minify size | gzip size | minify time (seconds) | | d3.js | minify size | gzip size | minify time (seconds) |
| --- | ---: | ---: | ---: | | --- | ---: | ---: | ---: |
| original | 451,131 | 108,733 | - | | original | 451,131 | 108,733 | - |
| uglify-js@3.0.23 mangle=false, compress=false | 316,600 | 85,245 | 0.73 | | uglify-js@3.0.24 mangle=false, compress=false | 316,600 | 85,245 | 0.70 |
| uglify-js@3.0.23 mangle=true, compress=false | 220,216 | 72,730 | 1.21 | | uglify-js@3.0.24 mangle=true, compress=false | 220,216 | 72,730 | 1.13 |
| Butternut 0.4.6 | 217,568 | 72,738 | 1.81 | | butternut@0.4.6 | 217,568 | 72,738 | 1.41 |
| uglify-js@3.0.23 mangle=true, compress=true | 212,511 | 71,560 | 4.64 | | uglify-js@3.0.24 mangle=true, compress=true | 212,511 | 71,560 | 3.36 |
| babili@0.1.4 | 210,713 | 72,140 | 12.64 |
To enable fast minify mode from the CLI use: To enable fast minify mode from the CLI use:
``` ```

View File

@@ -35,11 +35,11 @@ else if (process.argv.indexOf("options") >= 0) program.helpInformation = functio
} }
return text.join("\n"); return text.join("\n");
}; };
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true)); program.option("-p, --parse <options>", "Specify parser options.", parse_js());
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js("compress", true)); program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js());
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js("mangle", true)); program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js("mangle-props", true)); program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js("beautify", true)); program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js());
program.option("-o, --output <file>", "Output file (default STDOUT)."); program.option("-o, --output <file>", "Output file (default STDOUT).");
program.option("--comments [filter]", "Preserve copyright comments in the output."); program.option("--comments [filter]", "Preserve copyright comments in the output.");
program.option("--config-file <file>", "Read minify() options from JSON file."); program.option("--config-file <file>", "Read minify() options from JSON file.");
@@ -310,7 +310,7 @@ function read_file(path, default_value) {
} }
} }
function parse_js(flag, constants) { function parse_js(flag) {
return function(value, options) { return function(value, options) {
options = options || {}; options = options || {};
try { try {
@@ -328,7 +328,7 @@ function parse_js(flag, constants) {
if (node instanceof UglifyJS.AST_Assign) { if (node instanceof UglifyJS.AST_Assign) {
var name = node.left.print_to_string(); var name = node.left.print_to_string();
var value = node.right; var value = node.right;
if (!constants) { if (flag) {
options[name] = value; options[name] = value;
} else if (value instanceof UglifyJS.AST_Array) { } else if (value instanceof UglifyJS.AST_Array) {
options[name] = value.elements.map(to_string); options[name] = value.elements.map(to_string);
@@ -351,14 +351,18 @@ function parse_js(flag, constants) {
} }
})); }));
} catch(ex) { } catch(ex) {
options[value] = null; if (flag) {
fatal("Error parsing arguments for '" + flag + "': " + value);
} else {
options[value] = null;
}
} }
return options; return options;
} }
} }
function parse_source_map() { function parse_source_map() {
var parse = parse_js("sourceMap", true); var parse = parse_js();
return function(value, options) { return function(value, options) {
var hasContent = options && "content" in options; var hasContent = options && "content" in options;
var settings = parse(value, options); var settings = parse(value, options);

View File

@@ -148,10 +148,20 @@ merge(Compressor.prototype, {
node.process_expression(true); node.process_expression(true);
} }
var passes = +this.options.passes || 1; var passes = +this.options.passes || 1;
for (var pass = 0; pass < passes && pass < 3; ++pass) { var last_count = 1 / 0;
for (var pass = 0; pass < passes; pass++) {
if (pass > 0 || this.option("reduce_vars")) if (pass > 0 || this.option("reduce_vars"))
node.reset_opt_flags(this, true); node.reset_opt_flags(this, true);
node = node.transform(this); node = node.transform(this);
if (passes > 1) {
var count = 0;
node.walk(new TreeWalker(function() {
count++;
}));
this.info("pass " + pass + ": last_count: " + last_count + ", count: " + count);
if (count >= last_count) break;
last_count = count;
}
} }
if (this.option("expression")) { if (this.option("expression")) {
node.process_expression(false); node.process_expression(false);
@@ -679,6 +689,16 @@ merge(Compressor.prototype, {
return false; return false;
} }
function is_undeclared_ref(node) {
return node instanceof AST_SymbolRef && node.definition().undeclared;
}
var global_names = makePredicate("Array Boolean console Error Function Math Number RegExp Object String");
AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) {
return !this.definition().undeclared
|| compressor.option("unsafe") && global_names(this.name);
});
function tighten_body(statements, compressor) { function tighten_body(statements, compressor) {
var CHANGED, max_iter = 10; var CHANGED, max_iter = 10;
do { do {
@@ -748,7 +768,7 @@ merge(Compressor.prototype, {
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression) || node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|| node instanceof AST_Debugger || node instanceof AST_Debugger
|| node instanceof AST_IterationStatement && !(node instanceof AST_For) || node instanceof AST_IterationStatement && !(node instanceof AST_For)
|| node instanceof AST_SymbolRef && node.undeclared() || node instanceof AST_SymbolRef && !node.is_declared(compressor)
|| node instanceof AST_Try || node instanceof AST_Try
|| node instanceof AST_With || node instanceof AST_With
|| parent instanceof AST_For && node !== parent.init) { || parent instanceof AST_For && node !== parent.init) {
@@ -780,6 +800,7 @@ merge(Compressor.prototype, {
right: candidate.value right: candidate.value
}); });
} }
candidate.write_only = false;
return candidate; return candidate;
} }
// These node types have child nodes that execute sequentially, // These node types have child nodes that execute sequentially,
@@ -1309,12 +1330,12 @@ merge(Compressor.prototype, {
// returns true if this node may be null, undefined or contain `AST_Accessor` // returns true if this node may be null, undefined or contain `AST_Accessor`
(function(def) { (function(def) {
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) { AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
var pure_getters = compressor.option("pure_getters"); return !compressor.option("pure_getters")
return !pure_getters || this._throw_on_access(pure_getters); || this._dot_throw(compressor);
}); });
function is_strict(pure_getters) { function is_strict(compressor) {
return /strict/.test(pure_getters); return /strict/.test(compressor.option("pure_getters"));
} }
def(AST_Node, is_strict); def(AST_Node, is_strict);
@@ -1322,8 +1343,8 @@ merge(Compressor.prototype, {
def(AST_Undefined, return_true); def(AST_Undefined, return_true);
def(AST_Constant, return_false); def(AST_Constant, return_false);
def(AST_Array, return_false); def(AST_Array, return_false);
def(AST_Object, function(pure_getters) { def(AST_Object, function(compressor) {
if (!is_strict(pure_getters)) return false; if (!is_strict(compressor)) return false;
for (var i = this.properties.length; --i >=0;) for (var i = this.properties.length; --i >=0;)
if (this.properties[i].value instanceof AST_Accessor) return true; if (this.properties[i].value instanceof AST_Accessor) return true;
return false; return false;
@@ -1333,37 +1354,38 @@ merge(Compressor.prototype, {
def(AST_UnaryPrefix, function() { def(AST_UnaryPrefix, function() {
return this.operator == "void"; return this.operator == "void";
}); });
def(AST_Binary, function(pure_getters) { def(AST_Binary, function(compressor) {
switch (this.operator) { switch (this.operator) {
case "&&": case "&&":
return this.left._throw_on_access(pure_getters); return this.left._dot_throw(compressor);
case "||": case "||":
return this.left._throw_on_access(pure_getters) return this.left._dot_throw(compressor)
&& this.right._throw_on_access(pure_getters); && this.right._dot_throw(compressor);
default: default:
return false; return false;
} }
}) })
def(AST_Assign, function(pure_getters) { def(AST_Assign, function(compressor) {
return this.operator == "=" return this.operator == "="
&& this.right._throw_on_access(pure_getters); && this.right._dot_throw(compressor);
}) })
def(AST_Conditional, function(pure_getters) { def(AST_Conditional, function(compressor) {
return this.consequent._throw_on_access(pure_getters) return this.consequent._dot_throw(compressor)
|| this.alternative._throw_on_access(pure_getters); || this.alternative._dot_throw(compressor);
}) })
def(AST_Sequence, function(pure_getters) { def(AST_Sequence, function(compressor) {
return this.expressions[this.expressions.length - 1]._throw_on_access(pure_getters); return this.expressions[this.expressions.length - 1]._dot_throw(compressor);
}); });
def(AST_SymbolRef, function(pure_getters) { def(AST_SymbolRef, function(compressor) {
if (this.is_undefined) return true; if (this.is_undefined) return true;
if (!is_strict(pure_getters)) return false; if (!is_strict(compressor)) return false;
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
if (this.is_immutable()) return false; if (this.is_immutable()) return false;
var fixed = this.fixed_value(); var fixed = this.fixed_value();
return !fixed || fixed._throw_on_access(pure_getters); return !fixed || fixed._dot_throw(compressor);
}); });
})(function(node, func) { })(function(node, func) {
node.DEFMETHOD("_throw_on_access", func); node.DEFMETHOD("_dot_throw", func);
}); });
/* -----[ boolean/negation helpers ]----- */ /* -----[ boolean/negation helpers ]----- */
@@ -1724,11 +1746,8 @@ merge(Compressor.prototype, {
}); });
var global_objs = { var global_objs = {
Array: Array, Array: Array,
Boolean: Boolean,
Math: Math, Math: Math,
Number: Number, Number: Number,
RegExp: RegExp,
Object: Object,
String: String, String: String,
}; };
function convert_to_predicate(obj) { function convert_to_predicate(obj) {
@@ -1765,7 +1784,7 @@ merge(Compressor.prototype, {
} }
var exp = this.expression; var exp = this.expression;
var val; var val;
if (exp instanceof AST_SymbolRef && exp.undeclared()) { if (is_undeclared_ref(exp)) {
if (!(static_values[exp.name] || return_false)(key)) return this; if (!(static_values[exp.name] || return_false)(key)) return this;
val = global_objs[exp.name]; val = global_objs[exp.name];
} else { } else {
@@ -1842,10 +1861,6 @@ merge(Compressor.prototype, {
"isFinite", "isFinite",
"isNaN", "isNaN",
], ],
Object: [
"keys",
"getOwnPropertyNames",
],
String: [ String: [
"fromCharCode", "fromCharCode",
], ],
@@ -1861,7 +1876,7 @@ merge(Compressor.prototype, {
} }
var val; var val;
var e = exp.expression; var e = exp.expression;
if (e instanceof AST_SymbolRef && e.undeclared()) { if (is_undeclared_ref(e)) {
if (!(static_fns[e.name] || return_false)(key)) return this; if (!(static_fns[e.name] || return_false)(key)) return this;
val = global_objs[e.name]; val = global_objs[e.name];
} else { } else {
@@ -2043,7 +2058,7 @@ merge(Compressor.prototype, {
|| this.expression.has_side_effects(compressor); || this.expression.has_side_effects(compressor);
}); });
def(AST_SymbolRef, function(compressor){ def(AST_SymbolRef, function(compressor){
return this.undeclared(); return !this.is_declared(compressor);
}); });
def(AST_SymbolDeclaration, return_false); def(AST_SymbolDeclaration, return_false);
def(AST_Object, function(compressor){ def(AST_Object, function(compressor){
@@ -2167,7 +2182,12 @@ merge(Compressor.prototype, {
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs; var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars; var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
if (!drop_funcs && !drop_vars) return; if (!drop_funcs && !drop_vars) return;
var assign_as_unused = !/keep_assign/.test(compressor.option("unused")); var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node) {
if (node instanceof AST_Assign && (node.write_only || node.operator == "=")) {
return node.left;
}
if (node instanceof AST_Unary && node.write_only) return node.expression;
};
var in_use = []; var in_use = [];
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
if (self instanceof AST_Toplevel && compressor.top_retain) { if (self instanceof AST_Toplevel && compressor.top_retain) {
@@ -2217,12 +2237,8 @@ merge(Compressor.prototype, {
}); });
return true; return true;
} }
if (assign_as_unused if (assign_as_unused(node) instanceof AST_SymbolRef && scope === self) {
&& node instanceof AST_Assign if (node instanceof AST_Assign) node.right.walk(tw);
&& node.operator == "="
&& node.left instanceof AST_SymbolRef
&& scope === self) {
node.right.walk(tw);
return true; return true;
} }
if (node instanceof AST_SymbolRef) { if (node instanceof AST_SymbolRef) {
@@ -2386,14 +2402,17 @@ merge(Compressor.prototype, {
}); });
} }
} }
if (drop_vars && assign_as_unused if (drop_vars) {
&& node instanceof AST_Assign var def = assign_as_unused(node);
&& node.operator == "=" if (def instanceof AST_SymbolRef
&& node.left instanceof AST_SymbolRef) { && !((def = def.definition()).id in in_use_ids)
var def = node.left.definition();
if (!(def.id in in_use_ids)
&& self.variables.get(def.name) === def) { && self.variables.get(def.name) === def) {
return maintain_this_binding(tt.parent(), node, node.right.transform(tt)); if (node instanceof AST_Assign) {
return maintain_this_binding(tt.parent(), node, node.right.transform(tt));
}
return make_node(AST_Number, node, {
value: 0
});
} }
} }
// certain combination of unused name + side effect leads to: // certain combination of unused name + side effect leads to:
@@ -2632,7 +2651,10 @@ merge(Compressor.prototype, {
return make_sequence(this, [ left, right ]); return make_sequence(this, [ left, right ]);
} }
}); });
def(AST_Assign, return_this); def(AST_Assign, function(compressor){
this.write_only = !this.left.has_side_effects(compressor);
return this;
});
def(AST_Conditional, function(compressor){ def(AST_Conditional, function(compressor){
var consequent = this.consequent.drop_side_effect_free(compressor); var consequent = this.consequent.drop_side_effect_free(compressor);
var alternative = this.alternative.drop_side_effect_free(compressor); var alternative = this.alternative.drop_side_effect_free(compressor);
@@ -2653,7 +2675,10 @@ merge(Compressor.prototype, {
return node; return node;
}); });
def(AST_Unary, function(compressor, first_in_statement){ def(AST_Unary, function(compressor, first_in_statement){
if (unary_side_effects(this.operator)) return this; if (unary_side_effects(this.operator)) {
this.write_only = !this.expression.has_side_effects(compressor);
return this;
}
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) return null; if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) return null;
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement); var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
if (first_in_statement if (first_in_statement
@@ -2667,8 +2692,8 @@ merge(Compressor.prototype, {
} }
return expression; return expression;
}); });
def(AST_SymbolRef, function() { def(AST_SymbolRef, function(compressor) {
return this.undeclared() ? this : null; return this.is_declared(compressor) ? null : this;
}); });
def(AST_Object, function(compressor, first_in_statement){ def(AST_Object, function(compressor, first_in_statement){
var values = trim(this.properties, compressor, first_in_statement); var values = trim(this.properties, compressor, first_in_statement);
@@ -3130,7 +3155,7 @@ merge(Compressor.prototype, {
self.args.length = last; self.args.length = last;
} }
if (compressor.option("unsafe")) { if (compressor.option("unsafe")) {
if (exp instanceof AST_SymbolRef && exp.undeclared()) { if (is_undeclared_ref(exp)) {
switch (exp.name) { switch (exp.name) {
case "Array": case "Array":
if (self.args.length != 1) { if (self.args.length != 1) {
@@ -3257,8 +3282,7 @@ merge(Compressor.prototype, {
} }
} }
if (compressor.option("unsafe_Func") if (compressor.option("unsafe_Func")
&& exp instanceof AST_SymbolRef && is_undeclared_ref(exp)
&& exp.undeclared()
&& exp.name == "Function") { && exp.name == "Function") {
// new Function() => function(){} // new Function() => function(){}
if (self.args.length == 0) return make_node(AST_Function, self, { if (self.args.length == 0) return make_node(AST_Function, self, {
@@ -3375,9 +3399,7 @@ merge(Compressor.prototype, {
while (name.expression) { while (name.expression) {
name = name.expression; name = name.expression;
} }
if (name instanceof AST_SymbolRef if (is_undeclared_ref(name) && name.name == "console") {
&& name.name == "console"
&& name.undeclared()) {
return make_node(AST_Undefined, self).optimize(compressor); return make_node(AST_Undefined, self).optimize(compressor);
} }
} }
@@ -3398,7 +3420,7 @@ merge(Compressor.prototype, {
OPT(AST_New, function(self, compressor){ OPT(AST_New, function(self, compressor){
if (compressor.option("unsafe")) { if (compressor.option("unsafe")) {
var exp = self.expression; var exp = self.expression;
if (exp instanceof AST_SymbolRef && exp.undeclared()) { if (is_undeclared_ref(exp)) {
switch (exp.name) { switch (exp.name) {
case "Object": case "Object":
case "RegExp": case "RegExp":
@@ -3475,6 +3497,8 @@ merge(Compressor.prototype, {
operator: car.operator, operator: car.operator,
expression: left expression: left
}); });
} else {
car.write_only = false;
} }
if (parent) { if (parent) {
parent[field] = car; parent[field] = car;
@@ -3690,7 +3714,7 @@ merge(Compressor.prototype, {
&& self.right instanceof AST_UnaryPrefix && self.right instanceof AST_UnaryPrefix
&& self.right.operator == "typeof") { && self.right.operator == "typeof") {
var expr = self.right.expression; var expr = self.right.expression;
if (expr instanceof AST_SymbolRef ? !expr.undeclared() if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) { : !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
self.right = expr; self.right = expr;
self.left = make_node(AST_Undefined, self.left).optimize(compressor); self.left = make_node(AST_Undefined, self.left).optimize(compressor);
@@ -4016,7 +4040,7 @@ merge(Compressor.prototype, {
} }
// testing against !self.scope.uses_with first is an optimization // testing against !self.scope.uses_with first is an optimization
if (!compressor.option("ie8") if (!compressor.option("ie8")
&& self.undeclared() && is_undeclared_ref(self)
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) { && (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
switch (self.name) { switch (self.name) {
case "undefined": case "undefined":
@@ -4371,7 +4395,7 @@ merge(Compressor.prototype, {
var prop = self.property; var prop = self.property;
if (prop instanceof AST_String && compressor.option("properties")) { if (prop instanceof AST_String && compressor.option("properties")) {
prop = prop.getValue(); prop = prop.getValue();
if (RESERVED_WORDS(prop) ? !compressor.option("ie8") : is_identifier_string(prop)) { if (is_identifier_string(prop)) {
return make_node(AST_Dot, self, { return make_node(AST_Dot, self, {
expression : self.expression, expression : self.expression,
property : prop property : prop
@@ -4408,19 +4432,10 @@ merge(Compressor.prototype, {
if (def) { if (def) {
return def.optimize(compressor); return def.optimize(compressor);
} }
var prop = self.property;
if (RESERVED_WORDS(prop) && compressor.option("ie8")) {
return make_node(AST_Sub, self, {
expression : self.expression,
property : make_node(AST_String, self, {
value: prop
})
}).optimize(compressor);
}
if (compressor.option("unsafe") && self.expression instanceof AST_Object) { if (compressor.option("unsafe") && self.expression instanceof AST_Object) {
var values = self.expression.properties; var values = self.expression.properties;
for (var i = values.length; --i >= 0;) { for (var i = values.length; --i >= 0;) {
if (values[i].key === prop) { if (values[i].key === self.property) {
var value = values[i].value; var value = values[i].value;
if (value instanceof AST_Function ? !value.contains_this() : !value.has_side_effects(compressor)) { if (value instanceof AST_Function ? !value.contains_this() : !value.has_side_effects(compressor)) {
var obj = self.expression.clone(); var obj = self.expression.clone();
@@ -4435,7 +4450,7 @@ merge(Compressor.prototype, {
&& self.expression instanceof AST_Dot && self.expression instanceof AST_Dot
&& self.expression.property == "prototype") { && self.expression.property == "prototype") {
var exp = self.expression.expression; var exp = self.expression.expression;
if (exp instanceof AST_SymbolRef && exp.undeclared()) switch (exp.name) { if (is_undeclared_ref(exp)) switch (exp.name) {
case "Array": case "Array":
self.expression = make_node(AST_Array, self.expression, { self.expression = make_node(AST_Array, self.expression, {
elements: [] elements: []

View File

@@ -68,6 +68,7 @@ function minify(files, options) {
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]); set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]); set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]); set_shorthand("warnings", options, [ "compress" ]);
var quoted_props;
if (options.mangle) { if (options.mangle) {
options.mangle = defaults(options.mangle, { options.mangle = defaults(options.mangle, {
cache: options.nameCache && (options.nameCache.vars || {}), cache: options.nameCache && (options.nameCache.vars || {}),
@@ -78,11 +79,16 @@ function minify(files, options) {
reserved: [], reserved: [],
toplevel: false, toplevel: false,
}, true); }, true);
if (options.nameCache && options.mangle.properties) { if (options.mangle.properties) {
if (typeof options.mangle.properties != "object") { if (typeof options.mangle.properties != "object") {
options.mangle.properties = {}; options.mangle.properties = {};
} }
if (!("cache" in options.mangle.properties)) { if (options.mangle.properties.keep_quoted) {
quoted_props = options.mangle.properties.reserved;
if (!Array.isArray(quoted_props)) quoted_props = [];
options.mangle.properties.reserved = quoted_props;
}
if (options.nameCache && !("cache" in options.mangle.properties)) {
options.mangle.properties.cache = options.nameCache.props || {}; options.mangle.properties.cache = options.nameCache.props || {};
} }
} }
@@ -125,6 +131,9 @@ function minify(files, options) {
} }
toplevel = options.parse.toplevel; toplevel = options.parse.toplevel;
} }
if (quoted_props) {
reserve_quoted_keys(toplevel, quoted_props);
}
if (options.wrap) { if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap); toplevel = toplevel.wrap_commonjs(options.wrap);
} }

View File

@@ -109,7 +109,7 @@ function OutputStream(options) {
var current_pos = 0; var current_pos = 0;
var OUTPUT = ""; var OUTPUT = "";
function to_ascii(str, identifier) { var to_utf8 = options.ascii_only ? function(str, identifier) {
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) { return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
var code = ch.charCodeAt(0).toString(16); var code = ch.charCodeAt(0).toString(16);
if (code.length <= 2 && !identifier) { if (code.length <= 2 && !identifier) {
@@ -120,6 +120,12 @@ function OutputStream(options) {
return "\\u" + code; return "\\u" + code;
} }
}); });
} : function(str) {
return str.replace(/[\ud800-\udbff](?![\udc00-\udfff])/g, function(ch) {
return "\\u" + ch.charCodeAt(0).toString(16);
}).replace(/(^|[^\ud800-\udbff])([\udc00-\udfff])/g, function(match, prefix, ch) {
return prefix + "\\u" + ch.charCodeAt(0).toString(16);
});
}; };
function make_string(str, quote) { function make_string(str, quote) {
@@ -140,7 +146,7 @@ function OutputStream(options) {
case "\u2029": return "\\u2029"; case "\u2029": return "\\u2029";
case "\ufeff": return "\\ufeff"; case "\ufeff": return "\\ufeff";
case "\0": case "\0":
return /[0-7]/.test(str.charAt(i+1)) ? "\\x00" : "\\0"; return /[0-9]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
} }
return s; return s;
}); });
@@ -150,7 +156,7 @@ function OutputStream(options) {
function quote_double() { function quote_double() {
return '"' + str.replace(/\x22/g, '\\"') + '"'; return '"' + str.replace(/\x22/g, '\\"') + '"';
} }
if (options.ascii_only) str = to_ascii(str); str = to_utf8(str);
switch (options.quote_style) { switch (options.quote_style) {
case 1: case 1:
return quote_single(); return quote_single();
@@ -175,8 +181,7 @@ function OutputStream(options) {
function make_name(name) { function make_name(name) {
name = name.toString(); name = name.toString();
if (options.ascii_only) name = to_utf8(name, true);
name = to_ascii(name, true);
return name; return name;
}; };
@@ -433,7 +438,7 @@ function OutputStream(options) {
last : function() { return last }, last : function() { return last },
semicolon : semicolon, semicolon : semicolon,
force_semicolon : force_semicolon, force_semicolon : force_semicolon,
to_ascii : to_ascii, to_utf8 : to_utf8,
print_name : function(name) { print(make_name(name)) }, print_name : function(name) { print(make_name(name)) },
print_string : function(str, quote, escape_directive) { print_string : function(str, quote, escape_directive) {
var encoded = encode_string(str, quote); var encoded = encode_string(str, quote);
@@ -1104,6 +1109,9 @@ function OutputStream(options) {
self.expression.print(output); self.expression.print(output);
if (self instanceof AST_New && !need_constructor_parens(self, output)) if (self instanceof AST_New && !need_constructor_parens(self, output))
return; return;
if (self.expression instanceof AST_Lambda) {
output.add_mapping(self.start);
}
output.with_parens(function(){ output.with_parens(function(){
self.args.forEach(function(expr, i){ self.args.forEach(function(expr, i){
if (i) output.comma(); if (i) output.comma();
@@ -1143,15 +1151,23 @@ function OutputStream(options) {
DEFPRINT(AST_Dot, function(self, output){ DEFPRINT(AST_Dot, function(self, output){
var expr = self.expression; var expr = self.expression;
expr.print(output); expr.print(output);
if (expr instanceof AST_Number && expr.getValue() >= 0) { var prop = self.property;
if (!/[xa-f.)]/i.test(output.last())) { if (output.option("ie8") && RESERVED_WORDS(prop)) {
output.print("."); output.print("[");
output.add_mapping(self.end);
output.print_string(prop);
output.print("]");
} else {
if (expr instanceof AST_Number && expr.getValue() >= 0) {
if (!/[xa-f.)]/i.test(output.last())) {
output.print(".");
}
} }
output.print(".");
// the name after dot would be mapped about here.
output.add_mapping(self.end);
output.print_name(prop);
} }
output.print(".");
// the name after dot would be mapped about here.
output.add_mapping(self.end);
output.print_name(self.property);
}); });
DEFPRINT(AST_Sub, function(self, output){ DEFPRINT(AST_Sub, function(self, output){
self.expression.print(output); self.expression.print(output);
@@ -1307,9 +1323,7 @@ function OutputStream(options) {
if (regexp.raw_source) { if (regexp.raw_source) {
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/")); str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
} }
if (output.option("ascii_only")) { str = output.to_utf8(str);
str = output.to_ascii(str);
}
output.print(str); output.print(str);
var p = output.parent(); var p = output.parent();
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self) if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)

View File

@@ -67,6 +67,34 @@ function find_builtins(reserved) {
} }
} }
function reserve_quoted_keys(ast, reserved) {
function add(name) {
push_uniq(reserved, name);
}
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal && node.quote) {
add(node.key);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
}
}));
}
function addStrings(node, add) {
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_Sequence) {
addStrings(node.expressions[node.expressions.length - 1], add);
} else if (node instanceof AST_String) {
add(node.value);
} else if (node instanceof AST_Conditional) {
addStrings(node.consequent, add);
addStrings(node.alternative, add);
}
return true;
}));
}
function mangle_properties(ast, options) { function mangle_properties(ast, options) {
options = defaults(options, { options = defaults(options, {
builtins: false, builtins: false,
@@ -76,7 +104,7 @@ function mangle_properties(ast, options) {
only_cache: false, only_cache: false,
regex: null, regex: null,
reserved: null, reserved: null,
}); }, true);
var reserved = options.reserved; var reserved = options.reserved;
if (!Array.isArray(reserved)) reserved = []; if (!Array.isArray(reserved)) reserved = [];
@@ -91,7 +119,6 @@ function mangle_properties(ast, options) {
} }
var regex = options.regex; var regex = options.regex;
var keep_quoted = options.keep_quoted;
// note debug is either false (disabled), or a string of the debug suffix to use (enabled). // note debug is either false (disabled), or a string of the debug suffix to use (enabled).
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true' // note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
@@ -104,12 +131,11 @@ function mangle_properties(ast, options) {
var names_to_mangle = []; var names_to_mangle = [];
var unmangleable = []; var unmangleable = [];
var to_keep = {};
// step 1: find candidates to mangle // step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node){ ast.walk(new TreeWalker(function(node){
if (node instanceof AST_ObjectKeyVal) { if (node instanceof AST_ObjectKeyVal) {
add(node.key, keep_quoted && node.quote); add(node.key);
} }
else if (node instanceof AST_ObjectProperty) { else if (node instanceof AST_ObjectProperty) {
// setter or getter, since KeyVal is handled above // setter or getter, since KeyVal is handled above
@@ -119,15 +145,14 @@ function mangle_properties(ast, options) {
add(node.property); add(node.property);
} }
else if (node instanceof AST_Sub) { else if (node instanceof AST_Sub) {
addStrings(node.property, keep_quoted); addStrings(node.property, add);
} }
})); }));
// step 2: transform the tree, renaming properties // step 2: transform the tree, renaming properties
return ast.transform(new TreeTransformer(function(node){ return ast.transform(new TreeTransformer(function(node){
if (node instanceof AST_ObjectKeyVal) { if (node instanceof AST_ObjectKeyVal) {
if (!(keep_quoted && node.quote)) node.key = mangle(node.key);
node.key = mangle(node.key);
} }
else if (node instanceof AST_ObjectProperty) { else if (node instanceof AST_ObjectProperty) {
// setter or getter // setter or getter
@@ -136,22 +161,9 @@ function mangle_properties(ast, options) {
else if (node instanceof AST_Dot) { else if (node instanceof AST_Dot) {
node.property = mangle(node.property); node.property = mangle(node.property);
} }
else if (node instanceof AST_Sub) { else if (!options.keep_quoted && node instanceof AST_Sub) {
if (!keep_quoted) node.property = mangleStrings(node.property);
node.property = mangleStrings(node.property);
} }
// else if (node instanceof AST_String) {
// if (should_mangle(node.value)) {
// AST_Node.warn(
// "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", {
// file : node.start.file,
// line : node.start.line,
// col : node.start.col,
// prop : node.value
// }
// );
// }
// }
})); }));
// only function declarations after this line // only function declarations after this line
@@ -167,19 +179,13 @@ function mangle_properties(ast, options) {
} }
function should_mangle(name) { function should_mangle(name) {
if (keep_quoted && name in to_keep) return false;
if (regex && !regex.test(name)) return false; if (regex && !regex.test(name)) return false;
if (reserved.indexOf(name) >= 0) return false; if (reserved.indexOf(name) >= 0) return false;
return cache.props.has(name) return cache.props.has(name)
|| names_to_mangle.indexOf(name) >= 0; || names_to_mangle.indexOf(name) >= 0;
} }
function add(name, keep) { function add(name) {
if (keep) {
to_keep[name] = true;
return;
}
if (can_mangle(name)) if (can_mangle(name))
push_uniq(names_to_mangle, name); push_uniq(names_to_mangle, name);
@@ -199,19 +205,16 @@ function mangle_properties(ast, options) {
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_. // debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_"; var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
if (can_mangle(debug_mangled) && !(keep_quoted && debug_mangled in to_keep)) { if (can_mangle(debug_mangled)) {
mangled = debug_mangled; mangled = debug_mangled;
} }
} }
// either debug mode is off, or it is on and we could not use the mangled name // either debug mode is off, or it is on and we could not use the mangled name
if (!mangled) { if (!mangled) {
// Note: `can_mangle()` does not check if the name collides with the `to_keep` set
// (filled with quoted properties when `keep_quoted` is set). Make sure we add this
// check so we don't collide with a quoted name.
do { do {
mangled = base54(++cache.cname); mangled = base54(++cache.cname);
} while (!can_mangle(mangled) || keep_quoted && mangled in to_keep); } while (!can_mangle(mangled));
} }
cache.props.set(name, mangled); cache.props.set(name, mangled);
@@ -219,32 +222,6 @@ function mangle_properties(ast, options) {
return mangled; return mangled;
} }
function addStrings(node, keep) {
var out = {};
try {
(function walk(node){
node.walk(new TreeWalker(function(node){
if (node instanceof AST_Sequence) {
walk(node.expressions[node.expressions.length - 1]);
return true;
}
if (node instanceof AST_String) {
add(node.value, keep);
return true;
}
if (node instanceof AST_Conditional) {
walk(node.consequent);
walk(node.alternative);
return true;
}
throw out;
}));
})(node);
} catch(ex) {
if (ex !== out) throw ex;
}
}
function mangleStrings(node) { function mangleStrings(node) {
return node.transform(new TreeTransformer(function(node){ return node.transform(new TreeTransformer(function(node){
if (node instanceof AST_Sequence) { if (node instanceof AST_Sequence) {

View File

@@ -235,6 +235,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
ref.reference(options); ref.reference(options);
}); });
node.thedef = def; node.thedef = def;
node.reference(options);
return true; return true;
} }
})); }));
@@ -373,14 +374,6 @@ AST_Symbol.DEFMETHOD("unreferenced", function(){
&& !(this.scope.uses_eval || this.scope.uses_with); && !(this.scope.uses_eval || this.scope.uses_with);
}); });
AST_Symbol.DEFMETHOD("undeclared", function(){
return this.definition().undeclared;
});
AST_LabelRef.DEFMETHOD("undeclared", return_false);
AST_Label.DEFMETHOD("undeclared", return_false);
AST_Symbol.DEFMETHOD("definition", function(){ AST_Symbol.DEFMETHOD("definition", function(){
return this.thedef; return this.thedef;
}); });

View File

@@ -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": "3.0.24", "version": "3.0.28",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
@@ -29,12 +29,12 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"commander": "~2.9.0", "commander": "~2.11.0",
"source-map": "~0.5.1" "source-map": "~0.5.1"
}, },
"devDependencies": { "devDependencies": {
"acorn": "~5.0.3", "acorn": "~5.1.1",
"mocha": "~2.3.4", "mocha": "~3.4.2",
"semver": "~5.3.0" "semver": "~5.3.0"
}, },
"scripts": { "scripts": {

View File

@@ -6,6 +6,7 @@
var createHash = require("crypto").createHash; var createHash = require("crypto").createHash;
var fetch = require("./fetch"); var fetch = require("./fetch");
var fork = require("child_process").fork; var fork = require("child_process").fork;
var zlib = require("zlib");
var args = process.argv.slice(2); var args = process.argv.slice(2);
if (!args.length) { if (!args.length) {
args.push("-mc"); args.push("-mc");
@@ -33,6 +34,7 @@ function done() {
console.log(info.log); console.log(info.log);
console.log("Original:", info.input, "bytes"); console.log("Original:", info.input, "bytes");
console.log("Uglified:", info.output, "bytes"); console.log("Uglified:", info.output, "bytes");
console.log("GZipped: ", info.gzip, "bytes");
console.log("SHA1 sum:", info.sha1); console.log("SHA1 sum:", info.sha1);
if (info.code) { if (info.code) {
failures.push(url); failures.push(url);
@@ -51,6 +53,7 @@ urls.forEach(function(url) {
results[url] = { results[url] = {
input: 0, input: 0,
output: 0, output: 0,
gzip: 0,
log: "" log: ""
}; };
fetch(url, function(err, res) { fetch(url, function(err, res) {
@@ -61,6 +64,10 @@ urls.forEach(function(url) {
}).pipe(uglifyjs.stdin); }).pipe(uglifyjs.stdin);
uglifyjs.stdout.on("data", function(data) { uglifyjs.stdout.on("data", function(data) {
results[url].output += data.length; results[url].output += data.length;
}).pipe(zlib.createGzip({
level: zlib.Z_BEST_COMPRESSION
})).on("data", function(data) {
results[url].gzip += data.length;
}).pipe(createHash("sha1")).on("data", function(data) { }).pipe(createHash("sha1")).on("data", function(data) {
results[url].sha1 = data.toString("hex"); results[url].sha1 = data.toString("hex");
done(); done();

View File

@@ -13,7 +13,7 @@ ascii_only_true: {
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"; "\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
} }
} }
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}' expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
} }
ascii_only_false: { ascii_only_false: {
@@ -31,5 +31,5 @@ ascii_only_false: {
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"; "\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
} }
} }
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}' expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
} }

View File

@@ -863,7 +863,7 @@ collapse_vars_unary: {
input: { input: {
function f0(o, p) { function f0(o, p) {
var x = o[p]; var x = o[p];
delete x; return delete x;
} }
function f1(n) { function f1(n) {
var k = !!n; var k = !!n;
@@ -893,7 +893,7 @@ collapse_vars_unary: {
expect: { expect: {
function f0(o, p) { function f0(o, p) {
var x = o[p]; var x = o[p];
delete x; return delete x;
} }
function f1(n) { function f1(n) {
return n > +!!n return n > +!!n

View File

@@ -21,7 +21,7 @@ concat_1: {
var c = 1 + x() + 2 + "boo"; var c = 1 + x() + 2 + "boo";
var d = 1 + x() + 2 + 3 + "boo"; var d = 1 + x() + 2 + 3 + "boo";
var e = 1 + x() + 2 + "X3boo"; var e = 1 + x() + 2 + "X3boo";
var f = "\x00360\08\0"; var f = "\x00360\x008\0";
} }
} }

View File

@@ -230,3 +230,82 @@ accessor: {
} }
expect: {} expect: {}
} }
issue_2233_1: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
Array.isArray;
Boolean;
console.log;
Error.name;
Function.length;
Math.random;
Number.isNaN;
RegExp;
Object.defineProperty;
String.fromCharCode;
}
expect: {}
expect_stdout: true
}
issue_2233_2: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
var RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Number.isNaN;
}
}
}
issue_2233_3: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
UndeclaredGlobal;
}
}

View File

@@ -1090,6 +1090,7 @@ var_catch_toplevel: {
a--; a--;
try { try {
a++; a++;
x();
} catch(a) { } catch(a) {
if (a) var a; if (a) var a;
var a = 10; var a = 10;
@@ -1099,9 +1100,8 @@ var_catch_toplevel: {
} }
expect: { expect: {
!function() { !function() {
a--;
try { try {
a++; x();
} catch(a) { } catch(a) {
var a; var a;
} }
@@ -1153,3 +1153,89 @@ issue_2105: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_2226_1: {
options = {
side_effects: true,
unused: true,
}
input: {
function f1() {
var a = b;
a += c;
}
function f2(a) {
a <<= b;
}
function f3(a) {
--a;
}
function f4() {
var a = b;
return a *= c;
}
function f5(a) {
x(a /= b);
}
}
expect: {
function f1() {
b;
c;
}
function f2(a) {
b;
}
function f3(a) {
0;
}
function f4() {
var a = b;
return a *= c;
}
function f5(a) {
x(a /= b);
}
}
}
issue_2226_2: {
options = {
cascade: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
console.log(function(a, b) {
a += b;
return a;
}(1, 2));
}
expect: {
console.log(function(a, b) {
return a += b;
}(1, 2));
}
expect_stdout: "3"
}
issue_2226_3: {
options = {
collapse_vars: true,
side_effects: true,
unused: true,
}
input: {
console.log(function(a, b) {
a += b;
return a;
}(1, 2));
}
expect: {
console.log(function(a, b) {
return a += 2;
}(1));
}
expect_stdout: "3"
}

View File

@@ -1157,3 +1157,31 @@ issue_2207_3: {
} }
expect_stdout: true expect_stdout: true
} }
issue_2231_1: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(Object.keys(void 0));
}
expect: {
console.log(Object.keys(void 0));
}
expect_stdout: true
}
issue_2231_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(Object.getOwnPropertyNames(null));
}
expect: {
console.log(Object.getOwnPropertyNames(null));
}
expect_stdout: true
}

View File

@@ -71,11 +71,13 @@ non_hoisted_function_after_return_2a: {
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]", "WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]",
"WARN: pass 0: last_count: Infinity, count: 37",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]", "WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]", "WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]",
"WARN: pass 1: last_count: 37, count: 18",
] ]
} }
@@ -109,11 +111,11 @@ non_hoisted_function_after_return_2b: {
} }
expect_warnings: [ expect_warnings: [
// duplicate warnings no longer emitted // duplicate warnings no longer emitted
"WARN: Dropping unreachable code [test/compress/issue-1034.js:95,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:97,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:95,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:99,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:99,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:103,12]",
] ]
} }
@@ -151,10 +153,10 @@ non_hoisted_function_after_return_strict: {
} }
expect_stdout: "8 7" expect_stdout: "8 7"
expect_warnings: [ expect_warnings: [
'WARN: Dropping unreachable code [test/compress/issue-1034.js:131,16]', "WARN: Dropping unreachable code [test/compress/issue-1034.js:133,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:134,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:136,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:137,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:139,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:138,21]" "WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:140,21]",
] ]
} }
@@ -194,17 +196,19 @@ non_hoisted_function_after_return_2a_strict: {
} }
expect_stdout: "5 6" expect_stdout: "5 6"
expect_warnings: [ expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:173,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:175,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:173,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:175,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:176,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:178,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:176,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:173,20]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:175,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:180,21]", "WARN: Dropping unused function nope [test/compress/issue-1034.js:182,21]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:178,12]", "WARN: pass 0: last_count: Infinity, count: 48",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:180,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:181,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:180,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:176,20]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:183,12]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:178,16]", "WARN: Dropping unused variable b [test/compress/issue-1034.js:178,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:180,16]",
"WARN: pass 1: last_count: 48, count: 29",
] ]
} }
@@ -243,10 +247,10 @@ non_hoisted_function_after_return_2b_strict: {
expect_stdout: "5 6" expect_stdout: "5 6"
expect_warnings: [ expect_warnings: [
// duplicate warnings no longer emitted // duplicate warnings no longer emitted
"WARN: Dropping unreachable code [test/compress/issue-1034.js:225,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:229,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:225,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:229,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:227,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:227,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:231,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:231,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:231,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:235,12]",
] ]
} }

View File

@@ -1,6 +1,8 @@
issue_1321_no_debug: { issue_1321_no_debug: {
mangle_props = { mangle = {
keep_quoted: true properties: {
keep_quoted: true,
},
} }
input: { input: {
var x = {}; var x = {};
@@ -10,17 +12,19 @@ issue_1321_no_debug: {
} }
expect: { expect: {
var x = {}; var x = {};
x.o = 1; x.x = 1;
x["a"] = 2 * x.o; x["a"] = 2 * x.x;
console.log(x.o, x["a"]); console.log(x.x, x["a"]);
} }
expect_stdout: true expect_stdout: true
} }
issue_1321_debug: { issue_1321_debug: {
mangle_props = { mangle = {
keep_quoted: true, properties: {
debug: "" debug: "",
keep_quoted: true,
},
} }
input: { input: {
var x = {}; var x = {};
@@ -30,16 +34,18 @@ issue_1321_debug: {
} }
expect: { expect: {
var x = {}; var x = {};
x.o = 1; x.x = 1;
x["_$foo$_"] = 2 * x.o; x["_$foo$_"] = 2 * x.x;
console.log(x.o, x["_$foo$_"]); console.log(x.x, x["_$foo$_"]);
} }
expect_stdout: true expect_stdout: true
} }
issue_1321_with_quoted: { issue_1321_with_quoted: {
mangle_props = { mangle = {
keep_quoted: false properties: {
keep_quoted: false,
},
} }
input: { input: {
var x = {}; var x = {};
@@ -49,9 +55,9 @@ issue_1321_with_quoted: {
} }
expect: { expect: {
var x = {}; var x = {};
x.o = 1; x.x = 1;
x["x"] = 2 * x.o; x["o"] = 2 * x.x;
console.log(x.o, x["x"]); console.log(x.x, x["o"]);
} }
expect_stdout: true expect_stdout: true
} }

View File

@@ -1,5 +1,7 @@
mangle_props: { mangle_props: {
mangle_props = {} mangle = {
properties: true,
}
input: { input: {
var obj = { var obj = {
undefined: 1, undefined: 1,
@@ -54,10 +56,12 @@ mangle_props: {
} }
numeric_literal: { numeric_literal: {
mangle = {
properties: true,
}
beautify = { beautify = {
beautify: true, beautify: true,
} }
mangle_props = {}
input: { input: {
var obj = { var obj = {
0: 0, 0: 0,
@@ -105,7 +109,9 @@ numeric_literal: {
} }
identifier: { identifier: {
mangle_props = {} mangle = {
properties: true,
}
input: { input: {
var obj = { var obj = {
abstract: 1, abstract: 1,

View File

@@ -1,6 +1,8 @@
dont_reuse_prop: { dont_reuse_prop: {
mangle_props = { mangle = {
regex: /asd/ properties: {
regex: /asd/,
},
} }
input: { input: {
"aaaaaaaaaabbbbb"; "aaaaaaaaaabbbbb";
@@ -20,8 +22,10 @@ dont_reuse_prop: {
} }
unmangleable_props_should_always_be_reserved: { unmangleable_props_should_always_be_reserved: {
mangle_props = { mangle = {
regex: /asd/ properties: {
regex: /asd/,
},
} }
input: { input: {
"aaaaaaaaaabbbbb"; "aaaaaaaaaabbbbb";

View File

@@ -13,8 +13,10 @@ keep_properties: {
dot_properties: { dot_properties: {
options = { options = {
properties: true, properties: true,
}
beautify = {
ie8: true, ie8: true,
}; }
input: { input: {
a["foo"] = "bar"; a["foo"] = "bar";
a["if"] = "if"; a["if"] = "if";
@@ -36,8 +38,10 @@ dot_properties: {
dot_properties_es5: { dot_properties_es5: {
options = { options = {
properties: true, properties: true,
}
beautify = {
ie8: false, ie8: false,
}; }
input: { input: {
a["foo"] = "bar"; a["foo"] = "bar";
a["if"] = "if"; a["if"] = "if";
@@ -124,9 +128,11 @@ evaluate_string_length: {
} }
mangle_properties: { mangle_properties: {
mangle_props = { mangle = {
keep_quoted: false properties: {
}; keep_quoted: false,
},
}
input: { input: {
a["foo"] = "bar"; a["foo"] = "bar";
a.color = "red"; a.color = "red";
@@ -135,11 +141,11 @@ mangle_properties: {
a['run']({color: "blue", foo: "baz"}); a['run']({color: "blue", foo: "baz"});
} }
expect: { expect: {
a["o"] = "bar"; a["a"] = "bar";
a.a = "red"; a.b = "red";
x = {r: 10}; x = {o: 10};
a.b(x.r, a.o); a.r(x.o, a.a);
a['b']({a: "blue", o: "baz"}); a['r']({b: "blue", a: "baz"});
} }
} }
@@ -147,8 +153,10 @@ mangle_unquoted_properties: {
options = { options = {
properties: false properties: false
} }
mangle_props = { mangle = {
keep_quoted: true properties: {
keep_quoted: true,
},
} }
beautify = { beautify = {
beautify: false, beautify: false,
@@ -177,24 +185,26 @@ mangle_unquoted_properties: {
function f1() { function f1() {
a["foo"] = "bar"; a["foo"] = "bar";
a.color = "red"; a.color = "red";
a.o = 2; a.r = 2;
x = {"bar": 10, f: 7}; x = {"bar": 10, b: 7};
a.f = 9; a.b = 9;
} }
function f2() { function f2() {
a.foo = "bar"; a.foo = "bar";
a['color'] = "red"; a['color'] = "red";
x = {bar: 10, f: 7}; x = {bar: 10, b: 7};
a.f = 9; a.b = 9;
a.o = 3; a.r = 3;
} }
} }
} }
mangle_debug: { mangle_debug: {
mangle_props = { mangle = {
debug: "" properties: {
}; debug: "",
},
}
input: { input: {
a.foo = "bar"; a.foo = "bar";
x = { baz: "ban" }; x = { baz: "ban" };
@@ -206,9 +216,11 @@ mangle_debug: {
} }
mangle_debug_true: { mangle_debug_true: {
mangle_props = { mangle = {
debug: true properties: {
}; debug: true,
},
}
input: { input: {
a.foo = "bar"; a.foo = "bar";
x = { baz: "ban" }; x = { baz: "ban" };
@@ -220,9 +232,11 @@ mangle_debug_true: {
} }
mangle_debug_suffix: { mangle_debug_suffix: {
mangle_props = { mangle = {
debug: "XYZ" properties: {
}; debug: "XYZ",
},
}
input: { input: {
a.foo = "bar"; a.foo = "bar";
x = { baz: "ban" }; x = { baz: "ban" };
@@ -237,10 +251,12 @@ mangle_debug_suffix_keep_quoted: {
options = { options = {
properties: false properties: false
} }
mangle_props = { mangle = {
keep_quoted: true, properties: {
debug: "XYZ", debug: "XYZ",
reserved: [] keep_quoted: true,
reserved: [],
},
} }
beautify = { beautify = {
beautify: false, beautify: false,
@@ -770,3 +786,21 @@ issue_2208_5: {
} }
expect_stdout: "42" expect_stdout: "42"
} }
issue_2256: {
options = {
side_effects: true,
}
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
({ "keep": 1 });
g.keep = g.change;
}
expect: {
g.keep = g.g;
}
}

View File

@@ -325,3 +325,69 @@ issue_2120_2: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_2254_1: {
mangle = {
ie8: false,
}
input: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(s) {
try {
throw "FAIL";
} catch (e) {
return s;
}
}
}
expect: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(e) {
try {
throw "FAIL";
} catch (t) {
return e;
}
}
}
expect_stdout: "PASS"
}
issue_2254_2: {
mangle = {
ie8: true,
}
input: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(s) {
try {
throw "FAIL";
} catch (e) {
return s;
}
}
}
expect: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(t) {
try {
throw "FAIL";
} catch (e) {
return t;
}
}
}
expect_stdout: "PASS"
}

View File

@@ -15,3 +15,43 @@ unicode_parse_variables: {
var l = 3; var l = 3;
} }
} }
issue_2242_1: {
beautify = {
ascii_only: false,
}
input: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\ud83d\ude00","\\ud83d@\\ude00");'
}
issue_2242_2: {
beautify = {
ascii_only: true,
}
input: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\\ud83d\\ude00","\\ud83d@\\ude00");'
}
issue_2242_3: {
options = {
evaluate: false,
}
input: {
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
}
expect_exact: 'console.log("\\ud83d"+"\\ude00","\\ud83d"+"@"+"\\ude00");'
}
issue_2242_4: {
options = {
evaluate: true,
}
input: {
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
}
expect_exact: 'console.log("\ud83d\ude00","\\ud83d@\\ude00");'
}

View File

@@ -8,6 +8,7 @@ exports["defaults"] = defaults;
exports["mangle_properties"] = mangle_properties; exports["mangle_properties"] = mangle_properties;
exports["minify"] = minify; exports["minify"] = minify;
exports["parse"] = parse; exports["parse"] = parse;
exports["reserve_quoted_keys"] = reserve_quoted_keys;
exports["string_template"] = string_template; exports["string_template"] = string_template;
exports["tokenizer"] = tokenizer; exports["tokenizer"] = tokenizer;
exports["is_identifier"] = is_identifier; exports["is_identifier"] = is_identifier;

View File

@@ -63,7 +63,7 @@ describe("bin/uglifyjs", function () {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" + assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=\n"); "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==\n");
done(); done();
}); });
}); });
@@ -192,7 +192,7 @@ describe("bin/uglifyjs", function () {
assert.strictEqual(stdout, [ assert.strictEqual(stdout, [
"var bar=function(){function foo(bar){return bar}return foo}();", "var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=", "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
"", "",
].join("\n")); ].join("\n"));
assert.strictEqual(stderr, "WARN: inline source map not found\n"); assert.strictEqual(stderr, "WARN: inline source map not found\n");
@@ -593,8 +593,8 @@ describe("bin/uglifyjs", function () {
done(); done();
}); });
}); });
it("Should work with --mangle reserved=[]", function (done) { it("Should work with --mangle reserved=[]", function(done) {
var command = uglifyjscmd + ' test/input/issue-505/input.js -m reserved=[callback]'; var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=[callback]";
exec(command, function (err, stdout) { exec(command, function (err, stdout) {
if (err) throw err; if (err) throw err;
@@ -603,8 +603,8 @@ describe("bin/uglifyjs", function () {
done(); done();
}); });
}); });
it("Should work with --mangle reserved=false", function (done) { it("Should work with --mangle reserved=false", function(done) {
var command = uglifyjscmd + ' test/input/issue-505/input.js -m reserved=false'; var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=false";
exec(command, function (err, stdout) { exec(command, function (err, stdout) {
if (err) throw err; if (err) throw err;
@@ -613,4 +613,22 @@ describe("bin/uglifyjs", function () {
done(); done();
}); });
}); });
it("Should fail with --mangle-props reserved=[in]", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js --mangle-props reserved=[in]";
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.ok(/^Supported options:\n[\s\S]*?\nERROR: `reserved=\[in]` is not a supported option/.test(stderr), stderr);
done();
});
});
it("Should fail with --define a-b", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js --define a-b";
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr, "Error parsing arguments for 'define': a-b\n");
done();
});
});
}); });

View File

@@ -2,16 +2,17 @@ var Uglify = require('../../');
var assert = require("assert"); var assert = require("assert");
describe("let", function() { describe("let", function() {
it("Should not produce reserved keywords as variable name in mangle", function(done) { this.timeout(30000);
this.timeout(10000); it("Should not produce reserved keywords as variable name in mangle", function() {
// Produce a lot of variables in a function and run it through mangle. // Produce a lot of variables in a function and run it through mangle.
var s = '"dddddeeeeelllllooooottttt"; function foo() {'; var s = '"dddddeeeeelllllooooottttt"; function foo() {';
for (var i = 0; i < 18000; i++) { for (var i = 0; i < 18000; i++) {
s += "var v" + i + "=0;"; s += "var v" + i + "=0;";
} }
s += '}'; s += '}';
var result = Uglify.minify(s, {compress: false}); var result = Uglify.minify(s, {
compress: false
}).code;
// Verify that select keywords and reserved keywords not produced // Verify that select keywords and reserved keywords not produced
[ [
@@ -19,7 +20,7 @@ describe("let", function() {
"let", "let",
"var", "var",
].forEach(function(name) { ].forEach(function(name) {
assert.strictEqual(result.code.indexOf("var " + name + "="), -1); assert.strictEqual(result.indexOf("var " + name + "="), -1);
}); });
// Verify that the variable names that appeared immediately before // Verify that the variable names that appeared immediately before
@@ -30,9 +31,27 @@ describe("let", function() {
"eet", "fet", "eet", "fet",
"rar", "oar", "rar", "oar",
].forEach(function(name) { ].forEach(function(name) {
assert.ok(result.code.indexOf("var " + name + "=") >= 0); assert.notStrictEqual(result.indexOf("var " + name + "="), -1);
});
});
it("Should quote mangled properties that are reserved keywords", function() {
var s = '"rrrrrnnnnniiiiiaaaaa";';
for (var i = 0; i < 18000; i++) {
s += "v.b" + i + ";";
}
var result = Uglify.minify(s, {
compress: false,
ie8: true,
mangle: {
properties: true,
}
}).code;
[
"in",
"var",
].forEach(function(name) {
assert.notStrictEqual(result.indexOf(name), -1);
assert.notStrictEqual(result.indexOf('v["' + name + '"]'), -1);
}); });
done();
}); });
}); });

View File

@@ -124,6 +124,17 @@ describe("minify", function() {
assert.strictEqual(result.code, assert.strictEqual(result.code,
'a["foo"]="bar",a.a="red",x={"bar":10};'); 'a["foo"]="bar",a.a="red",x={"bar":10};');
}); });
it("Should not mangle quoted property within dead code", function() {
var result = Uglify.minify('({ "keep": 1 }); g.keep = g.change;', {
mangle: {
properties: {
keep_quoted: true
}
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "g.keep=g.g;");
});
}); });
describe("inSourceMap", function() { describe("inSourceMap", function() {

View File

@@ -61,9 +61,9 @@ describe("String literals", function() {
var tests = [ var tests = [
['"\\76";', ';">";'], ['"\\76";', ';">";'],
['"\\0"', '"\\0";'], ['"\\0"', '"\\0";'],
['"\\08"', '"\\08";'], ['"\\08"', '"\\x008";'],
['"\\008"', '"\\08";'], ['"\\008"', '"\\x008";'],
['"\\0008"', '"\\08";'], ['"\\0008"', '"\\x008";'],
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'], ['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
['"use\\\n strict";\n"\\07";', ';"use strict";"\07";'] ['"use\\\n strict";\n"\\07";', ';"use strict";"\07";']
]; ];
@@ -75,7 +75,44 @@ describe("String literals", function() {
}); });
it("Should not throw error when digit is 8 or 9", function() { it("Should not throw error when digit is 8 or 9", function() {
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\08";'); assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\x008";');
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\09";'); assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\x009";');
});
it("Should not unescape unpaired surrogates", function() {
var code = [];
for (var i = 0; i <= 0xF; i++) {
code.push("\\u000" + i.toString(16));
}
for (;i <= 0xFF; i++) {
code.push("\\u00" + i.toString(16));
}
for (;i <= 0xFFF; i++) {
code.push("\\u0" + i.toString(16));
}
for (; i <= 0xFFFF; i++) {
code.push("\\u" + i.toString(16));
}
code = '"' + code.join() + '"';
var normal = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
ascii_only: false
}
});
if (normal.error) throw normal.error;
assert.ok(code.length > normal.code.length);
assert.strictEqual(eval(code), eval(normal.code));
var ascii = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
ascii_only: false
}
});
if (ascii.error) throw ascii.error;
assert.ok(code.length > ascii.code.length);
assert.strictEqual(eval(code), eval(ascii.code));
}); });
}); });

View File

@@ -111,18 +111,22 @@ function run_compress_tests() {
}; };
if (!options.warnings) options.warnings = true; if (!options.warnings) options.warnings = true;
} }
if (test.mangle && test.mangle.properties && test.mangle.properties.keep_quoted) {
var quoted_props = test.mangle.properties.reserved;
if (!Array.isArray(quoted_props)) quoted_props = [];
test.mangle.properties.reserved = quoted_props;
U.reserve_quoted_keys(input, quoted_props);
}
var cmp = new U.Compressor(options, true); var cmp = new U.Compressor(options, true);
var output = cmp.compress(input); var output = cmp.compress(input);
output.figure_out_scope(test.mangle); output.figure_out_scope(test.mangle);
if (test.mangle || test.mangle_props) { if (test.mangle) {
U.base54.reset(); U.base54.reset();
output.compute_char_frequency(test.mangle); output.compute_char_frequency(test.mangle);
}
if (test.mangle) {
output.mangle_names(test.mangle); output.mangle_names(test.mangle);
} if (test.mangle.properties) {
if (test.mangle_props) { output = U.mangle_properties(output, test.mangle.properties);
output = U.mangle_properties(output, test.mangle_props); }
} }
output = make_code(output, output_options); output = make_code(output, output_options);
if (expect != output) { if (expect != output) {