Merge remote-tracking branch 'refs/remotes/mishoo/master'
This commit is contained in:
commit
9e8da9ed85
20
README.md
20
README.md
|
|
@ -10,6 +10,9 @@ There's also an
|
||||||
[in-browser online demo](http://lisperator.net/uglifyjs/#demo) (for Firefox,
|
[in-browser online demo](http://lisperator.net/uglifyjs/#demo) (for Firefox,
|
||||||
Chrome and probably Safari).
|
Chrome and probably Safari).
|
||||||
|
|
||||||
|
Note: release versions of `uglify-js` only support ECMAScript 5 (ES5). If you wish to minify
|
||||||
|
ES2015+ (ES6+) code then please use the [harmony](#harmony) development branch.
|
||||||
|
|
||||||
Install
|
Install
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
@ -969,3 +972,20 @@ The `source_map_options` (optional) can contain the following properties:
|
||||||
[codegen]: http://lisperator.net/uglifyjs/codegen
|
[codegen]: http://lisperator.net/uglifyjs/codegen
|
||||||
[compressor]: http://lisperator.net/uglifyjs/compress
|
[compressor]: http://lisperator.net/uglifyjs/compress
|
||||||
[parser]: http://lisperator.net/uglifyjs/parser
|
[parser]: http://lisperator.net/uglifyjs/parser
|
||||||
|
|
||||||
|
#### Harmony
|
||||||
|
|
||||||
|
If you wish to use the experimental [harmony](https://github.com/mishoo/UglifyJS2/commits/harmony)
|
||||||
|
branch to minify ES2015+ (ES6+) code please use the following in your `package.json` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
"uglify-js": "git+https://github.com/mishoo/UglifyJS2.git#harmony"
|
||||||
|
```
|
||||||
|
|
||||||
|
or to directly install the experimental harmony version of uglify:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install --save-dev uglify-js@github:mishoo/UglifyJS2#harmony
|
||||||
|
```
|
||||||
|
|
||||||
|
See [#448](https://github.com/mishoo/UglifyJS2/issues/448) for additional details.
|
||||||
|
|
|
||||||
18
bin/uglifyjs
18
bin/uglifyjs
|
|
@ -364,7 +364,21 @@ async.eachLimit(files, 1, function (file, cb) {
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
||||||
print_error("Parse error at " + file + ":" + ex.line + "," + ex.col);
|
print_error("Parse error at " + file + ":" + ex.line + "," + ex.col);
|
||||||
print_error(ex.message);
|
var col = ex.col;
|
||||||
|
var line = code.split(/\r?\n/)[ex.line - (col ? 1 : 2)];
|
||||||
|
if (line) {
|
||||||
|
if (col > 40) {
|
||||||
|
line = line.slice(col - 40);
|
||||||
|
col = 40;
|
||||||
|
}
|
||||||
|
if (col) {
|
||||||
|
print_error(line.slice(0, 80));
|
||||||
|
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
|
||||||
|
} else {
|
||||||
|
print_error(line.slice(-40));
|
||||||
|
print_error(line.slice(-40).replace(/\S/g, " ") + "^");
|
||||||
|
}
|
||||||
|
}
|
||||||
print_error(ex.stack);
|
print_error(ex.stack);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
@ -390,7 +404,7 @@ async.eachLimit(files, 1, function (file, cb) {
|
||||||
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
|
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex instanceof UglifyJS.DefaultsError) {
|
if (ex instanceof UglifyJS.DefaultsError) {
|
||||||
print_error(ex.msg);
|
print_error(ex.message);
|
||||||
print_error("Supported options:");
|
print_error("Supported options:");
|
||||||
print_error(sys.inspect(ex.defs));
|
print_error(sys.inspect(ex.defs));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|
|
||||||
154
lib/compress.js
154
lib/compress.js
|
|
@ -1376,9 +1376,7 @@ merge(Compressor.prototype, {
|
||||||
&& (comments = this.start.comments_before)
|
&& (comments = this.start.comments_before)
|
||||||
&& comments.length
|
&& comments.length
|
||||||
&& /[@#]__PURE__/.test((last_comment = comments[comments.length - 1]).value)) {
|
&& /[@#]__PURE__/.test((last_comment = comments[comments.length - 1]).value)) {
|
||||||
compressor.warn("Dropping __PURE__ call [{file}:{line},{col}]", this.start);
|
pure = last_comment;
|
||||||
last_comment.value = last_comment.value.replace(/[@#]__PURE__/g, ' ');
|
|
||||||
pure = true;
|
|
||||||
}
|
}
|
||||||
return this.pure = pure;
|
return this.pure = pure;
|
||||||
});
|
});
|
||||||
|
|
@ -1677,8 +1675,7 @@ merge(Compressor.prototype, {
|
||||||
line : def.name.start.line,
|
line : def.name.start.line,
|
||||||
col : def.name.start.col
|
col : def.name.start.col
|
||||||
};
|
};
|
||||||
if (def.value && def.value.has_side_effects(compressor)) {
|
if (def.value && (def._unused_side_effects = def.value.drop_side_effect_free(compressor))) {
|
||||||
def._unused_side_effects = true;
|
|
||||||
compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);
|
compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1698,7 +1695,7 @@ merge(Compressor.prototype, {
|
||||||
for (var i = 0; i < def.length;) {
|
for (var i = 0; i < def.length;) {
|
||||||
var x = def[i];
|
var x = def[i];
|
||||||
if (x._unused_side_effects) {
|
if (x._unused_side_effects) {
|
||||||
side_effects.push(x.value);
|
side_effects.push(x._unused_side_effects);
|
||||||
def.splice(i, 1);
|
def.splice(i, 1);
|
||||||
} else {
|
} else {
|
||||||
if (side_effects.length > 0) {
|
if (side_effects.length > 0) {
|
||||||
|
|
@ -1928,6 +1925,10 @@ merge(Compressor.prototype, {
|
||||||
def(AST_This, return_null);
|
def(AST_This, return_null);
|
||||||
def(AST_Call, function(compressor, first_in_statement){
|
def(AST_Call, function(compressor, first_in_statement){
|
||||||
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) return this;
|
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) return this;
|
||||||
|
if (this.pure) {
|
||||||
|
compressor.warn("Dropping __PURE__ call [{file}:{line},{col}]", this.start);
|
||||||
|
this.pure.value = this.pure.value.replace(/[@#]__PURE__/g, ' ');
|
||||||
|
}
|
||||||
var args = trim(this.args, compressor, first_in_statement);
|
var args = trim(this.args, compressor, first_in_statement);
|
||||||
return args && AST_Seq.from_array(args);
|
return args && AST_Seq.from_array(args);
|
||||||
});
|
});
|
||||||
|
|
@ -1979,8 +1980,17 @@ merge(Compressor.prototype, {
|
||||||
case "typeof":
|
case "typeof":
|
||||||
if (this.expression instanceof AST_SymbolRef) return null;
|
if (this.expression instanceof AST_SymbolRef) return null;
|
||||||
default:
|
default:
|
||||||
if (first_in_statement && is_iife_call(this.expression)) return this;
|
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
if (first_in_statement
|
||||||
|
&& this instanceof AST_UnaryPrefix
|
||||||
|
&& is_iife_call(expression)) {
|
||||||
|
if (expression === this.expression && this.operator.length === 1) return this;
|
||||||
|
return make_node(AST_UnaryPrefix, this, {
|
||||||
|
operator: this.operator.length === 1 ? this.operator : "!",
|
||||||
|
expression: expression
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return expression;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function() {
|
def(AST_SymbolRef, function() {
|
||||||
|
|
@ -2028,10 +2038,6 @@ merge(Compressor.prototype, {
|
||||||
OPT(AST_SimpleStatement, function(self, compressor){
|
OPT(AST_SimpleStatement, function(self, compressor){
|
||||||
if (compressor.option("side_effects")) {
|
if (compressor.option("side_effects")) {
|
||||||
var body = self.body;
|
var body = self.body;
|
||||||
if (!body.has_side_effects(compressor)) {
|
|
||||||
compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
|
|
||||||
return make_node(AST_EmptyStatement, self);
|
|
||||||
}
|
|
||||||
var node = body.drop_side_effect_free(compressor, true);
|
var node = body.drop_side_effect_free(compressor, true);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
|
compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
|
||||||
|
|
@ -2687,17 +2693,10 @@ merge(Compressor.prototype, {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!self.car.has_side_effects(compressor)
|
if (!self.car.has_side_effects(compressor)
|
||||||
&& !self.cdr.has_side_effects(compressor)
|
|
||||||
&& self.car.equivalent_to(self.cdr)) {
|
&& self.car.equivalent_to(self.cdr)) {
|
||||||
return self.car;
|
return self.car;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.cdr instanceof AST_UnaryPrefix
|
|
||||||
&& self.cdr.operator == "void"
|
|
||||||
&& !self.cdr.expression.has_side_effects(compressor)) {
|
|
||||||
self.cdr.expression = self.car;
|
|
||||||
return self.cdr;
|
|
||||||
}
|
|
||||||
if (self.cdr instanceof AST_Undefined) {
|
if (self.cdr instanceof AST_Undefined) {
|
||||||
return make_node(AST_UnaryPrefix, self, {
|
return make_node(AST_UnaryPrefix, self, {
|
||||||
operator : "void",
|
operator : "void",
|
||||||
|
|
@ -2726,8 +2725,20 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_UnaryPrefix, function(self, compressor){
|
OPT(AST_UnaryPrefix, function(self, compressor){
|
||||||
self = self.lift_sequences(compressor);
|
var seq = self.lift_sequences(compressor);
|
||||||
|
if (seq !== self) {
|
||||||
|
return seq;
|
||||||
|
}
|
||||||
var e = self.expression;
|
var e = self.expression;
|
||||||
|
if (compressor.option("side_effects") && self.operator == "void") {
|
||||||
|
e = e.drop_side_effect_free(compressor);
|
||||||
|
if (e) {
|
||||||
|
self.expression = e;
|
||||||
|
return self;
|
||||||
|
} else {
|
||||||
|
return make_node(AST_Undefined, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||||
switch (self.operator) {
|
switch (self.operator) {
|
||||||
case "!":
|
case "!":
|
||||||
|
|
@ -2744,13 +2755,10 @@ merge(Compressor.prototype, {
|
||||||
// typeof always returns a non-empty string, thus it's
|
// typeof always returns a non-empty string, thus it's
|
||||||
// always true in booleans
|
// always true in booleans
|
||||||
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
compressor.warn("Boolean expression always true [{file}:{line},{col}]", self.start);
|
||||||
if (self.expression.has_side_effects(compressor)) {
|
return make_node(AST_Seq, self, {
|
||||||
return make_node(AST_Seq, self, {
|
car: e,
|
||||||
car: self.expression,
|
cdr: make_node(AST_True, self)
|
||||||
cdr: make_node(AST_True, self)
|
}).optimize(compressor);
|
||||||
});
|
|
||||||
}
|
|
||||||
return make_node(AST_True, self);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self.evaluate(compressor)[0];
|
return self.evaluate(compressor)[0];
|
||||||
|
|
@ -2880,13 +2888,10 @@ merge(Compressor.prototype, {
|
||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
|
if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
|
||||||
compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
|
compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
|
||||||
if (self.left.has_side_effects(compressor)) {
|
return make_node(AST_Seq, self, {
|
||||||
return make_node(AST_Seq, self, {
|
car: self.left,
|
||||||
car: self.left,
|
cdr: make_node(AST_False)
|
||||||
cdr: make_node(AST_False)
|
}).optimize(compressor);
|
||||||
}).optimize(compressor);
|
|
||||||
}
|
|
||||||
return make_node(AST_False, self);
|
|
||||||
}
|
}
|
||||||
if (ll.length > 1 && ll[1]) {
|
if (ll.length > 1 && ll[1]) {
|
||||||
return rr[0];
|
return rr[0];
|
||||||
|
|
@ -2900,13 +2905,10 @@ merge(Compressor.prototype, {
|
||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
|
if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
|
||||||
compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
|
compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
|
||||||
if (self.left.has_side_effects(compressor)) {
|
return make_node(AST_Seq, self, {
|
||||||
return make_node(AST_Seq, self, {
|
car: self.left,
|
||||||
car: self.left,
|
cdr: make_node(AST_True, self)
|
||||||
cdr: make_node(AST_True)
|
}).optimize(compressor);
|
||||||
}).optimize(compressor);
|
|
||||||
}
|
|
||||||
return make_node(AST_True, self);
|
|
||||||
}
|
}
|
||||||
if (ll.length > 1 && !ll[1]) {
|
if (ll.length > 1 && !ll[1]) {
|
||||||
return rr[0];
|
return rr[0];
|
||||||
|
|
@ -2918,10 +2920,19 @@ merge(Compressor.prototype, {
|
||||||
case "+":
|
case "+":
|
||||||
var ll = self.left.evaluate(compressor);
|
var ll = self.left.evaluate(compressor);
|
||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if ((ll.length > 1 && ll[0] instanceof AST_String && ll[1] && !self.right.has_side_effects(compressor)) ||
|
if (ll.length > 1 && ll[0] instanceof AST_String && ll[1]) {
|
||||||
(rr.length > 1 && rr[0] instanceof AST_String && rr[1] && !self.left.has_side_effects(compressor))) {
|
|
||||||
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_True, self);
|
return make_node(AST_Seq, self, {
|
||||||
|
car: self.right,
|
||||||
|
cdr: make_node(AST_True, self)
|
||||||
|
}).optimize(compressor);
|
||||||
|
}
|
||||||
|
if (rr.length > 1 && rr[0] instanceof AST_String && rr[1]) {
|
||||||
|
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||||
|
return make_node(AST_Seq, self, {
|
||||||
|
car: self.left,
|
||||||
|
cdr: make_node(AST_True, self)
|
||||||
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -3171,7 +3182,8 @@ merge(Compressor.prototype, {
|
||||||
&& alternative instanceof AST_Assign
|
&& alternative instanceof AST_Assign
|
||||||
&& consequent.operator == alternative.operator
|
&& consequent.operator == alternative.operator
|
||||||
&& consequent.left.equivalent_to(alternative.left)
|
&& consequent.left.equivalent_to(alternative.left)
|
||||||
&& !consequent.left.has_side_effects(compressor)
|
&& (!consequent.left.has_side_effects(compressor)
|
||||||
|
|| !self.condition.has_side_effects(compressor))
|
||||||
) {
|
) {
|
||||||
/*
|
/*
|
||||||
* Stuff like this:
|
* Stuff like this:
|
||||||
|
|
@ -3189,25 +3201,19 @@ merge(Compressor.prototype, {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// x ? y(a) : y(b) --> y(x ? a : b)
|
||||||
if (consequent instanceof AST_Call
|
if (consequent instanceof AST_Call
|
||||||
&& alternative.TYPE === consequent.TYPE
|
&& alternative.TYPE === consequent.TYPE
|
||||||
&& consequent.args.length == alternative.args.length
|
&& consequent.args.length == 1
|
||||||
&& !consequent.expression.has_side_effects(compressor)
|
&& alternative.args.length == 1
|
||||||
&& consequent.expression.equivalent_to(alternative.expression)) {
|
&& consequent.expression.equivalent_to(alternative.expression)
|
||||||
if (consequent.args.length == 0) {
|
&& !consequent.expression.has_side_effects(compressor)) {
|
||||||
return make_node(AST_Seq, self, {
|
consequent.args[0] = make_node(AST_Conditional, self, {
|
||||||
car: self.condition,
|
condition: self.condition,
|
||||||
cdr: consequent
|
consequent: consequent.args[0],
|
||||||
});
|
alternative: alternative.args[0]
|
||||||
}
|
});
|
||||||
if (consequent.args.length == 1) {
|
return consequent;
|
||||||
consequent.args[0] = make_node(AST_Conditional, self, {
|
|
||||||
condition: self.condition,
|
|
||||||
consequent: consequent.args[0],
|
|
||||||
alternative: alternative.args[0]
|
|
||||||
});
|
|
||||||
return consequent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// x?y?z:a:a --> x&&y?z:a
|
// x?y?z:a:a --> x&&y?z:a
|
||||||
if (consequent instanceof AST_Conditional
|
if (consequent instanceof AST_Conditional
|
||||||
|
|
@ -3222,16 +3228,12 @@ merge(Compressor.prototype, {
|
||||||
alternative: alternative
|
alternative: alternative
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// y?1:1 --> 1
|
// x ? y : y --> x, y
|
||||||
if (consequent.is_constant()
|
if (consequent.equivalent_to(alternative)) {
|
||||||
&& alternative.is_constant()
|
return make_node(AST_Seq, self, {
|
||||||
&& consequent.equivalent_to(alternative)) {
|
car: self.condition,
|
||||||
var consequent_value = consequent.evaluate(compressor)[0];
|
cdr: consequent
|
||||||
if (self.condition.has_side_effects(compressor)) {
|
}).optimize(compressor);
|
||||||
return AST_Seq.from_array([self.condition, consequent_value]);
|
|
||||||
} else {
|
|
||||||
return consequent_value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_true(self.consequent)) {
|
if (is_true(self.consequent)) {
|
||||||
|
|
@ -3390,8 +3392,12 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
|
|
||||||
function literals_in_boolean_context(self, compressor) {
|
function literals_in_boolean_context(self, compressor) {
|
||||||
if (compressor.option("booleans") && compressor.in_boolean_context() && !self.has_side_effects(compressor)) {
|
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||||
return make_node(AST_True, self);
|
var best = first_in_statement(compressor) ? best_of_statement : best_of;
|
||||||
|
return best(self, make_node(AST_Seq, self, {
|
||||||
|
car: self,
|
||||||
|
cdr: make_node(AST_True, self)
|
||||||
|
}).optimize(compressor));
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
65
lib/parse.js
65
lib/parse.js
|
|
@ -195,12 +195,11 @@ function JS_Parse_Error(message, filename, line, col, pos) {
|
||||||
this.line = line;
|
this.line = line;
|
||||||
this.col = col;
|
this.col = col;
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
this.stack = new Error().stack;
|
|
||||||
};
|
|
||||||
|
|
||||||
JS_Parse_Error.prototype.toString = function() {
|
|
||||||
return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
|
|
||||||
};
|
};
|
||||||
|
JS_Parse_Error.prototype = Object.create(Error.prototype);
|
||||||
|
JS_Parse_Error.prototype.constructor = JS_Parse_Error;
|
||||||
|
JS_Parse_Error.prototype.name = "SyntaxError";
|
||||||
|
configure_error_stack(JS_Parse_Error);
|
||||||
|
|
||||||
function js_error(message, filename, line, col, pos) {
|
function js_error(message, filename, line, col, pos) {
|
||||||
throw new JS_Parse_Error(message, filename, line, col, pos);
|
throw new JS_Parse_Error(message, filename, line, col, pos);
|
||||||
|
|
@ -350,13 +349,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
});
|
});
|
||||||
if (prefix) num = prefix + num;
|
if (prefix) num = prefix + num;
|
||||||
if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
|
if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
|
||||||
parse_error("SyntaxError: Legacy octal literals are not allowed in strict mode");
|
parse_error("Legacy octal literals are not allowed in strict mode");
|
||||||
}
|
}
|
||||||
var valid = parse_js_number(num);
|
var valid = parse_js_number(num);
|
||||||
if (!isNaN(valid)) {
|
if (!isNaN(valid)) {
|
||||||
return token("num", valid);
|
return token("num", valid);
|
||||||
} else {
|
} else {
|
||||||
parse_error("SyntaxError: Invalid syntax: " + num);
|
parse_error("Invalid syntax: " + num);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -395,7 +394,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
// Parse
|
// Parse
|
||||||
if (ch === "0") return "\0";
|
if (ch === "0") return "\0";
|
||||||
if (ch.length > 0 && next_token.has_directive("use strict"))
|
if (ch.length > 0 && next_token.has_directive("use strict"))
|
||||||
parse_error("SyntaxError: Legacy octal escape sequences are not allowed in strict mode");
|
parse_error("Legacy octal escape sequences are not allowed in strict mode");
|
||||||
return String.fromCharCode(parseInt(ch, 8));
|
return String.fromCharCode(parseInt(ch, 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -404,18 +403,18 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
for (; n > 0; --n) {
|
for (; n > 0; --n) {
|
||||||
var digit = parseInt(next(true), 16);
|
var digit = parseInt(next(true), 16);
|
||||||
if (isNaN(digit))
|
if (isNaN(digit))
|
||||||
parse_error("SyntaxError: Invalid hex-character pattern in string");
|
parse_error("Invalid hex-character pattern in string");
|
||||||
num = (num << 4) | digit;
|
num = (num << 4) | digit;
|
||||||
}
|
}
|
||||||
return num;
|
return num;
|
||||||
};
|
};
|
||||||
|
|
||||||
var read_string = with_eof_error("SyntaxError: Unterminated string constant", function(quote_char){
|
var read_string = with_eof_error("Unterminated string constant", function(quote_char){
|
||||||
var quote = next(), ret = "";
|
var quote = next(), ret = "";
|
||||||
for (;;) {
|
for (;;) {
|
||||||
var ch = next(true, true);
|
var ch = next(true, true);
|
||||||
if (ch == "\\") ch = read_escaped_char(true);
|
if (ch == "\\") ch = read_escaped_char(true);
|
||||||
else if (NEWLINE_CHARS(ch)) parse_error("SyntaxError: Unterminated string constant");
|
else if (NEWLINE_CHARS(ch)) parse_error("Unterminated string constant");
|
||||||
else if (ch == quote) break;
|
else if (ch == quote) break;
|
||||||
ret += ch;
|
ret += ch;
|
||||||
}
|
}
|
||||||
|
|
@ -440,7 +439,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
return next_token;
|
return next_token;
|
||||||
};
|
};
|
||||||
|
|
||||||
var skip_multiline_comment = with_eof_error("SyntaxError: Unterminated multiline comment", function(){
|
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
|
||||||
var regex_allowed = S.regex_allowed;
|
var regex_allowed = S.regex_allowed;
|
||||||
var i = find("*/", true);
|
var i = find("*/", true);
|
||||||
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, '\n');
|
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, '\n');
|
||||||
|
|
@ -460,9 +459,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (ch != "u") parse_error("SyntaxError: Expecting UnicodeEscapeSequence -- uXXXX");
|
if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
|
||||||
ch = read_escaped_char();
|
ch = read_escaped_char();
|
||||||
if (!is_identifier_char(ch)) parse_error("SyntaxError: Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
|
if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
|
||||||
name += ch;
|
name += ch;
|
||||||
backslash = false;
|
backslash = false;
|
||||||
}
|
}
|
||||||
|
|
@ -474,10 +473,10 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
var read_regexp = with_eof_error("SyntaxError: Unterminated regular expression", function(regexp){
|
var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
|
||||||
var prev_backslash = false, ch, in_class = false;
|
var prev_backslash = false, ch, in_class = false;
|
||||||
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
|
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
|
||||||
parse_error("SyntaxError: Unexpected line terminator");
|
parse_error("Unexpected line terminator");
|
||||||
} else if (prev_backslash) {
|
} else if (prev_backslash) {
|
||||||
regexp += "\\" + ch;
|
regexp += "\\" + ch;
|
||||||
prev_backslash = false;
|
prev_backslash = false;
|
||||||
|
|
@ -498,7 +497,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
try {
|
try {
|
||||||
return token("regexp", new RegExp(regexp, mods));
|
return token("regexp", new RegExp(regexp, mods));
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
parse_error("SyntaxError: " + e.message);
|
parse_error(e.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -599,7 +598,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
parse_error("SyntaxError: Unexpected character '" + ch + "'");
|
parse_error("Unexpected character '" + ch + "'");
|
||||||
};
|
};
|
||||||
|
|
||||||
next_token.context = function(nc) {
|
next_token.context = function(nc) {
|
||||||
|
|
@ -756,14 +755,14 @@ function parse($TEXT, options) {
|
||||||
function unexpected(token) {
|
function unexpected(token) {
|
||||||
if (token == null)
|
if (token == null)
|
||||||
token = S.token;
|
token = S.token;
|
||||||
token_error(token, "SyntaxError: Unexpected token: " + token.type + " (" + token.value + ")");
|
token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
|
||||||
};
|
};
|
||||||
|
|
||||||
function expect_token(type, val) {
|
function expect_token(type, val) {
|
||||||
if (is(type, val)) {
|
if (is(type, val)) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
token_error(S.token, "SyntaxError: Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
|
token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
|
||||||
};
|
};
|
||||||
|
|
||||||
function expect(punc) { return expect_token("punc", punc); };
|
function expect(punc) { return expect_token("punc", punc); };
|
||||||
|
|
@ -892,7 +891,7 @@ function parse($TEXT, options) {
|
||||||
|
|
||||||
case "return":
|
case "return":
|
||||||
if (S.in_function == 0 && !options.bare_returns)
|
if (S.in_function == 0 && !options.bare_returns)
|
||||||
croak("SyntaxError: 'return' outside of function");
|
croak("'return' outside of function");
|
||||||
return new AST_Return({
|
return new AST_Return({
|
||||||
value: ( is("punc", ";")
|
value: ( is("punc", ";")
|
||||||
? (next(), null)
|
? (next(), null)
|
||||||
|
|
@ -909,7 +908,7 @@ function parse($TEXT, options) {
|
||||||
|
|
||||||
case "throw":
|
case "throw":
|
||||||
if (S.token.nlb)
|
if (S.token.nlb)
|
||||||
croak("SyntaxError: Illegal newline after 'throw'");
|
croak("Illegal newline after 'throw'");
|
||||||
return new AST_Throw({
|
return new AST_Throw({
|
||||||
value: (tmp = expression(true), semicolon(), tmp)
|
value: (tmp = expression(true), semicolon(), tmp)
|
||||||
});
|
});
|
||||||
|
|
@ -925,7 +924,7 @@ function parse($TEXT, options) {
|
||||||
|
|
||||||
case "with":
|
case "with":
|
||||||
if (S.input.has_directive("use strict")) {
|
if (S.input.has_directive("use strict")) {
|
||||||
croak("SyntaxError: Strict mode may not include a with statement");
|
croak("Strict mode may not include a with statement");
|
||||||
}
|
}
|
||||||
return new AST_With({
|
return new AST_With({
|
||||||
expression : parenthesised(),
|
expression : parenthesised(),
|
||||||
|
|
@ -945,7 +944,7 @@ function parse($TEXT, options) {
|
||||||
// syntactically incorrect if it contains a
|
// syntactically incorrect if it contains a
|
||||||
// LabelledStatement that is enclosed by a
|
// LabelledStatement that is enclosed by a
|
||||||
// LabelledStatement with the same Identifier as label.
|
// LabelledStatement with the same Identifier as label.
|
||||||
croak("SyntaxError: Label " + label.name + " defined twice");
|
croak("Label " + label.name + " defined twice");
|
||||||
}
|
}
|
||||||
expect(":");
|
expect(":");
|
||||||
S.labels.push(label);
|
S.labels.push(label);
|
||||||
|
|
@ -958,7 +957,7 @@ function parse($TEXT, options) {
|
||||||
label.references.forEach(function(ref){
|
label.references.forEach(function(ref){
|
||||||
if (ref instanceof AST_Continue) {
|
if (ref instanceof AST_Continue) {
|
||||||
ref = ref.label.start;
|
ref = ref.label.start;
|
||||||
croak("SyntaxError: Continue label `" + label.name + "` refers to non-IterationStatement.",
|
croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
|
||||||
ref.line, ref.col, ref.pos);
|
ref.line, ref.col, ref.pos);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -978,11 +977,11 @@ function parse($TEXT, options) {
|
||||||
if (label != null) {
|
if (label != null) {
|
||||||
ldef = find_if(function(l){ return l.name == label.name }, S.labels);
|
ldef = find_if(function(l){ return l.name == label.name }, S.labels);
|
||||||
if (!ldef)
|
if (!ldef)
|
||||||
croak("SyntaxError: Undefined label " + label.name);
|
croak("Undefined label " + label.name);
|
||||||
label.thedef = ldef;
|
label.thedef = ldef;
|
||||||
}
|
}
|
||||||
else if (S.in_loop == 0)
|
else if (S.in_loop == 0)
|
||||||
croak("SyntaxError: " + type.TYPE + " not inside a loop or switch");
|
croak(type.TYPE + " not inside a loop or switch");
|
||||||
semicolon();
|
semicolon();
|
||||||
var stat = new type({ label: label });
|
var stat = new type({ label: label });
|
||||||
if (ldef) ldef.references.push(stat);
|
if (ldef) ldef.references.push(stat);
|
||||||
|
|
@ -998,7 +997,7 @@ function parse($TEXT, options) {
|
||||||
: expression(true, true);
|
: expression(true, true);
|
||||||
if (is("operator", "in")) {
|
if (is("operator", "in")) {
|
||||||
if (init instanceof AST_Var && init.definitions.length > 1)
|
if (init instanceof AST_Var && init.definitions.length > 1)
|
||||||
croak("SyntaxError: Only one variable declaration allowed in for..in loop");
|
croak("Only one variable declaration allowed in for..in loop");
|
||||||
next();
|
next();
|
||||||
return for_in(init);
|
return for_in(init);
|
||||||
}
|
}
|
||||||
|
|
@ -1148,7 +1147,7 @@ function parse($TEXT, options) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!bcatch && !bfinally)
|
if (!bcatch && !bfinally)
|
||||||
croak("SyntaxError: Missing catch/finally blocks");
|
croak("Missing catch/finally blocks");
|
||||||
return new AST_Try({
|
return new AST_Try({
|
||||||
body : body,
|
body : body,
|
||||||
bcatch : bcatch,
|
bcatch : bcatch,
|
||||||
|
|
@ -1242,7 +1241,7 @@ function parse($TEXT, options) {
|
||||||
break;
|
break;
|
||||||
case "operator":
|
case "operator":
|
||||||
if (!is_identifier_string(tok.value)) {
|
if (!is_identifier_string(tok.value)) {
|
||||||
croak("SyntaxError: Invalid getter/setter name: " + tok.value,
|
croak("Invalid getter/setter name: " + tok.value,
|
||||||
tok.line, tok.col, tok.pos);
|
tok.line, tok.col, tok.pos);
|
||||||
}
|
}
|
||||||
ret = _make_symbol(AST_SymbolRef);
|
ret = _make_symbol(AST_SymbolRef);
|
||||||
|
|
@ -1397,7 +1396,7 @@ function parse($TEXT, options) {
|
||||||
|
|
||||||
function as_symbol(type, noerror) {
|
function as_symbol(type, noerror) {
|
||||||
if (!is("name")) {
|
if (!is("name")) {
|
||||||
if (!noerror) croak("SyntaxError: Name expected");
|
if (!noerror) croak("Name expected");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var sym = _make_symbol(type);
|
var sym = _make_symbol(type);
|
||||||
|
|
@ -1461,7 +1460,7 @@ function parse($TEXT, options) {
|
||||||
|
|
||||||
function make_unary(ctor, op, expr) {
|
function make_unary(ctor, op, expr) {
|
||||||
if ((op == "++" || op == "--") && !is_assignable(expr))
|
if ((op == "++" || op == "--") && !is_assignable(expr))
|
||||||
croak("SyntaxError: Invalid use of " + op + " operator");
|
croak("Invalid use of " + op + " operator");
|
||||||
return new ctor({ operator: op, expression: expr });
|
return new ctor({ operator: op, expression: expr });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1525,7 +1524,7 @@ function parse($TEXT, options) {
|
||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
croak("SyntaxError: Invalid assignment");
|
croak("Invalid assignment");
|
||||||
}
|
}
|
||||||
return left;
|
return left;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
19
lib/utils.js
19
lib/utils.js
|
|
@ -78,13 +78,28 @@ function repeat_string(str, i) {
|
||||||
return d;
|
return d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function configure_error_stack(fn) {
|
||||||
|
Object.defineProperty(fn.prototype, "stack", {
|
||||||
|
get: function() {
|
||||||
|
var err = new Error(this.message);
|
||||||
|
err.name = this.name;
|
||||||
|
try {
|
||||||
|
throw err;
|
||||||
|
} catch(e) {
|
||||||
|
return e.stack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function DefaultsError(msg, defs) {
|
function DefaultsError(msg, defs) {
|
||||||
Error.call(this, msg);
|
this.message = msg;
|
||||||
this.msg = msg;
|
|
||||||
this.defs = defs;
|
this.defs = defs;
|
||||||
};
|
};
|
||||||
DefaultsError.prototype = Object.create(Error.prototype);
|
DefaultsError.prototype = Object.create(Error.prototype);
|
||||||
DefaultsError.prototype.constructor = DefaultsError;
|
DefaultsError.prototype.constructor = DefaultsError;
|
||||||
|
DefaultsError.prototype.name = "DefaultsError";
|
||||||
|
configure_error_stack(DefaultsError);
|
||||||
|
|
||||||
DefaultsError.croak = function(msg, defs) {
|
DefaultsError.croak = function(msg, defs) {
|
||||||
throw new DefaultsError(msg, defs);
|
throw new DefaultsError(msg, defs);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "2.7.5",
|
"version": "2.8.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,8 @@ ifs_3_should_warn: {
|
||||||
conditionals : true,
|
conditionals : true,
|
||||||
dead_code : true,
|
dead_code : true,
|
||||||
evaluate : true,
|
evaluate : true,
|
||||||
booleans : true
|
booleans : true,
|
||||||
|
side_effects : true,
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
var x, y;
|
var x, y;
|
||||||
|
|
@ -135,16 +136,28 @@ ifs_6: {
|
||||||
comparisons: true
|
comparisons: true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
var x;
|
var x, y;
|
||||||
if (!foo && !bar && !baz && !boo) {
|
if (!foo && !bar && !baz && !boo) {
|
||||||
x = 10;
|
x = 10;
|
||||||
} else {
|
} else {
|
||||||
x = 20;
|
x = 20;
|
||||||
}
|
}
|
||||||
|
if (y) {
|
||||||
|
x[foo] = 10;
|
||||||
|
} else {
|
||||||
|
x[foo] = 20;
|
||||||
|
}
|
||||||
|
if (foo) {
|
||||||
|
x[bar] = 10;
|
||||||
|
} else {
|
||||||
|
x[bar] = 20;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x;
|
var x, y;
|
||||||
x = foo || bar || baz || boo ? 20 : 10;
|
x = foo || bar || baz || boo ? 20 : 10;
|
||||||
|
x[foo] = y ? 10 : 20;
|
||||||
|
foo ? x[bar] = 10 : x[bar] = 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,10 +172,16 @@ cond_1: {
|
||||||
} else {
|
} else {
|
||||||
do_something(y);
|
do_something(y);
|
||||||
}
|
}
|
||||||
|
if (some_condition()) {
|
||||||
|
side_effects(x);
|
||||||
|
} else {
|
||||||
|
side_effects(y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var do_something;
|
var do_something;
|
||||||
do_something(some_condition() ? x : y);
|
do_something(some_condition() ? x : y);
|
||||||
|
some_condition() ? side_effects(x) : side_effects(y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,10 +232,16 @@ cond_4: {
|
||||||
} else {
|
} else {
|
||||||
do_something();
|
do_something();
|
||||||
}
|
}
|
||||||
|
if (some_condition()) {
|
||||||
|
side_effects();
|
||||||
|
} else {
|
||||||
|
side_effects();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var do_something;
|
var do_something;
|
||||||
some_condition(), do_something();
|
some_condition(), do_something();
|
||||||
|
some_condition(), side_effects();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -250,7 +275,8 @@ cond_5: {
|
||||||
cond_7: {
|
cond_7: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
evaluate : true
|
evaluate : true,
|
||||||
|
side_effects: true,
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
var x, y, z, a, b;
|
var x, y, z, a, b;
|
||||||
|
|
@ -714,6 +740,7 @@ issue_1154: {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
evaluate : true,
|
evaluate : true,
|
||||||
booleans : true,
|
booleans : true,
|
||||||
|
side_effects: true,
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
function f1(x) { return x ? -1 : -1; }
|
function f1(x) { return x ? -1 : -1; }
|
||||||
|
|
@ -742,7 +769,7 @@ issue_1154: {
|
||||||
function g2() { return g(), 2; }
|
function g2() { return g(), 2; }
|
||||||
function g3() { return g(), -4; }
|
function g3() { return g(), -4; }
|
||||||
function g4() { return g(), !1; }
|
function g4() { return g(), !1; }
|
||||||
function g5() { return g(), void 0; }
|
function g5() { return void g(); }
|
||||||
function g6() { return g(), "number"; }
|
function g6() { return g(), "number"; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -750,7 +777,8 @@ issue_1154: {
|
||||||
no_evaluate: {
|
no_evaluate: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
evaluate : false
|
evaluate : false,
|
||||||
|
side_effects: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f(b) {
|
function f(b) {
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,8 @@ dead_code_constant_boolean_should_warn_more: {
|
||||||
loops : true,
|
loops : true,
|
||||||
booleans : true,
|
booleans : true,
|
||||||
conditionals : true,
|
conditionals : true,
|
||||||
evaluate : true
|
evaluate : true,
|
||||||
|
side_effects : true,
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
while (!((foo && bar) || (x + "0"))) {
|
while (!((foo && bar) || (x + "0"))) {
|
||||||
|
|
|
||||||
|
|
@ -624,25 +624,35 @@ in_boolean_context: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
!42;
|
console.log(
|
||||||
!"foo";
|
!42,
|
||||||
![1, 2];
|
!"foo",
|
||||||
!/foo/;
|
![1, 2],
|
||||||
!b(42);
|
!/foo/,
|
||||||
!b("foo");
|
!b(42),
|
||||||
!b([1, 2]);
|
!b("foo"),
|
||||||
!b(/foo/);
|
!b([1, 2]),
|
||||||
|
!b(/foo/),
|
||||||
|
![1, foo()],
|
||||||
|
![1, foo(), 2]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
!1;
|
console.log(
|
||||||
!1;
|
!1,
|
||||||
!1;
|
!1,
|
||||||
!1;
|
!1,
|
||||||
!b(42);
|
!1,
|
||||||
!b("foo");
|
!b(42),
|
||||||
!b([1, 2]);
|
!b("foo"),
|
||||||
!b(/foo/);
|
!b([1, 2]),
|
||||||
|
!b(/foo/),
|
||||||
|
![1, foo()],
|
||||||
|
(foo(), !1)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,3 +116,61 @@ pure_function_calls_toplevel: {
|
||||||
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
|
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
should_warn: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
/* @__PURE__ */(function(){x})(), void/* @__PURE__ */(function(){y})();
|
||||||
|
/* @__PURE__ */(function(){x})() || true ? foo() : bar();
|
||||||
|
true || /* @__PURE__ */(function(){y})() ? foo() : bar();
|
||||||
|
/* @__PURE__ */(function(){x})() && false ? foo() : bar();
|
||||||
|
false && /* @__PURE__ */(function(){y})() ? foo() : bar();
|
||||||
|
/* @__PURE__ */(function(){x})() + "foo" ? bar() : baz();
|
||||||
|
"foo" + /* @__PURE__ */(function(){y})() ? bar() : baz();
|
||||||
|
/* @__PURE__ */(function(){x})() ? foo() : foo();
|
||||||
|
[/* @__PURE__ */(function(){x})()] ? foo() : bar();
|
||||||
|
!{ foo: /* @__PURE__ */(function(){x})() } ? bar() : baz();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
foo();
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
bar();
|
||||||
|
bar();
|
||||||
|
bar();
|
||||||
|
foo();
|
||||||
|
foo();
|
||||||
|
baz();
|
||||||
|
}
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,61]",
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,23]",
|
||||||
|
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:128,23]",
|
||||||
|
"WARN: Boolean || always true [test/compress/issue-1261.js:129,23]",
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:129,23]",
|
||||||
|
"WARN: Condition always true [test/compress/issue-1261.js:129,23]",
|
||||||
|
"WARN: Boolean || always true [test/compress/issue-1261.js:130,8]",
|
||||||
|
"WARN: Condition always true [test/compress/issue-1261.js:130,8]",
|
||||||
|
"WARN: Boolean && always false [test/compress/issue-1261.js:131,23]",
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:131,23]",
|
||||||
|
"WARN: Condition always false [test/compress/issue-1261.js:131,23]",
|
||||||
|
"WARN: Boolean && always false [test/compress/issue-1261.js:132,8]",
|
||||||
|
"WARN: Condition always false [test/compress/issue-1261.js:132,8]",
|
||||||
|
"WARN: + in boolean context always true [test/compress/issue-1261.js:133,23]",
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:133,23]",
|
||||||
|
"WARN: Condition always true [test/compress/issue-1261.js:133,23]",
|
||||||
|
"WARN: + in boolean context always true [test/compress/issue-1261.js:134,8]",
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:134,31]",
|
||||||
|
"WARN: Condition always true [test/compress/issue-1261.js:134,8]",
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]",
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,24]",
|
||||||
|
"WARN: Condition always true [test/compress/issue-1261.js:136,8]",
|
||||||
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,31]",
|
||||||
|
"WARN: Condition always false [test/compress/issue-1261.js:137,8]",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ string_plus_optimization: {
|
||||||
throw "nope";
|
throw "nope";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
console.log('0' + throwing_function() ? "yes" : "no");
|
console.log((throwing_function(), "yes"));
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.log(ex);
|
console.log(ex);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ typeof_in_boolean_context: {
|
||||||
booleans : true,
|
booleans : true,
|
||||||
evaluate : true,
|
evaluate : true,
|
||||||
conditionals : true,
|
conditionals : true,
|
||||||
|
side_effects : true,
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
function f1(x) { return typeof x ? "yes" : "no"; }
|
function f1(x) { return typeof x ? "yes" : "no"; }
|
||||||
|
|
@ -36,12 +37,14 @@ typeof_in_boolean_context: {
|
||||||
typeof 0 ? foo() : bar();
|
typeof 0 ? foo() : bar();
|
||||||
!typeof console.log(1);
|
!typeof console.log(1);
|
||||||
var a = !typeof console.log(2);
|
var a = !typeof console.log(2);
|
||||||
|
if (typeof (1 + foo()));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f1(x) { return "yes"; }
|
function f1(x) { return "yes"; }
|
||||||
function f2() { return g(), "Yes"; }
|
function f2() { return g(), "Yes"; }
|
||||||
foo();
|
foo();
|
||||||
!(console.log(1), !0);
|
console.log(1);
|
||||||
var a = !(console.log(2), !0);
|
var a = !(console.log(2), !0);
|
||||||
|
foo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
test/input/invalid/eof.js
Normal file
1
test/input/invalid/eof.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
foo, bar(
|
||||||
1
test/input/invalid/simple.js
Normal file
1
test/input/invalid/simple.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
function f(a{}
|
||||||
1
test/input/invalid/tab.js
Normal file
1
test/input/invalid/tab.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
foo( xyz, 0abc);
|
||||||
|
|
@ -199,4 +199,43 @@ describe("bin/uglifyjs", function () {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Should fail with invalid syntax", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/simple.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
var lines = stderr.split(/\n/);
|
||||||
|
assert.strictEqual(lines[0], "Parse error at test/input/invalid/simple.js:1,12");
|
||||||
|
assert.strictEqual(lines[1], "function f(a{}");
|
||||||
|
assert.strictEqual(lines[2], " ^");
|
||||||
|
assert.strictEqual(lines[3], "SyntaxError: Unexpected token punc «{», expected punc «,»");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should fail with correct marking of tabs", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/tab.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
var lines = stderr.split(/\n/);
|
||||||
|
assert.strictEqual(lines[0], "Parse error at test/input/invalid/tab.js:1,12");
|
||||||
|
assert.strictEqual(lines[1], "\t\tfoo(\txyz, 0abc);");
|
||||||
|
assert.strictEqual(lines[2], "\t\t \t ^");
|
||||||
|
assert.strictEqual(lines[3], "SyntaxError: Invalid syntax: 0abc");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should fail with correct marking at start of line", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/eof.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
var lines = stderr.split(/\n/);
|
||||||
|
assert.strictEqual(lines[0], "Parse error at test/input/invalid/eof.js:2,0");
|
||||||
|
assert.strictEqual(lines[1], "foo, bar(");
|
||||||
|
assert.strictEqual(lines[2], " ^");
|
||||||
|
assert.strictEqual(lines[3], "SyntaxError: Unexpected token: eof (undefined)");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ describe("Comment", function() {
|
||||||
|
|
||||||
var fail = function(e) {
|
var fail = function(e) {
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
return e instanceof uglify.JS_Parse_Error &&
|
||||||
e.message === "SyntaxError: Unexpected token: operator (>)" &&
|
e.message === "Unexpected token: operator (>)" &&
|
||||||
e.line === 2 &&
|
e.line === 2 &&
|
||||||
e.col === 0;
|
e.col === 0;
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +36,7 @@ describe("Comment", function() {
|
||||||
|
|
||||||
var fail = function(e) {
|
var fail = function(e) {
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
return e instanceof uglify.JS_Parse_Error &&
|
||||||
e.message === "SyntaxError: Unexpected token: operator (>)" &&
|
e.message === "Unexpected token: operator (>)" &&
|
||||||
e.line === 5 &&
|
e.line === 5 &&
|
||||||
e.col === 0;
|
e.col === 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ describe("Directives", function() {
|
||||||
throw new Error("Expected parser to fail");
|
throw new Error("Expected parser to fail");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assert.strictEqual(e instanceof uglify.JS_Parse_Error, true);
|
assert.strictEqual(e instanceof uglify.JS_Parse_Error, true);
|
||||||
assert.strictEqual(e.message, "SyntaxError: Unexpected token: punc (])");
|
assert.strictEqual(e.message, "Unexpected token: punc (])");
|
||||||
}
|
}
|
||||||
|
|
||||||
test_directive(tokenizer, tests[i]);
|
test_directive(tokenizer, tests[i]);
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ describe("Getters and setters", function() {
|
||||||
var fail = function(data) {
|
var fail = function(data) {
|
||||||
return function (e) {
|
return function (e) {
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
e.message === "SyntaxError: Invalid getter/setter name: " + data.operator;
|
e.message === "Invalid getter/setter name: " + data.operator;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ describe("line-endings", function() {
|
||||||
}
|
}
|
||||||
var fail = function(e) {
|
var fail = function(e) {
|
||||||
return e instanceof Uglify.JS_Parse_Error &&
|
return e instanceof Uglify.JS_Parse_Error &&
|
||||||
e.message === "SyntaxError: Unexpected line terminator";
|
e.message === "Unexpected line terminator";
|
||||||
}
|
}
|
||||||
for (var i = 0; i < inputs.length; i++) {
|
for (var i = 0; i < inputs.length; i++) {
|
||||||
assert.throws(test(inputs[i]), fail);
|
assert.throws(test(inputs[i]), fail);
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ describe("minify", function() {
|
||||||
inSourceMap: "inline",
|
inSourceMap: "inline",
|
||||||
sourceMapInline: true
|
sourceMapInline: true
|
||||||
});
|
});
|
||||||
}, "multiple input and inline source map");
|
});
|
||||||
});
|
});
|
||||||
it("Should fail with SpiderMonkey and inline source map", function() {
|
it("Should fail with SpiderMonkey and inline source map", function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
|
|
@ -119,7 +119,7 @@ describe("minify", function() {
|
||||||
sourceMapInline: true,
|
sourceMapInline: true,
|
||||||
spidermonkey: true
|
spidermonkey: true
|
||||||
});
|
});
|
||||||
}, "SpiderMonkey and inline source map");
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -154,6 +154,32 @@ describe("minify", function() {
|
||||||
var code = result.code;
|
var code = result.code;
|
||||||
assert.strictEqual(code, "// comment1 comment2\nbar();");
|
assert.strictEqual(code, "// comment1 comment2\nbar();");
|
||||||
});
|
});
|
||||||
|
it("should not drop #__PURE__ hint if function is retained", function() {
|
||||||
|
var result = Uglify.minify("var a = /*#__PURE__*/(function(){return 1})();", {
|
||||||
|
fromString: true,
|
||||||
|
output: {
|
||||||
|
comments: "all",
|
||||||
|
beautify: false,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var code = result.code;
|
||||||
|
assert.strictEqual(code, "var a=/*#__PURE__*/function(){return 1}();");
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("JS_Parse_Error", function() {
|
||||||
|
it("should throw syntax error", function() {
|
||||||
|
assert.throws(function() {
|
||||||
|
Uglify.minify("function f(a{}", { fromString: true });
|
||||||
|
}, function(err) {
|
||||||
|
assert.ok(err instanceof Error);
|
||||||
|
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token punc «{», expected punc «,»");
|
||||||
|
assert.strictEqual(err.filename, 0);
|
||||||
|
assert.strictEqual(err.line, 1);
|
||||||
|
assert.strictEqual(err.col, 12);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ describe("Number literals", function () {
|
||||||
}
|
}
|
||||||
var error = function(e) {
|
var error = function(e) {
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
return e instanceof uglify.JS_Parse_Error &&
|
||||||
e.message === "SyntaxError: Legacy octal literals are not allowed in strict mode";
|
e.message === "Legacy octal literals are not allowed in strict mode";
|
||||||
}
|
}
|
||||||
for (var i = 0; i < inputs.length; i++) {
|
for (var i = 0; i < inputs.length; i++) {
|
||||||
assert.throws(test(inputs[i]), error, inputs[i]);
|
assert.throws(test(inputs[i]), error, inputs[i]);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ describe("String literals", function() {
|
||||||
|
|
||||||
var error = function(e) {
|
var error = function(e) {
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
e.message === "SyntaxError: Unterminated string constant";
|
e.message === "Unterminated string constant";
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var input in inputs) {
|
for (var input in inputs) {
|
||||||
|
|
@ -49,7 +49,7 @@ describe("String literals", function() {
|
||||||
|
|
||||||
var error = function(e) {
|
var error = function(e) {
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
e.message === "SyntaxError: Legacy octal escape sequences are not allowed in strict mode";
|
e.message === "Legacy octal escape sequences are not allowed in strict mode";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var input in inputs) {
|
for (var input in inputs) {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ describe("With", function() {
|
||||||
}
|
}
|
||||||
var error = function(e) {
|
var error = function(e) {
|
||||||
return e instanceof uglify.JS_Parse_Error &&
|
return e instanceof uglify.JS_Parse_Error &&
|
||||||
e.message === "SyntaxError: Strict mode may not include a with statement";
|
e.message === "Strict mode may not include a with statement";
|
||||||
}
|
}
|
||||||
assert.throws(test, error);
|
assert.throws(test, error);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user