Compare commits
14 Commits
harmony-v3
...
v3.0.26
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc61deeca9 | ||
|
|
6a5e74b44e | ||
|
|
54446341ee | ||
|
|
4e12a6f740 | ||
|
|
b35dfc2599 | ||
|
|
9e1da9235e | ||
|
|
a5ffe2c23f | ||
|
|
9282e7b0c6 | ||
|
|
5229cb2b1b | ||
|
|
458e3e15f0 | ||
|
|
c615a1e80a | ||
|
|
10a938cb79 | ||
|
|
4956ad311b | ||
|
|
145874e504 |
15
README.md
15
README.md
@@ -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
|
||||
`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
|
||||
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
|
||||
|
||||
It's not well known, but variable and function name mangling accounts for
|
||||
95% of the size reduction in minified code for most javascript - not
|
||||
It's not well known, but whitespace removal and symbol mangling accounts
|
||||
for 95% of the size reduction in minified code for most javascript - not
|
||||
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
|
||||
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) |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| original | 451,131 | 108,733 | - |
|
||||
| uglify-js@3.0.23 mangle=false, compress=false | 316,600 | 85,245 | 0.73 |
|
||||
| uglify-js@3.0.23 mangle=true, compress=false | 220,216 | 72,730 | 1.21 |
|
||||
| Butternut 0.4.6 | 217,568 | 72,738 | 1.81 |
|
||||
| uglify-js@3.0.23 mangle=true, compress=true | 212,511 | 71,560 | 4.64 |
|
||||
| uglify-js@3.0.24 mangle=false, compress=false | 316,600 | 85,245 | 0.70 |
|
||||
| uglify-js@3.0.24 mangle=true, compress=false | 220,216 | 72,730 | 1.13 |
|
||||
| butternut@0.4.6 | 217,568 | 72,738 | 1.41 |
|
||||
| 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:
|
||||
```
|
||||
|
||||
22
bin/uglifyjs
22
bin/uglifyjs
@@ -35,11 +35,11 @@ else if (process.argv.indexOf("options") >= 0) program.helpInformation = functio
|
||||
}
|
||||
return text.join("\n");
|
||||
};
|
||||
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true));
|
||||
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js("compress", true));
|
||||
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js("mangle", true));
|
||||
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js("mangle-props", true));
|
||||
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js("beautify", true));
|
||||
program.option("-p, --parse <options>", "Specify parser options.", parse_js());
|
||||
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js());
|
||||
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
|
||||
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
|
||||
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js());
|
||||
program.option("-o, --output <file>", "Output file (default STDOUT).");
|
||||
program.option("--comments [filter]", "Preserve copyright comments in the output.");
|
||||
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) {
|
||||
options = options || {};
|
||||
try {
|
||||
@@ -328,7 +328,7 @@ function parse_js(flag, constants) {
|
||||
if (node instanceof UglifyJS.AST_Assign) {
|
||||
var name = node.left.print_to_string();
|
||||
var value = node.right;
|
||||
if (!constants) {
|
||||
if (flag) {
|
||||
options[name] = value;
|
||||
} else if (value instanceof UglifyJS.AST_Array) {
|
||||
options[name] = value.elements.map(to_string);
|
||||
@@ -351,14 +351,18 @@ function parse_js(flag, constants) {
|
||||
}
|
||||
}));
|
||||
} catch(ex) {
|
||||
options[value] = null;
|
||||
if (flag) {
|
||||
fatal("Error parsing arguments for '" + flag + "': " + value);
|
||||
} else {
|
||||
options[value] = null;
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
function parse_source_map() {
|
||||
var parse = parse_js("sourceMap", true);
|
||||
var parse = parse_js();
|
||||
return function(value, options) {
|
||||
var hasContent = options && "content" in options;
|
||||
var settings = parse(value, options);
|
||||
|
||||
159
lib/compress.js
159
lib/compress.js
@@ -148,10 +148,20 @@ merge(Compressor.prototype, {
|
||||
node.process_expression(true);
|
||||
}
|
||||
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"))
|
||||
node.reset_opt_flags(this, true);
|
||||
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")) {
|
||||
node.process_expression(false);
|
||||
@@ -679,6 +689,16 @@ merge(Compressor.prototype, {
|
||||
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) {
|
||||
var CHANGED, max_iter = 10;
|
||||
do {
|
||||
@@ -748,7 +768,7 @@ merge(Compressor.prototype, {
|
||||
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|
||||
|| node instanceof AST_Debugger
|
||||
|| 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_With
|
||||
|| parent instanceof AST_For && node !== parent.init) {
|
||||
@@ -780,6 +800,7 @@ merge(Compressor.prototype, {
|
||||
right: candidate.value
|
||||
});
|
||||
}
|
||||
candidate.write_only = false;
|
||||
return candidate;
|
||||
}
|
||||
// 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`
|
||||
(function(def) {
|
||||
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
|
||||
var pure_getters = compressor.option("pure_getters");
|
||||
return !pure_getters || this._throw_on_access(pure_getters);
|
||||
return !compressor.option("pure_getters")
|
||||
|| this._dot_throw(compressor);
|
||||
});
|
||||
|
||||
function is_strict(pure_getters) {
|
||||
return /strict/.test(pure_getters);
|
||||
function is_strict(compressor) {
|
||||
return /strict/.test(compressor.option("pure_getters"));
|
||||
}
|
||||
|
||||
def(AST_Node, is_strict);
|
||||
@@ -1322,8 +1343,8 @@ merge(Compressor.prototype, {
|
||||
def(AST_Undefined, return_true);
|
||||
def(AST_Constant, return_false);
|
||||
def(AST_Array, return_false);
|
||||
def(AST_Object, function(pure_getters) {
|
||||
if (!is_strict(pure_getters)) return false;
|
||||
def(AST_Object, function(compressor) {
|
||||
if (!is_strict(compressor)) return false;
|
||||
for (var i = this.properties.length; --i >=0;)
|
||||
if (this.properties[i].value instanceof AST_Accessor) return true;
|
||||
return false;
|
||||
@@ -1333,37 +1354,38 @@ merge(Compressor.prototype, {
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "void";
|
||||
});
|
||||
def(AST_Binary, function(pure_getters) {
|
||||
def(AST_Binary, function(compressor) {
|
||||
switch (this.operator) {
|
||||
case "&&":
|
||||
return this.left._throw_on_access(pure_getters);
|
||||
return this.left._dot_throw(compressor);
|
||||
case "||":
|
||||
return this.left._throw_on_access(pure_getters)
|
||||
&& this.right._throw_on_access(pure_getters);
|
||||
return this.left._dot_throw(compressor)
|
||||
&& this.right._dot_throw(compressor);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
})
|
||||
def(AST_Assign, function(pure_getters) {
|
||||
def(AST_Assign, function(compressor) {
|
||||
return this.operator == "="
|
||||
&& this.right._throw_on_access(pure_getters);
|
||||
&& this.right._dot_throw(compressor);
|
||||
})
|
||||
def(AST_Conditional, function(pure_getters) {
|
||||
return this.consequent._throw_on_access(pure_getters)
|
||||
|| this.alternative._throw_on_access(pure_getters);
|
||||
def(AST_Conditional, function(compressor) {
|
||||
return this.consequent._dot_throw(compressor)
|
||||
|| this.alternative._dot_throw(compressor);
|
||||
})
|
||||
def(AST_Sequence, function(pure_getters) {
|
||||
return this.expressions[this.expressions.length - 1]._throw_on_access(pure_getters);
|
||||
def(AST_Sequence, function(compressor) {
|
||||
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 (!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;
|
||||
var fixed = this.fixed_value();
|
||||
return !fixed || fixed._throw_on_access(pure_getters);
|
||||
return !fixed || fixed._dot_throw(compressor);
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("_throw_on_access", func);
|
||||
node.DEFMETHOD("_dot_throw", func);
|
||||
});
|
||||
|
||||
/* -----[ boolean/negation helpers ]----- */
|
||||
@@ -1724,11 +1746,8 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
var global_objs = {
|
||||
Array: Array,
|
||||
Boolean: Boolean,
|
||||
Math: Math,
|
||||
Number: Number,
|
||||
RegExp: RegExp,
|
||||
Object: Object,
|
||||
String: String,
|
||||
};
|
||||
function convert_to_predicate(obj) {
|
||||
@@ -1765,7 +1784,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
var exp = this.expression;
|
||||
var val;
|
||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
||||
if (is_undeclared_ref(exp)) {
|
||||
if (!(static_values[exp.name] || return_false)(key)) return this;
|
||||
val = global_objs[exp.name];
|
||||
} else {
|
||||
@@ -1842,10 +1861,6 @@ merge(Compressor.prototype, {
|
||||
"isFinite",
|
||||
"isNaN",
|
||||
],
|
||||
Object: [
|
||||
"keys",
|
||||
"getOwnPropertyNames",
|
||||
],
|
||||
String: [
|
||||
"fromCharCode",
|
||||
],
|
||||
@@ -1861,7 +1876,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
var val;
|
||||
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;
|
||||
val = global_objs[e.name];
|
||||
} else {
|
||||
@@ -2043,7 +2058,7 @@ merge(Compressor.prototype, {
|
||||
|| this.expression.has_side_effects(compressor);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor){
|
||||
return this.undeclared();
|
||||
return !this.is_declared(compressor);
|
||||
});
|
||||
def(AST_SymbolDeclaration, return_false);
|
||||
def(AST_Object, function(compressor){
|
||||
@@ -2167,7 +2182,12 @@ merge(Compressor.prototype, {
|
||||
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
|
||||
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
|
||||
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_ids = Object.create(null); // avoid expensive linear scans of in_use
|
||||
if (self instanceof AST_Toplevel && compressor.top_retain) {
|
||||
@@ -2217,12 +2237,8 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (assign_as_unused
|
||||
&& node instanceof AST_Assign
|
||||
&& node.operator == "="
|
||||
&& node.left instanceof AST_SymbolRef
|
||||
&& scope === self) {
|
||||
node.right.walk(tw);
|
||||
if (assign_as_unused(node) instanceof AST_SymbolRef && scope === self) {
|
||||
if (node instanceof AST_Assign) node.right.walk(tw);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
@@ -2386,14 +2402,17 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
}
|
||||
if (drop_vars && assign_as_unused
|
||||
&& node instanceof AST_Assign
|
||||
&& node.operator == "="
|
||||
&& node.left instanceof AST_SymbolRef) {
|
||||
var def = node.left.definition();
|
||||
if (!(def.id in in_use_ids)
|
||||
if (drop_vars) {
|
||||
var def = assign_as_unused(node);
|
||||
if (def instanceof AST_SymbolRef
|
||||
&& !((def = def.definition()).id in in_use_ids)
|
||||
&& 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:
|
||||
@@ -2632,7 +2651,10 @@ merge(Compressor.prototype, {
|
||||
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){
|
||||
var consequent = this.consequent.drop_side_effect_free(compressor);
|
||||
var alternative = this.alternative.drop_side_effect_free(compressor);
|
||||
@@ -2653,7 +2675,10 @@ merge(Compressor.prototype, {
|
||||
return node;
|
||||
});
|
||||
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;
|
||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (first_in_statement
|
||||
@@ -2667,8 +2692,8 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
return expression;
|
||||
});
|
||||
def(AST_SymbolRef, function() {
|
||||
return this.undeclared() ? this : null;
|
||||
def(AST_SymbolRef, function(compressor) {
|
||||
return this.is_declared(compressor) ? null : this;
|
||||
});
|
||||
def(AST_Object, function(compressor, first_in_statement){
|
||||
var values = trim(this.properties, compressor, first_in_statement);
|
||||
@@ -3130,7 +3155,7 @@ merge(Compressor.prototype, {
|
||||
self.args.length = last;
|
||||
}
|
||||
if (compressor.option("unsafe")) {
|
||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
||||
if (is_undeclared_ref(exp)) {
|
||||
switch (exp.name) {
|
||||
case "Array":
|
||||
if (self.args.length != 1) {
|
||||
@@ -3257,8 +3282,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
if (compressor.option("unsafe_Func")
|
||||
&& exp instanceof AST_SymbolRef
|
||||
&& exp.undeclared()
|
||||
&& is_undeclared_ref(exp)
|
||||
&& exp.name == "Function") {
|
||||
// new Function() => function(){}
|
||||
if (self.args.length == 0) return make_node(AST_Function, self, {
|
||||
@@ -3375,9 +3399,7 @@ merge(Compressor.prototype, {
|
||||
while (name.expression) {
|
||||
name = name.expression;
|
||||
}
|
||||
if (name instanceof AST_SymbolRef
|
||||
&& name.name == "console"
|
||||
&& name.undeclared()) {
|
||||
if (is_undeclared_ref(name) && name.name == "console") {
|
||||
return make_node(AST_Undefined, self).optimize(compressor);
|
||||
}
|
||||
}
|
||||
@@ -3398,7 +3420,7 @@ merge(Compressor.prototype, {
|
||||
OPT(AST_New, function(self, compressor){
|
||||
if (compressor.option("unsafe")) {
|
||||
var exp = self.expression;
|
||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
||||
if (is_undeclared_ref(exp)) {
|
||||
switch (exp.name) {
|
||||
case "Object":
|
||||
case "RegExp":
|
||||
@@ -3475,6 +3497,8 @@ merge(Compressor.prototype, {
|
||||
operator: car.operator,
|
||||
expression: left
|
||||
});
|
||||
} else {
|
||||
car.write_only = false;
|
||||
}
|
||||
if (parent) {
|
||||
parent[field] = car;
|
||||
@@ -3690,7 +3714,7 @@ merge(Compressor.prototype, {
|
||||
&& self.right instanceof AST_UnaryPrefix
|
||||
&& self.right.operator == "typeof") {
|
||||
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"))) {
|
||||
self.right = expr;
|
||||
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
|
||||
if (!compressor.option("ie8")
|
||||
&& self.undeclared()
|
||||
&& is_undeclared_ref(self)
|
||||
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
||||
switch (self.name) {
|
||||
case "undefined":
|
||||
@@ -4371,7 +4395,7 @@ merge(Compressor.prototype, {
|
||||
var prop = self.property;
|
||||
if (prop instanceof AST_String && compressor.option("properties")) {
|
||||
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, {
|
||||
expression : self.expression,
|
||||
property : prop
|
||||
@@ -4408,19 +4432,10 @@ merge(Compressor.prototype, {
|
||||
if (def) {
|
||||
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) {
|
||||
var values = self.expression.properties;
|
||||
for (var i = values.length; --i >= 0;) {
|
||||
if (values[i].key === prop) {
|
||||
if (values[i].key === self.property) {
|
||||
var value = values[i].value;
|
||||
if (value instanceof AST_Function ? !value.contains_this() : !value.has_side_effects(compressor)) {
|
||||
var obj = self.expression.clone();
|
||||
@@ -4435,7 +4450,7 @@ merge(Compressor.prototype, {
|
||||
&& self.expression instanceof AST_Dot
|
||||
&& self.expression.property == "prototype") {
|
||||
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":
|
||||
self.expression = make_node(AST_Array, self.expression, {
|
||||
elements: []
|
||||
|
||||
@@ -109,7 +109,7 @@ function OutputStream(options) {
|
||||
var current_pos = 0;
|
||||
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) {
|
||||
var code = ch.charCodeAt(0).toString(16);
|
||||
if (code.length <= 2 && !identifier) {
|
||||
@@ -120,6 +120,12 @@ function OutputStream(options) {
|
||||
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) {
|
||||
@@ -150,7 +156,7 @@ function OutputStream(options) {
|
||||
function quote_double() {
|
||||
return '"' + str.replace(/\x22/g, '\\"') + '"';
|
||||
}
|
||||
if (options.ascii_only) str = to_ascii(str);
|
||||
str = to_utf8(str);
|
||||
switch (options.quote_style) {
|
||||
case 1:
|
||||
return quote_single();
|
||||
@@ -175,8 +181,7 @@ function OutputStream(options) {
|
||||
|
||||
function make_name(name) {
|
||||
name = name.toString();
|
||||
if (options.ascii_only)
|
||||
name = to_ascii(name, true);
|
||||
name = to_utf8(name, true);
|
||||
return name;
|
||||
};
|
||||
|
||||
@@ -433,7 +438,7 @@ function OutputStream(options) {
|
||||
last : function() { return last },
|
||||
semicolon : semicolon,
|
||||
force_semicolon : force_semicolon,
|
||||
to_ascii : to_ascii,
|
||||
to_utf8 : to_utf8,
|
||||
print_name : function(name) { print(make_name(name)) },
|
||||
print_string : function(str, quote, escape_directive) {
|
||||
var encoded = encode_string(str, quote);
|
||||
@@ -1104,6 +1109,9 @@ function OutputStream(options) {
|
||||
self.expression.print(output);
|
||||
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
||||
return;
|
||||
if (self.expression instanceof AST_Lambda) {
|
||||
output.add_mapping(self.start);
|
||||
}
|
||||
output.with_parens(function(){
|
||||
self.args.forEach(function(expr, i){
|
||||
if (i) output.comma();
|
||||
@@ -1143,15 +1151,23 @@ function OutputStream(options) {
|
||||
DEFPRINT(AST_Dot, function(self, output){
|
||||
var expr = self.expression;
|
||||
expr.print(output);
|
||||
if (expr instanceof AST_Number && expr.getValue() >= 0) {
|
||||
if (!/[xa-f.)]/i.test(output.last())) {
|
||||
output.print(".");
|
||||
var prop = self.property;
|
||||
if (output.option("ie8") && RESERVED_WORDS(prop)) {
|
||||
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){
|
||||
self.expression.print(output);
|
||||
@@ -1307,9 +1323,7 @@ function OutputStream(options) {
|
||||
if (regexp.raw_source) {
|
||||
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
|
||||
}
|
||||
if (output.option("ascii_only")) {
|
||||
str = output.to_ascii(str);
|
||||
}
|
||||
str = output.to_utf8(str);
|
||||
output.print(str);
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
||||
|
||||
@@ -76,7 +76,7 @@ function mangle_properties(ast, options) {
|
||||
only_cache: false,
|
||||
regex: null,
|
||||
reserved: null,
|
||||
});
|
||||
}, true);
|
||||
|
||||
var reserved = options.reserved;
|
||||
if (!Array.isArray(reserved)) reserved = [];
|
||||
|
||||
@@ -373,14 +373,6 @@ AST_Symbol.DEFMETHOD("unreferenced", function(){
|
||||
&& !(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(){
|
||||
return this.thedef;
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": "http://lisperator.net/uglifyjs",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.0.24",
|
||||
"version": "3.0.26",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
@@ -29,12 +29,12 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "~2.9.0",
|
||||
"commander": "~2.11.0",
|
||||
"source-map": "~0.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"acorn": "~5.0.3",
|
||||
"mocha": "~2.3.4",
|
||||
"acorn": "~5.1.1",
|
||||
"mocha": "~3.4.2",
|
||||
"semver": "~5.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
var createHash = require("crypto").createHash;
|
||||
var fetch = require("./fetch");
|
||||
var fork = require("child_process").fork;
|
||||
var zlib = require("zlib");
|
||||
var args = process.argv.slice(2);
|
||||
if (!args.length) {
|
||||
args.push("-mc");
|
||||
@@ -33,6 +34,7 @@ function done() {
|
||||
console.log(info.log);
|
||||
console.log("Original:", info.input, "bytes");
|
||||
console.log("Uglified:", info.output, "bytes");
|
||||
console.log("GZipped: ", info.gzip, "bytes");
|
||||
console.log("SHA1 sum:", info.sha1);
|
||||
if (info.code) {
|
||||
failures.push(url);
|
||||
@@ -51,6 +53,7 @@ urls.forEach(function(url) {
|
||||
results[url] = {
|
||||
input: 0,
|
||||
output: 0,
|
||||
gzip: 0,
|
||||
log: ""
|
||||
};
|
||||
fetch(url, function(err, res) {
|
||||
@@ -61,6 +64,10 @@ urls.forEach(function(url) {
|
||||
}).pipe(uglifyjs.stdin);
|
||||
uglifyjs.stdout.on("data", function(data) {
|
||||
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) {
|
||||
results[url].sha1 = data.toString("hex");
|
||||
done();
|
||||
|
||||
@@ -863,7 +863,7 @@ collapse_vars_unary: {
|
||||
input: {
|
||||
function f0(o, p) {
|
||||
var x = o[p];
|
||||
delete x;
|
||||
return delete x;
|
||||
}
|
||||
function f1(n) {
|
||||
var k = !!n;
|
||||
@@ -893,7 +893,7 @@ collapse_vars_unary: {
|
||||
expect: {
|
||||
function f0(o, p) {
|
||||
var x = o[p];
|
||||
delete x;
|
||||
return delete x;
|
||||
}
|
||||
function f1(n) {
|
||||
return n > +!!n
|
||||
|
||||
@@ -230,3 +230,82 @@ accessor: {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1090,6 +1090,7 @@ var_catch_toplevel: {
|
||||
a--;
|
||||
try {
|
||||
a++;
|
||||
x();
|
||||
} catch(a) {
|
||||
if (a) var a;
|
||||
var a = 10;
|
||||
@@ -1099,9 +1100,8 @@ var_catch_toplevel: {
|
||||
}
|
||||
expect: {
|
||||
!function() {
|
||||
a--;
|
||||
try {
|
||||
a++;
|
||||
x();
|
||||
} catch(a) {
|
||||
var a;
|
||||
}
|
||||
@@ -1153,3 +1153,89 @@ issue_2105: {
|
||||
}
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -1157,3 +1157,31 @@ issue_2207_3: {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -71,11 +71,13 @@ non_hoisted_function_after_return_2a: {
|
||||
"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 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: Declarations in unreachable code! [test/compress/issue-1034.js:53,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 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: [
|
||||
// duplicate warnings no longer emitted
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:95,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:95,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:99,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:99,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_warnings: [
|
||||
'WARN: Dropping unreachable code [test/compress/issue-1034.js:131,16]',
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:134,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:137,12]",
|
||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:138,21]"
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:133,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:136,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:139,12]",
|
||||
"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_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:173,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:173,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:176,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:176,16]",
|
||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:173,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:180,21]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:178,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:181,12]",
|
||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:176,20]",
|
||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:178,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:175,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:175,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:178,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,16]",
|
||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:175,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:182,21]",
|
||||
"WARN: pass 0: last_count: Infinity, count: 48",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:180,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:180,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:183,12]",
|
||||
"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_warnings: [
|
||||
// duplicate warnings no longer emitted
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:225,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:225,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:229,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:229,16]",
|
||||
"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]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@ keep_properties: {
|
||||
dot_properties: {
|
||||
options = {
|
||||
properties: true,
|
||||
}
|
||||
beautify = {
|
||||
ie8: true,
|
||||
};
|
||||
}
|
||||
input: {
|
||||
a["foo"] = "bar";
|
||||
a["if"] = "if";
|
||||
@@ -36,8 +38,10 @@ dot_properties: {
|
||||
dot_properties_es5: {
|
||||
options = {
|
||||
properties: true,
|
||||
}
|
||||
beautify = {
|
||||
ie8: false,
|
||||
};
|
||||
}
|
||||
input: {
|
||||
a["foo"] = "bar";
|
||||
a["if"] = "if";
|
||||
|
||||
@@ -15,3 +15,43 @@ unicode_parse_variables: {
|
||||
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");'
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ describe("bin/uglifyjs", function () {
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=\n");
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==\n");
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -192,7 +192,7 @@ describe("bin/uglifyjs", function () {
|
||||
|
||||
assert.strictEqual(stdout, [
|
||||
"var bar=function(){function foo(bar){return bar}return foo}();",
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DIn0=",
|
||||
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
|
||||
"",
|
||||
].join("\n"));
|
||||
assert.strictEqual(stderr, "WARN: inline source map not found\n");
|
||||
@@ -593,8 +593,8 @@ describe("bin/uglifyjs", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should work with --mangle reserved=[]", function (done) {
|
||||
var command = uglifyjscmd + ' test/input/issue-505/input.js -m reserved=[callback]';
|
||||
it("Should work with --mangle reserved=[]", function(done) {
|
||||
var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=[callback]";
|
||||
|
||||
exec(command, function (err, stdout) {
|
||||
if (err) throw err;
|
||||
@@ -603,8 +603,8 @@ describe("bin/uglifyjs", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should work with --mangle reserved=false", function (done) {
|
||||
var command = uglifyjscmd + ' test/input/issue-505/input.js -m reserved=false';
|
||||
it("Should work with --mangle reserved=false", function(done) {
|
||||
var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=false";
|
||||
|
||||
exec(command, function (err, stdout) {
|
||||
if (err) throw err;
|
||||
@@ -613,4 +613,22 @@ describe("bin/uglifyjs", function () {
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,16 +2,17 @@ var Uglify = require('../../');
|
||||
var assert = require("assert");
|
||||
|
||||
describe("let", function() {
|
||||
it("Should not produce reserved keywords as variable name in mangle", function(done) {
|
||||
this.timeout(10000);
|
||||
|
||||
this.timeout(30000);
|
||||
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.
|
||||
var s = '"dddddeeeeelllllooooottttt"; function foo() {';
|
||||
for (var i = 0; i < 18000; i++) {
|
||||
s += "var v" + i + "=0;";
|
||||
}
|
||||
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
|
||||
[
|
||||
@@ -19,7 +20,7 @@ describe("let", function() {
|
||||
"let",
|
||||
"var",
|
||||
].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
|
||||
@@ -30,9 +31,27 @@ describe("let", function() {
|
||||
"eet", "fet",
|
||||
"rar", "oar",
|
||||
].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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -78,4 +78,41 @@ describe("String literals", function() {
|
||||
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\08";');
|
||||
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\09";');
|
||||
});
|
||||
|
||||
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));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user