diff options
Diffstat (limited to 'lib/propmangle.js')
-rw-r--r-- | lib/propmangle.js | 142 |
1 files changed, 85 insertions, 57 deletions
diff --git a/lib/propmangle.js b/lib/propmangle.js index ebd1f4e9..04194393 100644 --- a/lib/propmangle.js +++ b/lib/propmangle.js @@ -43,7 +43,8 @@ "use strict"; -function find_builtins(reserved) { +var builtins = function() { + var names = []; // NaN will be included due to Number.NaN [ "null", @@ -67,19 +68,21 @@ function find_builtins(reserved) { ].forEach(function(ctor) { Object.getOwnPropertyNames(ctor).map(add); 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) { addStrings(node.property, add); } @@ -91,17 +94,14 @@ function reserve_quoted_keys(ast, reserved) { } 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); + } } function mangle_properties(ast, options) { @@ -115,16 +115,17 @@ function mangle_properties(ast, options) { reserved: null, }, true); - 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; + }); var cname = -1; var cache; if (options.cache) { cache = options.cache.props; - cache.each(function(mangled_name) { - push_uniq(reserved, mangled_name); + cache.each(function(name) { + reserved[name] = true; }); } else { cache = new Dictionary(); @@ -139,62 +140,93 @@ function mangle_properties(ast, options) { var debug_suffix; if (debug) debug_suffix = options.debug === true ? "" : options.debug; - 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); } else if (node instanceof AST_ObjectProperty) { // setter or getter, since KeyVal is handled above 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); } else if (node instanceof AST_ObjectProperty) { // setter or getter 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); } })); // only function declarations after this line 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); if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false; return true; } 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; } function mangle(name) { @@ -218,17 +250,13 @@ function mangle_properties(ast, options) { } 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); + } } } |