Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9336cc8247 | ||
|
|
9809567dfc | ||
|
|
1ee8be8d91 | ||
|
|
8430c2f9f8 | ||
|
|
659c8a7632 | ||
|
|
3564b4f20d | ||
|
|
3505a3604a | ||
|
|
9b1bc6c014 | ||
|
|
9f23185f2b | ||
|
|
b82feb9302 | ||
|
|
7f2a591c7e | ||
|
|
afbcebddf6 | ||
|
|
484e484571 | ||
|
|
6f3f21233f | ||
|
|
a6873a3859 | ||
|
|
7a6d452b54 | ||
|
|
9b58b54e2d | ||
|
|
c598a12af9 | ||
|
|
cfe3a98ce5 | ||
|
|
14778e049b | ||
|
|
446fb0198b | ||
|
|
7d3cddf9d6 | ||
|
|
6dead95eb3 | ||
|
|
cc931b3ad8 | ||
|
|
d838b4b52e | ||
|
|
2f3bddbaca | ||
|
|
673b071637 | ||
|
|
da82fa59a7 | ||
|
|
333792352e | ||
|
|
e2ec270b04 | ||
|
|
ed7a0a454e | ||
|
|
d819559a01 |
@@ -640,7 +640,13 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
|
|
||||||
- `if_return` (default: `true`) -- optimizations for if/return and if/continue
|
- `if_return` (default: `true`) -- optimizations for if/return and if/continue
|
||||||
|
|
||||||
- `inline` (default: `true`) -- embed simple functions
|
- `inline` (default: `true`) -- inline calls to function with simple/`return` statement:
|
||||||
|
- `false` -- same as `0`
|
||||||
|
- `0` -- disabled inlining
|
||||||
|
- `1` -- inline simple functions
|
||||||
|
- `2` -- inline functions with arguments
|
||||||
|
- `3` -- inline functions with arguments and variables
|
||||||
|
- `true` -- same as `3`
|
||||||
|
|
||||||
- `join_vars` (default: `true`) -- join consecutive `var` statements
|
- `join_vars` (default: `true`) -- join consecutive `var` statements
|
||||||
|
|
||||||
|
|||||||
28
appveyor.yml
28
appveyor.yml
@@ -1,24 +1,20 @@
|
|||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- nodejs_version: "0.10"
|
- nodejs_version: "0.10"
|
||||||
- nodejs_version: "0.12"
|
- nodejs_version: "0.12"
|
||||||
- nodejs_version: "4.0"
|
- nodejs_version: "4"
|
||||||
- nodejs_version: "6.0"
|
- nodejs_version: "6"
|
||||||
|
- nodejs_version: "8"
|
||||||
|
install:
|
||||||
|
- ps: Install-Product node $env:nodejs_version
|
||||||
|
- set UGLIFYJS_TEST_ALL=1
|
||||||
|
- npm install
|
||||||
|
build: off
|
||||||
|
cache:
|
||||||
|
- tmp
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
||||||
platform:
|
|
||||||
- x86
|
|
||||||
- x64
|
|
||||||
|
|
||||||
install:
|
|
||||||
- ps: Install-Product node $env:nodejs_version $env:platform
|
|
||||||
- npm install
|
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- node --version
|
- node --version
|
||||||
- npm --version
|
- npm --version
|
||||||
- npm test
|
- npm test
|
||||||
|
|
||||||
build: off
|
|
||||||
|
|||||||
@@ -3,11 +3,7 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// workaround for tty output truncation upon process.exit()
|
require("../tools/exit");
|
||||||
[process.stdout, process.stderr].forEach(function(stream){
|
|
||||||
if (stream._handle && stream._handle.setBlocking)
|
|
||||||
stream._handle.setBlocking(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var info = require("../package.json");
|
var info = require("../package.json");
|
||||||
|
|||||||
525
lib/compress.js
525
lib/compress.js
@@ -99,6 +99,7 @@ function Compressor(options, false_by_default) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.options["inline"] === true) this.options["inline"] = 3;
|
||||||
var pure_funcs = this.options["pure_funcs"];
|
var pure_funcs = this.options["pure_funcs"];
|
||||||
if (typeof pure_funcs == "function") {
|
if (typeof pure_funcs == "function") {
|
||||||
this.pure_funcs = pure_funcs;
|
this.pure_funcs = pure_funcs;
|
||||||
@@ -310,12 +311,13 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Node, noop);
|
def(AST_Node, noop);
|
||||||
|
|
||||||
function reset_def(compressor, def) {
|
function reset_def(compressor, def) {
|
||||||
|
def.assignments = 0;
|
||||||
def.direct_access = false;
|
def.direct_access = false;
|
||||||
def.escaped = false;
|
def.escaped = false;
|
||||||
if (def.scope.uses_eval || def.scope.uses_with) {
|
if (def.scope.uses_eval || def.scope.uses_with) {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
} else if (!compressor.exposed(def)) {
|
} else if (!compressor.exposed(def)) {
|
||||||
def.fixed = undefined;
|
def.fixed = def.init;
|
||||||
} else {
|
} else {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
}
|
}
|
||||||
@@ -325,9 +327,16 @@ merge(Compressor.prototype, {
|
|||||||
def.single_use = undefined;
|
def.single_use = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset_variables(compressor, node) {
|
function reset_variables(tw, compressor, node) {
|
||||||
node.variables.each(function(def) {
|
node.variables.each(function(def) {
|
||||||
reset_def(compressor, def);
|
reset_def(compressor, def);
|
||||||
|
if (def.fixed === null) {
|
||||||
|
def.safe_ids = tw.safe_ids;
|
||||||
|
mark(tw, def, true);
|
||||||
|
} else if (def.fixed) {
|
||||||
|
tw.loop_ids[def.id] = tw.in_loop;
|
||||||
|
mark(tw, def, true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,10 +365,16 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function safe_to_assign(tw, def, value) {
|
function safe_to_assign(tw, def, value) {
|
||||||
|
if (def.fixed === undefined) return true;
|
||||||
|
if (def.fixed === null && def.safe_ids) {
|
||||||
|
def.safe_ids[def.id] = false;
|
||||||
|
delete def.safe_ids;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (!HOP(tw.safe_ids, def.id)) return false;
|
if (!HOP(tw.safe_ids, def.id)) return false;
|
||||||
if (!safe_to_read(tw, def)) return false;
|
if (!safe_to_read(tw, def)) return false;
|
||||||
if (def.fixed === false) return false;
|
if (def.fixed === false) return false;
|
||||||
if (def.fixed != null && (!value || def.references.length > 0)) return false;
|
if (def.fixed != null && (!value || def.references.length > def.assignments)) return false;
|
||||||
return all(def.orig, function(sym) {
|
return all(def.orig, function(sym) {
|
||||||
return !(sym instanceof AST_SymbolDefun
|
return !(sym instanceof AST_SymbolDefun
|
||||||
|| sym instanceof AST_SymbolLambda);
|
|| sym instanceof AST_SymbolLambda);
|
||||||
@@ -462,11 +477,9 @@ merge(Compressor.prototype, {
|
|||||||
var node = this;
|
var node = this;
|
||||||
if (node.operator != "=" || !(node.left instanceof AST_SymbolRef)) return;
|
if (node.operator != "=" || !(node.left instanceof AST_SymbolRef)) return;
|
||||||
var d = node.left.definition();
|
var d = node.left.definition();
|
||||||
if (safe_to_assign(tw, d, node.right)
|
if (safe_to_assign(tw, d, node.right)) {
|
||||||
|| d.fixed === undefined && all(d.orig, function(sym) {
|
|
||||||
return sym instanceof AST_SymbolVar;
|
|
||||||
})) {
|
|
||||||
d.references.push(node.left);
|
d.references.push(node.left);
|
||||||
|
d.assignments++;
|
||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return node.right;
|
return node.right;
|
||||||
};
|
};
|
||||||
@@ -495,19 +508,10 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Defun, function(tw, descend, compressor) {
|
def(AST_Defun, function(tw, descend, compressor) {
|
||||||
reset_variables(compressor, this);
|
|
||||||
this.inlined = false;
|
this.inlined = false;
|
||||||
var d = this.name.definition();
|
|
||||||
if (compressor.exposed(d) || safe_to_read(tw, d)) {
|
|
||||||
d.fixed = false;
|
|
||||||
} else {
|
|
||||||
d.fixed = this;
|
|
||||||
d.single_use = ref_once(tw, compressor, d);
|
|
||||||
tw.loop_ids[d.id] = tw.in_loop;
|
|
||||||
mark(tw, d, true);
|
|
||||||
}
|
|
||||||
var save_ids = tw.safe_ids;
|
var save_ids = tw.safe_ids;
|
||||||
tw.safe_ids = Object.create(null);
|
tw.safe_ids = Object.create(null);
|
||||||
|
reset_variables(tw, compressor, this);
|
||||||
descend();
|
descend();
|
||||||
tw.safe_ids = save_ids;
|
tw.safe_ids = save_ids;
|
||||||
return true;
|
return true;
|
||||||
@@ -555,9 +559,9 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Function, function(tw, descend, compressor) {
|
def(AST_Function, function(tw, descend, compressor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
reset_variables(compressor, node);
|
|
||||||
node.inlined = false;
|
node.inlined = false;
|
||||||
push(tw);
|
push(tw);
|
||||||
|
reset_variables(tw, compressor, node);
|
||||||
var iife;
|
var iife;
|
||||||
if (!node.name
|
if (!node.name
|
||||||
&& (iife = tw.parent()) instanceof AST_Call
|
&& (iife = tw.parent()) instanceof AST_Call
|
||||||
@@ -644,7 +648,7 @@ merge(Compressor.prototype, {
|
|||||||
this.globals.each(function(def) {
|
this.globals.each(function(def) {
|
||||||
reset_def(compressor, def);
|
reset_def(compressor, def);
|
||||||
});
|
});
|
||||||
reset_variables(compressor, this);
|
reset_variables(tw, compressor, this);
|
||||||
});
|
});
|
||||||
def(AST_Try, function(tw) {
|
def(AST_Try, function(tw) {
|
||||||
push(tw);
|
push(tw);
|
||||||
@@ -661,7 +665,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_VarDef, function(tw, descend) {
|
def(AST_VarDef, function(tw, descend) {
|
||||||
var node = this;
|
var node = this;
|
||||||
var d = node.name.definition();
|
var d = node.name.definition();
|
||||||
if (d.fixed === undefined || safe_to_assign(tw, d, node.value)) {
|
if (safe_to_assign(tw, d, node.value)) {
|
||||||
if (node.value) {
|
if (node.value) {
|
||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return node.value;
|
return node.value;
|
||||||
@@ -669,8 +673,6 @@ merge(Compressor.prototype, {
|
|||||||
tw.loop_ids[d.id] = tw.in_loop;
|
tw.loop_ids[d.id] = tw.in_loop;
|
||||||
mark(tw, d, false);
|
mark(tw, d, false);
|
||||||
descend();
|
descend();
|
||||||
} else {
|
|
||||||
d.fixed = null;
|
|
||||||
}
|
}
|
||||||
mark(tw, d, true);
|
mark(tw, d, true);
|
||||||
return true;
|
return true;
|
||||||
@@ -879,6 +881,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (compressor.sequences_limit > 0) {
|
if (compressor.sequences_limit > 0) {
|
||||||
sequencesize(statements, compressor);
|
sequencesize(statements, compressor);
|
||||||
|
sequencesize_2(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("join_vars")) {
|
if (compressor.option("join_vars")) {
|
||||||
join_consecutive_vars(statements, compressor);
|
join_consecutive_vars(statements, compressor);
|
||||||
@@ -1153,10 +1156,10 @@ merge(Compressor.prototype, {
|
|||||||
if (!expr.left.has_side_effects(compressor)) {
|
if (!expr.left.has_side_effects(compressor)) {
|
||||||
candidates.push(hit_stack.slice());
|
candidates.push(hit_stack.slice());
|
||||||
}
|
}
|
||||||
} else if (expr instanceof AST_Unary) {
|
extract_candidates(expr.right);
|
||||||
if (expr.operator == "++" || expr.operator == "--") {
|
} else if (expr instanceof AST_Binary) {
|
||||||
candidates.push(hit_stack.slice());
|
extract_candidates(expr.left);
|
||||||
}
|
extract_candidates(expr.right);
|
||||||
} else if (expr instanceof AST_Call) {
|
} else if (expr instanceof AST_Call) {
|
||||||
extract_candidates(expr.expression);
|
extract_candidates(expr.expression);
|
||||||
expr.args.forEach(extract_candidates);
|
expr.args.forEach(extract_candidates);
|
||||||
@@ -1168,10 +1171,14 @@ merge(Compressor.prototype, {
|
|||||||
extract_candidates(expr.alternative);
|
extract_candidates(expr.alternative);
|
||||||
} else if (expr instanceof AST_Definitions) {
|
} else if (expr instanceof AST_Definitions) {
|
||||||
expr.definitions.forEach(extract_candidates);
|
expr.definitions.forEach(extract_candidates);
|
||||||
|
} else if (expr instanceof AST_DWLoop) {
|
||||||
|
extract_candidates(expr.condition);
|
||||||
} else if (expr instanceof AST_Exit) {
|
} else if (expr instanceof AST_Exit) {
|
||||||
if (expr.value) extract_candidates(expr.value);
|
if (expr.value) extract_candidates(expr.value);
|
||||||
} else if (expr instanceof AST_For) {
|
} else if (expr instanceof AST_For) {
|
||||||
if (expr.init) extract_candidates(expr.init);
|
if (expr.init) extract_candidates(expr.init);
|
||||||
|
if (expr.condition) extract_candidates(expr.condition);
|
||||||
|
if (expr.step) extract_candidates(expr.step);
|
||||||
} else if (expr instanceof AST_If) {
|
} else if (expr instanceof AST_If) {
|
||||||
extract_candidates(expr.condition);
|
extract_candidates(expr.condition);
|
||||||
} else if (expr instanceof AST_Sequence) {
|
} else if (expr instanceof AST_Sequence) {
|
||||||
@@ -1181,21 +1188,31 @@ merge(Compressor.prototype, {
|
|||||||
} else if (expr instanceof AST_Switch) {
|
} else if (expr instanceof AST_Switch) {
|
||||||
extract_candidates(expr.expression);
|
extract_candidates(expr.expression);
|
||||||
expr.body.forEach(extract_candidates);
|
expr.body.forEach(extract_candidates);
|
||||||
|
} else if (expr instanceof AST_Unary) {
|
||||||
|
if (expr.operator == "++" || expr.operator == "--") {
|
||||||
|
candidates.push(hit_stack.slice());
|
||||||
|
}
|
||||||
} else if (expr instanceof AST_VarDef) {
|
} else if (expr instanceof AST_VarDef) {
|
||||||
if (expr.value) candidates.push(hit_stack.slice());
|
if (expr.value) {
|
||||||
|
candidates.push(hit_stack.slice());
|
||||||
|
extract_candidates(expr.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hit_stack.pop();
|
hit_stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_stop(node, level) {
|
function find_stop(node, level) {
|
||||||
var parent = scanner.parent(level);
|
var parent = scanner.parent(level);
|
||||||
|
if (parent instanceof AST_Binary) return node;
|
||||||
if (parent instanceof AST_Call) return node;
|
if (parent instanceof AST_Call) return node;
|
||||||
if (parent instanceof AST_Case) return node;
|
if (parent instanceof AST_Case) return node;
|
||||||
if (parent instanceof AST_Conditional) return node;
|
if (parent instanceof AST_Conditional) return node;
|
||||||
if (parent instanceof AST_Exit) return node;
|
if (parent instanceof AST_Exit) return node;
|
||||||
if (parent instanceof AST_If) return node;
|
if (parent instanceof AST_If) return node;
|
||||||
|
if (parent instanceof AST_IterationStatement) return node;
|
||||||
if (parent instanceof AST_Sequence) return find_stop(parent, level + 1);
|
if (parent instanceof AST_Sequence) return find_stop(parent, level + 1);
|
||||||
if (parent instanceof AST_Switch) return node;
|
if (parent instanceof AST_Switch) return node;
|
||||||
|
if (parent instanceof AST_VarDef) return node;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1337,12 +1354,13 @@ merge(Compressor.prototype, {
|
|||||||
var in_lambda = self instanceof AST_Lambda;
|
var in_lambda = self instanceof AST_Lambda;
|
||||||
for (var i = statements.length; --i >= 0;) {
|
for (var i = statements.length; --i >= 0;) {
|
||||||
var stat = statements[i];
|
var stat = statements[i];
|
||||||
var next = statements[i + 1];
|
var j = next_index(i);
|
||||||
|
var next = statements[j];
|
||||||
|
|
||||||
if (in_lambda && !next && stat instanceof AST_Return) {
|
if (in_lambda && !next && stat instanceof AST_Return) {
|
||||||
if (!stat.value) {
|
if (!stat.value) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
statements.length--;
|
statements.splice(i, 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (stat.value instanceof AST_UnaryPrefix && stat.value.operator == "void") {
|
if (stat.value instanceof AST_UnaryPrefix && stat.value.operator == "void") {
|
||||||
@@ -1412,19 +1430,22 @@ merge(Compressor.prototype, {
|
|||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = next;
|
stat.alternative = next;
|
||||||
statements.splice(i, 2, stat.transform(compressor));
|
statements.splice(i, 1, stat.transform(compressor));
|
||||||
|
statements.splice(j, 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
||||||
if (multiple_if_returns && in_lambda && value && !stat.alternative
|
if (value && !stat.alternative
|
||||||
&& (!next || next instanceof AST_Return)) {
|
&& (!next && in_lambda && multiple_if_returns
|
||||||
|
|| next instanceof AST_Return)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = next || make_node(AST_Return, stat, {
|
stat.alternative = next || make_node(AST_Return, stat, {
|
||||||
value: null
|
value: null
|
||||||
});
|
});
|
||||||
statements.splice(i, next ? 2 : 1, stat.transform(compressor));
|
statements.splice(i, 1, stat.transform(compressor));
|
||||||
|
if (next) statements.splice(j, 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
@@ -1433,10 +1454,10 @@ merge(Compressor.prototype, {
|
|||||||
// if sequences is not enabled, this can lead to an endless loop (issue #866).
|
// if sequences is not enabled, this can lead to an endless loop (issue #866).
|
||||||
// however, with sequences on this helps producing slightly better output for
|
// however, with sequences on this helps producing slightly better output for
|
||||||
// the example code.
|
// the example code.
|
||||||
var prev = statements[i - 1];
|
var prev = statements[prev_index(i)];
|
||||||
if (compressor.option("sequences") && in_lambda && !stat.alternative
|
if (compressor.option("sequences") && in_lambda && !stat.alternative
|
||||||
&& prev instanceof AST_If && prev.body instanceof AST_Return
|
&& prev instanceof AST_If && prev.body instanceof AST_Return
|
||||||
&& i + 2 == statements.length && next instanceof AST_SimpleStatement) {
|
&& next_index(j) == statements.length && next instanceof AST_SimpleStatement) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = make_node(AST_BlockStatement, next, {
|
stat.alternative = make_node(AST_BlockStatement, next, {
|
||||||
@@ -1447,7 +1468,8 @@ merge(Compressor.prototype, {
|
|||||||
})
|
})
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
statements.splice(i, 2, stat.transform(compressor));
|
statements.splice(i, 1, stat.transform(compressor));
|
||||||
|
statements.splice(j, 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1497,6 +1519,26 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function next_index(i) {
|
||||||
|
for (var j = i + 1, len = statements.length; j < len; j++) {
|
||||||
|
var stat = statements[j];
|
||||||
|
if (!(stat instanceof AST_Definitions && declarations_only(stat))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prev_index(i) {
|
||||||
|
for (var j = i; --j >= 0;) {
|
||||||
|
var stat = statements[j];
|
||||||
|
if (!(stat instanceof AST_Definitions && declarations_only(stat))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function eliminate_dead_code(statements, compressor) {
|
function eliminate_dead_code(statements, compressor) {
|
||||||
@@ -1532,6 +1574,12 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function declarations_only(node) {
|
||||||
|
return all(node.definitions, function(var_def) {
|
||||||
|
return !var_def.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function sequencesize(statements, compressor) {
|
function sequencesize(statements, compressor) {
|
||||||
if (statements.length < 2) return;
|
if (statements.length < 2) return;
|
||||||
var seq = [], n = 0;
|
var seq = [], n = 0;
|
||||||
@@ -1548,6 +1596,9 @@ merge(Compressor.prototype, {
|
|||||||
var body = stat.body;
|
var body = stat.body;
|
||||||
if (seq.length > 0) body = body.drop_side_effect_free(compressor);
|
if (seq.length > 0) body = body.drop_side_effect_free(compressor);
|
||||||
if (body) merge_sequence(seq, body);
|
if (body) merge_sequence(seq, body);
|
||||||
|
} else if (stat instanceof AST_Definitions && declarations_only(stat)
|
||||||
|
|| stat instanceof AST_Defun) {
|
||||||
|
statements[n++] = stat;
|
||||||
} else {
|
} else {
|
||||||
push_seq();
|
push_seq();
|
||||||
statements[n++] = stat;
|
statements[n++] = stat;
|
||||||
@@ -1555,18 +1606,34 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
push_seq();
|
push_seq();
|
||||||
statements.length = n;
|
statements.length = n;
|
||||||
sequencesize_2(statements, compressor);
|
if (n != len) CHANGED = true;
|
||||||
CHANGED = statements.length != len;
|
}
|
||||||
|
|
||||||
|
function to_simple_statement(block, decls) {
|
||||||
|
if (!(block instanceof AST_BlockStatement)) return block;
|
||||||
|
var stat = null;
|
||||||
|
for (var i = 0, len = block.body.length; i < len; i++) {
|
||||||
|
var line = block.body[i];
|
||||||
|
if (line instanceof AST_Definitions && declarations_only(line)) {
|
||||||
|
decls.push(line);
|
||||||
|
} else if (stat) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
stat = line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sequencesize_2(statements, compressor) {
|
function sequencesize_2(statements, compressor) {
|
||||||
function cons_seq(right) {
|
function cons_seq(right) {
|
||||||
n--;
|
n--;
|
||||||
|
CHANGED = true;
|
||||||
var left = prev.body;
|
var left = prev.body;
|
||||||
return make_sequence(left, [ left, right ]).transform(compressor);
|
return make_sequence(left, [ left, right ]).transform(compressor);
|
||||||
};
|
};
|
||||||
var n = 0, prev;
|
var n = 0, prev;
|
||||||
for (var i = 0, len = statements.length; i < len; i++) {
|
for (var i = 0; i < statements.length; i++) {
|
||||||
var stat = statements[i];
|
var stat = statements[i];
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (stat instanceof AST_For && !(stat.init instanceof AST_Definitions)) {
|
if (stat instanceof AST_For && !(stat.init instanceof AST_Definitions)) {
|
||||||
@@ -1583,6 +1650,7 @@ merge(Compressor.prototype, {
|
|||||||
else {
|
else {
|
||||||
stat.init = prev.body;
|
stat.init = prev.body;
|
||||||
n--;
|
n--;
|
||||||
|
CHANGED = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1602,6 +1670,26 @@ merge(Compressor.prototype, {
|
|||||||
stat.expression = cons_seq(stat.expression);
|
stat.expression = cons_seq(stat.expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (compressor.option("conditionals") && stat instanceof AST_If) {
|
||||||
|
var decls = [];
|
||||||
|
var body = to_simple_statement(stat.body, decls);
|
||||||
|
var alt = to_simple_statement(stat.alternative, decls);
|
||||||
|
if (body !== false && alt !== false && decls.length > 0) {
|
||||||
|
var len = decls.length;
|
||||||
|
decls.push(make_node(AST_If, stat, {
|
||||||
|
condition: stat.condition,
|
||||||
|
body: body || make_node(AST_EmptyStatement, stat.body),
|
||||||
|
alternative: alt
|
||||||
|
}));
|
||||||
|
decls.unshift(n, 1);
|
||||||
|
[].splice.apply(statements, decls);
|
||||||
|
i += len;
|
||||||
|
n += len + 1;
|
||||||
|
prev = null;
|
||||||
|
CHANGED = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
statements[n++] = stat;
|
statements[n++] = stat;
|
||||||
prev = stat instanceof AST_SimpleStatement ? stat : null;
|
prev = stat instanceof AST_SimpleStatement ? stat : null;
|
||||||
}
|
}
|
||||||
@@ -1609,30 +1697,43 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function join_consecutive_vars(statements, compressor) {
|
function join_consecutive_vars(statements, compressor) {
|
||||||
|
var defs;
|
||||||
for (var i = 0, j = -1, len = statements.length; i < len; i++) {
|
for (var i = 0, j = -1, len = statements.length; i < len; i++) {
|
||||||
var stat = statements[i];
|
var stat = statements[i];
|
||||||
var prev = statements[j];
|
var prev = statements[j];
|
||||||
if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
|
if (stat instanceof AST_Definitions) {
|
||||||
prev.definitions = prev.definitions.concat(stat.definitions);
|
if (prev && prev.TYPE == stat.TYPE) {
|
||||||
CHANGED = true;
|
prev.definitions = prev.definitions.concat(stat.definitions);
|
||||||
}
|
CHANGED = true;
|
||||||
else if (stat instanceof AST_For
|
} else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) {
|
||||||
&& prev instanceof AST_Var
|
defs.definitions = defs.definitions.concat(stat.definitions);
|
||||||
&& (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
CHANGED = true;
|
||||||
CHANGED = true;
|
|
||||||
if (stat.init) {
|
|
||||||
stat.init.definitions = prev.definitions.concat(stat.init.definitions);
|
|
||||||
} else {
|
} else {
|
||||||
stat.init = prev;
|
statements[++j] = stat;
|
||||||
|
defs = stat;
|
||||||
}
|
}
|
||||||
statements[j] = stat;
|
} else if (stat instanceof AST_For) {
|
||||||
}
|
if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
||||||
else {
|
if (stat.init) {
|
||||||
|
prev.definitions = prev.definitions.concat(stat.init.definitions);
|
||||||
|
}
|
||||||
|
stat.init = prev;
|
||||||
|
statements[j] = stat;
|
||||||
|
CHANGED = true;
|
||||||
|
} else if (defs && stat.init && defs.TYPE == stat.init.TYPE && declarations_only(stat.init)) {
|
||||||
|
defs.definitions = defs.definitions.concat(stat.init.definitions);
|
||||||
|
stat.init = null;
|
||||||
|
statements[++j] = stat;
|
||||||
|
CHANGED = true;
|
||||||
|
} else {
|
||||||
|
statements[++j] = stat;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
statements[++j] = stat;
|
statements[++j] = stat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statements.length = j + 1;
|
statements.length = j + 1;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
||||||
@@ -1646,7 +1747,7 @@ merge(Compressor.prototype, {
|
|||||||
target.push(node);
|
target.push(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Defun && (node === stat || !compressor.has_directive("use strict"))) {
|
if (node instanceof AST_Defun) {
|
||||||
target.push(node);
|
target.push(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2625,6 +2726,7 @@ merge(Compressor.prototype, {
|
|||||||
};
|
};
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
||||||
|
var fixed_ids = Object.create(null);
|
||||||
if (self instanceof AST_Toplevel && compressor.top_retain) {
|
if (self instanceof AST_Toplevel && compressor.top_retain) {
|
||||||
self.variables.each(function(def) {
|
self.variables.each(function(def) {
|
||||||
if (compressor.top_retain(def) && !(def.id in in_use_ids)) {
|
if (compressor.top_retain(def) && !(def.id in in_use_ids)) {
|
||||||
@@ -2671,6 +2773,9 @@ merge(Compressor.prototype, {
|
|||||||
if (def.value.has_side_effects(compressor)) {
|
if (def.value.has_side_effects(compressor)) {
|
||||||
def.value.walk(tw);
|
def.value.walk(tw);
|
||||||
}
|
}
|
||||||
|
if (def.name.fixed_value() === def.value) {
|
||||||
|
fixed_ids[node_def.id] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
@@ -2694,12 +2799,16 @@ merge(Compressor.prototype, {
|
|||||||
var parent = tt.parent();
|
var parent = tt.parent();
|
||||||
if (drop_vars) {
|
if (drop_vars) {
|
||||||
var sym = assign_as_unused(node);
|
var sym = assign_as_unused(node);
|
||||||
if (sym instanceof AST_SymbolRef
|
if (sym instanceof AST_SymbolRef) {
|
||||||
&& !(sym.definition().id in in_use_ids)) {
|
var def = sym.definition();
|
||||||
|
var in_use = def.id in in_use_ids;
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
return maintain_this_binding(parent, node, node.right.transform(tt));
|
if (!in_use
|
||||||
}
|
|| def.id in fixed_ids
|
||||||
return make_node(AST_Number, node, {
|
&& node.left.fixed_value() !== node.right) {
|
||||||
|
return maintain_this_binding(parent, node, node.right.transform(tt));
|
||||||
|
}
|
||||||
|
} else if (!in_use) return make_node(AST_Number, node, {
|
||||||
value: 0
|
value: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2759,13 +2868,16 @@ merge(Compressor.prototype, {
|
|||||||
operator: "=",
|
operator: "=",
|
||||||
left: make_node(AST_SymbolRef, def.name, def.name),
|
left: make_node(AST_SymbolRef, def.name, def.name),
|
||||||
right: def.value
|
right: def.value
|
||||||
}));
|
}).transform(tt));
|
||||||
}
|
}
|
||||||
remove(var_defs, def);
|
remove(var_defs, def);
|
||||||
sym.eliminated++;
|
sym.eliminated++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (def.value && sym.id in fixed_ids && def.name.fixed_value() !== def.value) {
|
||||||
|
def.value = def.value.drop_side_effect_free(compressor);
|
||||||
|
}
|
||||||
if (def.value) {
|
if (def.value) {
|
||||||
if (side_effects.length > 0) {
|
if (side_effects.length > 0) {
|
||||||
if (tail.length > 0) {
|
if (tail.length > 0) {
|
||||||
@@ -2870,14 +2982,19 @@ merge(Compressor.prototype, {
|
|||||||
self.transform(tt);
|
self.transform(tt);
|
||||||
|
|
||||||
function scan_ref_scoped(node, descend) {
|
function scan_ref_scoped(node, descend) {
|
||||||
var sym;
|
var node_def, sym = assign_as_unused(node);
|
||||||
if ((sym = assign_as_unused(node)) instanceof AST_SymbolRef
|
if (sym instanceof AST_SymbolRef
|
||||||
&& self.variables.get(sym.name) === sym.definition()) {
|
&& self.variables.get(sym.name) === (node_def = sym.definition())) {
|
||||||
if (node instanceof AST_Assign) node.right.walk(tw);
|
if (node instanceof AST_Assign) {
|
||||||
|
node.right.walk(tw);
|
||||||
|
if (node.left.fixed_value() === node.right) {
|
||||||
|
fixed_ids[node_def.id] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var node_def = node.definition();
|
node_def = node.definition();
|
||||||
if (!(node_def.id in in_use_ids)) {
|
if (!(node_def.id in in_use_ids)) {
|
||||||
in_use_ids[node_def.id] = true;
|
in_use_ids[node_def.id] = true;
|
||||||
in_use.push(node_def);
|
in_use.push(node_def);
|
||||||
@@ -3163,7 +3280,12 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Assign, function(compressor){
|
def(AST_Assign, function(compressor){
|
||||||
var left = this.left;
|
var left = this.left;
|
||||||
if (left.has_side_effects(compressor)) return this;
|
if (left.has_side_effects(compressor)
|
||||||
|
|| compressor.has_directive("use strict")
|
||||||
|
&& left instanceof AST_PropAccess
|
||||||
|
&& left.expression.is_constant()) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
this.write_only = true;
|
this.write_only = true;
|
||||||
while (left instanceof AST_PropAccess) {
|
while (left instanceof AST_PropAccess) {
|
||||||
left = left.expression;
|
left = left.expression;
|
||||||
@@ -3747,6 +3869,27 @@ merge(Compressor.prototype, {
|
|||||||
operator: "!"
|
operator: "!"
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
break;
|
break;
|
||||||
|
case "RegExp":
|
||||||
|
var params = [];
|
||||||
|
if (all(self.args, function(arg) {
|
||||||
|
var value = arg.evaluate(compressor);
|
||||||
|
params.unshift(value);
|
||||||
|
return arg !== value;
|
||||||
|
})) {
|
||||||
|
try {
|
||||||
|
return best_of(compressor, self, make_node(AST_RegExp, self, {
|
||||||
|
value: RegExp.apply(RegExp, params),
|
||||||
|
}));
|
||||||
|
} catch (ex) {
|
||||||
|
compressor.warn("Error converting {expr} [{file}:{line},{col}]", {
|
||||||
|
expr: self.print_to_string(),
|
||||||
|
file: self.start.file,
|
||||||
|
line: self.start.line,
|
||||||
|
col: self.start.col
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
} else if (exp instanceof AST_Dot) switch(exp.property) {
|
} else if (exp instanceof AST_Dot) switch(exp.property) {
|
||||||
case "toString":
|
case "toString":
|
||||||
if (self.args.length == 0) return make_node(AST_Binary, self, {
|
if (self.args.length == 0) return make_node(AST_Binary, self, {
|
||||||
@@ -3928,23 +4071,21 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_func) {
|
if (is_func) {
|
||||||
var def, value, scope, level = -1;
|
var def, value, scope, in_loop, level = -1;
|
||||||
if (compressor.option("inline")
|
if (compressor.option("inline")
|
||||||
&& !fn.uses_arguments
|
&& !fn.uses_arguments
|
||||||
&& !fn.uses_eval
|
&& !fn.uses_eval
|
||||||
&& fn.body.length == 1
|
&& !(fn.name && fn instanceof AST_Function)
|
||||||
&& (exp === fn ? !fn.name
|
&& (value = can_flatten_body(stat))
|
||||||
: compressor.option("unused")
|
&& (exp === fn
|
||||||
|
|| compressor.option("unused")
|
||||||
&& (def = exp.definition()).references.length == 1
|
&& (def = exp.definition()).references.length == 1
|
||||||
&& !recursive_ref(compressor, def)
|
&& !recursive_ref(compressor, def)
|
||||||
&& fn.is_constant_expression(exp.scope))
|
&& fn.is_constant_expression(exp.scope))
|
||||||
&& !self.pure
|
&& !self.pure
|
||||||
&& !fn.contains_this()
|
&& !fn.contains_this()
|
||||||
&& can_flatten_args(fn)
|
&& can_inject_symbols()) {
|
||||||
&& (value = flatten_body(stat))) {
|
return make_sequence(self, flatten_fn()).optimize(compressor);
|
||||||
var expressions = flatten_args(fn);
|
|
||||||
expressions.push(value.clone(true));
|
|
||||||
return make_sequence(self, expressions).optimize(compressor);
|
|
||||||
}
|
}
|
||||||
if (compressor.option("side_effects") && all(fn.body, is_empty)) {
|
if (compressor.option("side_effects") && all(fn.body, is_empty)) {
|
||||||
var args = self.args.concat(make_node(AST_Undefined, self));
|
var args = self.args.concat(make_node(AST_Undefined, self));
|
||||||
@@ -3974,19 +4115,44 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
function can_flatten_args(fn) {
|
function return_value(stat) {
|
||||||
var catches = Object.create(null), defs;
|
if (!stat) return make_node(AST_Undefined, self);
|
||||||
do {
|
if (stat instanceof AST_Return) {
|
||||||
scope = compressor.parent(++level);
|
if (!stat.value) return make_node(AST_Undefined, self);
|
||||||
if (scope instanceof AST_Catch) {
|
return stat.value.clone(true);
|
||||||
catches[scope.argname.name] = true;
|
}
|
||||||
} else if (scope instanceof AST_IterationStatement) {
|
if (stat instanceof AST_SimpleStatement) {
|
||||||
defs = [];
|
return make_node(AST_UnaryPrefix, stat, {
|
||||||
} else if (scope instanceof AST_SymbolRef) {
|
operator: "void",
|
||||||
if (scope.fixed_value() instanceof AST_Scope) return false;
|
expression: stat.body.clone(true)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function can_flatten_body(stat) {
|
||||||
|
var len = fn.body.length;
|
||||||
|
if (compressor.option("inline") < 3) {
|
||||||
|
return len == 1 && return_value(stat);
|
||||||
|
}
|
||||||
|
stat = null;
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
|
var line = fn.body[i];
|
||||||
|
if (line instanceof AST_Var) {
|
||||||
|
if (stat && !all(line.definitions, function(var_def) {
|
||||||
|
return !var_def.value;
|
||||||
|
})) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (stat) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
stat = line;
|
||||||
}
|
}
|
||||||
} while (!(scope instanceof AST_Scope));
|
}
|
||||||
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
|
return return_value(stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
function can_inject_args(catches, safe_to_inject) {
|
||||||
for (var i = 0, len = fn.argnames.length; i < len; i++) {
|
for (var i = 0, len = fn.argnames.length; i < len; i++) {
|
||||||
var arg = fn.argnames[i];
|
var arg = fn.argnames[i];
|
||||||
if (arg.__unused) continue;
|
if (arg.__unused) continue;
|
||||||
@@ -3996,44 +4162,119 @@ merge(Compressor.prototype, {
|
|||||||
|| scope.var_names()[arg.name]) {
|
|| scope.var_names()[arg.name]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (defs) defs.push(arg.definition());
|
if (in_loop) in_loop.push(arg.definition());
|
||||||
}
|
}
|
||||||
return !defs || defs.length == 0 || !is_reachable(fn.body[0], defs);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function flatten_args(fn) {
|
function can_inject_vars(catches, safe_to_inject) {
|
||||||
var decls = [];
|
var len = fn.body.length;
|
||||||
var expressions = [];
|
for (var i = 0; i < len; i++) {
|
||||||
for (var len = fn.argnames.length, i = len; --i >= 0;) {
|
var stat = fn.body[i];
|
||||||
var name = fn.argnames[i];
|
if (!(stat instanceof AST_Var)) continue;
|
||||||
var value = self.args[i];
|
if (!safe_to_inject) return false;
|
||||||
if (name.__unused) {
|
for (var j = stat.definitions.length; --j >= 0;) {
|
||||||
if (value || expressions.length) {
|
var name = stat.definitions[j].name;
|
||||||
expressions.unshift(value || make_node(AST_Undefined, self));
|
if (catches[name.name]
|
||||||
|
|| identifier_atom(name.name)
|
||||||
|
|| scope.var_names()[name.name]) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
if (in_loop) in_loop.push(name.definition());
|
||||||
var def = name.definition();
|
|
||||||
scope.var_names()[name.name] = true;
|
|
||||||
scope.variables.set(name.name, def);
|
|
||||||
scope.enclosed.push(def);
|
|
||||||
var symbol = make_node(AST_SymbolVar, name, name);
|
|
||||||
def.orig.push(symbol);
|
|
||||||
decls.unshift(make_node(AST_VarDef, name, {
|
|
||||||
name: symbol,
|
|
||||||
value: null
|
|
||||||
}));
|
|
||||||
var sym = make_node(AST_SymbolRef, name, name);
|
|
||||||
def.references.push(sym);
|
|
||||||
expressions.unshift(make_node(AST_Assign, self, {
|
|
||||||
operator: "=",
|
|
||||||
left: sym,
|
|
||||||
right: value || make_node(AST_Undefined, self)
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = len, len = self.args.length; i < len; i++) {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function can_inject_symbols() {
|
||||||
|
var catches = Object.create(null);
|
||||||
|
do {
|
||||||
|
scope = compressor.parent(++level);
|
||||||
|
if (scope instanceof AST_Catch) {
|
||||||
|
catches[scope.argname.name] = true;
|
||||||
|
} else if (scope instanceof AST_IterationStatement) {
|
||||||
|
in_loop = [];
|
||||||
|
} else if (scope instanceof AST_SymbolRef) {
|
||||||
|
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||||
|
}
|
||||||
|
} while (!(scope instanceof AST_Scope));
|
||||||
|
var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars;
|
||||||
|
var inline = compressor.option("inline");
|
||||||
|
if (!can_inject_vars(catches, inline >= 3 && safe_to_inject)) return false;
|
||||||
|
if (!can_inject_args(catches, inline >= 2 && safe_to_inject)) return false;
|
||||||
|
return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
function append_var(decls, expressions, name, value) {
|
||||||
|
var def = name.definition();
|
||||||
|
scope.variables.set(name.name, def);
|
||||||
|
scope.enclosed.push(def);
|
||||||
|
if (!scope.var_names()[name.name]) {
|
||||||
|
scope.var_names()[name.name] = true;
|
||||||
|
decls.push(make_node(AST_VarDef, name, {
|
||||||
|
name: name,
|
||||||
|
value: null
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
var sym = make_node(AST_SymbolRef, name, name);
|
||||||
|
def.references.push(sym);
|
||||||
|
if (value) expressions.push(make_node(AST_Assign, self, {
|
||||||
|
operator: "=",
|
||||||
|
left: sym,
|
||||||
|
right: value
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatten_args(decls, expressions) {
|
||||||
|
var len = fn.argnames.length;
|
||||||
|
for (var i = self.args.length; --i >= len;) {
|
||||||
expressions.push(self.args[i]);
|
expressions.push(self.args[i]);
|
||||||
}
|
}
|
||||||
|
for (i = len; --i >= 0;) {
|
||||||
|
var name = fn.argnames[i];
|
||||||
|
var value = self.args[i];
|
||||||
|
if (name.__unused || scope.var_names()[name.name]) {
|
||||||
|
if (value) expressions.push(value);
|
||||||
|
} else {
|
||||||
|
var symbol = make_node(AST_SymbolVar, name, name);
|
||||||
|
name.definition().orig.push(symbol);
|
||||||
|
if (!value && in_loop) value = make_node(AST_Undefined, self);
|
||||||
|
append_var(decls, expressions, symbol, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decls.reverse();
|
||||||
|
expressions.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatten_vars(decls, expressions) {
|
||||||
|
var pos = expressions.length;
|
||||||
|
for (var i = 0, lines = fn.body.length; i < lines; i++) {
|
||||||
|
var stat = fn.body[i];
|
||||||
|
if (!(stat instanceof AST_Var)) continue;
|
||||||
|
for (var j = 0, defs = stat.definitions.length; j < defs; j++) {
|
||||||
|
var var_def = stat.definitions[j];
|
||||||
|
var name = var_def.name;
|
||||||
|
append_var(decls, expressions, name, var_def.value);
|
||||||
|
if (in_loop) {
|
||||||
|
var def = name.definition();
|
||||||
|
var sym = make_node(AST_SymbolRef, name, name);
|
||||||
|
def.references.push(sym);
|
||||||
|
expressions.splice(pos++, 0, make_node(AST_Assign, var_def, {
|
||||||
|
operator: "=",
|
||||||
|
left: sym,
|
||||||
|
right: make_node(AST_Undefined, name)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatten_fn() {
|
||||||
|
var decls = [];
|
||||||
|
var expressions = [];
|
||||||
|
flatten_args(decls, expressions);
|
||||||
|
flatten_vars(decls, expressions);
|
||||||
|
expressions.push(value);
|
||||||
if (decls.length) {
|
if (decls.length) {
|
||||||
i = scope.body.indexOf(compressor.parent(level - 1)) + 1;
|
i = scope.body.indexOf(compressor.parent(level - 1)) + 1;
|
||||||
scope.body.splice(i, 0, make_node(AST_Var, fn, {
|
scope.body.splice(i, 0, make_node(AST_Var, fn, {
|
||||||
@@ -4042,17 +4283,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return expressions;
|
return expressions;
|
||||||
}
|
}
|
||||||
|
|
||||||
function flatten_body(stat) {
|
|
||||||
if (stat instanceof AST_Return) {
|
|
||||||
return stat.value;
|
|
||||||
} else if (stat instanceof AST_SimpleStatement) {
|
|
||||||
return make_node(AST_UnaryPrefix, stat, {
|
|
||||||
operator: "void",
|
|
||||||
expression: stat.body
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_New, function(self, compressor){
|
OPT(AST_New, function(self, compressor){
|
||||||
@@ -4838,7 +5068,7 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
function is_reachable(node, defs) {
|
function is_reachable(self, defs) {
|
||||||
var reachable = false;
|
var reachable = false;
|
||||||
var find_ref = new TreeWalker(function(node) {
|
var find_ref = new TreeWalker(function(node) {
|
||||||
if (reachable) return true;
|
if (reachable) return true;
|
||||||
@@ -4848,15 +5078,14 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
var scan_scope = new TreeWalker(function(node) {
|
var scan_scope = new TreeWalker(function(node) {
|
||||||
if (reachable) return true;
|
if (reachable) return true;
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope && node !== self) {
|
||||||
var parent = scan_scope.parent();
|
var parent = scan_scope.parent();
|
||||||
if (!(parent instanceof AST_Call && parent.expression === node)) {
|
if (parent instanceof AST_Call && parent.expression === node) return;
|
||||||
node.walk(find_ref);
|
node.walk(find_ref);
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
node.walk(scan_scope);
|
self.walk(scan_scope);
|
||||||
return reachable;
|
return reachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4873,7 +5102,7 @@ merge(Compressor.prototype, {
|
|||||||
parent = compressor.parent(level++);
|
parent = compressor.parent(level++);
|
||||||
if (parent instanceof AST_Exit) {
|
if (parent instanceof AST_Exit) {
|
||||||
if (in_try(level, parent instanceof AST_Throw)) break;
|
if (in_try(level, parent instanceof AST_Throw)) break;
|
||||||
if (is_reachable(self, [ def ])) break;
|
if (is_reachable(def.scope, [ def ])) break;
|
||||||
if (self.operator == "=") return self.right;
|
if (self.operator == "=") return self.right;
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: self.operator.slice(0, -1),
|
operator: self.operator.slice(0, -1),
|
||||||
@@ -5255,6 +5484,14 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Dot, function(self, compressor){
|
OPT(AST_Dot, function(self, compressor){
|
||||||
|
if (self.property == "arguments" || self.property == "caller") {
|
||||||
|
compressor.warn("Function.protoype.{prop} not supported [{file}:{line},{col}]", {
|
||||||
|
prop: self.property,
|
||||||
|
file: self.start.file,
|
||||||
|
line: self.start.line,
|
||||||
|
col: self.start.col
|
||||||
|
});
|
||||||
|
}
|
||||||
var def = self.resolve_defines(compressor);
|
var def = self.resolve_defines(compressor);
|
||||||
if (def) {
|
if (def) {
|
||||||
return def.optimize(compressor);
|
return def.optimize(compressor);
|
||||||
@@ -5269,11 +5506,27 @@ merge(Compressor.prototype, {
|
|||||||
elements: []
|
elements: []
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "Function":
|
||||||
|
self.expression = make_node(AST_Function, self.expression, {
|
||||||
|
argnames: [],
|
||||||
|
body: []
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "Number":
|
||||||
|
self.expression = make_node(AST_Number, self.expression, {
|
||||||
|
value: 0
|
||||||
|
});
|
||||||
|
break;
|
||||||
case "Object":
|
case "Object":
|
||||||
self.expression = make_node(AST_Object, self.expression, {
|
self.expression = make_node(AST_Object, self.expression, {
|
||||||
properties: []
|
properties: []
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "RegExp":
|
||||||
|
self.expression = make_node(AST_RegExp, self.expression, {
|
||||||
|
value: /t/
|
||||||
|
});
|
||||||
|
break;
|
||||||
case "String":
|
case "String":
|
||||||
self.expression = make_node(AST_String, self.expression, {
|
self.expression = make_node(AST_String, self.expression, {
|
||||||
value: ""
|
value: ""
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ function set_shorthand(name, options, keys) {
|
|||||||
|
|
||||||
function init_cache(cache) {
|
function init_cache(cache) {
|
||||||
if (!cache) return;
|
if (!cache) return;
|
||||||
if (!("cname" in cache)) cache.cname = -1;
|
|
||||||
if (!("props" in cache)) {
|
if (!("props" in cache)) {
|
||||||
cache.props = new Dictionary();
|
cache.props = new Dictionary();
|
||||||
} else if (!(cache.props instanceof Dictionary)) {
|
} else if (!(cache.props instanceof Dictionary)) {
|
||||||
@@ -39,7 +38,6 @@ function init_cache(cache) {
|
|||||||
|
|
||||||
function to_json(cache) {
|
function to_json(cache) {
|
||||||
return {
|
return {
|
||||||
cname: cache.cname,
|
|
||||||
props: cache.props.toObject()
|
props: cache.props.toObject()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -534,7 +534,11 @@ function OutputStream(options) {
|
|||||||
var token = node.end;
|
var token = node.end;
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
var comments = token[tail ? "comments_before" : "comments_after"];
|
var comments = token[tail ? "comments_before" : "comments_after"];
|
||||||
if (comments && comments._dumped !== self) {
|
if (comments
|
||||||
|
&& comments._dumped !== self
|
||||||
|
&& (node instanceof AST_Statement || all(comments, function(c) {
|
||||||
|
return !/comment[134]/.test(c.type);
|
||||||
|
}))) {
|
||||||
comments._dumped = self;
|
comments._dumped = self;
|
||||||
var insert = OUTPUT.length;
|
var insert = OUTPUT.length;
|
||||||
comments.filter(comment_filter, node).forEach(function(c, i) {
|
comments.filter(comment_filter, node).forEach(function(c, i) {
|
||||||
@@ -599,7 +603,7 @@ function OutputStream(options) {
|
|||||||
add_mapping : add_mapping,
|
add_mapping : add_mapping,
|
||||||
option : function(opt) { return options[opt] },
|
option : function(opt) { return options[opt] },
|
||||||
prepend_comments: readonly ? noop : prepend_comments,
|
prepend_comments: readonly ? noop : prepend_comments,
|
||||||
append_comments : readonly ? noop : append_comments,
|
append_comments : readonly || comment_filter === return_false ? noop : append_comments,
|
||||||
line : function() { return current_line },
|
line : function() { return current_line },
|
||||||
col : function() { return current_col },
|
col : function() { return current_col },
|
||||||
pos : function() { return current_pos },
|
pos : function() { return current_pos },
|
||||||
@@ -671,9 +675,7 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PARENS(AST_Node, function(){
|
PARENS(AST_Node, return_false);
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// a function expression needs parens around it when it's provably
|
// a function expression needs parens around it when it's provably
|
||||||
// the first token to appear in a statement.
|
// the first token to appear in a statement.
|
||||||
@@ -699,9 +701,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
// same goes for an object literal, because otherwise it would be
|
// same goes for an object literal, because otherwise it would be
|
||||||
// interpreted as a block of code.
|
// interpreted as a block of code.
|
||||||
PARENS(AST_Object, function(output){
|
PARENS(AST_Object, first_in_statement);
|
||||||
return first_in_statement(output);
|
|
||||||
});
|
|
||||||
|
|
||||||
PARENS(AST_Unary, function(output){
|
PARENS(AST_Unary, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
|
|||||||
21
lib/parse.js
21
lib/parse.js
@@ -800,7 +800,7 @@ function parse($TEXT, options) {
|
|||||||
function embed_tokens(parser) {
|
function embed_tokens(parser) {
|
||||||
return function() {
|
return function() {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var expr = parser();
|
var expr = parser.apply(null, arguments);
|
||||||
var end = prev();
|
var end = prev();
|
||||||
expr.start = start;
|
expr.start = start;
|
||||||
expr.end = end;
|
expr.end = end;
|
||||||
@@ -815,7 +815,7 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var statement = embed_tokens(function() {
|
var statement = embed_tokens(function(strict_defun) {
|
||||||
handle_regexp();
|
handle_regexp();
|
||||||
switch (S.token.type) {
|
switch (S.token.type) {
|
||||||
case "string":
|
case "string":
|
||||||
@@ -901,6 +901,9 @@ function parse($TEXT, options) {
|
|||||||
return for_();
|
return for_();
|
||||||
|
|
||||||
case "function":
|
case "function":
|
||||||
|
if (!strict_defun && S.input.has_directive("use strict")) {
|
||||||
|
croak("In strict mode code, functions can only be declared at top level or immediately within another function.");
|
||||||
|
}
|
||||||
next();
|
next();
|
||||||
return function_(AST_Defun);
|
return function_(AST_Defun);
|
||||||
|
|
||||||
@@ -1083,7 +1086,7 @@ function parse($TEXT, options) {
|
|||||||
S.input.push_directives_stack();
|
S.input.push_directives_stack();
|
||||||
S.in_loop = 0;
|
S.in_loop = 0;
|
||||||
S.labels = [];
|
S.labels = [];
|
||||||
var body = block_();
|
var body = block_(true);
|
||||||
if (S.input.has_directive("use strict")) {
|
if (S.input.has_directive("use strict")) {
|
||||||
if (name) strict_verify_symbol(name);
|
if (name) strict_verify_symbol(name);
|
||||||
argnames.forEach(strict_verify_symbol);
|
argnames.forEach(strict_verify_symbol);
|
||||||
@@ -1112,12 +1115,12 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function block_() {
|
function block_(strict_defun) {
|
||||||
expect("{");
|
expect("{");
|
||||||
var a = [];
|
var a = [];
|
||||||
while (!is("punc", "}")) {
|
while (!is("punc", "}")) {
|
||||||
if (is("eof")) unexpected();
|
if (is("eof")) unexpected();
|
||||||
a.push(statement());
|
a.push(statement(strict_defun));
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return a;
|
return a;
|
||||||
@@ -1225,12 +1228,14 @@ function parse($TEXT, options) {
|
|||||||
} else {
|
} else {
|
||||||
args = [];
|
args = [];
|
||||||
}
|
}
|
||||||
return subscripts(new AST_New({
|
var call = new AST_New({
|
||||||
start : start,
|
start : start,
|
||||||
expression : newexp,
|
expression : newexp,
|
||||||
args : args,
|
args : args,
|
||||||
end : prev()
|
end : prev()
|
||||||
}), allow_calls);
|
});
|
||||||
|
mark_pure(call);
|
||||||
|
return subscripts(call, allow_calls);
|
||||||
};
|
};
|
||||||
|
|
||||||
function as_atom_node() {
|
function as_atom_node() {
|
||||||
@@ -1628,7 +1633,7 @@ function parse($TEXT, options) {
|
|||||||
var body = [];
|
var body = [];
|
||||||
S.input.push_directives_stack();
|
S.input.push_directives_stack();
|
||||||
while (!is("eof"))
|
while (!is("eof"))
|
||||||
body.push(statement());
|
body.push(statement(true));
|
||||||
S.input.pop_directives_stack();
|
S.input.pop_directives_stack();
|
||||||
var end = prev();
|
var end = prev();
|
||||||
var toplevel = options.toplevel;
|
var toplevel = options.toplevel;
|
||||||
|
|||||||
@@ -110,12 +110,15 @@ function mangle_properties(ast, options) {
|
|||||||
if (!Array.isArray(reserved)) reserved = [];
|
if (!Array.isArray(reserved)) reserved = [];
|
||||||
if (!options.builtins) find_builtins(reserved);
|
if (!options.builtins) find_builtins(reserved);
|
||||||
|
|
||||||
var cache = options.cache;
|
var cname = -1;
|
||||||
if (cache == null) {
|
var cache;
|
||||||
cache = {
|
if (options.cache) {
|
||||||
cname: -1,
|
cache = options.cache.props;
|
||||||
props: new Dictionary()
|
cache.each(function(mangled_name) {
|
||||||
};
|
push_uniq(reserved, mangled_name);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cache = new Dictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
var regex = options.regex;
|
var regex = options.regex;
|
||||||
@@ -172,7 +175,7 @@ function mangle_properties(ast, options) {
|
|||||||
if (unmangleable.indexOf(name) >= 0) return false;
|
if (unmangleable.indexOf(name) >= 0) return false;
|
||||||
if (reserved.indexOf(name) >= 0) return false;
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
if (options.only_cache) {
|
if (options.only_cache) {
|
||||||
return cache.props.has(name);
|
return cache.has(name);
|
||||||
}
|
}
|
||||||
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
||||||
return true;
|
return true;
|
||||||
@@ -181,7 +184,7 @@ function mangle_properties(ast, options) {
|
|||||||
function should_mangle(name) {
|
function should_mangle(name) {
|
||||||
if (regex && !regex.test(name)) return false;
|
if (regex && !regex.test(name)) return false;
|
||||||
if (reserved.indexOf(name) >= 0) return false;
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
return cache.props.has(name)
|
return cache.has(name)
|
||||||
|| names_to_mangle.indexOf(name) >= 0;
|
|| names_to_mangle.indexOf(name) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +202,7 @@ function mangle_properties(ast, options) {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mangled = cache.props.get(name);
|
var mangled = cache.get(name);
|
||||||
if (!mangled) {
|
if (!mangled) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
||||||
@@ -213,11 +216,11 @@ function mangle_properties(ast, options) {
|
|||||||
// either debug mode is off, or it is on and we could not use the mangled name
|
// either debug mode is off, or it is on and we could not use the mangled name
|
||||||
if (!mangled) {
|
if (!mangled) {
|
||||||
do {
|
do {
|
||||||
mangled = base54(++cache.cname);
|
mangled = base54(++cname);
|
||||||
} while (!can_mangle(mangled));
|
} while (!can_mangle(mangled));
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.props.set(name, mangled);
|
cache.set(name, mangled);
|
||||||
}
|
}
|
||||||
return mangled;
|
return mangled;
|
||||||
}
|
}
|
||||||
|
|||||||
64
lib/scope.js
64
lib/scope.js
@@ -43,9 +43,10 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
function SymbolDef(scope, orig) {
|
function SymbolDef(scope, orig, init) {
|
||||||
this.name = orig.name;
|
this.name = orig.name;
|
||||||
this.orig = [ orig ];
|
this.orig = [ orig ];
|
||||||
|
this.init = init;
|
||||||
this.eliminated = 0;
|
this.eliminated = 0;
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
this.references = [];
|
this.references = [];
|
||||||
@@ -150,7 +151,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
node.references = [];
|
node.references = [];
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolLambda) {
|
if (node instanceof AST_SymbolLambda) {
|
||||||
defun.def_function(node);
|
defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolDefun) {
|
else if (node instanceof AST_SymbolDefun) {
|
||||||
// Careful here, the scope where this should be defined is
|
// Careful here, the scope where this should be defined is
|
||||||
@@ -158,10 +159,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
// scope when we encounter the AST_Defun node (which is
|
// scope when we encounter the AST_Defun node (which is
|
||||||
// instanceof AST_Scope) but we get to the symbol a bit
|
// instanceof AST_Scope) but we get to the symbol a bit
|
||||||
// later.
|
// later.
|
||||||
(node.scope = defun.parent_scope).def_function(node);
|
(node.scope = defun.parent_scope).def_function(node, defun);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolVar) {
|
else if (node instanceof AST_SymbolVar) {
|
||||||
defun.def_variable(node);
|
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
|
||||||
if (defun !== scope) {
|
if (defun !== scope) {
|
||||||
node.mark_enclosed(options);
|
node.mark_enclosed(options);
|
||||||
var def = scope.find_variable(node);
|
var def = scope.find_variable(node);
|
||||||
@@ -241,10 +242,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.cache) {
|
|
||||||
this.cname = options.cache.cname;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("def_global", function(node){
|
AST_Toplevel.DEFMETHOD("def_global", function(node){
|
||||||
@@ -306,29 +303,32 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
|
|||||||
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("def_function", function(symbol){
|
AST_Scope.DEFMETHOD("def_function", function(symbol, init){
|
||||||
var def = this.def_variable(symbol);
|
var def = this.def_variable(symbol, init);
|
||||||
|
if (!def.init) def.init = init;
|
||||||
this.functions.set(symbol.name, def);
|
this.functions.set(symbol.name, def);
|
||||||
return def;
|
return def;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
AST_Scope.DEFMETHOD("def_variable", function(symbol, init){
|
||||||
var def;
|
var def = this.variables.get(symbol.name);
|
||||||
if (!this.variables.has(symbol.name)) {
|
if (def) {
|
||||||
def = new SymbolDef(this, symbol);
|
def.orig.push(symbol);
|
||||||
|
if (def.init && (def.scope !== symbol.scope || def.init instanceof AST_Function)) {
|
||||||
|
def.init = init;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
def = new SymbolDef(this, symbol, init);
|
||||||
this.variables.set(symbol.name, def);
|
this.variables.set(symbol.name, def);
|
||||||
def.global = !this.parent_scope;
|
def.global = !this.parent_scope;
|
||||||
} else {
|
|
||||||
def = this.variables.get(symbol.name);
|
|
||||||
def.orig.push(symbol);
|
|
||||||
}
|
}
|
||||||
return symbol.thedef = def;
|
return symbol.thedef = def;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("next_mangled", function(options){
|
function next_mangled(scope, options) {
|
||||||
var ext = this.enclosed;
|
var ext = scope.enclosed;
|
||||||
out: while (true) {
|
out: while (true) {
|
||||||
var m = base54(++this.cname);
|
var m = base54(++scope.cname);
|
||||||
if (!is_identifier(m)) continue; // skip over "do"
|
if (!is_identifier(m)) continue; // skip over "do"
|
||||||
|
|
||||||
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
|
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
|
||||||
@@ -345,6 +345,18 @@ AST_Scope.DEFMETHOD("next_mangled", function(options){
|
|||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_Scope.DEFMETHOD("next_mangled", function(options){
|
||||||
|
return next_mangled(this, options);
|
||||||
|
});
|
||||||
|
|
||||||
|
AST_Toplevel.DEFMETHOD("next_mangled", function(options){
|
||||||
|
var name;
|
||||||
|
do {
|
||||||
|
name = next_mangled(this, options);
|
||||||
|
} while (member(name, this.mangled_names));
|
||||||
|
return name;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
||||||
@@ -358,7 +370,7 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
|||||||
var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null;
|
var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var name = AST_Lambda.prototype.next_mangled.call(this, options, def);
|
var name = next_mangled(this, options);
|
||||||
if (!tricky_name || tricky_name != name)
|
if (!tricky_name || tricky_name != name)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -409,8 +421,14 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
var lname = -1;
|
var lname = -1;
|
||||||
var to_mangle = [];
|
var to_mangle = [];
|
||||||
|
|
||||||
|
var mangled_names = this.mangled_names = [];
|
||||||
if (options.cache) {
|
if (options.cache) {
|
||||||
this.globals.each(collect);
|
this.globals.each(collect);
|
||||||
|
if (options.cache.props) {
|
||||||
|
options.cache.props.each(function(mangled_name) {
|
||||||
|
push_uniq(mangled_names, mangled_name);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
@@ -439,10 +457,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
this.walk(tw);
|
this.walk(tw);
|
||||||
to_mangle.forEach(function(def){ def.mangle(options) });
|
to_mangle.forEach(function(def){ def.mangle(options) });
|
||||||
|
|
||||||
if (options.cache) {
|
|
||||||
options.cache.cname = this.cname;
|
|
||||||
}
|
|
||||||
|
|
||||||
function collect(symbol) {
|
function collect(symbol) {
|
||||||
if (!member(symbol.name, options.reserved)) {
|
if (!member(symbol.name, options.reserved)) {
|
||||||
to_mangle.push(symbol);
|
to_mangle.push(symbol);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.3.3",
|
"version": "3.3.5",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1203,3 +1203,24 @@ issue_2560: {
|
|||||||
"2",
|
"2",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hoist_decl: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
join_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
if (x()) {
|
||||||
|
var a;
|
||||||
|
y();
|
||||||
|
} else {
|
||||||
|
z();
|
||||||
|
var b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
x() ? y() : z();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -62,46 +62,6 @@ dead_code_2_should_warn: {
|
|||||||
node_version: "<=4"
|
node_version: "<=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
dead_code_2_should_warn_strict: {
|
|
||||||
options = {
|
|
||||||
dead_code: true
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
"use strict";
|
|
||||||
function f() {
|
|
||||||
g();
|
|
||||||
x = 10;
|
|
||||||
throw new Error("foo");
|
|
||||||
// completely discarding the `if` would introduce some
|
|
||||||
// bugs. UglifyJS v1 doesn't deal with this issue; in v2
|
|
||||||
// we copy any declarations to the upper scope.
|
|
||||||
if (x) {
|
|
||||||
y();
|
|
||||||
var x;
|
|
||||||
function g(){};
|
|
||||||
// but nested declarations should not be kept.
|
|
||||||
(function(){
|
|
||||||
var q;
|
|
||||||
function y(){};
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
"use strict";
|
|
||||||
function f() {
|
|
||||||
g();
|
|
||||||
x = 10;
|
|
||||||
throw new Error("foo");
|
|
||||||
var x;
|
|
||||||
}
|
|
||||||
f();
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
node_version: ">=4"
|
|
||||||
}
|
|
||||||
|
|
||||||
dead_code_constant_boolean_should_warn_more: {
|
dead_code_constant_boolean_should_warn_more: {
|
||||||
options = {
|
options = {
|
||||||
dead_code : true,
|
dead_code : true,
|
||||||
@@ -137,42 +97,6 @@ dead_code_constant_boolean_should_warn_more: {
|
|||||||
node_version: "<=4"
|
node_version: "<=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
dead_code_constant_boolean_should_warn_more_strict: {
|
|
||||||
options = {
|
|
||||||
dead_code : true,
|
|
||||||
loops : true,
|
|
||||||
booleans : true,
|
|
||||||
conditionals : true,
|
|
||||||
evaluate : true,
|
|
||||||
side_effects : true,
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
"use strict";
|
|
||||||
while (!((foo && bar) || (x + "0"))) {
|
|
||||||
console.log("unreachable");
|
|
||||||
var foo;
|
|
||||||
function bar() {}
|
|
||||||
}
|
|
||||||
for (var x = 10, y; x && (y || x) && (!typeof x); ++x) {
|
|
||||||
asdf();
|
|
||||||
foo();
|
|
||||||
var moo;
|
|
||||||
}
|
|
||||||
bar();
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
"use strict";
|
|
||||||
var foo;
|
|
||||||
// nothing for the while
|
|
||||||
// as for the for, it should keep:
|
|
||||||
var moo;
|
|
||||||
var x = 10, y;
|
|
||||||
bar();
|
|
||||||
}
|
|
||||||
expect_stdout: true
|
|
||||||
node_version: ">=4"
|
|
||||||
}
|
|
||||||
|
|
||||||
try_catch_finally: {
|
try_catch_finally: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
@@ -855,3 +779,57 @@ issue_2666: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "object"
|
expect_stdout: "object"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2692: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
reduce_vars: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
return a = g;
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(typeof f()());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
return a = g;
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(typeof f()());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2701: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
inline: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
return a = function() {
|
||||||
|
return function() {
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
console.log(typeof f()());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
return a = function() {
|
||||||
|
return function() {
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
console.log(typeof f()());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1522,3 +1522,125 @@ issue_2665: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "-1"
|
expect_stdout: "-1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double_assign_1: {
|
||||||
|
options = {
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f1() {
|
||||||
|
var a = {};
|
||||||
|
var a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
var a = {};
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f3() {
|
||||||
|
a = {};
|
||||||
|
var a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f4(a) {
|
||||||
|
a = {};
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f5(a) {
|
||||||
|
var a = {};
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f6(a) {
|
||||||
|
a = {};
|
||||||
|
var a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(f1(), f2(), f3(), f4(), f5(), f6());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f1() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
var a;
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f3() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
function f4(a) {
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f5(a) {
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function f6(a) {
|
||||||
|
a = [];
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
console.log(f1(), f2(), f3(), f4(), f5(), f6());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
double_assign_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
a = void 0, a = {}, console.log(a);
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
void 0, a = {}, console.log(a);
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double_assign_3: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
a = void 0, a = { a: a }, console.log(a);
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
a = void 0, a = { a: a }, console.log(a);
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cascade_drop_assign: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b = a = "PASS";
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var b = "PASS";
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -214,46 +214,6 @@ hoist_funs: {
|
|||||||
node_version: "<=4"
|
node_version: "<=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
hoist_funs_strict: {
|
|
||||||
options = {
|
|
||||||
hoist_funs: true,
|
|
||||||
}
|
|
||||||
input: {
|
|
||||||
"use strict";
|
|
||||||
console.log(1, typeof f, typeof g);
|
|
||||||
if (console.log(2, typeof f, typeof g))
|
|
||||||
console.log(3, typeof f, typeof g);
|
|
||||||
else {
|
|
||||||
console.log(4, typeof f, typeof g);
|
|
||||||
function f() {}
|
|
||||||
console.log(5, typeof f, typeof g);
|
|
||||||
}
|
|
||||||
function g() {}
|
|
||||||
console.log(6, typeof f, typeof g);
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
"use strict";
|
|
||||||
function g() {}
|
|
||||||
console.log(1, typeof f, typeof g);
|
|
||||||
if (console.log(2, typeof f, typeof g))
|
|
||||||
console.log(3, typeof f, typeof g);
|
|
||||||
else {
|
|
||||||
console.log(4, typeof f, typeof g);
|
|
||||||
function f() {}
|
|
||||||
console.log(5, typeof f, typeof g);
|
|
||||||
}
|
|
||||||
console.log(6, typeof f, typeof g);
|
|
||||||
}
|
|
||||||
expect_stdout: [
|
|
||||||
"1 'undefined' 'function'",
|
|
||||||
"2 'undefined' 'function'",
|
|
||||||
"4 'function' 'function'",
|
|
||||||
"5 'function' 'function'",
|
|
||||||
"6 'undefined' 'function'",
|
|
||||||
]
|
|
||||||
node_version: ">=4"
|
|
||||||
}
|
|
||||||
|
|
||||||
issue_203: {
|
issue_203: {
|
||||||
options = {
|
options = {
|
||||||
keep_fargs: false,
|
keep_fargs: false,
|
||||||
@@ -800,12 +760,12 @@ issue_2601_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
var a = "FAIL";
|
var a = "FAIL";
|
||||||
(function() {
|
(function() {
|
||||||
|
var b;
|
||||||
b = "foo",
|
b = "foo",
|
||||||
function(b) {
|
function(b) {
|
||||||
b && b();
|
b && b();
|
||||||
}(),
|
}(),
|
||||||
b && (a = "PASS");
|
b && (a = "PASS");
|
||||||
var b;
|
|
||||||
})(),
|
})(),
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
@@ -1285,7 +1245,7 @@ issue_2630_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
var c = 0;
|
var c = 0;
|
||||||
(function() {
|
(function() {
|
||||||
while (c++, void (c = 1 + c));
|
while (void (c = 1 + ++c));
|
||||||
})(),
|
})(),
|
||||||
console.log(c);
|
console.log(c);
|
||||||
}
|
}
|
||||||
@@ -1299,6 +1259,7 @@ issue_2630_2: {
|
|||||||
passes: 2,
|
passes: 2,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
sequences: true,
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
@@ -1316,7 +1277,7 @@ issue_2630_2: {
|
|||||||
expect: {
|
expect: {
|
||||||
var c = 0;
|
var c = 0;
|
||||||
!function() {
|
!function() {
|
||||||
while (c += 1, void (c = 1 + c));
|
while (void (c = 1 + (c += 1)));
|
||||||
}(), console.log(c);
|
}(), console.log(c);
|
||||||
}
|
}
|
||||||
expect_stdout: "2"
|
expect_stdout: "2"
|
||||||
@@ -1416,7 +1377,7 @@ issue_2630_5: {
|
|||||||
!function() {
|
!function() {
|
||||||
do {
|
do {
|
||||||
c *= 10;
|
c *= 10;
|
||||||
} while (c += 3, (c = 2 + c) < 100);
|
} while ((c = 2 + (c += 3)) < 100);
|
||||||
}();
|
}();
|
||||||
console.log(c);
|
console.log(c);
|
||||||
}
|
}
|
||||||
@@ -1646,3 +1607,347 @@ issue_2663_3: {
|
|||||||
"reset",
|
"reset",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duplicate_argnames: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS";
|
||||||
|
function f(b, b, b) {
|
||||||
|
b && (a = "FAIL");
|
||||||
|
}
|
||||||
|
f(0, console);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS";
|
||||||
|
console, b && (a = "FAIL");
|
||||||
|
var b;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
loop_init_arg: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS";
|
||||||
|
for (var k in "12") (function (b) {
|
||||||
|
(b >>= 1) && (a = "FAIL"), b = 2;
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS";
|
||||||
|
for (var k in "12")
|
||||||
|
b = void 0, (b >>= 1) && (a = "FAIL"), b = 2;
|
||||||
|
var b;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_false: {
|
||||||
|
options = {
|
||||||
|
inline: false,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
console.log(1);
|
||||||
|
})();
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
})(2);
|
||||||
|
(function(b) {
|
||||||
|
var c = b;
|
||||||
|
console.log(c);
|
||||||
|
})(3);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
console.log(1);
|
||||||
|
})();
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
})(2);
|
||||||
|
(function(b) {
|
||||||
|
var c = b;
|
||||||
|
console.log(c);
|
||||||
|
})(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_0: {
|
||||||
|
options = {
|
||||||
|
inline: 0,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
console.log(1);
|
||||||
|
})();
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
})(2);
|
||||||
|
(function(b) {
|
||||||
|
var c = b;
|
||||||
|
console.log(c);
|
||||||
|
})(3);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
console.log(1);
|
||||||
|
})();
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
})(2);
|
||||||
|
(function(b) {
|
||||||
|
var c = b;
|
||||||
|
console.log(c);
|
||||||
|
})(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_1: {
|
||||||
|
options = {
|
||||||
|
inline: 1,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
console.log(1);
|
||||||
|
})();
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
})(2);
|
||||||
|
(function(b) {
|
||||||
|
var c = b;
|
||||||
|
console.log(c);
|
||||||
|
})(3);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
})(2);
|
||||||
|
(function(b) {
|
||||||
|
var c = b;
|
||||||
|
console.log(c);
|
||||||
|
})(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_2: {
|
||||||
|
options = {
|
||||||
|
inline: 2,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
console.log(1);
|
||||||
|
})();
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
})(2);
|
||||||
|
(function(b) {
|
||||||
|
var c = b;
|
||||||
|
console.log(c);
|
||||||
|
})(3);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
a = 2, console.log(a);
|
||||||
|
var a;
|
||||||
|
(function(b) {
|
||||||
|
var c = b;
|
||||||
|
console.log(c);
|
||||||
|
})(3);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_3: {
|
||||||
|
options = {
|
||||||
|
inline: 3,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
console.log(1);
|
||||||
|
})();
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
})(2);
|
||||||
|
(function(b) {
|
||||||
|
var c = b;
|
||||||
|
console.log(c);
|
||||||
|
})(3);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
a = 2, console.log(a);
|
||||||
|
var a;
|
||||||
|
b = 3, c = b, console.log(c);
|
||||||
|
var b, c;
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_true: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
console.log(1);
|
||||||
|
})();
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
})(2);
|
||||||
|
(function(b) {
|
||||||
|
var c = b;
|
||||||
|
console.log(c);
|
||||||
|
})(3);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
a = 2, console.log(a);
|
||||||
|
var a;
|
||||||
|
b = 3, c = b, console.log(c);
|
||||||
|
var b, c;
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
use_before_init_in_loop: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS";
|
||||||
|
for (var b = 2; --b >= 0;) (function() {
|
||||||
|
var c = function() {
|
||||||
|
return 1;
|
||||||
|
}(c && (a = "FAIL"));
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS";
|
||||||
|
for (var b = 2; --b >= 0;)
|
||||||
|
c = void 0, c = (c && (a = "FAIL"), 1);
|
||||||
|
var c;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_arg_var: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(b) {
|
||||||
|
return b;
|
||||||
|
var b;
|
||||||
|
}("PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log((b = "PASS", b));
|
||||||
|
var b;
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2737_1: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
while (a());
|
||||||
|
})(function f() {
|
||||||
|
console.log(typeof f);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
while (a());
|
||||||
|
})(function f() {
|
||||||
|
console.log(typeof f);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2737_2: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(bar) {
|
||||||
|
for (;bar(); ) break;
|
||||||
|
})(function qux() {
|
||||||
|
return console.log("PASS"), qux;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(bar) {
|
||||||
|
for (;bar(); ) break;
|
||||||
|
})(function qux() {
|
||||||
|
return console.log("PASS"), qux;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -326,3 +326,73 @@ issue_512: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if_var_return: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
join_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var a;
|
||||||
|
return;
|
||||||
|
var b;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
var a;
|
||||||
|
if (u()) {
|
||||||
|
var b;
|
||||||
|
return v();
|
||||||
|
var c;
|
||||||
|
}
|
||||||
|
var d;
|
||||||
|
if (w()) {
|
||||||
|
var e;
|
||||||
|
return x();
|
||||||
|
var f;
|
||||||
|
} else {
|
||||||
|
var g;
|
||||||
|
y();
|
||||||
|
var h;
|
||||||
|
}
|
||||||
|
var i;
|
||||||
|
z();
|
||||||
|
var j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
var a, b;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
var a, b, c, d, e, f, g, h, i, j;
|
||||||
|
return u() ? v() : w() ? x() : (y(), z(), void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if_if_return_return: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a, b) {
|
||||||
|
if (a) {
|
||||||
|
if (b)
|
||||||
|
return b;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a, b) {
|
||||||
|
if (a)
|
||||||
|
return b || void 0;
|
||||||
|
g();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -64,3 +64,27 @@ strings_concat: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regexp: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
RegExp("foo");
|
||||||
|
RegExp("bar", "ig");
|
||||||
|
RegExp(foo);
|
||||||
|
RegExp("bar", ig);
|
||||||
|
RegExp("should", "fail");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
/foo/;
|
||||||
|
/bar/ig;
|
||||||
|
RegExp(foo);
|
||||||
|
RegExp("bar", ig);
|
||||||
|
RegExp("should", "fail");
|
||||||
|
}
|
||||||
|
expect_warnings: [
|
||||||
|
'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:78,2]',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
32
test/compress/issue-2719.js
Normal file
32
test/compress/issue-2719.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
warn: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
properties: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
return g();
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
return g["call" + "er"].arguments;
|
||||||
|
}
|
||||||
|
// 3
|
||||||
|
console.log(f(1, 2, 3).length);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
// TypeError: Cannot read property 'arguments' of null
|
||||||
|
console.log(function g() {
|
||||||
|
return g.caller.arguments;
|
||||||
|
}().length);
|
||||||
|
}
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: Function.protoype.caller not supported [test/compress/issue-2719.js:17,19]",
|
||||||
|
"WARN: Function.protoype.arguments not supported [test/compress/issue-2719.js:17,19]",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -567,12 +567,18 @@ native_prototype: {
|
|||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
Array.prototype.splice.apply(a, [1, 2, b, c]);
|
Array.prototype.splice.apply(a, [1, 2, b, c]);
|
||||||
|
Function.prototype.call.apply(console.log, console, [ "foo" ]);
|
||||||
|
Number.prototype.toFixed.call(Math.PI, 2);
|
||||||
Object.prototype.hasOwnProperty.call(d, "foo");
|
Object.prototype.hasOwnProperty.call(d, "foo");
|
||||||
|
RegExp.prototype.test.call(/foo/, "bar");
|
||||||
String.prototype.indexOf.call(e, "bar");
|
String.prototype.indexOf.call(e, "bar");
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
[].splice.apply(a, [1, 2, b, c]);
|
[].splice.apply(a, [1, 2, b, c]);
|
||||||
|
(function() {}).call.apply(console.log, console, [ "foo" ]);
|
||||||
|
0..toFixed.call(Math.PI, 2);
|
||||||
({}).hasOwnProperty.call(d, "foo");
|
({}).hasOwnProperty.call(d, "foo");
|
||||||
|
/t/.test.call(/foo/, "bar");
|
||||||
"".indexOf.call(e, "bar");
|
"".indexOf.call(e, "bar");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -414,3 +414,124 @@ issue_2638: {
|
|||||||
"/* */(a()||b())(c(),d());",
|
"/* */(a()||b())(c(),d());",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2705_1: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
comments: "all",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
/*@__PURE__*/ new a();
|
||||||
|
/*@__PURE__*/ (new b());
|
||||||
|
new (/*@__PURE__*/ c)();
|
||||||
|
(/*@__PURE__*/ new d());
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"new/* */c;",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2705_2: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
comments: "all",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
/*@__PURE__*/ new a(1)(2)(3);
|
||||||
|
/*@__PURE__*/ new (b(1))(2)(3);
|
||||||
|
/*@__PURE__*/ new (c(1)(2))(3);
|
||||||
|
/*@__PURE__*/ new (d(1)(2)(3));
|
||||||
|
new (/*@__PURE__*/ e)(1)(2)(3);
|
||||||
|
(/*@__PURE__*/ new f(1))(2)(3);
|
||||||
|
(/*@__PURE__*/ new g(1)(2))(3);
|
||||||
|
(/*@__PURE__*/ new h(1)(2)(3));
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"new/* */e(1)(2)(3);",
|
||||||
|
"/* */new f(1)(2)(3);",
|
||||||
|
"/* */new g(1)(2)(3);",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2705_3: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
comments: "all",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
/*@__PURE__*/ new a.x(1).y(2).z(3);
|
||||||
|
/*@__PURE__*/ new (b.x)(1).y(2).z(3);
|
||||||
|
/*@__PURE__*/ new (c.x(1)).y(2).z(3);
|
||||||
|
/*@__PURE__*/ new (d.x(1).y)(2).z(3);
|
||||||
|
/*@__PURE__*/ new (e.x(1).y(2)).z(3);
|
||||||
|
/*@__PURE__*/ new (f.x(1).y(2).z)(3);
|
||||||
|
/*@__PURE__*/ new (g.x(1).y(2).z(3));
|
||||||
|
new (/*@__PURE__*/ h).x(1).y(2).z(3);
|
||||||
|
/* */ new (/*@__PURE__*/ i.x)(1).y(2).z(3);
|
||||||
|
(/*@__PURE__*/ new j.x(1)).y(2).z(3);
|
||||||
|
(/*@__PURE__*/ new k.x(1).y)(2).z(3);
|
||||||
|
(/*@__PURE__*/ new l.x(1).y(2)).z(3);
|
||||||
|
(/*@__PURE__*/ new m.x(1).y(2).z)(3);
|
||||||
|
(/*@__PURE__*/ new n.x(1).y(2).z(3));
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"new/* */h.x(1).y(2).z(3);",
|
||||||
|
"/* */new/* */i.x(1).y(2).z(3);",
|
||||||
|
"/* */new j.x(1).y(2).z(3);",
|
||||||
|
"/* */new k.x(1).y(2).z(3);",
|
||||||
|
"/* */new l.x(1).y(2).z(3);",
|
||||||
|
"/* */new m.x(1).y(2).z(3);",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2705_4: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(/*@__PURE__*/ new x(), y());
|
||||||
|
(w(), /*@__PURE__*/ new x(), y());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
y();
|
||||||
|
w(), y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2705_5: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
[ /*@__PURE__*/ new x() ];
|
||||||
|
[ /*@__PURE__*/ new x(), y() ];
|
||||||
|
[ w(), /*@__PURE__*/ new x(), y() ];
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
y();
|
||||||
|
w(), y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2705_6: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
comments: "all",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
/*@__PURE__*/new (g() || h())(x(), y());
|
||||||
|
/* */ new (/*@__PURE__*/ (a() || b()))(c(), d());
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"/* */x(),y();",
|
||||||
|
"/* */new(/* */a()||b())(c(),d());",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -348,6 +348,57 @@ set_immutable_4: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_immutable_5: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
1..foo += "";
|
||||||
|
1..foo ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
set_immutable_6: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
1..foo ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
set_mutable_1: {
|
set_mutable_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ unsafe_evaluate_modified: {
|
|||||||
console.log(function(){ var o={p:1}; o.p++; console.log(o.p); return o.p; }());
|
console.log(function(){ var o={p:1}; o.p++; console.log(o.p); return o.p; }());
|
||||||
console.log(function(){ var o={p:2}; --o.p; console.log(o.p); return o.p; }());
|
console.log(function(){ var o={p:2}; --o.p; console.log(o.p); return o.p; }());
|
||||||
console.log(function(){ var o={p:3}; o.p += ""; console.log(o.p); return o.p; }());
|
console.log(function(){ var o={p:3}; o.p += ""; console.log(o.p); return o.p; }());
|
||||||
console.log(function(){ var o={p:4}; o = {}; console.log(o.p); return o.p; }());
|
console.log(function(){ var o; o = {}; console.log(o.p); return o.p; }());
|
||||||
console.log(function(){ var o={p:5}; o.p = -9; console.log(o.p); return o.p; }());
|
console.log(function(){ var o={p:5}; o.p = -9; console.log(o.p); return o.p; }());
|
||||||
function inc() { this.p++; }
|
function inc() { this.p++; }
|
||||||
console.log(function(){ var o={p:6}; inc.call(o); console.log(o.p); return o.p; }());
|
console.log(function(){ var o={p:6}; inc.call(o); console.log(o.p); return o.p; }());
|
||||||
@@ -2312,8 +2312,7 @@ delay_def: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
return a;
|
return;
|
||||||
var a;
|
|
||||||
}
|
}
|
||||||
function g() {
|
function g() {
|
||||||
return a;
|
return a;
|
||||||
@@ -2324,6 +2323,28 @@ delay_def: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delay_def_lhs: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
long_name++;
|
||||||
|
return long_name;
|
||||||
|
var long_name;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
long_name++;
|
||||||
|
return long_name;
|
||||||
|
var long_name;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "NaN"
|
||||||
|
}
|
||||||
|
|
||||||
booleans: {
|
booleans: {
|
||||||
options = {
|
options = {
|
||||||
booleans: true,
|
booleans: true,
|
||||||
@@ -4952,3 +4973,306 @@ issue_2598: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "true"
|
expect_stdout: "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var_if: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
if (x()) {
|
||||||
|
var a;
|
||||||
|
if (!g) a = true;
|
||||||
|
if (a) g();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
if (x()) {
|
||||||
|
var a;
|
||||||
|
if (!g) a = true;
|
||||||
|
if (a) g();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_assign: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(typeof a);
|
||||||
|
a = 42;
|
||||||
|
console.log(typeof a);
|
||||||
|
function a() {}
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof a);
|
||||||
|
a = 42;
|
||||||
|
console.log(typeof a);
|
||||||
|
function a() {}
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"function",
|
||||||
|
"number",
|
||||||
|
"number",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_var_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
typeofs: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 42, b;
|
||||||
|
function a() {}
|
||||||
|
function b() {}
|
||||||
|
console.log(typeof a, typeof b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 42;
|
||||||
|
function a() {}
|
||||||
|
console.log(typeof a, "function");
|
||||||
|
}
|
||||||
|
expect_stdout: "number function"
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_var_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
typeofs: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function a() {}
|
||||||
|
function b() {}
|
||||||
|
var a = 42, b;
|
||||||
|
console.log(typeof a, typeof b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function a() {}
|
||||||
|
var a = 42;
|
||||||
|
console.log(typeof a, "function");
|
||||||
|
}
|
||||||
|
expect_stdout: "number function"
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_var_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
typeofs: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function a() {}
|
||||||
|
function b() {}
|
||||||
|
console.log(typeof a, typeof b);
|
||||||
|
var a = 42, b;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function a() {}
|
||||||
|
console.log(typeof a, "function");
|
||||||
|
var a = 42;
|
||||||
|
}
|
||||||
|
expect_stdout: "function function"
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_catch_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function a() {}
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_catch_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
function a() {}
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_catch_3: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
function a() {}
|
||||||
|
} catch (a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_catch_4: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
function a() {}
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
function a() {}
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_catch_5: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
console.log(a);
|
||||||
|
function a() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
console.log(a);
|
||||||
|
function a() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
defun_catch_6: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
function a() {}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (a) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_lambda_defun_name_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f(a) {
|
||||||
|
function f() {}
|
||||||
|
return f.length;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f(a) {
|
||||||
|
function f() {}
|
||||||
|
return f.length;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_lambda_defun_name_2: {
|
||||||
|
options = {
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f(a) {
|
||||||
|
function f() {}
|
||||||
|
return f.length;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return function() {}.length;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|||||||
@@ -796,3 +796,66 @@ cascade_assignment_in_return: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hoist_defun: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
x();
|
||||||
|
function f() {}
|
||||||
|
y();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {}
|
||||||
|
x(), y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hoist_decl: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
w();
|
||||||
|
var b = x();
|
||||||
|
y();
|
||||||
|
for (var c; 0;) z();
|
||||||
|
var d;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
w();
|
||||||
|
var b = x(), c, d;
|
||||||
|
for (y(); 0;) z();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_init_var: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
unused: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "PASS";
|
||||||
|
(function() {
|
||||||
|
var b = 42;
|
||||||
|
for (var c = 5; c > 0;) c--;
|
||||||
|
a = "FAIL";
|
||||||
|
var a;
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "PASS";
|
||||||
|
(function() {
|
||||||
|
for (var b = 42, c = 5, a; c > 0;) c--;
|
||||||
|
a = "FAIL";
|
||||||
|
})();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ typeof_defun_1: {
|
|||||||
g = 42;
|
g = 42;
|
||||||
console.log("YES");
|
console.log("YES");
|
||||||
"function" == typeof g && g();
|
"function" == typeof g && g();
|
||||||
h();
|
"function" == typeof h && h();
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"YES",
|
"YES",
|
||||||
@@ -138,3 +138,166 @@ typeof_defun_2: {
|
|||||||
"2",
|
"2",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duplicate_defun_arg_name: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function long_name(long_name) {
|
||||||
|
return typeof long_name;
|
||||||
|
}
|
||||||
|
console.log(typeof long_name, long_name());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function long_name(long_name) {
|
||||||
|
return typeof long_name;
|
||||||
|
}
|
||||||
|
console.log(typeof long_name, long_name());
|
||||||
|
}
|
||||||
|
expect_stdout: "function undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicate_lambda_arg_name: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function long_name(long_name) {
|
||||||
|
return typeof long_name;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function long_name(long_name) {
|
||||||
|
return typeof long_name;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2728_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function arguments() {
|
||||||
|
console.log(typeof arguments);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function arguments() {
|
||||||
|
console.log(typeof arguments);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2728_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function arguments() {
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
console.log(typeof arguments, arguments());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function arguments() {
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
console.log(typeof arguments, arguments());
|
||||||
|
}
|
||||||
|
expect_stdout: "function object"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2728_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
function arguments() {
|
||||||
|
}
|
||||||
|
console.log(typeof arguments);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
function arguments() {
|
||||||
|
}
|
||||||
|
console.log("function");
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2728_4: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function arguments() {
|
||||||
|
}
|
||||||
|
console.log(typeof arguments);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function arguments() {
|
||||||
|
}
|
||||||
|
console.log("function");
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2728_5: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function arguments(arguments) {
|
||||||
|
console.log(typeof arguments);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function arguments(arguments) {
|
||||||
|
console.log(typeof arguments);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2728_6: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
typeofs: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function arguments(arguments) {
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
console.log(typeof arguments, arguments());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function arguments(arguments) {
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
console.log(typeof arguments, arguments());
|
||||||
|
}
|
||||||
|
expect_stdout: "function undefined"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
var a = bar(1+2);
|
var x = bar(1+2);
|
||||||
var b = baz(3+9);
|
var y = baz(3+9);
|
||||||
print('q' + 'u' + 'x', a, b);
|
print('q' + 'u' + 'x', x, y);
|
||||||
foo(5+6);
|
foo(5+6);
|
||||||
|
|||||||
@@ -5,11 +5,7 @@
|
|||||||
|
|
||||||
var site = "http://browserbench.org/JetStream";
|
var site = "http://browserbench.org/JetStream";
|
||||||
if (typeof phantom == "undefined") {
|
if (typeof phantom == "undefined") {
|
||||||
// workaround for tty output truncation upon process.exit()
|
require("../tools/exit");
|
||||||
[process.stdout, process.stderr].forEach(function(stream){
|
|
||||||
if (stream._handle && stream._handle.setBlocking)
|
|
||||||
stream._handle.setBlocking(true);
|
|
||||||
});
|
|
||||||
var args = process.argv.slice(2);
|
var args = process.argv.slice(2);
|
||||||
var debug = args.indexOf("--debug");
|
var debug = args.indexOf("--debug");
|
||||||
if (debug >= 0) {
|
if (debug >= 0) {
|
||||||
|
|||||||
@@ -219,4 +219,24 @@ describe("Comment", function() {
|
|||||||
if (result.error) throw result.error;
|
if (result.error) throw result.error;
|
||||||
assert.strictEqual(result.code, "/*a*/ /*b*/(function(){/*c*/}/*d*/ /*e*/)();");
|
assert.strictEqual(result.code, "/*a*/ /*b*/(function(){/*c*/}/*d*/ /*e*/)();");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should output line comments after statements", function() {
|
||||||
|
var result = uglify.minify([
|
||||||
|
"x()//foo",
|
||||||
|
"{y()//bar",
|
||||||
|
"}",
|
||||||
|
].join("\n"), {
|
||||||
|
compress: false,
|
||||||
|
mangle: false,
|
||||||
|
output: {
|
||||||
|
comments: "all",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, [
|
||||||
|
"x();//foo",
|
||||||
|
"{y();//bar",
|
||||||
|
"}",
|
||||||
|
].join("\n"));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -42,8 +42,15 @@ describe("minify", function() {
|
|||||||
original += code;
|
original += code;
|
||||||
compressed += result.code;
|
compressed += result.code;
|
||||||
});
|
});
|
||||||
assert.strictEqual(JSON.stringify(cache).slice(0, 20), '{"cname":5,"props":{');
|
assert.strictEqual(JSON.stringify(cache).slice(0, 10), '{"props":{');
|
||||||
assert.strictEqual(compressed, 'function n(n){return 3*n}function r(n){return n/2}var c=console.log.bind(console);function l(o){c("Foo:",2*o)}var f=n(3),i=r(12);c("qux",f,i),l(11);');
|
assert.strictEqual(compressed, [
|
||||||
|
"function n(n){return 3*n}",
|
||||||
|
"function r(n){return n/2}",
|
||||||
|
"var o=console.log.bind(console);",
|
||||||
|
'function c(n){o("Foo:",2*n)}',
|
||||||
|
"var a=n(3),b=r(12);",
|
||||||
|
'o("qux",a,b),c(11);',
|
||||||
|
].join(""));
|
||||||
assert.strictEqual(run_code(compressed), run_code(original));
|
assert.strictEqual(run_code(compressed), run_code(original));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -68,12 +75,48 @@ describe("minify", function() {
|
|||||||
original += code;
|
original += code;
|
||||||
compressed += result.code;
|
compressed += result.code;
|
||||||
});
|
});
|
||||||
assert.strictEqual(JSON.stringify(cache).slice(0, 28), '{"vars":{"cname":5,"props":{');
|
assert.strictEqual(JSON.stringify(cache).slice(0, 18), '{"vars":{"props":{');
|
||||||
assert.strictEqual(compressed, 'function n(n){return 3*n}function r(n){return n/2}var c=console.log.bind(console);function l(o){c("Foo:",2*o)}var f=n(3),i=r(12);c("qux",f,i),l(11);');
|
assert.strictEqual(compressed, [
|
||||||
|
"function n(n){return 3*n}",
|
||||||
|
"function r(n){return n/2}",
|
||||||
|
"var o=console.log.bind(console);",
|
||||||
|
'function c(n){o("Foo:",2*n)}',
|
||||||
|
"var a=n(3),b=r(12);",
|
||||||
|
'o("qux",a,b),c(11);',
|
||||||
|
].join(""));
|
||||||
assert.strictEqual(run_code(compressed), run_code(original));
|
assert.strictEqual(run_code(compressed), run_code(original));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not parse invalid use of reserved words", function() {
|
it("Should avoid mangled names in cache", function() {
|
||||||
|
var cache = {};
|
||||||
|
var original = "";
|
||||||
|
var compressed = "";
|
||||||
|
[
|
||||||
|
'"xxxyy";var i={s:1};',
|
||||||
|
'"xxyyy";var j={t:2,u:3},k=4;',
|
||||||
|
'console.log(i.s,j.t,j.u,k);',
|
||||||
|
].forEach(function(code) {
|
||||||
|
var result = Uglify.minify(code, {
|
||||||
|
compress: false,
|
||||||
|
mangle: {
|
||||||
|
properties: true,
|
||||||
|
toplevel: true
|
||||||
|
},
|
||||||
|
nameCache: cache
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
original += code;
|
||||||
|
compressed += result.code;
|
||||||
|
});
|
||||||
|
assert.strictEqual(compressed, [
|
||||||
|
'"xxxyy";var x={x:1};',
|
||||||
|
'"xxyyy";var y={y:2,a:3},a=4;',
|
||||||
|
'console.log(x.x,y.y,y.a,a);',
|
||||||
|
].join(""));
|
||||||
|
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 enum(){}").error, undefined);
|
||||||
assert.strictEqual(Uglify.minify("function static(){}").error, undefined);
|
assert.strictEqual(Uglify.minify("function static(){}").error, undefined);
|
||||||
assert.strictEqual(Uglify.minify("function this(){}").error.message, "Unexpected token: name (this)");
|
assert.strictEqual(Uglify.minify("function this(){}").error.message, "Unexpected token: name (this)");
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ var semver = require("semver");
|
|||||||
var tests_dir = path.dirname(module.filename);
|
var tests_dir = path.dirname(module.filename);
|
||||||
var failures = 0;
|
var failures = 0;
|
||||||
var failed_files = {};
|
var failed_files = {};
|
||||||
|
var minify_options = require("./ufuzz.json").map(JSON.stringify);
|
||||||
|
|
||||||
run_compress_tests();
|
run_compress_tests();
|
||||||
if (failures) {
|
if (failures) {
|
||||||
@@ -100,6 +101,15 @@ function run_compress_tests() {
|
|||||||
quote_style: 3,
|
quote_style: 3,
|
||||||
keep_quoted_props: true
|
keep_quoted_props: true
|
||||||
});
|
});
|
||||||
|
try {
|
||||||
|
U.parse(input_code);
|
||||||
|
} catch (ex) {
|
||||||
|
log("!!! Cannot parse input\n---INPUT---\n{input}\n--PARSE ERROR--\n{error}\n\n", {
|
||||||
|
input: input_formatted,
|
||||||
|
error: ex,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
var options = U.defaults(test.options, {
|
var options = U.defaults(test.options, {
|
||||||
warnings: false
|
warnings: false
|
||||||
});
|
});
|
||||||
@@ -139,78 +149,77 @@ function run_compress_tests() {
|
|||||||
output: output,
|
output: output,
|
||||||
expected: expect
|
expected: expect
|
||||||
});
|
});
|
||||||
failures++;
|
return false;
|
||||||
failed_files[file] = 1;
|
|
||||||
}
|
}
|
||||||
else {
|
// expect == output
|
||||||
// expect == output
|
try {
|
||||||
try {
|
U.parse(output);
|
||||||
var reparsed_ast = U.parse(output);
|
} catch (ex) {
|
||||||
} catch (ex) {
|
log("!!! Test matched expected result but cannot parse output\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n--REPARSE ERROR--\n{error}\n\n", {
|
||||||
log("!!! Test matched expected result but cannot parse output\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n--REPARSE ERROR--\n{error}\n\n", {
|
input: input_formatted,
|
||||||
|
output: output,
|
||||||
|
error: ex,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (test.expect_warnings) {
|
||||||
|
U.AST_Node.warn_function = original_warn_function;
|
||||||
|
var expected_warnings = make_code(test.expect_warnings, {
|
||||||
|
beautify: false,
|
||||||
|
quote_style: 2, // force double quote to match JSON
|
||||||
|
});
|
||||||
|
warnings_emitted = warnings_emitted.map(function(input) {
|
||||||
|
return input.split(process.cwd() + path.sep).join("").split(path.sep).join("/");
|
||||||
|
});
|
||||||
|
var actual_warnings = JSON.stringify(warnings_emitted);
|
||||||
|
if (expected_warnings != actual_warnings) {
|
||||||
|
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED WARNINGS---\n{expected_warnings}\n---ACTUAL WARNINGS---\n{actual_warnings}\n\n", {
|
||||||
input: input_formatted,
|
input: input_formatted,
|
||||||
output: output,
|
expected_warnings: expected_warnings,
|
||||||
error: ex.toString(),
|
actual_warnings: actual_warnings,
|
||||||
});
|
});
|
||||||
failures++;
|
return false;
|
||||||
failed_files[file] = 1;
|
|
||||||
}
|
|
||||||
if (test.expect_warnings) {
|
|
||||||
U.AST_Node.warn_function = original_warn_function;
|
|
||||||
var expected_warnings = make_code(test.expect_warnings, {
|
|
||||||
beautify: false,
|
|
||||||
quote_style: 2, // force double quote to match JSON
|
|
||||||
});
|
|
||||||
warnings_emitted = warnings_emitted.map(function(input) {
|
|
||||||
return input.split(process.cwd() + path.sep).join("").split(path.sep).join("/");
|
|
||||||
});
|
|
||||||
var actual_warnings = JSON.stringify(warnings_emitted);
|
|
||||||
if (expected_warnings != actual_warnings) {
|
|
||||||
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED WARNINGS---\n{expected_warnings}\n---ACTUAL WARNINGS---\n{actual_warnings}\n\n", {
|
|
||||||
input: input_formatted,
|
|
||||||
expected_warnings: expected_warnings,
|
|
||||||
actual_warnings: actual_warnings,
|
|
||||||
});
|
|
||||||
failures++;
|
|
||||||
failed_files[file] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (test.expect_stdout
|
|
||||||
&& (!test.node_version || semver.satisfies(process.version, test.node_version))) {
|
|
||||||
var stdout = sandbox.run_code(input_code);
|
|
||||||
if (test.expect_stdout === true) {
|
|
||||||
test.expect_stdout = stdout;
|
|
||||||
}
|
|
||||||
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
|
|
||||||
log("!!! Invalid input or expected stdout\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
|
||||||
input: input_formatted,
|
|
||||||
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
|
|
||||||
expected: test.expect_stdout,
|
|
||||||
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
|
||||||
actual: stdout,
|
|
||||||
});
|
|
||||||
failures++;
|
|
||||||
failed_files[file] = 1;
|
|
||||||
} else {
|
|
||||||
stdout = sandbox.run_code(output);
|
|
||||||
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
|
|
||||||
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
|
||||||
input: input_formatted,
|
|
||||||
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
|
|
||||||
expected: test.expect_stdout,
|
|
||||||
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
|
||||||
actual: stdout,
|
|
||||||
});
|
|
||||||
failures++;
|
|
||||||
failed_files[file] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (test.expect_stdout
|
||||||
|
&& (!test.node_version || semver.satisfies(process.version, test.node_version))) {
|
||||||
|
var stdout = sandbox.run_code(input_code);
|
||||||
|
if (test.expect_stdout === true) {
|
||||||
|
test.expect_stdout = stdout;
|
||||||
|
}
|
||||||
|
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
|
||||||
|
log("!!! Invalid input or expected stdout\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||||
|
input: input_formatted,
|
||||||
|
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
|
||||||
|
expected: test.expect_stdout,
|
||||||
|
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
||||||
|
actual: stdout,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
stdout = sandbox.run_code(output);
|
||||||
|
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
|
||||||
|
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||||
|
input: input_formatted,
|
||||||
|
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
|
||||||
|
expected: test.expect_stdout,
|
||||||
|
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
||||||
|
actual: stdout,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!reminify(test.options, input_code, input_formatted, test.expect_stdout)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
var tests = parse_test(path.resolve(dir, file));
|
var tests = parse_test(path.resolve(dir, file));
|
||||||
for (var i in tests) if (tests.hasOwnProperty(i)) {
|
for (var i in tests) if (tests.hasOwnProperty(i)) {
|
||||||
test_case(tests[i]);
|
if (!test_case(tests[i])) {
|
||||||
|
failures++;
|
||||||
|
failed_files[file] = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
files.forEach(function(file){
|
files.forEach(function(file){
|
||||||
@@ -346,3 +355,46 @@ function evaluate(code) {
|
|||||||
code = make_code(code, { beautify: true });
|
code = make_code(code, { beautify: true });
|
||||||
return new Function("return(" + code + ")")();
|
return new Function("return(" + code + ")")();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to reminify original input with standard options
|
||||||
|
// to see if it matches expect_stdout.
|
||||||
|
function reminify(orig_options, input_code, input_formatted, expect_stdout) {
|
||||||
|
for (var i = 0; i < minify_options.length; i++) {
|
||||||
|
var options = JSON.parse(minify_options[i]);
|
||||||
|
if (options.compress) [
|
||||||
|
"keep_fargs",
|
||||||
|
"keep_fnames",
|
||||||
|
].forEach(function(name) {
|
||||||
|
if (name in orig_options) {
|
||||||
|
options.compress[name] = orig_options[name];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var options_formatted = JSON.stringify(options, null, 4);
|
||||||
|
var result = U.minify(input_code, options);
|
||||||
|
if (result.error) {
|
||||||
|
log("!!! failed input reminify\n---INPUT---\n{input}\n--ERROR---\n{error}\n\n", {
|
||||||
|
input: input_formatted,
|
||||||
|
error: result.error,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
var stdout = sandbox.run_code(result.code);
|
||||||
|
if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) {
|
||||||
|
stdout = expect_stdout;
|
||||||
|
}
|
||||||
|
if (!sandbox.same_stdout(expect_stdout, stdout)) {
|
||||||
|
log("!!! failed running reminified input\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n---OUTPUT---\n{output}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||||
|
input: input_formatted,
|
||||||
|
options: options_formatted,
|
||||||
|
output: result.code,
|
||||||
|
expected_type: typeof expect_stdout == "string" ? "STDOUT" : "ERROR",
|
||||||
|
expected: expect_stdout,
|
||||||
|
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
||||||
|
actual: stdout,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,11 +6,7 @@
|
|||||||
// bin/uglifyjs s.js -c && bin/uglifyjs s.js -c passes=3 && bin/uglifyjs s.js -c passes=3 -m
|
// bin/uglifyjs s.js -c && bin/uglifyjs s.js -c passes=3 && bin/uglifyjs s.js -c passes=3 -m
|
||||||
// cat s.js | node && node s.js && bin/uglifyjs s.js -c | node && bin/uglifyjs s.js -c passes=3 | node && bin/uglifyjs s.js -c passes=3 -m | node
|
// cat s.js | node && node s.js && bin/uglifyjs s.js -c | node && bin/uglifyjs s.js -c passes=3 | node && bin/uglifyjs s.js -c passes=3 -m | node
|
||||||
|
|
||||||
// workaround for tty output truncation upon process.exit()
|
require("../tools/exit");
|
||||||
[process.stdout, process.stderr].forEach(function(stream){
|
|
||||||
if (stream._handle && stream._handle.setBlocking)
|
|
||||||
stream._handle.setBlocking(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
var UglifyJS = require("..");
|
var UglifyJS = require("..");
|
||||||
var randomBytes = require("crypto").randomBytes;
|
var randomBytes = require("crypto").randomBytes;
|
||||||
@@ -127,6 +123,9 @@ for (var i = 2; i < process.argv.length; ++i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var VALUES = [
|
var VALUES = [
|
||||||
|
'"a"',
|
||||||
|
'"b"',
|
||||||
|
'"c"',
|
||||||
'""',
|
'""',
|
||||||
'true',
|
'true',
|
||||||
'false',
|
'false',
|
||||||
|
|||||||
15
tools/exit.js
Normal file
15
tools/exit.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// workaround for tty output truncation upon process.exit()
|
||||||
|
var exit = process.exit;
|
||||||
|
process.exit = function() {
|
||||||
|
var args = [].slice.call(arguments);
|
||||||
|
process.once("uncaughtException", function() {
|
||||||
|
(function callback() {
|
||||||
|
if (process.stdout.bufferSize || process.stderr.bufferSize) {
|
||||||
|
setImmediate(callback);
|
||||||
|
} else {
|
||||||
|
exit.apply(process, args);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
throw exit;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user