Compare commits

...

18 Commits

Author SHA1 Message Date
Alex Lam S.L
6920e898d1 v3.1.3 2017-10-01 12:36:07 +08:00
Alex Lam S.L
dd71639264 enhance reduce_vars for AST_Accessor (#2339)
fixes #2336
2017-10-01 03:01:50 +08:00
Alex Lam S.L
2dcc552ce0 trap invalid use of reserved words (#2338)
fixes #2337
2017-10-01 02:10:41 +08:00
Alex Lam S.L
55387e8fd0 v3.1.2 2017-09-24 02:02:04 +08:00
kzc
7e3e9da860 fix "use asm" numeric output (#2328)
fixes #2324
2017-09-21 04:42:40 +08:00
Alex Lam S.L
00f509405b suppress collapse_vars of this into "use strict" (#2326)
fixes #2319
2017-09-20 05:23:20 +08:00
Alex Lam S.L
aceb0af36b v3.1.1 2017-09-17 04:36:27 +08:00
Alex Lam S.L
4f0953f7e9 handle LHS side-effects on cascade & collapse_vars (#2314)
fixes #2313
2017-09-16 11:45:19 +08:00
Alex Lam S.L
182a47bfb1 improve source mapping (#2312)
fixes #2310
2017-09-15 12:46:48 +08:00
Alex Lam S.L
cd27f4ec38 v3.1.0 2017-09-10 15:17:24 +08:00
Mateusz Burzyński
8158b1bdcf Testing all leading comments against being PURE comments (#2305) 2017-09-10 02:08:15 +08:00
Alex Lam S.L
aacf3edc68 extend unsafe on pure global functions (#2303) 2017-09-07 22:08:34 +08:00
kzc
8b89072190 add Date and other known globals to unsafe compress option (#2302) 2017-09-07 02:44:26 +08:00
Alex Lam S.L
395a17ccda fix collapse_vars on default function argument (#2299)
Avoid collision with local variable `undefined` under certain corner cases.

fixes #2298
2017-09-04 02:32:33 +08:00
Alex Lam S.L
3f355866cf correctly count declarations after hoist_vars (#2297)
fixes #2295
2017-09-03 17:23:31 +08:00
David Šanda
71d52f147d Fix CLI example for mangle reserved list of names (#2294) 2017-08-31 00:55:32 +08:00
David Šanda
eb7adaa6fc Fix CLI source-maps examples (#2291)
fixes #2284
2017-08-29 23:49:20 +08:00
Alex Lam S.L
e5cf7972ea fix unused patching of AST_For.init blocks (#2289)
fixes #2288
2017-08-29 01:10:04 +08:00
18 changed files with 802 additions and 65 deletions

View File

@@ -150,19 +150,19 @@ debugging your compressed JavaScript. To get a source map, pass
Additional options:
- `--source-map filename=<NAME>` to specify the name of the source map.
- `--source-map "filename='<NAME>'"` to specify the name of the source map.
- `--source-map root=<URL>` to pass the URL where the original files can be found.
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
`//# sourceMappingURL=` directive.
- `--source-map url=<URL>` to specify the URL where the source map can be found.
- `--source-map "url='<URL>'"` to specify the URL where the source map can be found.
For example:
uglifyjs js/file1.js js/file2.js \
-o foo.min.js -c -m \
--source-map root="http://foo.com/src",url=foo.min.js.map
--source-map "root='http://foo.com/src',url='foo.min.js.map'"
The above will compress and mangle `file1.js` and `file2.js`, will drop the
output in `foo.min.js` and the source map in `foo.min.js.map`. The source
@@ -181,8 +181,8 @@ CoffeeScript → compiled JS, UglifyJS can generate a map from CoffeeScript →
compressed JS by mapping every token in the compiled JS to its original
location.
To use this feature pass `--source-map content="/path/to/input/source.map"`
or `--source-map content=inline` if the source map is included inline with
To use this feature pass `--source-map "content='/path/to/input/source.map'"`
or `--source-map "content=inline"` if the source map is included inline with
the sources.
## CLI compress options
@@ -213,7 +213,7 @@ When mangling is enabled but you want to prevent certain names from being
mangled, you can declare those names with `--mangle reserved` — pass a
comma-separated list of names. For example:
uglifyjs ... -m reserved=[$,require,exports]
uglifyjs ... -m reserved=['$','require','exports']
to prevent the `require`, `exports` and `$` names from being changed.

View File

@@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, {
$documentation: "Represents a debugger statement",
}, AST_Statement);
var AST_Directive = DEFNODE("Directive", "value scope quote", {
var AST_Directive = DEFNODE("Directive", "value quote", {
$documentation: "Represents a directive, like \"use strict\";",
$propdoc: {
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
scope: "[AST_Scope/S] The scope that this directive affects",
quote: "[string] the original quote character"
},
}, AST_Statement);
@@ -299,10 +298,9 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
directives: "[string*/S] an array of directives declared in this scope",
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
functions: "[Object/S] like `variables`, but only lists function declarations",
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",

View File

@@ -285,6 +285,10 @@ merge(Compressor.prototype, {
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) {
var reduce_vars = rescan && compressor.option("reduce_vars");
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
// properly assigned before use:
// - `push()` & `pop()` when visiting conditional branches
// - backup & restore via `save_ids` when visiting out-of-order sections
var safe_ids = Object.create(null);
var suppressor = new TreeWalker(function(node) {
if (!(node instanceof AST_Symbol)) return;
@@ -391,10 +395,9 @@ merge(Compressor.prototype, {
return true;
}
if (node instanceof AST_Accessor) {
var save_ids = safe_ids;
safe_ids = Object.create(null);
push();
descend();
safe_ids = save_ids;
pop();
return true;
}
if (node instanceof AST_Binary
@@ -561,6 +564,7 @@ merge(Compressor.prototype, {
});
function is_lhs_read_only(lhs) {
if (lhs instanceof AST_This) return true;
if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
if (lhs instanceof AST_PropAccess) {
lhs = lhs.expression;
@@ -693,7 +697,7 @@ merge(Compressor.prototype, {
return node instanceof AST_SymbolRef && node.definition().undeclared;
}
var global_names = makePredicate("Array Boolean console Error Function Math Number RegExp Object String");
var global_names = makePredicate("Array Boolean clearInterval clearTimeout console Date decodeURI decodeURIComponent encodeURI encodeURIComponent Error escape eval EvalError Function isFinite isNaN JSON Math Number parseFloat parseInt RangeError ReferenceError RegExp Object setInterval setTimeout String SyntaxError TypeError unescape URIError");
AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) {
return !this.definition().undeclared
|| compressor.option("unsafe") && global_names(this.name);
@@ -745,7 +749,7 @@ merge(Compressor.prototype, {
while (candidates.length > 0) {
var candidate = candidates.pop();
var lhs = get_lhs(candidate);
if (!lhs || is_lhs_read_only(lhs)) continue;
if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor)) continue;
// Locate symbols which may execute code outside of scanning range
var lvalues = get_lvalues(candidate);
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
@@ -841,13 +845,15 @@ merge(Compressor.prototype, {
&& !fn.uses_eval
&& (iife = compressor.parent()) instanceof AST_Call
&& iife.expression === fn) {
var fn_strict = compressor.has_directive("use strict");
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
var names = Object.create(null);
for (var i = fn.argnames.length; --i >= 0;) {
var sym = fn.argnames[i];
if (sym.name in names) continue;
names[sym.name] = true;
var arg = iife.args[i];
if (!arg) arg = make_node(AST_Undefined, sym);
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
else {
var tw = new TreeWalker(function(node) {
if (!arg) return true;
@@ -858,7 +864,7 @@ merge(Compressor.prototype, {
}
arg = null;
}
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
if (node instanceof AST_This && (fn_strict || !tw.find_parent(AST_Scope))) {
arg = null;
return true;
}
@@ -1980,16 +1986,27 @@ merge(Compressor.prototype, {
if (!compressor.option("side_effects")) return false;
if (this.pure !== undefined) return this.pure;
var pure = false;
var comments, last_comment;
var comments, pure_comment;
if (this.start
&& (comments = this.start.comments_before)
&& comments.length
&& /[@#]__PURE__/.test((last_comment = comments[comments.length - 1]).value)) {
pure = last_comment;
&& (pure_comment = find_if(function (comment) {
return /[@#]__PURE__/.test(comment.value);
}, comments))) {
pure = pure_comment;
}
return this.pure = pure;
});
var global_pure_fns = makePredicate("Boolean decodeURI decodeURIComponent Date encodeURI encodeURIComponent Error escape EvalError isFinite isNaN Number Object parseFloat parseInt RangeError ReferenceError String SyntaxError TypeError unescape URIError");
AST_Call.DEFMETHOD("is_expr_pure", function(compressor) {
if (compressor.option("unsafe")) {
var expr = this.expression;
if (is_undeclared_ref(expr) && global_pure_fns(expr.name)) return true;
}
return this.has_pure_annotation(compressor) || !compressor.pure_funcs(this);
});
// determine if expression has side effects
(function(def){
def(AST_Node, return_true);
@@ -1999,7 +2016,7 @@ merge(Compressor.prototype, {
def(AST_This, return_false);
def(AST_Call, function(compressor){
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) return true;
if (!this.is_expr_pure(compressor)) return true;
for (var i = this.args.length; --i >= 0;) {
if (this.args[i].has_side_effects(compressor))
return true;
@@ -2423,17 +2440,18 @@ merge(Compressor.prototype, {
// We fix it at this stage by moving the `var` outside the `for`.
if (node instanceof AST_For) {
descend(node, this);
var block;
if (node.init instanceof AST_BlockStatement) {
var block = node.init;
block = node.init;
node.init = block.body.pop();
block.body.push(node);
return in_list ? MAP.splice(block.body) : block;
} else if (node.init instanceof AST_SimpleStatement) {
}
if (node.init instanceof AST_SimpleStatement) {
node.init = node.init.body;
} else if (is_empty(node.init)) {
node.init = null;
}
return node;
return !block ? node : in_list ? MAP.splice(block.body) : block;
}
if (node instanceof AST_LabeledStatement && node.body instanceof AST_For) {
descend(node, this);
@@ -2617,7 +2635,7 @@ merge(Compressor.prototype, {
def(AST_Constant, return_null);
def(AST_This, return_null);
def(AST_Call, function(compressor, first_in_statement){
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) {
if (!this.is_expr_pure(compressor)) {
if (this.expression instanceof AST_Function
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
var node = this.clone();
@@ -3112,6 +3130,7 @@ merge(Compressor.prototype, {
}));
if (reduce_vars) name.definition().fixed = false;
}
remove(def.name.definition().orig, def.name);
return a;
}, []);
if (assignments.length == 0) return null;
@@ -3483,7 +3502,7 @@ merge(Compressor.prototype, {
&& (left.operator == "++" || left.operator == "--")) {
left = left.expression;
} else left = null;
if (!left || is_lhs_read_only(left)) {
if (!left || is_lhs_read_only(left) || left.has_side_effects(compressor)) {
expressions[++i] = cdr;
continue;
}

View File

@@ -482,13 +482,17 @@ function OutputStream(options) {
nodetype.DEFMETHOD("_codegen", generator);
};
var use_asm = false;
var in_directive = false;
var active_scope = null;
var use_asm = null;
AST_Node.DEFMETHOD("print", function(stream, force_parens){
var self = this, generator = self._codegen, prev_use_asm = use_asm;
if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
use_asm = true;
var self = this, generator = self._codegen;
if (self instanceof AST_Scope) {
active_scope = self;
}
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
use_asm = active_scope;
}
function doit() {
self.add_comments(stream);
@@ -502,8 +506,8 @@ function OutputStream(options) {
doit();
}
stream.pop_node();
if (self instanceof AST_Scope) {
use_asm = prev_use_asm;
if (self === use_asm) {
use_asm = null;
}
});
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
@@ -1109,7 +1113,7 @@ function OutputStream(options) {
self.expression.print(output);
if (self instanceof AST_New && !need_constructor_parens(self, output))
return;
if (self.expression instanceof AST_Lambda) {
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
output.add_mapping(self.start);
}
output.with_parens(function(){

View File

@@ -1054,6 +1054,8 @@ function parse($TEXT, options) {
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
if (in_statement && !name)
unexpected();
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
unexpected(prev());
expect("(");
var argnames = [];
for (var first = true; !is("punc", ")");) {

View File

@@ -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.28",
"version": "3.1.3",
"engines": {
"node": ">=0.8.0"
},
@@ -34,8 +34,8 @@
},
"devDependencies": {
"acorn": "~5.1.1",
"mocha": "~3.4.2",
"semver": "~5.3.0"
"mocha": "~3.5.1",
"semver": "~5.4.1"
},
"scripts": {
"test": "node test/run-tests.js"

View File

@@ -104,3 +104,65 @@ asm_mixed: {
}
}
asm_toplevel: {
options = {}
input: {
"use asm";
0.0;
function f() {
0.0;
(function(){
0.0;
});
}
0.0;
}
expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;'
}
asm_function_expression: {
options = {}
input: {
0.0;
var a = function() {
"use asm";
0.0;
}
function f() {
0.0;
return function(){
"use asm";
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;'
}
asm_nested_functions: {
options = {}
input: {
0.0;
function a() {
"use asm";
0.0;
}
0.0;
function b() {
0.0;
function c(){
"use asm";
0.0;
}
0.0;
function d(){
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
}

View File

@@ -2342,3 +2342,182 @@ duplicate_argname: {
}
expect_stdout: "PASS"
}
issue_2298: {
options = {
collapse_vars: true,
reduce_vars: true,
unused: true,
}
input: {
!function() {
function f() {
var a = undefined;
var undefined = a++;
try {
!function g(b) {
b[1] = "foo";
}();
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
f();
}();
}
expect: {
!function() {
(function() {
var a = undefined;
var undefined = a++;
try {
!function(b) {
(void 0)[1] = "foo";
}();
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
})();
}();
}
expect_stdout: "PASS"
}
issue_2313_1: {
options = {
collapse_vars: true,
conditionals: true,
}
input: {
var a = 0, b = 0;
var foo = {
get c() {
a++;
return 42;
},
set c(c) {
b++;
},
d: function() {
this.c++;
if (this.c) console.log(a, b);
}
}
foo.d();
}
expect: {
var a = 0, b = 0;
var foo = {
get c() {
a++;
return 42;
},
set c(c) {
b++;
},
d: function() {
this.c++;
this.c && console.log(a, b);
}
}
foo.d();
}
expect_stdout: "2 1"
}
issue_2313_2: {
options = {
collapse_vars: true,
}
input: {
var c = 0;
!function a() {
a && c++;
var a = 0;
a && c++;
}();
console.log(c);
}
expect: {
var c = 0;
!function a() {
a && c++;
var a = 0;
a && c++;
}();
console.log(c);
}
expect_stdout: "0"
}
issue_2319_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
console.log(function(a) {
return a;
}(!function() {
return this;
}()));
}
expect: {
console.log(function(a) {
return !function() {
return this;
}();
}());
}
expect_stdout: "false"
}
issue_2319_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
console.log(function(a) {
"use strict";
return a;
}(!function() {
return this;
}()));
}
expect: {
console.log(function(a) {
"use strict";
return a;
}(!function() {
return this;
}()));
}
expect_stdout: "false"
}
issue_2319_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
"use strict";
console.log(function(a) {
return a;
}(!function() {
return this;
}()));
}
expect: {
"use strict";
console.log(function(a) {
return !function() {
return this;
}();
}());
}
expect_stdout: "true"
}

View File

@@ -241,18 +241,54 @@ issue_2233_1: {
Array.isArray;
Boolean;
console.log;
Date;
decodeURI;
decodeURIComponent;
encodeURI;
encodeURIComponent;
Error.name;
escape;
eval;
EvalError;
Function.length;
isFinite;
isNaN;
JSON;
Math.random;
Number.isNaN;
parseFloat;
parseInt;
RegExp;
Object.defineProperty;
String.fromCharCode;
RangeError;
ReferenceError;
SyntaxError;
TypeError;
unescape;
URIError;
}
expect: {}
expect_stdout: true
}
global_timeout_and_interval_symbols: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
// These global symbols do not exist in the test sandbox
// and must be tested separately.
clearInterval;
clearTimeout;
setInterval;
setTimeout;
}
expect: {}
}
issue_2233_2: {
options = {
pure_getters: "strict",
@@ -309,3 +345,71 @@ issue_2233_3: {
UndeclaredGlobal;
}
}
global_fns: {
options = {
side_effects: true,
unsafe: true,
}
input: {
Boolean(1, 2);
decodeURI(1, 2);
decodeURIComponent(1, 2);
Date(1, 2);
encodeURI(1, 2);
encodeURIComponent(1, 2);
Error(1, 2);
escape(1, 2);
EvalError(1, 2);
isFinite(1, 2);
isNaN(1, 2);
Number(1, 2);
Object(1, 2);
parseFloat(1, 2);
parseInt(1, 2);
RangeError(1, 2);
ReferenceError(1, 2);
String(1, 2);
SyntaxError(1, 2);
TypeError(1, 2);
unescape(1, 2);
URIError(1, 2);
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect: {
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect_stdout: [
"SyntaxError",
"SyntaxError",
"RangeError",
]
}

View File

@@ -1239,3 +1239,25 @@ issue_2226_3: {
}
expect_stdout: "3"
}
issue_2288: {
options = {
unused: true,
}
beautify = {
beautify: true,
}
input: {
function foo(o) {
for (var j = o.a, i = 0; i < 0; i++);
for (var i = 0; i < 0; i++);
}
}
expect: {
function foo(o) {
o.a;
for (i = 0; i < 0; i++);
for (var i = 0; i < 0; i++);
}
}
}

View File

@@ -88,3 +88,24 @@ sequences_funs: {
}
}
}
issue_2295: {
options = {
collapse_vars: true,
hoist_vars: true,
}
input: {
function foo(o) {
var a = o.a;
if (a) return a;
var a = 1;
}
}
expect: {
function foo(o) {
var a = o.a;
if (a) return a;
a = 1;
}
}
}

View File

@@ -96,6 +96,13 @@ pure_function_calls_toplevel: {
})();
})();
// pure top-level calls will be dropped regardless of the leading comments position
var MyClass = /*#__PURE__*//*@class*/(function(){
function MyClass() {}
MyClass.prototype.method = function() {};
return MyClass;
})();
// comment #__PURE__ comment
bar(), baz(), quux();
a.b(), /* @__PURE__ */ c.d.e(), f.g();
@@ -110,10 +117,12 @@ pure_function_calls_toplevel: {
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:101,31]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:107,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:108,31]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]",
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,45]",
"WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:100,12]",
]
}
@@ -148,29 +157,29 @@ should_warn: {
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: Condition left of || 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: Condition left of && 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]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,61]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,23]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:137,23]",
"WARN: Boolean || always true [test/compress/issue-1261.js:138,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:138,23]",
"WARN: Condition always true [test/compress/issue-1261.js:138,23]",
"WARN: Condition left of || always true [test/compress/issue-1261.js:139,8]",
"WARN: Condition always true [test/compress/issue-1261.js:139,8]",
"WARN: Boolean && always false [test/compress/issue-1261.js:140,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:140,23]",
"WARN: Condition always false [test/compress/issue-1261.js:140,23]",
"WARN: Condition left of && always false [test/compress/issue-1261.js:141,8]",
"WARN: Condition always false [test/compress/issue-1261.js:141,8]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:142,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:142,23]",
"WARN: Condition always true [test/compress/issue-1261.js:142,23]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:143,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:143,31]",
"WARN: Condition always true [test/compress/issue-1261.js:143,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:144,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:145,24]",
"WARN: Condition always true [test/compress/issue-1261.js:145,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:146,31]",
"WARN: Condition always false [test/compress/issue-1261.js:146,8]",
]
}

View File

@@ -385,3 +385,217 @@ set_mutable_2: {
}
expect_stdout: "PASS"
}
issue_2313_1: {
options = {
cascade: true,
conditionals: true,
pure_getters: "strict",
sequences: true,
side_effects: true,
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
return console.log(1), {
y: function() {
return console.log(2), {
z: 0
};
}
};
}
x().y().z++,
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_2: {
options = {
cascade: true,
conditionals: true,
pure_getters: true,
sequences: true,
side_effects: true,
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
return console.log(1), {
y: function() {
return console.log(2), {
z: 0
};
}
};
}
x().y().z++,
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_3: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_4: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: true,
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_5: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
x().y++;
x().y;
}
expect: {
x().y++;
x().y;
}
}
issue_2313_6: {
options = {
pure_getters: true,
side_effects: true,
}
input: {
x().y++;
x().y;
}
expect: {
x().y++;
x();
}
}

View File

@@ -2549,7 +2549,7 @@ issue_1922_2: {
expect_stdout: "1"
}
accessor: {
accessor_1: {
options = {
evaluate: true,
reduce_vars: true,
@@ -2578,6 +2578,33 @@ accessor: {
expect_stdout: "1 1"
}
accessor_2: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var A = 1;
var B = {
get c() {
console.log(A);
}
};
B.c;
}
expect: {
({
get c() {
console.log(1);
}
}).c;
}
expect_stdout: "1"
}
for_in_prop: {
options = {
reduce_vars: true,

View File

@@ -739,3 +739,44 @@ issue_2062: {
}
expect_stdout: "1"
}
issue_2313: {
options = {
cascade: true,
sequences: true,
side_effects: true,
}
input: {
var a = 0, b = 0;
var foo = {
get c() {
a++;
return 42;
},
set c(c) {
b++;
},
d: function() {
this.c++;
if (this.c) console.log(a, b);
}
}
foo.d();
}
expect: {
var a = 0, b = 0;
var foo = {
get c() {
return a++, 42;
},
set c(c) {
b++;
},
d: function() {
if (this.c++, this.c) console.log(a, b);
}
}
foo.d();
}
expect_stdout: "2 1"
}

View File

@@ -0,0 +1,10 @@
function foo() {
return function() {
console.log("PASS");
};
}
(function() {
var f = foo();
f();
})();

View File

@@ -573,6 +573,25 @@ describe("bin/uglifyjs", function () {
return JSON.stringify(map).replace(/"/g, '\\"');
}
});
it("Should include function calls in source map", function(done) {
var command = [
uglifyjscmd,
"test/input/issue-2310/input.js",
"-c",
"--source-map", "url=inline",
].join(" ");
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, [
'function foo(){return function(){console.log("PASS")}}foo()();',
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMjMxMC9pbnB1dC5qcyJdLCJuYW1lcyI6WyJmb28iLCJjb25zb2xlIiwibG9nIiwiZiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsTUFDTCxPQUFPLFdBQ0hDLFFBQVFDLElBQUksU0FLUkYsS0FDUkcifQ==",
""
].join("\n"));
done();
});
});
it("Should dump AST as JSON", function(done) {
var command = uglifyjscmd + " test/input/global_defs/simple.js -mco ast";
exec(command, function (err, stdout) {

View File

@@ -73,6 +73,12 @@ describe("minify", function() {
assert.strictEqual(run_code(compressed), run_code(original));
});
it("should not parse invalid use of reserved words", function() {
assert.strictEqual(Uglify.minify("function enum(){}").error, undefined);
assert.strictEqual(Uglify.minify("function static(){}").error, undefined);
assert.strictEqual(Uglify.minify("function this(){}").error.message, "Unexpected token: name (this)");
});
describe("keep_quoted_props", function() {
it("Should preserve quotes in object literals", function() {
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';