uglify-js
Advanced tools
Comparing version
@@ -200,5 +200,3 @@ "use strict"; | ||
if (timings) timings.properties = Date.now(); | ||
if (options.mangle && options.mangle.properties) { | ||
toplevel = mangle_properties(toplevel, options.mangle.properties); | ||
} | ||
if (options.mangle && options.mangle.properties) mangle_properties(toplevel, options.mangle.properties); | ||
if (timings) timings.output = Date.now(); | ||
@@ -205,0 +203,0 @@ var result = {}; |
@@ -1177,6 +1177,3 @@ /*********************************************************************** | ||
/* -----[ other expressions ]----- */ | ||
DEFPRINT(AST_Call, function(self, output) { | ||
self.expression.print(output); | ||
if (self instanceof AST_New && !need_constructor_parens(self, output)) | ||
return; | ||
function print_call_args(self, output) { | ||
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) { | ||
@@ -1191,2 +1188,6 @@ output.add_mapping(self.start); | ||
}); | ||
} | ||
DEFPRINT(AST_Call, function(self, output) { | ||
self.expression.print(output); | ||
print_call_args(self, output); | ||
}); | ||
@@ -1196,3 +1197,4 @@ DEFPRINT(AST_New, function(self, output) { | ||
output.space(); | ||
AST_Call.prototype._codegen(self, output); | ||
self.expression.print(output); | ||
if (need_constructor_parens(self, output)) print_call_args(self, output); | ||
}); | ||
@@ -1199,0 +1201,0 @@ DEFPRINT(AST_Sequence, function(self, output) { |
@@ -1095,3 +1095,3 @@ /*********************************************************************** | ||
expect("{"); | ||
var a = [], cur = null, branch = null, tmp; | ||
var a = [], branch, cur, default_branch, tmp; | ||
while (!is("punc", "}")) { | ||
@@ -1111,2 +1111,3 @@ if (is("eof")) expect_token("punc", "}"); | ||
if (branch) branch.end = prev(); | ||
if (default_branch) croak("More than one default clause in switch statement"); | ||
cur = []; | ||
@@ -1118,2 +1119,3 @@ branch = new AST_Default({ | ||
a.push(branch); | ||
default_branch = branch; | ||
} else { | ||
@@ -1120,0 +1122,0 @@ if (!cur) unexpected(); |
@@ -46,3 +46,4 @@ /*********************************************************************** | ||
function find_builtins(reserved) { | ||
var builtins = function() { | ||
var names = []; | ||
// NaN will be included due to Number.NaN | ||
@@ -71,15 +72,17 @@ [ | ||
if (ctor.prototype) { | ||
Object.getOwnPropertyNames(new ctor()).map(add); | ||
Object.getOwnPropertyNames(ctor.prototype).map(add); | ||
} | ||
}); | ||
return makePredicate(names); | ||
function add(name) { | ||
push_uniq(reserved, name); | ||
names.push(name); | ||
} | ||
} | ||
}(); | ||
function reserve_quoted_keys(ast, reserved) { | ||
ast.walk(new TreeWalker(function(node) { | ||
if (node instanceof AST_ObjectKeyVal && node.quote) { | ||
add(node.key); | ||
if (node instanceof AST_ObjectKeyVal) { | ||
if (node.quote) add(node.key); | ||
} else if (node instanceof AST_Sub) { | ||
@@ -96,13 +99,10 @@ addStrings(node.property, add); | ||
function addStrings(node, add) { | ||
node.walk(new TreeWalker(function(node) { | ||
if (node instanceof AST_Sequence) { | ||
addStrings(node.tail_node(), add); | ||
} else if (node instanceof AST_String) { | ||
add(node.value); | ||
} else if (node instanceof AST_Conditional) { | ||
addStrings(node.consequent, add); | ||
addStrings(node.alternative, add); | ||
} | ||
return true; | ||
})); | ||
if (node instanceof AST_Conditional) { | ||
addStrings(node.consequent, add); | ||
addStrings(node.alternative, add); | ||
} else if (node instanceof AST_Sequence) { | ||
addStrings(node.tail_node(), add); | ||
} else if (node instanceof AST_String) { | ||
add(node.value); | ||
} | ||
} | ||
@@ -121,5 +121,6 @@ | ||
var reserved = options.reserved; | ||
if (!Array.isArray(reserved)) reserved = []; | ||
if (!options.builtins) find_builtins(reserved); | ||
var reserved = Object.create(options.builtins ? null : builtins); | ||
if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) { | ||
reserved[name] = true; | ||
}); | ||
@@ -130,4 +131,4 @@ var cname = -1; | ||
cache = options.cache.props; | ||
cache.each(function(mangled_name) { | ||
push_uniq(reserved, mangled_name); | ||
cache.each(function(name) { | ||
reserved[name] = true; | ||
}); | ||
@@ -147,8 +148,29 @@ } else { | ||
var names_to_mangle = []; | ||
var unmangleable = []; | ||
var names_to_mangle = Object.create(null); | ||
var unmangleable = Object.create(reserved); | ||
// step 1: find candidates to mangle | ||
ast.walk(new TreeWalker(function(node) { | ||
if (node instanceof AST_ObjectKeyVal) { | ||
if (node instanceof AST_Binary) { | ||
if (node.operator == "in") addStrings(node.left, add); | ||
} else if (node.TYPE == "Call") { | ||
var exp = node.expression; | ||
if (exp instanceof AST_Dot) switch (exp.property) { | ||
case "defineProperty": | ||
case "getOwnPropertyDescriptor": | ||
if (node.args.length < 2) break; | ||
exp = exp.expression; | ||
if (!(exp instanceof AST_SymbolRef)) break; | ||
if (exp.name != "Object") break; | ||
if (!exp.definition().undeclared) break; | ||
addStrings(node.args[1], add); | ||
break; | ||
case "hasOwnProperty": | ||
if (node.args.length < 1) break; | ||
addStrings(node.args[0], add); | ||
break; | ||
} | ||
} else if (node instanceof AST_Dot) { | ||
add(node.property); | ||
} else if (node instanceof AST_ObjectKeyVal) { | ||
add(node.key); | ||
@@ -158,15 +180,31 @@ } else if (node instanceof AST_ObjectProperty) { | ||
add(node.key.name); | ||
} else if (node instanceof AST_Dot) { | ||
add(node.property); | ||
} else if (node instanceof AST_Sub) { | ||
addStrings(node.property, add); | ||
} else if (node instanceof AST_Call | ||
&& node.expression.print_to_string() == "Object.defineProperty") { | ||
addStrings(node.args[1], add); | ||
} | ||
})); | ||
// step 2: transform the tree, renaming properties | ||
return ast.transform(new TreeTransformer(function(node) { | ||
if (node instanceof AST_ObjectKeyVal) { | ||
// step 2: renaming properties | ||
ast.walk(new TreeWalker(function(node) { | ||
if (node instanceof AST_Binary) { | ||
if (node.operator == "in") mangleStrings(node.left); | ||
} else if (node.TYPE == "Call") { | ||
var exp = node.expression; | ||
if (exp instanceof AST_Dot) switch (exp.property) { | ||
case "defineProperty": | ||
case "getOwnPropertyDescriptor": | ||
if (node.args.length < 2) break; | ||
exp = exp.expression; | ||
if (!(exp instanceof AST_SymbolRef)) break; | ||
if (exp.name != "Object") break; | ||
if (!exp.definition().undeclared) break; | ||
mangleStrings(node.args[1]); | ||
break; | ||
case "hasOwnProperty": | ||
if (node.args.length < 1) break; | ||
mangleStrings(node.args[0]); | ||
break; | ||
} | ||
} else if (node instanceof AST_Dot) { | ||
node.property = mangle(node.property); | ||
} else if (node instanceof AST_ObjectKeyVal) { | ||
node.key = mangle(node.key); | ||
@@ -176,9 +214,4 @@ } else if (node instanceof AST_ObjectProperty) { | ||
node.key.name = mangle(node.key.name); | ||
} else if (node instanceof AST_Dot) { | ||
node.property = mangle(node.property); | ||
} else if (!options.keep_quoted && node instanceof AST_Sub) { | ||
node.property = mangleStrings(node.property); | ||
} else if (node instanceof AST_Call | ||
&& node.expression.print_to_string() == "Object.defineProperty") { | ||
node.args[1] = mangleStrings(node.args[1]); | ||
} else if (node instanceof AST_Sub) { | ||
if (!options.keep_quoted) mangleStrings(node.property); | ||
} | ||
@@ -190,4 +223,3 @@ })); | ||
function can_mangle(name) { | ||
if (unmangleable.indexOf(name) >= 0) return false; | ||
if (reserved.indexOf(name) >= 0) return false; | ||
if (unmangleable[name]) return false; | ||
if (options.only_cache) return cache.has(name); | ||
@@ -199,10 +231,10 @@ if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false; | ||
function should_mangle(name) { | ||
if (reserved[name]) return false; | ||
if (regex && !regex.test(name)) return false; | ||
if (reserved.indexOf(name) >= 0) return false; | ||
return cache.has(name) || names_to_mangle.indexOf(name) >= 0; | ||
return cache.has(name) || names_to_mangle[name]; | ||
} | ||
function add(name) { | ||
if (can_mangle(name)) push_uniq(names_to_mangle, name); | ||
if (!should_mangle(name)) push_uniq(unmangleable, name); | ||
if (can_mangle(name)) names_to_mangle[name] = true; | ||
if (!should_mangle(name)) unmangleable[name] = true; | ||
} | ||
@@ -231,15 +263,11 @@ | ||
function mangleStrings(node) { | ||
return node.transform(new TreeTransformer(function(node) { | ||
if (node instanceof AST_Sequence) { | ||
var last = node.expressions.length - 1; | ||
node.expressions[last] = mangleStrings(node.expressions[last]); | ||
} else if (node instanceof AST_String) { | ||
node.value = mangle(node.value); | ||
} else if (node instanceof AST_Conditional) { | ||
node.consequent = mangleStrings(node.consequent); | ||
node.alternative = mangleStrings(node.alternative); | ||
} | ||
return node; | ||
})); | ||
if (node instanceof AST_Sequence) { | ||
mangleStrings(node.expressions.tail_node()); | ||
} else if (node instanceof AST_String) { | ||
node.value = mangle(node.value); | ||
} else if (node instanceof AST_Conditional) { | ||
mangleStrings(node.consequent); | ||
mangleStrings(node.alternative); | ||
} | ||
} | ||
} |
@@ -562,17 +562,19 @@ /*********************************************************************** | ||
try { | ||
AST_Node.prototype.print = function(stream, force_parens) { | ||
this._print(stream, force_parens); | ||
if (this instanceof AST_Symbol && !this.unmangleable(options)) { | ||
base54.consider(this.name, -1); | ||
} else if (options.properties) { | ||
if (this instanceof AST_Dot) { | ||
base54.consider(this.property, -1); | ||
} else if (this instanceof AST_Sub) { | ||
skip_string(this.property); | ||
} | ||
} | ||
var fn = AST_Symbol.prototype.add_source_map; | ||
AST_Symbol.prototype.add_source_map = function() { | ||
if (!this.unmangleable(options)) base54.consider(this.name, -1); | ||
}; | ||
if (options.properties) { | ||
AST_Dot.prototype.add_source_map = function() { | ||
base54.consider(this.property, -1); | ||
}; | ||
AST_Sub.prototype.add_source_map = function() { | ||
skip_string(this.property); | ||
}; | ||
} | ||
base54.consider(this.print_to_string(), 1); | ||
} finally { | ||
AST_Node.prototype.print = AST_Node.prototype._print; | ||
AST_Symbol.prototype.add_source_map = fn; | ||
delete AST_Dot.prototype.add_source_map; | ||
delete AST_Sub.prototype.add_source_map; | ||
} | ||
@@ -579,0 +581,0 @@ base54.sort(); |
@@ -6,3 +6,3 @@ { | ||
"license": "BSD-2-Clause", | ||
"version": "3.10.1", | ||
"version": "3.10.2", | ||
"engines": { | ||
@@ -9,0 +9,0 @@ "node": ">=0.8.0" |
@@ -215,14 +215,13 @@ UglifyJS 3 | ||
- `toplevel` (default `false`) -- mangle names declared in the top level scope. | ||
- `eval` (default `false`) -- mangle names visible in scopes where `eval` or | ||
`with` are used. | ||
- `eval` (default `false`) -- mangle names visible in scopes where `eval` or `with` are used. | ||
- `reserved` (default: `[]`) -- when mangling is enabled but you want to | ||
prevent certain names from being mangled, you can declare those names with | ||
`--mangle reserved` — pass a comma-separated list of names. For example: | ||
When mangling is enabled but you want to prevent certain names from being | ||
mangled, you can declare those names with `--mangle reserved` — pass a | ||
comma-separated list of names. For example: | ||
uglifyjs ... -m reserved=['$','require','exports'] | ||
uglifyjs ... -m reserved=['$','require','exports'] | ||
to prevent the `require`, `exports` and `$` names from being changed. | ||
to prevent the `require`, `exports` and `$` names from being changed. | ||
### CLI mangling property names (`--mangle-props`) | ||
@@ -661,4 +660,4 @@ | ||
`var o={p:1, q:2}; f(o.p, o.q);` is converted to `f(1, 2);`. Note: `hoist_props` | ||
works best with `mangle` enabled, the `compress` option `passes` set to `2` or higher, | ||
and the `compress` option `toplevel` enabled. | ||
works best with `toplevel` and `mangle` enabled, alongside with `compress` option | ||
`passes` set to `2` or higher. | ||
@@ -1162,1 +1161,17 @@ - `hoist_vars` (default: `false`) -- hoist `var` declarations (this is `false` | ||
`Object.preventExtensions()` or `Object.seal()`). | ||
- When `toplevel` is enabled, UglifyJS effectively assumes input code is wrapped | ||
within `function(){ ... }`, thus forbids aliasing of declared global variables: | ||
```js | ||
A = "FAIL"; | ||
var B = "FAIL"; | ||
// can be `global`, `self`, `window` etc. | ||
var top = function() { | ||
return this; | ||
}(); | ||
// "PASS" | ||
top.A = "PASS"; | ||
console.log(A); | ||
// "FAIL" after compress and/or mangle | ||
top.B = "PASS"; | ||
console.log(B); | ||
``` |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
889871
4.23%23170
7.34%1175
1.29%