Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dde41615a | ||
|
|
8b69a3d18e | ||
|
|
d40950b741 | ||
|
|
7659ea1d2e | ||
|
|
bdeadffbf5 | ||
|
|
5e6f26445f | ||
|
|
f0a99125ee | ||
|
|
1e4de2e6d3 | ||
|
|
8b4dcd8f3e | ||
|
|
285401ced8 | ||
|
|
9db4c42380 | ||
|
|
94e5e00c03 | ||
|
|
dc6bcaa18e | ||
|
|
d58b184835 | ||
|
|
b3a57ff019 | ||
|
|
3d5bc08185 | ||
|
|
0692435f01 | ||
|
|
f67a6b0e43 | ||
|
|
343ea326c2 | ||
|
|
1c150c632f | ||
|
|
0a0f4f5591 | ||
|
|
931daa85bf | ||
|
|
00e4f7b3c1 | ||
|
|
11e63bc335 | ||
|
|
33405bb24b |
52
README.md
52
README.md
@@ -111,7 +111,7 @@ a double dash to prevent input files being used as option arguments:
|
|||||||
By default UglifyJS will not try to be IE-proof.
|
By default UglifyJS will not try to be IE-proof.
|
||||||
--keep-fnames Do not mangle/drop function names. Useful for
|
--keep-fnames Do not mangle/drop function names. Useful for
|
||||||
code relying on Function.prototype.name.
|
code relying on Function.prototype.name.
|
||||||
--name-cache File to hold mangled name mappings.
|
--name-cache <file> File to hold mangled name mappings.
|
||||||
--self Build UglifyJS as a library (implies --wrap UglifyJS)
|
--self Build UglifyJS as a library (implies --wrap UglifyJS)
|
||||||
--source-map [options] Enable source map/specify source map options:
|
--source-map [options] Enable source map/specify source map options:
|
||||||
`base` Path to compute relative paths from input files.
|
`base` Path to compute relative paths from input files.
|
||||||
@@ -383,7 +383,47 @@ var code = {
|
|||||||
var options = { toplevel: true };
|
var options = { toplevel: true };
|
||||||
var result = UglifyJS.minify(code, options);
|
var result = UglifyJS.minify(code, options);
|
||||||
console.log(result.code);
|
console.log(result.code);
|
||||||
// console.log(function(n,o){return n+o}(3,7));
|
// console.log(3+7);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `nameCache` option:
|
||||||
|
```javascript
|
||||||
|
var options = {
|
||||||
|
mangle: {
|
||||||
|
toplevel: true,
|
||||||
|
},
|
||||||
|
nameCache: {}
|
||||||
|
};
|
||||||
|
var result1 = UglifyJS.minify({
|
||||||
|
"file1.js": "function add(first, second) { return first + second; }"
|
||||||
|
}, options);
|
||||||
|
var result2 = UglifyJS.minify({
|
||||||
|
"file2.js": "console.log(add(1 + 2, 3 + 4));"
|
||||||
|
}, options);
|
||||||
|
console.log(result1.code);
|
||||||
|
// function n(n,r){return n+r}
|
||||||
|
console.log(result2.code);
|
||||||
|
// console.log(n(3,7));
|
||||||
|
```
|
||||||
|
|
||||||
|
You may persist the name cache to the file system in the following way:
|
||||||
|
```javascript
|
||||||
|
var cacheFileName = "/tmp/cache.json";
|
||||||
|
var options = {
|
||||||
|
mangle: {
|
||||||
|
properties: true,
|
||||||
|
},
|
||||||
|
nameCache: JSON.parse(fs.readFileSync(cacheFileName, "utf8"))
|
||||||
|
};
|
||||||
|
fs.writeFileSync("part1.js", UglifyJS.minify({
|
||||||
|
"file1.js": fs.readFileSync("file1.js", "utf8"),
|
||||||
|
"file2.js": fs.readFileSync("file2.js", "utf8")
|
||||||
|
}, options).code, "utf8");
|
||||||
|
fs.writeFileSync("part2.js", UglifyJS.minify({
|
||||||
|
"file3.js": fs.readFileSync("file3.js", "utf8"),
|
||||||
|
"file4.js": fs.readFileSync("file4.js", "utf8")
|
||||||
|
}, options).code, "utf8");
|
||||||
|
fs.writeFileSync(cacheFileName, JSON.stringify(options.nameCache), "utf8");
|
||||||
```
|
```
|
||||||
|
|
||||||
An example of a combination of `minify()` options:
|
An example of a combination of `minify()` options:
|
||||||
@@ -461,6 +501,13 @@ if (result.error) throw result.error;
|
|||||||
- `toplevel` (default `false`) - set to `true` if you wish to enable top level
|
- `toplevel` (default `false`) - set to `true` if you wish to enable top level
|
||||||
variable and function name mangling and to drop unused variables and functions.
|
variable and function name mangling and to drop unused variables and functions.
|
||||||
|
|
||||||
|
- `nameCache` (default `null`) - pass an empty object `{}` or a previously
|
||||||
|
used `nameCache` object if you wish to cache mangled variable and
|
||||||
|
property names across multiple invocations of `minify()`. Note: this is
|
||||||
|
a read/write property. `minify()` will read the name cache state of this
|
||||||
|
object and update it during minification so that it may be
|
||||||
|
reused or externally persisted by the user.
|
||||||
|
|
||||||
- `ie8` (default `false`) - set to `true` to support IE8.
|
- `ie8` (default `false`) - set to `true` to support IE8.
|
||||||
|
|
||||||
## Minify options structure
|
## Minify options structure
|
||||||
@@ -487,6 +534,7 @@ if (result.error) throw result.error;
|
|||||||
sourceMap: {
|
sourceMap: {
|
||||||
// source map options
|
// source map options
|
||||||
},
|
},
|
||||||
|
nameCache: null, // or specify a name cache object
|
||||||
toplevel: false,
|
toplevel: false,
|
||||||
ie8: false,
|
ie8: false,
|
||||||
}
|
}
|
||||||
|
|||||||
27
bin/uglifyjs
27
bin/uglifyjs
@@ -106,17 +106,8 @@ if (program.mangleProps) {
|
|||||||
if (typeof options.mangle != "object") options.mangle = {};
|
if (typeof options.mangle != "object") options.mangle = {};
|
||||||
options.mangle.properties = program.mangleProps;
|
options.mangle.properties = program.mangleProps;
|
||||||
}
|
}
|
||||||
var cache;
|
|
||||||
if (program.nameCache) {
|
if (program.nameCache) {
|
||||||
cache = JSON.parse(read_file(program.nameCache, "{}"));
|
options.nameCache = JSON.parse(read_file(program.nameCache, "{}"));
|
||||||
if (options.mangle) {
|
|
||||||
if (typeof options.mangle != "object") options.mangle = {};
|
|
||||||
options.mangle.cache = to_cache("vars");
|
|
||||||
if (options.mangle.properties) {
|
|
||||||
if (typeof options.mangle.properties != "object") options.mangle.properties = {};
|
|
||||||
options.mangle.properties.cache = to_cache("props");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (program.output == "ast") {
|
if (program.output == "ast") {
|
||||||
options.output = {
|
options.output = {
|
||||||
@@ -266,9 +257,7 @@ function run() {
|
|||||||
print(result.code);
|
print(result.code);
|
||||||
}
|
}
|
||||||
if (program.nameCache) {
|
if (program.nameCache) {
|
||||||
fs.writeFileSync(program.nameCache, JSON.stringify(cache, function(key, value) {
|
fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache));
|
||||||
return value instanceof UglifyJS.Dictionary ? value.toObject() : value;
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
if (result.timings) for (var phase in result.timings) {
|
if (result.timings) for (var phase in result.timings) {
|
||||||
print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
|
print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
|
||||||
@@ -381,18 +370,6 @@ function parse_source_map() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function to_cache(key) {
|
|
||||||
if (cache[key]) {
|
|
||||||
cache[key].props = UglifyJS.Dictionary.fromObject(cache[key].props);
|
|
||||||
} else {
|
|
||||||
cache[key] = {
|
|
||||||
cname: -1,
|
|
||||||
props: new UglifyJS.Dictionary()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return cache[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
function skip_key(key) {
|
function skip_key(key) {
|
||||||
return skip_keys.indexOf(key) >= 0;
|
return skip_keys.indexOf(key) >= 0;
|
||||||
}
|
}
|
||||||
|
|||||||
574
lib/compress.js
574
lib/compress.js
@@ -92,12 +92,9 @@ function Compressor(options, false_by_default) {
|
|||||||
var global_defs = this.options["global_defs"];
|
var global_defs = this.options["global_defs"];
|
||||||
if (typeof global_defs == "object") for (var key in global_defs) {
|
if (typeof global_defs == "object") for (var key in global_defs) {
|
||||||
if (/^@/.test(key) && HOP(global_defs, key)) {
|
if (/^@/.test(key) && HOP(global_defs, key)) {
|
||||||
var ast = parse(global_defs[key]);
|
global_defs[key.slice(1)] = parse(global_defs[key], {
|
||||||
if (ast.body.length == 1 && ast.body[0] instanceof AST_SimpleStatement) {
|
expression: true
|
||||||
global_defs[key.slice(1)] = ast.body[0].body;
|
});
|
||||||
} else throw new Error(string_template("Can't handle expression: {value}", {
|
|
||||||
value: global_defs[key]
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var pure_funcs = this.options["pure_funcs"];
|
var pure_funcs = this.options["pure_funcs"];
|
||||||
@@ -124,13 +121,13 @@ function Compressor(options, false_by_default) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
var toplevel = this.options["toplevel"];
|
var toplevel = this.options["toplevel"];
|
||||||
if (typeof toplevel == "string") {
|
this.toplevel = typeof toplevel == "string" ? {
|
||||||
this.toplevel.funcs = /funcs/.test(toplevel);
|
funcs: /funcs/.test(toplevel),
|
||||||
this.toplevel.vars = /vars/.test(toplevel);
|
vars: /vars/.test(toplevel)
|
||||||
} else {
|
} : {
|
||||||
this.toplevel = toplevel ? return_true : return_false;
|
funcs: toplevel,
|
||||||
this.toplevel.funcs = this.toplevel.vars = toplevel;
|
vars: toplevel
|
||||||
}
|
};
|
||||||
var sequences = this.options["sequences"];
|
var sequences = this.options["sequences"];
|
||||||
this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
|
this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
|
||||||
this.warnings_produced = {};
|
this.warnings_produced = {};
|
||||||
@@ -139,11 +136,11 @@ function Compressor(options, false_by_default) {
|
|||||||
Compressor.prototype = new TreeTransformer;
|
Compressor.prototype = new TreeTransformer;
|
||||||
merge(Compressor.prototype, {
|
merge(Compressor.prototype, {
|
||||||
option: function(key) { return this.options[key] },
|
option: function(key) { return this.options[key] },
|
||||||
toplevel: function(def) {
|
exposed: function(def) {
|
||||||
for (var i = 0, len = def.orig.length; i < len; i++)
|
if (def.global) for (var i = 0, len = def.orig.length; i < len; i++)
|
||||||
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
|
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
|
||||||
return false;
|
return true;
|
||||||
return true;
|
return false;
|
||||||
},
|
},
|
||||||
compress: function(node) {
|
compress: function(node) {
|
||||||
if (this.option("expression")) {
|
if (this.option("expression")) {
|
||||||
@@ -279,11 +276,11 @@ merge(Compressor.prototype, {
|
|||||||
var reduce_vars = rescan && compressor.option("reduce_vars");
|
var reduce_vars = rescan && compressor.option("reduce_vars");
|
||||||
var safe_ids = Object.create(null);
|
var safe_ids = Object.create(null);
|
||||||
var suppressor = new TreeWalker(function(node) {
|
var suppressor = new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_Symbol) {
|
if (!(node instanceof AST_Symbol)) return;
|
||||||
var d = node.definition();
|
var d = node.definition();
|
||||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
if (!d) return;
|
||||||
d.fixed = false;
|
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||||
}
|
d.fixed = false;
|
||||||
});
|
});
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
node._squeezed = false;
|
node._squeezed = false;
|
||||||
@@ -345,7 +342,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Defun) {
|
if (node instanceof AST_Defun) {
|
||||||
var d = node.name.definition();
|
var d = node.name.definition();
|
||||||
if (d.global && !compressor.toplevel(d) || safe_to_read(d)) {
|
if (compressor.exposed(d) || safe_to_read(d)) {
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
} else {
|
} else {
|
||||||
d.fixed = node;
|
d.fixed = node;
|
||||||
@@ -517,7 +514,7 @@ merge(Compressor.prototype, {
|
|||||||
def.escaped = false;
|
def.escaped = false;
|
||||||
if (def.scope.uses_eval) {
|
if (def.scope.uses_eval) {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
} else if (!def.global || compressor.toplevel(def)) {
|
} else if (!compressor.exposed(def)) {
|
||||||
def.fixed = undefined;
|
def.fixed = undefined;
|
||||||
} else {
|
} else {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
@@ -547,8 +544,25 @@ merge(Compressor.prototype, {
|
|||||||
return fixed();
|
return fixed();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_SymbolRef.DEFMETHOD("is_immutable", function() {
|
||||||
|
var orig = this.definition().orig;
|
||||||
|
return orig.length == 1 && orig[0] instanceof AST_SymbolLambda;
|
||||||
|
});
|
||||||
|
|
||||||
function is_lhs_read_only(lhs) {
|
function is_lhs_read_only(lhs) {
|
||||||
return lhs instanceof AST_SymbolRef && lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
||||||
|
if (lhs instanceof AST_PropAccess) {
|
||||||
|
lhs = lhs.expression;
|
||||||
|
if (lhs instanceof AST_SymbolRef) {
|
||||||
|
if (lhs.is_immutable()) return false;
|
||||||
|
lhs = lhs.fixed_value();
|
||||||
|
}
|
||||||
|
if (!lhs) return true;
|
||||||
|
if (lhs instanceof AST_RegExp) return false;
|
||||||
|
if (lhs instanceof AST_Constant) return true;
|
||||||
|
return is_lhs_read_only(lhs);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function find_variable(compressor, name) {
|
function find_variable(compressor, name) {
|
||||||
@@ -668,26 +682,24 @@ merge(Compressor.prototype, {
|
|||||||
var CHANGED, max_iter = 10;
|
var CHANGED, max_iter = 10;
|
||||||
do {
|
do {
|
||||||
CHANGED = false;
|
CHANGED = false;
|
||||||
statements = eliminate_spurious_blocks(statements);
|
eliminate_spurious_blocks(statements);
|
||||||
if (compressor.option("dead_code")) {
|
if (compressor.option("dead_code")) {
|
||||||
statements = eliminate_dead_code(statements, compressor);
|
eliminate_dead_code(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("if_return")) {
|
if (compressor.option("if_return")) {
|
||||||
statements = handle_if_return(statements, compressor);
|
handle_if_return(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.sequences_limit > 0) {
|
if (compressor.sequences_limit > 0) {
|
||||||
statements = sequencesize(statements, compressor);
|
sequencesize(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("join_vars")) {
|
if (compressor.option("join_vars")) {
|
||||||
statements = join_consecutive_vars(statements, compressor);
|
join_consecutive_vars(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("collapse_vars")) {
|
if (compressor.option("collapse_vars")) {
|
||||||
statements = collapse(statements, compressor);
|
collapse(statements, compressor);
|
||||||
}
|
}
|
||||||
} while (CHANGED && max_iter-- > 0);
|
} while (CHANGED && max_iter-- > 0);
|
||||||
|
|
||||||
return statements;
|
|
||||||
|
|
||||||
// Search from right to left for assignment-like expressions:
|
// Search from right to left for assignment-like expressions:
|
||||||
// - `var a = x;`
|
// - `var a = x;`
|
||||||
// - `a = x;`
|
// - `a = x;`
|
||||||
@@ -702,15 +714,23 @@ merge(Compressor.prototype, {
|
|||||||
var candidates = [];
|
var candidates = [];
|
||||||
var stat_index = statements.length;
|
var stat_index = statements.length;
|
||||||
while (--stat_index >= 0) {
|
while (--stat_index >= 0) {
|
||||||
|
// Treat parameters as collapsible in IIFE, i.e.
|
||||||
|
// function(a, b){ ... }(x());
|
||||||
|
// would be translated into equivalent assignments:
|
||||||
|
// var a = x(), b = undefined;
|
||||||
|
if (stat_index == 0 && compressor.option("unused")) extract_args();
|
||||||
|
// Find collapsible assignments
|
||||||
extract_candidates(statements[stat_index]);
|
extract_candidates(statements[stat_index]);
|
||||||
while (candidates.length > 0) {
|
while (candidates.length > 0) {
|
||||||
var candidate = candidates.pop();
|
var candidate = candidates.pop();
|
||||||
var lhs = get_lhs(candidate);
|
var lhs = get_lhs(candidate);
|
||||||
if (!lhs || is_lhs_read_only(lhs)) continue;
|
if (!lhs || is_lhs_read_only(lhs)) continue;
|
||||||
|
// Locate symbols which may execute code outside of scanning range
|
||||||
var lvalues = get_lvalues(candidate);
|
var lvalues = get_lvalues(candidate);
|
||||||
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
|
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
|
||||||
var side_effects = value_has_side_effects(candidate);
|
var side_effects = value_has_side_effects(candidate);
|
||||||
var hit = false, abort = false, replaced = false;
|
var hit = candidate.name instanceof AST_SymbolFunarg;
|
||||||
|
var abort = false, replaced = false;
|
||||||
var tt = new TreeTransformer(function(node, descend) {
|
var tt = new TreeTransformer(function(node, descend) {
|
||||||
if (abort) return node;
|
if (abort) return node;
|
||||||
// Skip nodes before `candidate` as quickly as possible
|
// Skip nodes before `candidate` as quickly as possible
|
||||||
@@ -724,6 +744,7 @@ merge(Compressor.prototype, {
|
|||||||
// Stop immediately if these node types are encountered
|
// Stop immediately if these node types are encountered
|
||||||
var parent = tt.parent();
|
var parent = tt.parent();
|
||||||
if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
|
if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
|
||||||
|
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|
||||||
|| node instanceof AST_Debugger
|
|| node instanceof AST_Debugger
|
||||||
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
||||||
|| node instanceof AST_SymbolRef && node.undeclared()
|
|| node instanceof AST_SymbolRef && node.undeclared()
|
||||||
@@ -749,7 +770,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (candidate instanceof AST_VarDef) {
|
if (candidate instanceof AST_VarDef) {
|
||||||
var def = candidate.name.definition();
|
var def = candidate.name.definition();
|
||||||
if (def.references.length == 1 && (!def.global || compressor.toplevel(def))) {
|
if (def.references.length == 1 && !compressor.exposed(def)) {
|
||||||
return maintain_this_binding(parent, node, candidate.value);
|
return maintain_this_binding(parent, node, candidate.value);
|
||||||
}
|
}
|
||||||
return make_node(AST_Assign, candidate, {
|
return make_node(AST_Assign, candidate, {
|
||||||
@@ -789,7 +810,35 @@ merge(Compressor.prototype, {
|
|||||||
if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
|
if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return statements;
|
|
||||||
|
function extract_args() {
|
||||||
|
var iife, fn = compressor.self();
|
||||||
|
if (fn instanceof AST_Function
|
||||||
|
&& !fn.name
|
||||||
|
&& !fn.uses_arguments
|
||||||
|
&& !fn.uses_eval
|
||||||
|
&& (iife = compressor.parent()) instanceof AST_Call
|
||||||
|
&& iife.expression === fn) {
|
||||||
|
fn.argnames.forEach(function(sym, i) {
|
||||||
|
var arg = iife.args[i];
|
||||||
|
if (!arg) arg = make_node(AST_Undefined, sym);
|
||||||
|
else arg.walk(new TreeWalker(function(node) {
|
||||||
|
if (!arg) return true;
|
||||||
|
if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) {
|
||||||
|
var s = node.definition().scope;
|
||||||
|
if (s !== scope) while (s = s.parent_scope) {
|
||||||
|
if (s === scope) return true;
|
||||||
|
}
|
||||||
|
arg = null;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
if (arg) candidates.push(make_node(AST_VarDef, sym, {
|
||||||
|
name: sym,
|
||||||
|
value: arg
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function extract_candidates(expr) {
|
function extract_candidates(expr) {
|
||||||
if (expr instanceof AST_Assign && !expr.left.has_side_effects(compressor)
|
if (expr instanceof AST_Assign && !expr.left.has_side_effects(compressor)
|
||||||
@@ -811,8 +860,8 @@ merge(Compressor.prototype, {
|
|||||||
function get_lhs(expr) {
|
function get_lhs(expr) {
|
||||||
if (expr instanceof AST_VarDef) {
|
if (expr instanceof AST_VarDef) {
|
||||||
var def = expr.name.definition();
|
var def = expr.name.definition();
|
||||||
if (def.orig.length > 1
|
if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg)
|
||||||
|| def.references.length == 1 && (!def.global || compressor.toplevel(def))) {
|
|| def.references.length == 1 && !compressor.exposed(def)) {
|
||||||
return make_node(AST_SymbolRef, expr.name, expr.name);
|
return make_node(AST_SymbolRef, expr.name, expr.name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -853,6 +902,14 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function remove_candidate(expr) {
|
function remove_candidate(expr) {
|
||||||
|
if (expr.name instanceof AST_SymbolFunarg) {
|
||||||
|
var index = compressor.self().argnames.indexOf(expr.name);
|
||||||
|
var args = compressor.parent().args;
|
||||||
|
if (args[index]) args[index] = make_node(AST_Number, args[index], {
|
||||||
|
value: 0
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
var found = false;
|
var found = false;
|
||||||
return statements[stat_index].transform(new TreeTransformer(function(node, descend, in_list) {
|
return statements[stat_index].transform(new TreeTransformer(function(node, descend, in_list) {
|
||||||
if (found) return node;
|
if (found) return node;
|
||||||
@@ -891,59 +948,60 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function eliminate_spurious_blocks(statements) {
|
function eliminate_spurious_blocks(statements) {
|
||||||
var seen_dirs = [];
|
var seen_dirs = [];
|
||||||
return statements.reduce(function(a, stat){
|
for (var i = 0; i < statements.length;) {
|
||||||
|
var stat = statements[i];
|
||||||
if (stat instanceof AST_BlockStatement) {
|
if (stat instanceof AST_BlockStatement) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
a.push.apply(a, eliminate_spurious_blocks(stat.body));
|
eliminate_spurious_blocks(stat.body);
|
||||||
|
[].splice.apply(statements, [i, 1].concat(stat.body));
|
||||||
|
i += stat.body.length;
|
||||||
} else if (stat instanceof AST_EmptyStatement) {
|
} else if (stat instanceof AST_EmptyStatement) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
|
statements.splice(i, 1);
|
||||||
} else if (stat instanceof AST_Directive) {
|
} else if (stat instanceof AST_Directive) {
|
||||||
if (seen_dirs.indexOf(stat.value) < 0) {
|
if (seen_dirs.indexOf(stat.value) < 0) {
|
||||||
a.push(stat);
|
i++;
|
||||||
seen_dirs.push(stat.value);
|
seen_dirs.push(stat.value);
|
||||||
} else {
|
} else {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
|
statements.splice(i, 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else i++;
|
||||||
a.push(stat);
|
}
|
||||||
}
|
}
|
||||||
return a;
|
|
||||||
}, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
function handle_if_return(statements, compressor) {
|
function handle_if_return(statements, compressor) {
|
||||||
var self = compressor.self();
|
var self = compressor.self();
|
||||||
var multiple_if_returns = has_multiple_if_returns(statements);
|
var multiple_if_returns = has_multiple_if_returns(statements);
|
||||||
var in_lambda = self instanceof AST_Lambda;
|
var in_lambda = self instanceof AST_Lambda;
|
||||||
var ret = []; // Optimized statements, build from tail to front
|
for (var i = statements.length; --i >= 0;) {
|
||||||
loop: for (var i = statements.length; --i >= 0;) {
|
|
||||||
var stat = statements[i];
|
var stat = statements[i];
|
||||||
switch (true) {
|
var next = statements[i + 1];
|
||||||
case (in_lambda && stat instanceof AST_Return && !stat.value && ret.length == 0):
|
|
||||||
|
if (in_lambda && stat instanceof AST_Return && !stat.value && !next) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
// note, ret.length is probably always zero
|
statements.length--;
|
||||||
// because we drop unreachable code before this
|
continue;
|
||||||
// step. nevertheless, it's good to check.
|
}
|
||||||
continue loop;
|
|
||||||
case stat instanceof AST_If:
|
if (stat instanceof AST_If) {
|
||||||
var ab = aborts(stat.body);
|
var ab = aborts(stat.body);
|
||||||
if (can_merge_flow(ab)) {
|
if (can_merge_flow(ab)) {
|
||||||
if (ab.label) {
|
if (ab.label) {
|
||||||
remove(ab.label.thedef.references, ab);
|
remove(ab.label.thedef.references, ab);
|
||||||
}
|
}
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
var funs = extract_functions_from_statement_array(ret);
|
|
||||||
var body = as_statement_array_with_return(stat.body, ab);
|
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.condition = stat.condition.negate(compressor);
|
stat.condition = stat.condition.negate(compressor);
|
||||||
|
var body = as_statement_array_with_return(stat.body, ab);
|
||||||
stat.body = make_node(AST_BlockStatement, stat, {
|
stat.body = make_node(AST_BlockStatement, stat, {
|
||||||
body: as_statement_array(stat.alternative).concat(ret)
|
body: as_statement_array(stat.alternative).concat(extract_functions())
|
||||||
});
|
});
|
||||||
stat.alternative = make_node(AST_BlockStatement, stat, {
|
stat.alternative = make_node(AST_BlockStatement, stat, {
|
||||||
body: body
|
body: body
|
||||||
});
|
});
|
||||||
ret = [ stat.transform(compressor) ].concat(funs);
|
statements[i] = stat.transform(compressor);
|
||||||
continue loop;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ab = aborts(stat.alternative);
|
var ab = aborts(stat.alternative);
|
||||||
@@ -952,81 +1010,71 @@ merge(Compressor.prototype, {
|
|||||||
remove(ab.label.thedef.references, ab);
|
remove(ab.label.thedef.references, ab);
|
||||||
}
|
}
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
var funs = extract_functions_from_statement_array(ret);
|
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.body = make_node(AST_BlockStatement, stat.body, {
|
stat.body = make_node(AST_BlockStatement, stat.body, {
|
||||||
body: as_statement_array(stat.body).concat(ret)
|
body: as_statement_array(stat.body).concat(extract_functions())
|
||||||
});
|
});
|
||||||
var body = as_statement_array_with_return(stat.alternative, ab);
|
var body = as_statement_array_with_return(stat.alternative, ab);
|
||||||
stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
|
stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
|
||||||
body: body
|
body: body
|
||||||
});
|
});
|
||||||
ret = [ stat.transform(compressor) ].concat(funs);
|
statements[i] = stat.transform(compressor);
|
||||||
continue loop;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (stat.body instanceof AST_Return) {
|
if (stat instanceof AST_If && stat.body instanceof AST_Return) {
|
||||||
var value = stat.body.value;
|
var value = stat.body.value;
|
||||||
//---
|
//---
|
||||||
// pretty silly case, but:
|
// pretty silly case, but:
|
||||||
// if (foo()) return; return; ==> foo(); return;
|
// if (foo()) return; return; ==> foo(); return;
|
||||||
if ((in_lambda && ret.length == 0 || ret[0] instanceof AST_Return && !ret[0].value)
|
if (!value && !stat.alternative
|
||||||
&& !value && !stat.alternative) {
|
&& (in_lambda && !next || next instanceof AST_Return && !next.value)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
var cond = make_node(AST_SimpleStatement, stat.condition, {
|
statements[i] = make_node(AST_SimpleStatement, stat.condition, {
|
||||||
body: stat.condition
|
body: stat.condition
|
||||||
});
|
});
|
||||||
ret.unshift(cond);
|
continue;
|
||||||
continue loop;
|
}
|
||||||
}
|
//---
|
||||||
//---
|
// if (foo()) return x; return y; ==> return foo() ? x : y;
|
||||||
// if (foo()) return x; return y; ==> return foo() ? x : y;
|
if (value && !stat.alternative && next instanceof AST_Return && next.value) {
|
||||||
if (ret[0] instanceof AST_Return && value && ret[0].value && !stat.alternative) {
|
CHANGED = true;
|
||||||
CHANGED = true;
|
stat = stat.clone();
|
||||||
stat = stat.clone();
|
stat.alternative = next;
|
||||||
stat.alternative = ret[0];
|
statements.splice(i, 2, stat.transform(compressor));
|
||||||
ret[0] = stat.transform(compressor);
|
continue;
|
||||||
continue loop;
|
}
|
||||||
}
|
//---
|
||||||
//---
|
// 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 (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return)
|
&& (!next || next instanceof AST_Return)) {
|
||||||
&& value && !stat.alternative && in_lambda) {
|
CHANGED = true;
|
||||||
CHANGED = true;
|
stat = stat.clone();
|
||||||
stat = stat.clone();
|
stat.alternative = next || make_node(AST_Return, stat, {
|
||||||
stat.alternative = ret[0] || make_node(AST_Return, stat, {
|
value: null
|
||||||
value: null
|
});
|
||||||
});
|
statements.splice(i, next ? 2 : 1, stat.transform(compressor));
|
||||||
ret[0] = stat.transform(compressor);
|
continue;
|
||||||
continue loop;
|
}
|
||||||
}
|
//---
|
||||||
//---
|
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
||||||
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
//
|
||||||
//
|
// 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];
|
||||||
if (compressor.option("sequences")
|
if (compressor.option("sequences") && in_lambda && !stat.alternative
|
||||||
&& i > 0 && statements[i - 1] instanceof AST_If && statements[i - 1].body instanceof AST_Return
|
&& prev instanceof AST_If && prev.body instanceof AST_Return
|
||||||
&& ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
|
&& i + 2 == statements.length && next instanceof AST_SimpleStatement) {
|
||||||
&& !stat.alternative) {
|
CHANGED = true;
|
||||||
CHANGED = true;
|
statements.push(make_node(AST_Return, next, {
|
||||||
ret.push(make_node(AST_Return, ret[0], {
|
value: null
|
||||||
value: null
|
}).transform(compressor));
|
||||||
}).transform(compressor));
|
continue;
|
||||||
ret.unshift(stat);
|
|
||||||
continue loop;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.unshift(stat);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret.unshift(stat);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
|
|
||||||
function has_multiple_if_returns(statements) {
|
function has_multiple_if_returns(statements) {
|
||||||
var n = 0;
|
var n = 0;
|
||||||
@@ -1051,6 +1099,18 @@ merge(Compressor.prototype, {
|
|||||||
|| ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct;
|
|| ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extract_functions() {
|
||||||
|
var tail = statements.slice(i + 1);
|
||||||
|
statements.length = i + 1;
|
||||||
|
return tail.filter(function(stat) {
|
||||||
|
if (stat instanceof AST_Defun) {
|
||||||
|
statements.push(stat);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function as_statement_array_with_return(node, ab) {
|
function as_statement_array_with_return(node, ab) {
|
||||||
var body = as_statement_array(node).slice(0, -1);
|
var body = as_statement_array(node).slice(0, -1);
|
||||||
if (ab.value) {
|
if (ab.value) {
|
||||||
@@ -1060,49 +1120,52 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function eliminate_dead_code(statements, compressor) {
|
function eliminate_dead_code(statements, compressor) {
|
||||||
var has_quit = false;
|
var has_quit;
|
||||||
var orig = statements.length;
|
|
||||||
var self = compressor.self();
|
var self = compressor.self();
|
||||||
statements = statements.reduce(function(a, stat){
|
for (var i = 0, n = 0, len = statements.length; i < len; i++) {
|
||||||
if (has_quit) {
|
var stat = statements[i];
|
||||||
extract_declarations_from_unreachable_code(compressor, stat, a);
|
if (stat instanceof AST_LoopControl) {
|
||||||
} else {
|
var lct = compressor.loopcontrol_target(stat);
|
||||||
if (stat instanceof AST_LoopControl) {
|
if (stat instanceof AST_Break
|
||||||
var lct = compressor.loopcontrol_target(stat);
|
&& !(lct instanceof AST_IterationStatement)
|
||||||
if ((stat instanceof AST_Break
|
&& loop_body(lct) === self
|
||||||
&& !(lct instanceof AST_IterationStatement)
|
|| stat instanceof AST_Continue
|
||||||
&& loop_body(lct) === self) || (stat instanceof AST_Continue
|
&& loop_body(lct) === self) {
|
||||||
&& loop_body(lct) === self)) {
|
if (stat.label) {
|
||||||
if (stat.label) {
|
remove(stat.label.thedef.references, stat);
|
||||||
remove(stat.label.thedef.references, stat);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a.push(stat);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
a.push(stat);
|
statements[n++] = stat;
|
||||||
}
|
}
|
||||||
if (aborts(stat)) has_quit = true;
|
} else {
|
||||||
|
statements[n++] = stat;
|
||||||
}
|
}
|
||||||
return a;
|
if (aborts(stat)) {
|
||||||
}, []);
|
has_quit = statements.slice(i + 1);
|
||||||
CHANGED = statements.length != orig;
|
break;
|
||||||
return statements;
|
}
|
||||||
};
|
}
|
||||||
|
statements.length = n;
|
||||||
|
CHANGED = n != len;
|
||||||
|
if (has_quit) has_quit.forEach(function(stat) {
|
||||||
|
extract_declarations_from_unreachable_code(compressor, stat, statements);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function sequencesize(statements, compressor) {
|
function sequencesize(statements, compressor) {
|
||||||
if (statements.length < 2) return statements;
|
if (statements.length < 2) return;
|
||||||
var seq = [], ret = [];
|
var seq = [], n = 0;
|
||||||
function push_seq() {
|
function push_seq() {
|
||||||
if (!seq.length) return;
|
if (!seq.length) return;
|
||||||
var body = make_sequence(seq[0], seq);
|
var body = make_sequence(seq[0], seq);
|
||||||
ret.push(make_node(AST_SimpleStatement, body, { body: body }));
|
statements[n++] = make_node(AST_SimpleStatement, body, { body: body });
|
||||||
seq = [];
|
seq = [];
|
||||||
};
|
}
|
||||||
statements.forEach(function(stat){
|
for (var i = 0, len = statements.length; i < len; i++) {
|
||||||
|
var stat = statements[i];
|
||||||
if (stat instanceof AST_SimpleStatement) {
|
if (stat instanceof AST_SimpleStatement) {
|
||||||
if (seq.length >= compressor.sequences_limit) push_seq();
|
if (seq.length >= compressor.sequences_limit) push_seq();
|
||||||
var body = stat.body;
|
var body = stat.body;
|
||||||
@@ -1110,18 +1173,18 @@ merge(Compressor.prototype, {
|
|||||||
if (body) merge_sequence(seq, body);
|
if (body) merge_sequence(seq, body);
|
||||||
} else {
|
} else {
|
||||||
push_seq();
|
push_seq();
|
||||||
ret.push(stat);
|
statements[n++] = stat;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
push_seq();
|
push_seq();
|
||||||
ret = sequencesize_2(ret, compressor);
|
statements.length = n;
|
||||||
CHANGED = ret.length != statements.length;
|
sequencesize_2(statements, compressor);
|
||||||
return ret;
|
CHANGED = statements.length != len;
|
||||||
};
|
}
|
||||||
|
|
||||||
function sequencesize_2(statements, compressor) {
|
function sequencesize_2(statements, compressor) {
|
||||||
function cons_seq(right) {
|
function cons_seq(right) {
|
||||||
ret.pop();
|
n--;
|
||||||
var left = prev.body;
|
var left = prev.body;
|
||||||
if (!(left instanceof AST_Sequence)) {
|
if (!(left instanceof AST_Sequence)) {
|
||||||
left = make_node(AST_Sequence, left, {
|
left = make_node(AST_Sequence, left, {
|
||||||
@@ -1131,8 +1194,9 @@ merge(Compressor.prototype, {
|
|||||||
merge_sequence(left.expressions, right);
|
merge_sequence(left.expressions, right);
|
||||||
return left.transform(compressor);
|
return left.transform(compressor);
|
||||||
};
|
};
|
||||||
var ret = [], prev = null;
|
var n = 0, prev;
|
||||||
statements.forEach(function(stat){
|
for (var i = 0, len = statements.length; i < len; i++) {
|
||||||
|
var stat = statements[i];
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (stat instanceof AST_For) {
|
if (stat instanceof AST_For) {
|
||||||
try {
|
try {
|
||||||
@@ -1145,7 +1209,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
else if (!stat.init) {
|
else if (!stat.init) {
|
||||||
stat.init = prev.body.drop_side_effect_free(compressor);
|
stat.init = prev.body.drop_side_effect_free(compressor);
|
||||||
ret.pop();
|
n--;
|
||||||
}
|
}
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex !== cons_seq) throw ex;
|
if (ex !== cons_seq) throw ex;
|
||||||
@@ -1167,15 +1231,16 @@ merge(Compressor.prototype, {
|
|||||||
stat.expression = cons_seq(stat.expression);
|
stat.expression = cons_seq(stat.expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret.push(stat);
|
statements[n++] = stat;
|
||||||
prev = stat instanceof AST_SimpleStatement ? stat : null;
|
prev = stat instanceof AST_SimpleStatement ? stat : null;
|
||||||
});
|
}
|
||||||
return ret;
|
statements.length = n;
|
||||||
};
|
}
|
||||||
|
|
||||||
function join_consecutive_vars(statements, compressor) {
|
function join_consecutive_vars(statements, compressor) {
|
||||||
var prev = null;
|
for (var i = 0, j = -1, len = statements.length; i < len; i++) {
|
||||||
return statements.reduce(function(a, stat){
|
var stat = statements[i];
|
||||||
|
var prev = statements[j];
|
||||||
if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
|
if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) {
|
||||||
prev.definitions = prev.definitions.concat(stat.definitions);
|
prev.definitions = prev.definitions.concat(stat.definitions);
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
@@ -1184,35 +1249,19 @@ merge(Compressor.prototype, {
|
|||||||
&& prev instanceof AST_Var
|
&& prev instanceof AST_Var
|
||||||
&& (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
&& (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
a.pop();
|
|
||||||
if (stat.init) {
|
if (stat.init) {
|
||||||
stat.init.definitions = prev.definitions.concat(stat.init.definitions);
|
stat.init.definitions = prev.definitions.concat(stat.init.definitions);
|
||||||
} else {
|
} else {
|
||||||
stat.init = prev;
|
stat.init = prev;
|
||||||
}
|
}
|
||||||
a.push(stat);
|
statements[j] = stat;
|
||||||
prev = stat;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
prev = stat;
|
statements[++j] = stat;
|
||||||
a.push(stat);
|
|
||||||
}
|
}
|
||||||
return a;
|
|
||||||
}, []);
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
function extract_functions_from_statement_array(statements) {
|
|
||||||
var funs = [];
|
|
||||||
for (var i = statements.length - 1; i >= 0; --i) {
|
|
||||||
var stat = statements[i];
|
|
||||||
if (stat instanceof AST_Defun) {
|
|
||||||
statements.splice(i, 1);
|
|
||||||
funs.unshift(stat);
|
|
||||||
}
|
}
|
||||||
}
|
statements.length = j + 1;
|
||||||
return funs;
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
||||||
@@ -1297,6 +1346,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_SymbolRef, function(pure_getters) {
|
def(AST_SymbolRef, function(pure_getters) {
|
||||||
if (this.is_undefined) return true;
|
if (this.is_undefined) return true;
|
||||||
if (!is_strict(pure_getters)) return false;
|
if (!is_strict(pure_getters)) return false;
|
||||||
|
if (this.is_immutable()) return false;
|
||||||
var fixed = this.fixed_value();
|
var fixed = this.fixed_value();
|
||||||
return !fixed || fixed._throw_on_access(pure_getters);
|
return !fixed || fixed._throw_on_access(pure_getters);
|
||||||
});
|
});
|
||||||
@@ -1989,12 +2039,12 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Block, function(self, compressor){
|
OPT(AST_Block, function(self, compressor){
|
||||||
self.body = tighten_body(self.body, compressor);
|
tighten_body(self.body, compressor);
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_BlockStatement, function(self, compressor){
|
OPT(AST_BlockStatement, function(self, compressor){
|
||||||
self.body = tighten_body(self.body, compressor);
|
tighten_body(self.body, compressor);
|
||||||
switch (self.body.length) {
|
switch (self.body.length) {
|
||||||
case 1: return self.body[0];
|
case 1: return self.body[0];
|
||||||
case 0: return make_node(AST_EmptyStatement, self);
|
case 0: return make_node(AST_EmptyStatement, self);
|
||||||
@@ -2901,7 +2951,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Try, function(self, compressor){
|
OPT(AST_Try, function(self, compressor){
|
||||||
self.body = tighten_body(self.body, compressor);
|
tighten_body(self.body, compressor);
|
||||||
if (self.bcatch && self.bfinally && all(self.bfinally.body, is_empty)) self.bfinally = null;
|
if (self.bcatch && self.bfinally && all(self.bfinally.body, is_empty)) self.bfinally = null;
|
||||||
if (all(self.body, is_empty)) {
|
if (all(self.body, is_empty)) {
|
||||||
var body = [];
|
var body = [];
|
||||||
@@ -2944,18 +2994,18 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
OPT(AST_Call, function(self, compressor){
|
OPT(AST_Call, function(self, compressor){
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
if (compressor.option("reduce_vars") && exp instanceof AST_SymbolRef) {
|
var fn = exp;
|
||||||
var fixed = exp.fixed_value();
|
|
||||||
if (fixed instanceof AST_Function) exp = fixed;
|
|
||||||
}
|
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& exp instanceof AST_Function
|
&& (fn instanceof AST_Function
|
||||||
&& !exp.uses_arguments
|
|| compressor.option("reduce_vars")
|
||||||
&& !exp.uses_eval) {
|
&& fn instanceof AST_SymbolRef
|
||||||
|
&& (fn = fn.fixed_value()) instanceof AST_Function)
|
||||||
|
&& !fn.uses_arguments
|
||||||
|
&& !fn.uses_eval) {
|
||||||
var pos = 0, last = 0;
|
var pos = 0, last = 0;
|
||||||
for (var i = 0, len = self.args.length; i < len; i++) {
|
for (var i = 0, len = self.args.length; i < len; i++) {
|
||||||
var trim = i >= exp.argnames.length;
|
var trim = i >= fn.argnames.length;
|
||||||
if (trim || exp.argnames[i].__unused) {
|
if (trim || fn.argnames[i].__unused) {
|
||||||
var node = self.args[i].drop_side_effect_free(compressor);
|
var node = self.args[i].drop_side_effect_free(compressor);
|
||||||
if (node) {
|
if (node) {
|
||||||
self.args[pos++] = node;
|
self.args[pos++] = node;
|
||||||
@@ -3115,7 +3165,7 @@ merge(Compressor.prototype, {
|
|||||||
// https://github.com/mishoo/UglifyJS2/issues/203
|
// https://github.com/mishoo/UglifyJS2/issues/203
|
||||||
// if the code argument is a constant, then we can minify it.
|
// if the code argument is a constant, then we can minify it.
|
||||||
try {
|
try {
|
||||||
var code = "NaN(function(" + self.args.slice(0, -1).map(function(arg) {
|
var code = "n(function(" + self.args.slice(0, -1).map(function(arg) {
|
||||||
return arg.value;
|
return arg.value;
|
||||||
}).join(",") + "){" + self.args[self.args.length - 1].value + "})";
|
}).join(",") + "){" + self.args[self.args.length - 1].value + "})";
|
||||||
var ast = parse(code);
|
var ast = parse(code);
|
||||||
@@ -3124,7 +3174,9 @@ merge(Compressor.prototype, {
|
|||||||
var comp = new Compressor(compressor.options);
|
var comp = new Compressor(compressor.options);
|
||||||
ast = ast.transform(comp);
|
ast = ast.transform(comp);
|
||||||
ast.figure_out_scope(mangle);
|
ast.figure_out_scope(mangle);
|
||||||
ast.mangle_names();
|
base54.reset();
|
||||||
|
ast.compute_char_frequency(mangle);
|
||||||
|
ast.mangle_names(mangle);
|
||||||
var fun;
|
var fun;
|
||||||
ast.walk(new TreeWalker(function(node) {
|
ast.walk(new TreeWalker(function(node) {
|
||||||
if (fun) return true;
|
if (fun) return true;
|
||||||
@@ -3133,18 +3185,18 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
var args = fun.argnames.map(function(arg, i) {
|
|
||||||
return make_node(AST_String, self.args[i], {
|
|
||||||
value: arg.print_to_string()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
var code = OutputStream();
|
var code = OutputStream();
|
||||||
AST_BlockStatement.prototype._codegen.call(fun, fun, code);
|
AST_BlockStatement.prototype._codegen.call(fun, fun, code);
|
||||||
code = code.toString().replace(/^\{|\}$/g, "");
|
self.args = [
|
||||||
args.push(make_node(AST_String, self.args[self.args.length - 1], {
|
make_node(AST_String, self, {
|
||||||
value: code
|
value: fun.argnames.map(function(arg) {
|
||||||
}));
|
return arg.print_to_string();
|
||||||
self.args = args;
|
}).join(",")
|
||||||
|
}),
|
||||||
|
make_node(AST_String, self.args[self.args.length - 1], {
|
||||||
|
value: code.get().replace(/^\{|\}$/g, "")
|
||||||
|
})
|
||||||
|
];
|
||||||
return self;
|
return self;
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
if (ex instanceof JS_Parse_Error) {
|
if (ex instanceof JS_Parse_Error) {
|
||||||
@@ -3156,79 +3208,58 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (exp instanceof AST_Function) {
|
var stat = fn instanceof AST_Function && fn.body[0];
|
||||||
var stat = exp.body[0];
|
if (compressor.option("inline") && stat instanceof AST_Return) {
|
||||||
if (compressor.option("inline") && stat instanceof AST_Return) {
|
var value = stat.value;
|
||||||
var value = stat && stat.value;
|
if (!value || value.is_constant_expression()) {
|
||||||
if (!value || value.is_constant_expression()) {
|
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
||||||
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
return make_sequence(self, args).optimize(compressor);
|
||||||
return make_sequence(self, args).transform(compressor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (exp instanceof AST_Function) {
|
||||||
if (compressor.option("inline")
|
if (compressor.option("inline")
|
||||||
&& !exp.name
|
&& !exp.name
|
||||||
&& exp.body.length == 1
|
|
||||||
&& !exp.uses_arguments
|
&& !exp.uses_arguments
|
||||||
&& !exp.uses_eval
|
&& !exp.uses_eval
|
||||||
|
&& exp.body.length == 1
|
||||||
|
&& all(exp.argnames, function(arg) {
|
||||||
|
return arg.__unused;
|
||||||
|
})
|
||||||
&& !self.has_pure_annotation(compressor)) {
|
&& !self.has_pure_annotation(compressor)) {
|
||||||
var value;
|
var value;
|
||||||
if (stat instanceof AST_Return) {
|
if (stat instanceof AST_Return) {
|
||||||
value = stat.value.clone(true);
|
value = stat.value;
|
||||||
} else if (stat instanceof AST_SimpleStatement) {
|
} else if (stat instanceof AST_SimpleStatement) {
|
||||||
value = make_node(AST_UnaryPrefix, stat, {
|
value = make_node(AST_UnaryPrefix, stat, {
|
||||||
operator: "void",
|
operator: "void",
|
||||||
expression: stat.body.clone(true)
|
expression: stat.body
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (value) {
|
if (value) {
|
||||||
var fn = exp.clone();
|
var tw = new TreeWalker(function(node) {
|
||||||
fn.argnames = [];
|
if (!value) return true;
|
||||||
fn.body = [];
|
if (node instanceof AST_SymbolRef) {
|
||||||
if (exp.argnames.length > 0) {
|
var ref = node.scope.find_variable(node);
|
||||||
fn.body.push(make_node(AST_Var, self, {
|
if (ref && ref.scope.parent_scope === fn.parent_scope) {
|
||||||
definitions: exp.argnames.map(function(sym, i) {
|
value = null;
|
||||||
return make_node(AST_VarDef, sym, {
|
|
||||||
name: sym,
|
|
||||||
value: self.args[i] || make_node(AST_Undefined, self)
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
if (self.args.length > exp.argnames.length) {
|
|
||||||
fn.body.push(make_node(AST_SimpleStatement, self, {
|
|
||||||
body: make_sequence(self, self.args.slice(exp.argnames.length))
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
fn.body.push(make_node(AST_Return, self, {
|
|
||||||
value: value
|
|
||||||
}));
|
|
||||||
var body = fn.transform(compressor).body;
|
|
||||||
if (body.length == 0) return make_node(AST_Undefined, self);
|
|
||||||
if (body.length == 1 && body[0] instanceof AST_Return) {
|
|
||||||
value = body[0].value;
|
|
||||||
if (!value) return make_node(AST_Undefined, self);
|
|
||||||
value.walk(new TreeWalker(function(node) {
|
|
||||||
if (value === self) return true;
|
|
||||||
if (node instanceof AST_SymbolRef && matches(node.scope.find_variable(node))
|
|
||||||
|| node instanceof AST_This && matches(node)) {
|
|
||||||
value = self;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function matches(ref) {
|
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
|
||||||
return ref && ref.scope.parent_scope === fn.parent_scope;
|
value = null;
|
||||||
}
|
return true;
|
||||||
}));
|
}
|
||||||
if (value !== self) value = best_of(compressor, value, self);
|
});
|
||||||
} else {
|
value.walk(tw);
|
||||||
value = self;
|
}
|
||||||
}
|
if (value) {
|
||||||
if (value !== self) return value;
|
var args = self.args.concat(value);
|
||||||
|
return make_sequence(self, args).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("side_effects") && all(exp.body, is_empty)) {
|
if (compressor.option("side_effects") && all(exp.body, is_empty)) {
|
||||||
var args = self.args.concat(make_node(AST_Undefined, self));
|
var args = self.args.concat(make_node(AST_Undefined, self));
|
||||||
return make_sequence(self, args).transform(compressor);
|
return make_sequence(self, args).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("drop_console")) {
|
if (compressor.option("drop_console")) {
|
||||||
@@ -3357,9 +3388,12 @@ merge(Compressor.prototype, {
|
|||||||
field = "left";
|
field = "left";
|
||||||
}
|
}
|
||||||
} else if (cdr instanceof AST_Call
|
} else if (cdr instanceof AST_Call
|
||||||
|
&& !(left instanceof AST_PropAccess && cdr.expression.equivalent_to(left))
|
||||||
|| cdr instanceof AST_PropAccess
|
|| cdr instanceof AST_PropAccess
|
||||||
|| cdr instanceof AST_Unary && !unary_side_effects(cdr.operator)) {
|
|| cdr instanceof AST_Unary && !unary_side_effects(cdr.operator)) {
|
||||||
field = "expression";
|
field = "expression";
|
||||||
|
} else if (cdr instanceof AST_Conditional) {
|
||||||
|
field = "condition";
|
||||||
} else {
|
} else {
|
||||||
expressions[++i] = expressions[j];
|
expressions[++i] = expressions[j];
|
||||||
break;
|
break;
|
||||||
@@ -3890,7 +3924,7 @@ merge(Compressor.prototype, {
|
|||||||
var d = self.definition();
|
var d = self.definition();
|
||||||
var fixed = self.fixed_value();
|
var fixed = self.fixed_value();
|
||||||
if (fixed instanceof AST_Defun) {
|
if (fixed instanceof AST_Defun) {
|
||||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed).clone(true);
|
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
||||||
}
|
}
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& fixed instanceof AST_Function
|
&& fixed instanceof AST_Function
|
||||||
@@ -3898,7 +3932,7 @@ merge(Compressor.prototype, {
|
|||||||
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
||||||
&& !d.scope.uses_eval
|
&& !d.scope.uses_eval
|
||||||
&& compressor.find_parent(AST_Scope) === fixed.parent_scope) {
|
&& compressor.find_parent(AST_Scope) === fixed.parent_scope) {
|
||||||
return fixed;
|
return fixed.clone(true);
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate") && fixed) {
|
if (compressor.option("evaluate") && fixed) {
|
||||||
if (d.should_replace === undefined) {
|
if (d.should_replace === undefined) {
|
||||||
@@ -3921,7 +3955,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
var name_length = d.name.length;
|
var name_length = d.name.length;
|
||||||
var overhead = 0;
|
var overhead = 0;
|
||||||
if (compressor.option("unused") && (!d.global || compressor.toplevel(d))) {
|
if (compressor.option("unused") && !compressor.exposed(d)) {
|
||||||
overhead = (name_length + 2 + value_length) / d.references.length;
|
overhead = (name_length + 2 + value_length) / d.references.length;
|
||||||
}
|
}
|
||||||
d.should_replace = value_length <= name_length + overhead ? fn : false;
|
d.should_replace = value_length <= name_length + overhead ? fn : false;
|
||||||
|
|||||||
@@ -27,6 +27,23 @@ function set_shorthand(name, options, keys) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function init_cache(cache) {
|
||||||
|
if (!cache) return;
|
||||||
|
if (!("cname" in cache)) cache.cname = -1;
|
||||||
|
if (!("props" in cache)) {
|
||||||
|
cache.props = new Dictionary();
|
||||||
|
} else if (!(cache.props instanceof Dictionary)) {
|
||||||
|
cache.props = Dictionary.fromObject(cache.props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function to_json(cache) {
|
||||||
|
return {
|
||||||
|
cname: cache.cname,
|
||||||
|
props: cache.props.toObject()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function minify(files, options) {
|
function minify(files, options) {
|
||||||
var warn_function = AST_Node.warn_function;
|
var warn_function = AST_Node.warn_function;
|
||||||
try {
|
try {
|
||||||
@@ -35,6 +52,7 @@ function minify(files, options) {
|
|||||||
ie8: false,
|
ie8: false,
|
||||||
keep_fnames: false,
|
keep_fnames: false,
|
||||||
mangle: {},
|
mangle: {},
|
||||||
|
nameCache: null,
|
||||||
output: {},
|
output: {},
|
||||||
parse: {},
|
parse: {},
|
||||||
sourceMap: false,
|
sourceMap: false,
|
||||||
@@ -52,7 +70,7 @@ function minify(files, options) {
|
|||||||
set_shorthand("warnings", options, [ "compress" ]);
|
set_shorthand("warnings", options, [ "compress" ]);
|
||||||
if (options.mangle) {
|
if (options.mangle) {
|
||||||
options.mangle = defaults(options.mangle, {
|
options.mangle = defaults(options.mangle, {
|
||||||
cache: null,
|
cache: options.nameCache && (options.nameCache.vars || {}),
|
||||||
eval: false,
|
eval: false,
|
||||||
ie8: false,
|
ie8: false,
|
||||||
keep_fnames: false,
|
keep_fnames: false,
|
||||||
@@ -60,6 +78,16 @@ function minify(files, options) {
|
|||||||
reserved: [],
|
reserved: [],
|
||||||
toplevel: false,
|
toplevel: false,
|
||||||
}, true);
|
}, true);
|
||||||
|
if (options.nameCache && options.mangle.properties) {
|
||||||
|
if (typeof options.mangle.properties != "object") {
|
||||||
|
options.mangle.properties = {};
|
||||||
|
}
|
||||||
|
if (!("cache" in options.mangle.properties)) {
|
||||||
|
options.mangle.properties.cache = options.nameCache.props || {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
init_cache(options.mangle.cache);
|
||||||
|
init_cache(options.mangle.properties.cache);
|
||||||
}
|
}
|
||||||
if (options.sourceMap) {
|
if (options.sourceMap) {
|
||||||
options.sourceMap = defaults(options.sourceMap, {
|
options.sourceMap = defaults(options.sourceMap, {
|
||||||
@@ -153,6 +181,12 @@ function minify(files, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (options.nameCache && options.mangle) {
|
||||||
|
if (options.mangle.cache) options.nameCache.vars = to_json(options.mangle.cache);
|
||||||
|
if (options.mangle.properties && options.mangle.properties.cache) {
|
||||||
|
options.nameCache.props = to_json(options.mangle.properties.cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (timings) {
|
if (timings) {
|
||||||
timings.end = Date.now();
|
timings.end = Date.now();
|
||||||
result.timings = {
|
result.timings = {
|
||||||
|
|||||||
@@ -501,6 +501,7 @@ function OutputStream(options) {
|
|||||||
use_asm = prev_use_asm;
|
use_asm = prev_use_asm;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print_to_string", function(options){
|
AST_Node.DEFMETHOD("print_to_string", function(options){
|
||||||
var s = OutputStream(options);
|
var s = OutputStream(options);
|
||||||
|
|||||||
@@ -1010,8 +1010,12 @@ function parse($TEXT, options) {
|
|||||||
? (next(), var_(true))
|
? (next(), var_(true))
|
||||||
: expression(true, true);
|
: expression(true, true);
|
||||||
if (is("operator", "in")) {
|
if (is("operator", "in")) {
|
||||||
if (init instanceof AST_Var && init.definitions.length > 1)
|
if (init instanceof AST_Var) {
|
||||||
croak("Only one variable declaration allowed in for..in loop");
|
if (init.definitions.length > 1)
|
||||||
|
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||||
|
} else if (!is_assignable(init)) {
|
||||||
|
croak("Invalid left-hand side in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||||
|
}
|
||||||
next();
|
next();
|
||||||
return for_in(init);
|
return for_in(init);
|
||||||
}
|
}
|
||||||
|
|||||||
138
lib/scope.js
138
lib/scope.js
@@ -79,7 +79,7 @@ SymbolDef.prototype = {
|
|||||||
if (options.ie8 && sym instanceof AST_SymbolLambda)
|
if (options.ie8 && sym instanceof AST_SymbolLambda)
|
||||||
s = s.parent_scope;
|
s = s.parent_scope;
|
||||||
var def;
|
var def;
|
||||||
if (this.defun && (def = this.defun.variables.get(this.name))) {
|
if (def = this.redefined()) {
|
||||||
this.mangled_name = def.mangled_name || def.name;
|
this.mangled_name = def.mangled_name || def.name;
|
||||||
} else
|
} else
|
||||||
this.mangled_name = s.next_mangled(options, this);
|
this.mangled_name = s.next_mangled(options, this);
|
||||||
@@ -87,6 +87,9 @@ SymbolDef.prototype = {
|
|||||||
cache.set(this.name, this.mangled_name);
|
cache.set(this.name, this.mangled_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
redefined: function() {
|
||||||
|
return this.defun && this.defun.variables.get(this.name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -206,6 +209,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
node.reference(options);
|
node.reference(options);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// ensure mangling works if catch reuses a scope variable
|
||||||
|
var def;
|
||||||
|
if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) {
|
||||||
|
var s = node.scope;
|
||||||
|
while (s) {
|
||||||
|
push_uniq(s.enclosed, def);
|
||||||
|
if (s === def.scope) break;
|
||||||
|
s = s.parent_scope;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
|
||||||
@@ -348,7 +361,8 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
||||||
return this.definition().unmangleable(options);
|
var def = this.definition();
|
||||||
|
return !def || def.unmangleable(options);
|
||||||
});
|
});
|
||||||
|
|
||||||
// labels are always mangleable
|
// labels are always mangleable
|
||||||
@@ -447,103 +461,69 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
||||||
options = this._default_mangler_options(options);
|
options = this._default_mangler_options(options);
|
||||||
var tw = new TreeWalker(function(node){
|
try {
|
||||||
if (node instanceof AST_Constant)
|
AST_Node.prototype.print = function(stream, force_parens) {
|
||||||
base54.consider(node.print_to_string());
|
this._print(stream, force_parens);
|
||||||
else if (node instanceof AST_Return)
|
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
|
||||||
base54.consider("return");
|
base54.consider(this.name, -1);
|
||||||
else if (node instanceof AST_Throw)
|
} else if (options.properties) {
|
||||||
base54.consider("throw");
|
if (this instanceof AST_Dot) {
|
||||||
else if (node instanceof AST_Continue)
|
base54.consider(this.property, -1);
|
||||||
base54.consider("continue");
|
} else if (this instanceof AST_Sub) {
|
||||||
else if (node instanceof AST_Break)
|
skip_string(this.property);
|
||||||
base54.consider("break");
|
}
|
||||||
else if (node instanceof AST_Debugger)
|
}
|
||||||
base54.consider("debugger");
|
};
|
||||||
else if (node instanceof AST_Directive)
|
base54.consider(this.print_to_string(), 1);
|
||||||
base54.consider(node.value);
|
} finally {
|
||||||
else if (node instanceof AST_While)
|
AST_Node.prototype.print = AST_Node.prototype._print;
|
||||||
base54.consider("while");
|
}
|
||||||
else if (node instanceof AST_Do)
|
|
||||||
base54.consider("do while");
|
|
||||||
else if (node instanceof AST_If) {
|
|
||||||
base54.consider("if");
|
|
||||||
if (node.alternative) base54.consider("else");
|
|
||||||
}
|
|
||||||
else if (node instanceof AST_Var)
|
|
||||||
base54.consider("var");
|
|
||||||
else if (node instanceof AST_Lambda)
|
|
||||||
base54.consider("function");
|
|
||||||
else if (node instanceof AST_For)
|
|
||||||
base54.consider("for");
|
|
||||||
else if (node instanceof AST_ForIn)
|
|
||||||
base54.consider("for in");
|
|
||||||
else if (node instanceof AST_Switch)
|
|
||||||
base54.consider("switch");
|
|
||||||
else if (node instanceof AST_Case)
|
|
||||||
base54.consider("case");
|
|
||||||
else if (node instanceof AST_Default)
|
|
||||||
base54.consider("default");
|
|
||||||
else if (node instanceof AST_With)
|
|
||||||
base54.consider("with");
|
|
||||||
else if (node instanceof AST_ObjectSetter)
|
|
||||||
base54.consider("set" + node.key);
|
|
||||||
else if (node instanceof AST_ObjectGetter)
|
|
||||||
base54.consider("get" + node.key);
|
|
||||||
else if (node instanceof AST_ObjectKeyVal)
|
|
||||||
base54.consider(node.key);
|
|
||||||
else if (node instanceof AST_New)
|
|
||||||
base54.consider("new");
|
|
||||||
else if (node instanceof AST_This)
|
|
||||||
base54.consider("this");
|
|
||||||
else if (node instanceof AST_Try)
|
|
||||||
base54.consider("try");
|
|
||||||
else if (node instanceof AST_Catch)
|
|
||||||
base54.consider("catch");
|
|
||||||
else if (node instanceof AST_Finally)
|
|
||||||
base54.consider("finally");
|
|
||||||
else if (node instanceof AST_Symbol && node.unmangleable(options))
|
|
||||||
base54.consider(node.name);
|
|
||||||
else if (node instanceof AST_Unary || node instanceof AST_Binary)
|
|
||||||
base54.consider(node.operator);
|
|
||||||
else if (node instanceof AST_Dot)
|
|
||||||
base54.consider(node.property);
|
|
||||||
});
|
|
||||||
this.walk(tw);
|
|
||||||
base54.sort();
|
base54.sort();
|
||||||
|
|
||||||
|
function skip_string(node) {
|
||||||
|
if (node instanceof AST_String) {
|
||||||
|
base54.consider(node.value, -1);
|
||||||
|
} else if (node instanceof AST_Conditional) {
|
||||||
|
skip_string(node.consequent);
|
||||||
|
skip_string(node.alternative);
|
||||||
|
} else if (node instanceof AST_Sequence) {
|
||||||
|
skip_string(node.expressions[node.expressions.length - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var base54 = (function() {
|
var base54 = (function() {
|
||||||
var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
|
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
|
||||||
|
var digits = "0123456789".split("");
|
||||||
var chars, frequency;
|
var chars, frequency;
|
||||||
function reset() {
|
function reset() {
|
||||||
frequency = Object.create(null);
|
frequency = Object.create(null);
|
||||||
chars = string.split("").map(function(ch){ return ch.charCodeAt(0) });
|
leading.forEach(function(ch) {
|
||||||
chars.forEach(function(ch){ frequency[ch] = 0 });
|
frequency[ch] = 0;
|
||||||
|
});
|
||||||
|
digits.forEach(function(ch) {
|
||||||
|
frequency[ch] = 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
base54.consider = function(str){
|
base54.consider = function(str, delta) {
|
||||||
for (var i = str.length; --i >= 0;) {
|
for (var i = str.length; --i >= 0;) {
|
||||||
var code = str.charCodeAt(i);
|
frequency[str[i]] += delta;
|
||||||
if (code in frequency) ++frequency[code];
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
function compare(a, b) {
|
||||||
|
return frequency[b] - frequency[a];
|
||||||
|
}
|
||||||
base54.sort = function() {
|
base54.sort = function() {
|
||||||
chars = mergeSort(chars, function(a, b){
|
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
|
||||||
if (is_digit(a) && !is_digit(b)) return 1;
|
|
||||||
if (is_digit(b) && !is_digit(a)) return -1;
|
|
||||||
return frequency[b] - frequency[a];
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
base54.reset = reset;
|
base54.reset = reset;
|
||||||
reset();
|
reset();
|
||||||
base54.get = function(){ return chars };
|
|
||||||
base54.freq = function(){ return frequency };
|
|
||||||
function base54(num) {
|
function base54(num) {
|
||||||
var ret = "", base = 54;
|
var ret = "", base = 54;
|
||||||
num++;
|
num++;
|
||||||
do {
|
do {
|
||||||
num--;
|
num--;
|
||||||
ret += String.fromCharCode(chars[num % base]);
|
ret += chars[num % base];
|
||||||
num = Math.floor(num / base);
|
num = Math.floor(num / base);
|
||||||
base = 64;
|
base = 64;
|
||||||
} while (num > 0);
|
} while (num > 0);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.0.17",
|
"version": "3.0.23",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1978,10 +1978,10 @@ chained_3: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function(a, b) {
|
console.log(function(a, b) {
|
||||||
var c = a, c = b;
|
var c = 1, c = b;
|
||||||
b++;
|
b++;
|
||||||
return c;
|
return c;
|
||||||
}(1, 2));
|
}(0, 2));
|
||||||
}
|
}
|
||||||
expect_stdout: "2"
|
expect_stdout: "2"
|
||||||
}
|
}
|
||||||
@@ -2186,3 +2186,73 @@ compound_assignment: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "4"
|
expect_stdout: "4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2187_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
!function(foo) {
|
||||||
|
foo();
|
||||||
|
var a = 2;
|
||||||
|
console.log(a);
|
||||||
|
}(function() {
|
||||||
|
console.log(a);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
!function(foo) {
|
||||||
|
foo();
|
||||||
|
var a = 2;
|
||||||
|
console.log(a);
|
||||||
|
}(function() {
|
||||||
|
console.log(a);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2187_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var b = 1;
|
||||||
|
console.log(function(a) {
|
||||||
|
return a && ++b;
|
||||||
|
}(b--));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var b = 1;
|
||||||
|
console.log(function(a) {
|
||||||
|
return b-- && ++b;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2187_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var b = 1;
|
||||||
|
console.log(function(a) {
|
||||||
|
return a && ++b;
|
||||||
|
}(b--));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var b = 1;
|
||||||
|
console.log(b-- && ++b);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1108,3 +1108,48 @@ var_catch_toplevel: {
|
|||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2105: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 3,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function(factory) {
|
||||||
|
factory();
|
||||||
|
}( function() {
|
||||||
|
return function(fn) {
|
||||||
|
fn()().prop();
|
||||||
|
}( function() {
|
||||||
|
function bar() {
|
||||||
|
var quux = function() {
|
||||||
|
console.log("PASS");
|
||||||
|
}, foo = function() {
|
||||||
|
console.log;
|
||||||
|
quux();
|
||||||
|
};
|
||||||
|
return { prop: foo };
|
||||||
|
}
|
||||||
|
return bar;
|
||||||
|
} );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
var quux = function() {
|
||||||
|
console.log("PASS");
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
prop: function() {
|
||||||
|
console.log;
|
||||||
|
quux();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})().prop();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ issue_203: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var m = {};
|
var m = {};
|
||||||
var fn = Function("a", "b", "b.exports=42");
|
var fn = Function("n,o", "o.exports=42");
|
||||||
fn(null, m, m.exports);
|
fn(null, m, m.exports);
|
||||||
console.log(m.exports);
|
console.log(m.exports);
|
||||||
}
|
}
|
||||||
@@ -414,3 +414,97 @@ inner_ref: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1 undefined"
|
expect_stdout: "1 undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2107: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = 0;
|
||||||
|
!function() {
|
||||||
|
c++;
|
||||||
|
}(c++ + new function() {
|
||||||
|
this.a = 0;
|
||||||
|
var a = (c = c + 1) + (c = 1 + c);
|
||||||
|
return c++ + a;
|
||||||
|
}());
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = 0;
|
||||||
|
c++, new function() {
|
||||||
|
this.a = 0, c = 1 + (c += 1), c++;
|
||||||
|
}(), c++, console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "5"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2114_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
if_return: true,
|
||||||
|
inline: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = 0;
|
||||||
|
!function(a) {
|
||||||
|
a = 0;
|
||||||
|
}([ {
|
||||||
|
0: c = c + 1,
|
||||||
|
length: c = 1 + c
|
||||||
|
}, typeof void function a() {
|
||||||
|
var b = function f1(a) {
|
||||||
|
}(b && (b.b += (c = c + 1, 0)));
|
||||||
|
}() ]);
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = 0;
|
||||||
|
c = 1 + (c += 1), function() {
|
||||||
|
var b = void (b && (b.b += (c += 1, 0)));
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2114_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
if_return: true,
|
||||||
|
inline: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
passes: 2,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = 0;
|
||||||
|
!function(a) {
|
||||||
|
a = 0;
|
||||||
|
}([ {
|
||||||
|
0: c = c + 1,
|
||||||
|
length: c = 1 + c
|
||||||
|
}, typeof void function a() {
|
||||||
|
var b = function f1(a) {
|
||||||
|
}(b && (b.b += (c = c + 1, 0)));
|
||||||
|
}() ]);
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = 0;
|
||||||
|
c = 1 + (c += 1), function() {
|
||||||
|
var b = void (b && (b.b += (c += 1, 0)));
|
||||||
|
}();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|||||||
@@ -174,3 +174,24 @@ issue_1986: {
|
|||||||
console.log(42);
|
console.log(42);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2167: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
|
global_defs: {
|
||||||
|
"@isDevMode": "function(){}",
|
||||||
|
},
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
if (isDevMode()) {
|
||||||
|
greetOverlord();
|
||||||
|
}
|
||||||
|
doWork();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
doWork();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ issue_1321_no_debug: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.b = 1;
|
x.o = 1;
|
||||||
x["a"] = 2 * x.b;
|
x["a"] = 2 * x.o;
|
||||||
console.log(x.b, x["a"]);
|
console.log(x.o, x["a"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -30,9 +30,9 @@ issue_1321_debug: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.a = 1;
|
x.o = 1;
|
||||||
x["_$foo$_"] = 2 * x.a;
|
x["_$foo$_"] = 2 * x.o;
|
||||||
console.log(x.a, x["_$foo$_"]);
|
console.log(x.o, x["_$foo$_"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -49,9 +49,9 @@ issue_1321_with_quoted: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x = {};
|
var x = {};
|
||||||
x.a = 1;
|
x.o = 1;
|
||||||
x["b"] = 2 * x.a;
|
x["x"] = 2 * x.o;
|
||||||
console.log(x.a, x["b"]);
|
console.log(x.o, x["x"]);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ numeric_literal: {
|
|||||||
' 42: 2,',
|
' 42: 2,',
|
||||||
' "42": 3,',
|
' "42": 3,',
|
||||||
' 37: 4,',
|
' 37: 4,',
|
||||||
' a: 5,',
|
' o: 5,',
|
||||||
' 1e42: 6,',
|
' 1e42: 6,',
|
||||||
' b: 7,',
|
' b: 7,',
|
||||||
' "1e+42": 8',
|
' "1e+42": 8',
|
||||||
@@ -92,7 +92,7 @@ numeric_literal: {
|
|||||||
'',
|
'',
|
||||||
'console.log(obj[42], obj["42"]);',
|
'console.log(obj[42], obj["42"]);',
|
||||||
'',
|
'',
|
||||||
'console.log(obj[37], obj["a"], obj[37], obj["37"]);',
|
'console.log(obj[37], obj["o"], obj[37], obj["37"]);',
|
||||||
'',
|
'',
|
||||||
'console.log(obj[1e42], obj["b"], obj["1e+42"]);',
|
'console.log(obj[1e42], obj["b"], obj["1e+42"]);',
|
||||||
]
|
]
|
||||||
@@ -173,32 +173,32 @@ identifier: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var obj = {
|
var obj = {
|
||||||
a: 1,
|
e: 1,
|
||||||
b: 2,
|
t: 2,
|
||||||
c: 3,
|
n: 3,
|
||||||
d: 4,
|
a: 4,
|
||||||
e: 5,
|
i: 5,
|
||||||
f: 6,
|
o: 6,
|
||||||
g: 7,
|
r: 7,
|
||||||
h: 8,
|
l: 8,
|
||||||
i: 9,
|
s: 9,
|
||||||
j: 10,
|
c: 10,
|
||||||
k: 11,
|
f: 11,
|
||||||
l: 12,
|
u: 12,
|
||||||
m: 13,
|
d: 13,
|
||||||
n: 14,
|
h: 14,
|
||||||
o: 15,
|
p: 15,
|
||||||
p: 16,
|
b: 16,
|
||||||
q: 17,
|
v: 17,
|
||||||
r: 18,
|
w: 18,
|
||||||
s: 19,
|
y: 19,
|
||||||
t: 20,
|
g: 20,
|
||||||
u: 21,
|
m: 21,
|
||||||
v: 22,
|
k: 22,
|
||||||
w: 23,
|
x: 23,
|
||||||
x: 24,
|
j: 24,
|
||||||
y: 25,
|
z: 25,
|
||||||
z: 26,
|
q: 26,
|
||||||
A: 27,
|
A: 27,
|
||||||
B: 28,
|
B: 28,
|
||||||
C: 29,
|
C: 29,
|
||||||
@@ -229,11 +229,11 @@ identifier: {
|
|||||||
Z: 54,
|
Z: 54,
|
||||||
$: 55,
|
$: 55,
|
||||||
_: 56,
|
_: 56,
|
||||||
aa: 57,
|
ee: 57,
|
||||||
ba: 58,
|
te: 58,
|
||||||
ca: 59,
|
ne: 59,
|
||||||
da: 60,
|
ae: 60,
|
||||||
ea: 61,
|
ie: 61,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -419,7 +419,7 @@ wrap_iife_in_return_call: {
|
|||||||
expect_exact: '(void console.log("test"))();'
|
expect_exact: '(void console.log("test"))();'
|
||||||
}
|
}
|
||||||
|
|
||||||
pure_annotation: {
|
pure_annotation_1: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -432,6 +432,20 @@ pure_annotation: {
|
|||||||
expect_exact: ""
|
expect_exact: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pure_annotation_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
/*@__PURE__*/(function(n) {
|
||||||
|
console.log("hello", n);
|
||||||
|
}(42));
|
||||||
|
}
|
||||||
|
expect_exact: ""
|
||||||
|
}
|
||||||
|
|
||||||
drop_fargs: {
|
drop_fargs: {
|
||||||
options = {
|
options = {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
@@ -449,9 +463,7 @@ drop_fargs: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = 1;
|
var a = 1;
|
||||||
!function() {
|
++a && a.var, a++;
|
||||||
a++;
|
|
||||||
}(++a && a.var);
|
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
expect_stdout: "3"
|
expect_stdout: "3"
|
||||||
@@ -474,9 +486,7 @@ keep_fargs: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = 1;
|
var a = 1;
|
||||||
!function(a_1) {
|
++a && a.var, a++;
|
||||||
a++;
|
|
||||||
}(++a && a.var);
|
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
expect_stdout: "3"
|
expect_stdout: "3"
|
||||||
|
|||||||
@@ -1,37 +1,41 @@
|
|||||||
dont_reuse_prop: {
|
dont_reuse_prop: {
|
||||||
mangle_props = {
|
mangle_props = {
|
||||||
regex: /asd/
|
regex: /asd/
|
||||||
};
|
}
|
||||||
|
|
||||||
input: {
|
input: {
|
||||||
|
"aaaaaaaaaabbbbb";
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.a = 123;
|
obj.a = 123;
|
||||||
obj.asd = 256;
|
obj.asd = 256;
|
||||||
console.log(obj.a);
|
console.log(obj.a);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
"aaaaaaaaaabbbbb";
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.a = 123;
|
obj.a = 123;
|
||||||
obj.b = 256;
|
obj.b = 256;
|
||||||
console.log(obj.a);
|
console.log(obj.a);
|
||||||
}
|
}
|
||||||
|
expect_stdout: "123"
|
||||||
}
|
}
|
||||||
|
|
||||||
unmangleable_props_should_always_be_reserved: {
|
unmangleable_props_should_always_be_reserved: {
|
||||||
mangle_props = {
|
mangle_props = {
|
||||||
regex: /asd/
|
regex: /asd/
|
||||||
};
|
}
|
||||||
|
|
||||||
input: {
|
input: {
|
||||||
|
"aaaaaaaaaabbbbb";
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.asd = 256;
|
obj.asd = 256;
|
||||||
obj.a = 123;
|
obj.a = 123;
|
||||||
console.log(obj.a);
|
console.log(obj.a);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
"aaaaaaaaaabbbbb";
|
||||||
var obj = {};
|
var obj = {};
|
||||||
obj.b = 256;
|
obj.b = 256;
|
||||||
obj.a = 123;
|
obj.a = 123;
|
||||||
console.log(obj.a);
|
console.log(obj.a);
|
||||||
}
|
}
|
||||||
}
|
expect_stdout: "123"
|
||||||
|
}
|
||||||
|
|||||||
@@ -135,11 +135,11 @@ mangle_properties: {
|
|||||||
a['run']({color: "blue", foo: "baz"});
|
a['run']({color: "blue", foo: "baz"});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
a["a"] = "bar";
|
a["o"] = "bar";
|
||||||
a.b = "red";
|
a.a = "red";
|
||||||
x = {c: 10};
|
x = {r: 10};
|
||||||
a.d(x.c, a.a);
|
a.b(x.r, a.o);
|
||||||
a['d']({b: "blue", a: "baz"});
|
a['b']({a: "blue", o: "baz"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,16 +177,16 @@ mangle_unquoted_properties: {
|
|||||||
function f1() {
|
function f1() {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
a.color = "red";
|
a.color = "red";
|
||||||
a.b = 2;
|
a.o = 2;
|
||||||
x = {"bar": 10, c: 7};
|
x = {"bar": 10, f: 7};
|
||||||
a.c = 9;
|
a.f = 9;
|
||||||
}
|
}
|
||||||
function f2() {
|
function f2() {
|
||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
a['color'] = "red";
|
a['color'] = "red";
|
||||||
x = {bar: 10, c: 7};
|
x = {bar: 10, f: 7};
|
||||||
a.c = 9;
|
a.f = 9;
|
||||||
a.b = 3;
|
a.o = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,3 +178,210 @@ impure_getter_2: {
|
|||||||
}
|
}
|
||||||
expect: {}
|
expect: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2110_1: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
function f() {}
|
||||||
|
function g() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
f.g = g;
|
||||||
|
return f.g();
|
||||||
|
}
|
||||||
|
console.log(typeof f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
function f() {}
|
||||||
|
return f.g = function() {
|
||||||
|
return this;
|
||||||
|
}, f.g();
|
||||||
|
}
|
||||||
|
console.log(typeof f());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2110_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
function f() {}
|
||||||
|
function g() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
f.g = g;
|
||||||
|
return f.g();
|
||||||
|
}
|
||||||
|
console.log(typeof f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
function f() {}
|
||||||
|
f.g = function() {
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
return f.g();
|
||||||
|
}
|
||||||
|
console.log(typeof f());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_immutable_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
1..foo += "";
|
||||||
|
if (1..foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_immutable_2: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_immutable_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: 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 += "";
|
||||||
|
if (1..foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
set_immutable_4: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("FAIL");
|
||||||
|
else console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
var a = 1;
|
||||||
|
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
set_mutable_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function a() {
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("PASS");
|
||||||
|
else console.log("FAIL");
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function a() {
|
||||||
|
if (a.foo += "") console.log("PASS");
|
||||||
|
else console.log("FAIL");
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_mutable_2: {
|
||||||
|
options = {
|
||||||
|
cascade: true,
|
||||||
|
conditionals: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function a() {
|
||||||
|
a.foo += "";
|
||||||
|
if (a.foo) console.log("PASS");
|
||||||
|
else console.log("FAIL");
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function a() {
|
||||||
|
(a.foo += "") ? console.log("PASS") : console.log("FAIL");
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -2575,3 +2575,28 @@ accessor: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1 1"
|
expect_stdout: "1 1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for_in_prop: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = {
|
||||||
|
foo: function() {
|
||||||
|
for (this.b in [1, 2]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
a.foo();
|
||||||
|
console.log(a.b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = {
|
||||||
|
foo: function() {
|
||||||
|
for (this.b in [1, 2]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
a.foo();
|
||||||
|
console.log(a.b);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -255,3 +255,73 @@ issue_1586_2: {
|
|||||||
}
|
}
|
||||||
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
|
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2120_1: {
|
||||||
|
mangle = {
|
||||||
|
ie8: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"aaaaaaaa";
|
||||||
|
var a = 1, b = "FAIL";
|
||||||
|
try {
|
||||||
|
throw 1;
|
||||||
|
} catch (c) {
|
||||||
|
try {
|
||||||
|
throw 0;
|
||||||
|
} catch (a) {
|
||||||
|
if (c) b = "PASS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"aaaaaaaa";
|
||||||
|
var a = 1, b = "FAIL";
|
||||||
|
try {
|
||||||
|
throw 1;
|
||||||
|
} catch (t) {
|
||||||
|
try {
|
||||||
|
throw 0;
|
||||||
|
} catch (a) {
|
||||||
|
if (t) b = "PASS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2120_2: {
|
||||||
|
mangle = {
|
||||||
|
ie8: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"aaaaaaaa";
|
||||||
|
var a = 1, b = "FAIL";
|
||||||
|
try {
|
||||||
|
throw 1;
|
||||||
|
} catch (c) {
|
||||||
|
try {
|
||||||
|
throw 0;
|
||||||
|
} catch (a) {
|
||||||
|
if (c) b = "PASS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"aaaaaaaa";
|
||||||
|
var a = 1, b = "FAIL";
|
||||||
|
try {
|
||||||
|
throw 1;
|
||||||
|
} catch (c) {
|
||||||
|
try {
|
||||||
|
throw 0;
|
||||||
|
} catch (a) {
|
||||||
|
if (c) b = "PASS";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
4
test/input/invalid/for-in_1.js
Normal file
4
test/input/invalid/for-in_1.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
var a, b = [1, 2];
|
||||||
|
for (1, 2, a in b) {
|
||||||
|
console.log(a, b[a]);
|
||||||
|
}
|
||||||
4
test/input/invalid/for-in_2.js
Normal file
4
test/input/invalid/for-in_2.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
var c = [1, 2];
|
||||||
|
for (var a, b in c) {
|
||||||
|
console.log(a, c[a]);
|
||||||
|
}
|
||||||
@@ -518,6 +518,36 @@ describe("bin/uglifyjs", function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Should throw syntax error (for-in init)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/for-in_1.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/for-in_1.js:2,5",
|
||||||
|
"for (1, 2, a in b) {",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Invalid left-hand side in for..in loop"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should throw syntax error (for-in var)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/for-in_2.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/for-in_2.js:2,5",
|
||||||
|
"for (var a, b in c) {",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Only one variable declaration allowed in for..in loop"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it("Should handle literal string as source map input", function(done) {
|
it("Should handle literal string as source map input", function(done) {
|
||||||
var command = [
|
var command = [
|
||||||
uglifyjscmd,
|
uglifyjscmd,
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ describe("bin/uglifyjs with input file globs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("bin/uglifyjs with multiple input file globs.", function(done) {
|
it("bin/uglifyjs with multiple input file globs.", function(done) {
|
||||||
var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel';
|
var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel,passes=2';
|
||||||
|
|
||||||
exec(command, function(err, stdout) {
|
exec(command, function(err, stdout) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",2*11);\n');
|
assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",22);\n');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,29 +2,37 @@ var Uglify = require('../../');
|
|||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
|
|
||||||
describe("let", function() {
|
describe("let", function() {
|
||||||
it("Should not produce `let` as a variable name in mangle", function(done) {
|
it("Should not produce reserved keywords as variable name in mangle", function(done) {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
// Produce a lot of variables in a function and run it through mangle.
|
// Produce a lot of variables in a function and run it through mangle.
|
||||||
var s = '"use strict"; function foo() {';
|
var s = '"dddddeeeeelllllooooottttt"; function foo() {';
|
||||||
for (var i = 0; i < 21000; ++i) {
|
for (var i = 0; i < 18000; i++) {
|
||||||
s += "var v" + i + "=0;";
|
s += "var v" + i + "=0;";
|
||||||
}
|
}
|
||||||
s += '}';
|
s += '}';
|
||||||
var result = Uglify.minify(s, {compress: false});
|
var result = Uglify.minify(s, {compress: false});
|
||||||
|
|
||||||
// Verify that select keywords and reserved keywords not produced
|
// Verify that select keywords and reserved keywords not produced
|
||||||
assert.strictEqual(result.code.indexOf("var let="), -1);
|
[
|
||||||
assert.strictEqual(result.code.indexOf("var do="), -1);
|
"do",
|
||||||
assert.strictEqual(result.code.indexOf("var var="), -1);
|
"let",
|
||||||
|
"var",
|
||||||
|
].forEach(function(name) {
|
||||||
|
assert.strictEqual(result.code.indexOf("var " + name + "="), -1);
|
||||||
|
});
|
||||||
|
|
||||||
// Verify that the variable names that appeared immediately before
|
// Verify that the variable names that appeared immediately before
|
||||||
// and after the erroneously generated `let` variable name still exist
|
// and after the erroneously generated variable name still exist
|
||||||
// to show the test generated enough symbols.
|
// to show the test generated enough symbols.
|
||||||
assert(result.code.indexOf("var ket=") >= 0);
|
[
|
||||||
assert(result.code.indexOf("var met=") >= 0);
|
"to", "eo",
|
||||||
|
"eet", "fet",
|
||||||
|
"rar", "oar",
|
||||||
|
].forEach(function(name) {
|
||||||
|
assert.ok(result.code.indexOf("var " + name + "=") >= 0);
|
||||||
|
});
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
var Uglify = require('../../');
|
var Uglify = require('../../');
|
||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
var readFileSync = require("fs").readFileSync;
|
var readFileSync = require("fs").readFileSync;
|
||||||
|
var run_code = require("../sandbox").run_code;
|
||||||
|
|
||||||
function read(path) {
|
function read(path) {
|
||||||
return readFileSync(path, "utf8");
|
return readFileSync(path, "utf8");
|
||||||
@@ -20,6 +21,58 @@ describe("minify", function() {
|
|||||||
assert.strictEqual(result.code, "alert(2);");
|
assert.strictEqual(result.code, "alert(2);");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should work with mangle.cache", function() {
|
||||||
|
var cache = {};
|
||||||
|
var original = "";
|
||||||
|
var compressed = "";
|
||||||
|
[
|
||||||
|
"bar.es5",
|
||||||
|
"baz.es5",
|
||||||
|
"foo.es5",
|
||||||
|
"qux.js",
|
||||||
|
].forEach(function(file) {
|
||||||
|
var code = read("test/input/issue-1242/" + file);
|
||||||
|
var result = Uglify.minify(code, {
|
||||||
|
mangle: {
|
||||||
|
cache: cache,
|
||||||
|
toplevel: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
original += code;
|
||||||
|
compressed += result.code;
|
||||||
|
});
|
||||||
|
assert.strictEqual(JSON.stringify(cache).slice(0, 20), '{"cname":5,"props":{');
|
||||||
|
assert.strictEqual(compressed, 'function n(n){return 3*n}function r(n){return n/2}function c(o){l("Foo:",2*o)}var l=console.log.bind(console);var f=n(3),i=r(12);l("qux",f,i),c(11);');
|
||||||
|
assert.strictEqual(run_code(compressed), run_code(original));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should work with nameCache", function() {
|
||||||
|
var cache = {};
|
||||||
|
var original = "";
|
||||||
|
var compressed = "";
|
||||||
|
[
|
||||||
|
"bar.es5",
|
||||||
|
"baz.es5",
|
||||||
|
"foo.es5",
|
||||||
|
"qux.js",
|
||||||
|
].forEach(function(file) {
|
||||||
|
var code = read("test/input/issue-1242/" + file);
|
||||||
|
var result = Uglify.minify(code, {
|
||||||
|
mangle: {
|
||||||
|
toplevel: true
|
||||||
|
},
|
||||||
|
nameCache: cache
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
original += code;
|
||||||
|
compressed += result.code;
|
||||||
|
});
|
||||||
|
assert.strictEqual(JSON.stringify(cache).slice(0, 28), '{"vars":{"cname":5,"props":{');
|
||||||
|
assert.strictEqual(compressed, 'function n(n){return 3*n}function r(n){return n/2}function c(o){l("Foo:",2*o)}var l=console.log.bind(console);var f=n(3),i=r(12);l("qux",f,i),c(11);');
|
||||||
|
assert.strictEqual(run_code(compressed), run_code(original));
|
||||||
|
});
|
||||||
|
|
||||||
describe("keep_quoted_props", function() {
|
describe("keep_quoted_props", function() {
|
||||||
it("Should preserve quotes in object literals", function() {
|
it("Should preserve quotes in object literals", function() {
|
||||||
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||||
@@ -212,7 +265,7 @@ describe("minify", function() {
|
|||||||
});
|
});
|
||||||
var err = result.error;
|
var err = result.error;
|
||||||
assert.ok(err instanceof Error);
|
assert.ok(err instanceof Error);
|
||||||
assert.strictEqual(err.stack.split(/\n/)[0], "Error: Can't handle expression: debugger");
|
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token: keyword (debugger)");
|
||||||
});
|
});
|
||||||
it("should skip inherited properties", function() {
|
it("should skip inherited properties", function() {
|
||||||
var foo = Object.create({ skip: this });
|
var foo = Object.create({ skip: this });
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ function run_compress_tests() {
|
|||||||
log_start_file(file);
|
log_start_file(file);
|
||||||
function test_case(test) {
|
function test_case(test) {
|
||||||
log_test(test.name);
|
log_test(test.name);
|
||||||
U.base54.reset();
|
|
||||||
var output_options = test.beautify || {};
|
var output_options = test.beautify || {};
|
||||||
var expect;
|
var expect;
|
||||||
if (test.expect) {
|
if (test.expect) {
|
||||||
@@ -101,9 +100,6 @@ function run_compress_tests() {
|
|||||||
quote_style: 3,
|
quote_style: 3,
|
||||||
keep_quoted_props: true
|
keep_quoted_props: true
|
||||||
});
|
});
|
||||||
if (test.mangle_props) {
|
|
||||||
input = U.mangle_properties(input, test.mangle_props);
|
|
||||||
}
|
|
||||||
var options = U.defaults(test.options, {
|
var options = U.defaults(test.options, {
|
||||||
warnings: false
|
warnings: false
|
||||||
});
|
});
|
||||||
@@ -118,10 +114,16 @@ function run_compress_tests() {
|
|||||||
var cmp = new U.Compressor(options, true);
|
var cmp = new U.Compressor(options, true);
|
||||||
var output = cmp.compress(input);
|
var output = cmp.compress(input);
|
||||||
output.figure_out_scope(test.mangle);
|
output.figure_out_scope(test.mangle);
|
||||||
if (test.mangle) {
|
if (test.mangle || test.mangle_props) {
|
||||||
|
U.base54.reset();
|
||||||
output.compute_char_frequency(test.mangle);
|
output.compute_char_frequency(test.mangle);
|
||||||
|
}
|
||||||
|
if (test.mangle) {
|
||||||
output.mangle_names(test.mangle);
|
output.mangle_names(test.mangle);
|
||||||
}
|
}
|
||||||
|
if (test.mangle_props) {
|
||||||
|
output = U.mangle_properties(output, test.mangle_props);
|
||||||
|
}
|
||||||
output = make_code(output, output_options);
|
output = make_code(output, output_options);
|
||||||
if (expect != output) {
|
if (expect != output) {
|
||||||
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
|
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
|
||||||
|
|||||||
Reference in New Issue
Block a user