aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/minify.js13
-rw-r--r--lib/propmangle.js95
-rw-r--r--test/compress/issue-1321.js38
-rw-r--r--test/compress/issue-1770.js12
-rw-r--r--test/compress/issue-747.js12
-rw-r--r--test/compress/properties.js88
-rw-r--r--test/exports.js1
-rw-r--r--test/mocha/minify.js11
-rwxr-xr-xtest/run-tests.js16
9 files changed, 167 insertions, 119 deletions
diff --git a/lib/minify.js b/lib/minify.js
index b4bfe451..773e953a 100644
--- a/lib/minify.js
+++ b/lib/minify.js
@@ -68,6 +68,7 @@ function minify(files, options) {
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]);
+ var quoted_props;
if (options.mangle) {
options.mangle = defaults(options.mangle, {
cache: options.nameCache && (options.nameCache.vars || {}),
@@ -78,11 +79,16 @@ function minify(files, options) {
reserved: [],
toplevel: false,
}, true);
- if (options.nameCache && options.mangle.properties) {
+ if (options.mangle.properties) {
if (typeof options.mangle.properties != "object") {
options.mangle.properties = {};
}
- if (!("cache" in options.mangle.properties)) {
+ if (options.mangle.properties.keep_quoted) {
+ quoted_props = options.mangle.properties.reserved;
+ if (!Array.isArray(quoted_props)) quoted_props = [];
+ options.mangle.properties.reserved = quoted_props;
+ }
+ if (options.nameCache && !("cache" in options.mangle.properties)) {
options.mangle.properties.cache = options.nameCache.props || {};
}
}
@@ -125,6 +131,9 @@ function minify(files, options) {
}
toplevel = options.parse.toplevel;
}
+ if (quoted_props) {
+ reserve_quoted_keys(toplevel, quoted_props);
+ }
if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap);
}
diff --git a/lib/propmangle.js b/lib/propmangle.js
index 49490755..36a67e80 100644
--- a/lib/propmangle.js
+++ b/lib/propmangle.js
@@ -67,6 +67,34 @@ function find_builtins(reserved) {
}
}
+function reserve_quoted_keys(ast, reserved) {
+ function add(name) {
+ push_uniq(reserved, name);
+ }
+
+ ast.walk(new TreeWalker(function(node) {
+ if (node instanceof AST_ObjectKeyVal && node.quote) {
+ add(node.key);
+ } else if (node instanceof AST_Sub) {
+ addStrings(node.property, add);
+ }
+ }));
+}
+
+function addStrings(node, add) {
+ node.walk(new TreeWalker(function(node) {
+ if (node instanceof AST_Sequence) {
+ addStrings(node.expressions[node.expressions.length - 1], 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;
+ }));
+}
+
function mangle_properties(ast, options) {
options = defaults(options, {
builtins: false,
@@ -91,7 +119,6 @@ function mangle_properties(ast, options) {
}
var regex = options.regex;
- var keep_quoted = options.keep_quoted;
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
@@ -104,12 +131,11 @@ function mangle_properties(ast, options) {
var names_to_mangle = [];
var unmangleable = [];
- var to_keep = {};
// step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node){
if (node instanceof AST_ObjectKeyVal) {
- add(node.key, keep_quoted && node.quote);
+ add(node.key);
}
else if (node instanceof AST_ObjectProperty) {
// setter or getter, since KeyVal is handled above
@@ -119,15 +145,14 @@ function mangle_properties(ast, options) {
add(node.property);
}
else if (node instanceof AST_Sub) {
- addStrings(node.property, keep_quoted);
+ addStrings(node.property, add);
}
}));
// step 2: transform the tree, renaming properties
return ast.transform(new TreeTransformer(function(node){
if (node instanceof AST_ObjectKeyVal) {
- if (!(keep_quoted && node.quote))
- node.key = mangle(node.key);
+ node.key = mangle(node.key);
}
else if (node instanceof AST_ObjectProperty) {
// setter or getter
@@ -136,22 +161,9 @@ function mangle_properties(ast, options) {
else if (node instanceof AST_Dot) {
node.property = mangle(node.property);
}
- else if (node instanceof AST_Sub) {
- if (!keep_quoted)
- node.property = mangleStrings(node.property);
+ else if (!options.keep_quoted && node instanceof AST_Sub) {
+ node.property = mangleStrings(node.property);
}
- // else if (node instanceof AST_String) {
- // if (should_mangle(node.value)) {
- // AST_Node.warn(
- // "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", {
- // file : node.start.file,
- // line : node.start.line,
- // col : node.start.col,
- // prop : node.value
- // }
- // );
- // }
- // }
}));
// only function declarations after this line
@@ -167,19 +179,13 @@ function mangle_properties(ast, options) {
}
function should_mangle(name) {
- if (keep_quoted && name in to_keep) return false;
if (regex && !regex.test(name)) return false;
if (reserved.indexOf(name) >= 0) return false;
return cache.props.has(name)
|| names_to_mangle.indexOf(name) >= 0;
}
- function add(name, keep) {
- if (keep) {
- to_keep[name] = true;
- return;
- }
-
+ function add(name) {
if (can_mangle(name))
push_uniq(names_to_mangle, name);
@@ -199,19 +205,16 @@ function mangle_properties(ast, options) {
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
- if (can_mangle(debug_mangled) && !(keep_quoted && debug_mangled in to_keep)) {
+ if (can_mangle(debug_mangled)) {
mangled = debug_mangled;
}
}
// either debug mode is off, or it is on and we could not use the mangled name
if (!mangled) {
- // Note: `can_mangle()` does not check if the name collides with the `to_keep` set
- // (filled with quoted properties when `keep_quoted` is set). Make sure we add this
- // check so we don't collide with a quoted name.
do {
mangled = base54(++cache.cname);
- } while (!can_mangle(mangled) || keep_quoted && mangled in to_keep);
+ } while (!can_mangle(mangled));
}
cache.props.set(name, mangled);
@@ -219,32 +222,6 @@ function mangle_properties(ast, options) {
return mangled;
}
- function addStrings(node, keep) {
- var out = {};
- try {
- (function walk(node){
- node.walk(new TreeWalker(function(node){
- if (node instanceof AST_Sequence) {
- walk(node.expressions[node.expressions.length - 1]);
- return true;
- }
- if (node instanceof AST_String) {
- add(node.value, keep);
- return true;
- }
- if (node instanceof AST_Conditional) {
- walk(node.consequent);
- walk(node.alternative);
- return true;
- }
- throw out;
- }));
- })(node);
- } catch(ex) {
- if (ex !== out) throw ex;
- }
- }
-
function mangleStrings(node) {
return node.transform(new TreeTransformer(function(node){
if (node instanceof AST_Sequence) {
diff --git a/test/compress/issue-1321.js b/test/compress/issue-1321.js
index 6b92291d..e55696d0 100644
--- a/test/compress/issue-1321.js
+++ b/test/compress/issue-1321.js
@@ -1,6 +1,8 @@
issue_1321_no_debug: {
- mangle_props = {
- keep_quoted: true
+ mangle = {
+ properties: {
+ keep_quoted: true,
+ },
}
input: {
var x = {};
@@ -10,17 +12,19 @@ issue_1321_no_debug: {
}
expect: {
var x = {};
- x.o = 1;
- x["a"] = 2 * x.o;
- console.log(x.o, x["a"]);
+ x.x = 1;
+ x["a"] = 2 * x.x;
+ console.log(x.x, x["a"]);
}
expect_stdout: true
}
issue_1321_debug: {
- mangle_props = {
- keep_quoted: true,
- debug: ""
+ mangle = {
+ properties: {
+ debug: "",
+ keep_quoted: true,
+ },
}
input: {
var x = {};
@@ -30,16 +34,18 @@ issue_1321_debug: {
}
expect: {
var x = {};
- x.o = 1;
- x["_$foo$_"] = 2 * x.o;
- console.log(x.o, x["_$foo$_"]);
+ x.x = 1;
+ x["_$foo$_"] = 2 * x.x;
+ console.log(x.x, x["_$foo$_"]);
}
expect_stdout: true
}
issue_1321_with_quoted: {
- mangle_props = {
- keep_quoted: false
+ mangle = {
+ properties: {
+ keep_quoted: false,
+ },
}
input: {
var x = {};
@@ -49,9 +55,9 @@ issue_1321_with_quoted: {
}
expect: {
var x = {};
- x.o = 1;
- x["x"] = 2 * x.o;
- console.log(x.o, x["x"]);
+ x.x = 1;
+ x["o"] = 2 * x.x;
+ console.log(x.x, x["o"]);
}
expect_stdout: true
}
diff --git a/test/compress/issue-1770.js b/test/compress/issue-1770.js
index f296a403..f63f8453 100644
--- a/test/compress/issue-1770.js
+++ b/test/compress/issue-1770.js
@@ -1,5 +1,7 @@
mangle_props: {
- mangle_props = {}
+ mangle = {
+ properties: true,
+ }
input: {
var obj = {
undefined: 1,
@@ -54,10 +56,12 @@ mangle_props: {
}
numeric_literal: {
+ mangle = {
+ properties: true,
+ }
beautify = {
beautify: true,
}
- mangle_props = {}
input: {
var obj = {
0: 0,
@@ -105,7 +109,9 @@ numeric_literal: {
}
identifier: {
- mangle_props = {}
+ mangle = {
+ properties: true,
+ }
input: {
var obj = {
abstract: 1,
diff --git a/test/compress/issue-747.js b/test/compress/issue-747.js
index 1f7079c2..e074305a 100644
--- a/test/compress/issue-747.js
+++ b/test/compress/issue-747.js
@@ -1,6 +1,8 @@
dont_reuse_prop: {
- mangle_props = {
- regex: /asd/
+ mangle = {
+ properties: {
+ regex: /asd/,
+ },
}
input: {
"aaaaaaaaaabbbbb";
@@ -20,8 +22,10 @@ dont_reuse_prop: {
}
unmangleable_props_should_always_be_reserved: {
- mangle_props = {
- regex: /asd/
+ mangle = {
+ properties: {
+ regex: /asd/,
+ },
}
input: {
"aaaaaaaaaabbbbb";
diff --git a/test/compress/properties.js b/test/compress/properties.js
index dda2e74f..c2c43f69 100644
--- a/test/compress/properties.js
+++ b/test/compress/properties.js
@@ -128,9 +128,11 @@ evaluate_string_length: {
}
mangle_properties: {
- mangle_props = {
- keep_quoted: false
- };
+ mangle = {
+ properties: {
+ keep_quoted: false,
+ },
+ }
input: {
a["foo"] = "bar";
a.color = "red";
@@ -139,11 +141,11 @@ mangle_properties: {
a['run']({color: "blue", foo: "baz"});
}
expect: {
- a["o"] = "bar";
- a.a = "red";
- x = {r: 10};
- a.b(x.r, a.o);
- a['b']({a: "blue", o: "baz"});
+ a["a"] = "bar";
+ a.b = "red";
+ x = {o: 10};
+ a.r(x.o, a.a);
+ a['r']({b: "blue", a: "baz"});
}
}
@@ -151,8 +153,10 @@ mangle_unquoted_properties: {
options = {
properties: false
}
- mangle_props = {
- keep_quoted: true
+ mangle = {
+ properties: {
+ keep_quoted: true,
+ },
}
beautify = {
beautify: false,
@@ -181,24 +185,26 @@ mangle_unquoted_properties: {
function f1() {
a["foo"] = "bar";
a.color = "red";
- a.o = 2;
- x = {"bar": 10, f: 7};
- a.f = 9;
+ a.r = 2;
+ x = {"bar": 10, b: 7};
+ a.b = 9;
}
function f2() {
a.foo = "bar";
a['color'] = "red";
- x = {bar: 10, f: 7};
- a.f = 9;
- a.o = 3;
+ x = {bar: 10, b: 7};
+ a.b = 9;
+ a.r = 3;
}
}
}
mangle_debug: {
- mangle_props = {
- debug: ""
- };
+ mangle = {
+ properties: {
+ debug: "",
+ },
+ }
input: {
a.foo = "bar";
x = { baz: "ban" };
@@ -210,9 +216,11 @@ mangle_debug: {
}
mangle_debug_true: {
- mangle_props = {
- debug: true
- };
+ mangle = {
+ properties: {
+ debug: true,
+ },
+ }
input: {
a.foo = "bar";
x = { baz: "ban" };
@@ -224,9 +232,11 @@ mangle_debug_true: {
}
mangle_debug_suffix: {
- mangle_props = {
- debug: "XYZ"
- };
+ mangle = {
+ properties: {
+ debug: "XYZ",
+ },
+ }
input: {
a.foo = "bar";
x = { baz: "ban" };
@@ -241,10 +251,12 @@ mangle_debug_suffix_keep_quoted: {
options = {
properties: false
}
- mangle_props = {
- keep_quoted: true,
- debug: "XYZ",
- reserved: []
+ mangle = {
+ properties: {
+ debug: "XYZ",
+ keep_quoted: true,
+ reserved: [],
+ },
}
beautify = {
beautify: false,
@@ -774,3 +786,21 @@ issue_2208_5: {
}
expect_stdout: "42"
}
+
+issue_2256: {
+ options = {
+ side_effects: true,
+ }
+ mangle = {
+ properties: {
+ keep_quoted: true,
+ },
+ }
+ input: {
+ ({ "keep": 1 });
+ g.keep = g.change;
+ }
+ expect: {
+ g.keep = g.g;
+ }
+}
diff --git a/test/exports.js b/test/exports.js
index f50b772c..997ad513 100644
--- a/test/exports.js
+++ b/test/exports.js
@@ -8,6 +8,7 @@ exports["defaults"] = defaults;
exports["mangle_properties"] = mangle_properties;
exports["minify"] = minify;
exports["parse"] = parse;
+exports["reserve_quoted_keys"] = reserve_quoted_keys;
exports["string_template"] = string_template;
exports["tokenizer"] = tokenizer;
exports["is_identifier"] = is_identifier;
diff --git a/test/mocha/minify.js b/test/mocha/minify.js
index 88e9c4eb..fc7332fb 100644
--- a/test/mocha/minify.js
+++ b/test/mocha/minify.js
@@ -124,6 +124,17 @@ describe("minify", function() {
assert.strictEqual(result.code,
'a["foo"]="bar",a.a="red",x={"bar":10};');
});
+ it("Should not mangle quoted property within dead code", function() {
+ var result = Uglify.minify('({ "keep": 1 }); g.keep = g.change;', {
+ mangle: {
+ properties: {
+ keep_quoted: true
+ }
+ }
+ });
+ if (result.error) throw result.error;
+ assert.strictEqual(result.code, "g.keep=g.g;");
+ });
});
describe("inSourceMap", function() {
diff --git a/test/run-tests.js b/test/run-tests.js
index 6b8c9ddf..0051c6c2 100755
--- a/test/run-tests.js
+++ b/test/run-tests.js
@@ -111,18 +111,22 @@ function run_compress_tests() {
};
if (!options.warnings) options.warnings = true;
}
+ if (test.mangle && test.mangle.properties && test.mangle.properties.keep_quoted) {
+ var quoted_props = test.mangle.properties.reserved;
+ if (!Array.isArray(quoted_props)) quoted_props = [];
+ test.mangle.properties.reserved = quoted_props;
+ U.reserve_quoted_keys(input, quoted_props);
+ }
var cmp = new U.Compressor(options, true);
var output = cmp.compress(input);
output.figure_out_scope(test.mangle);
- if (test.mangle || test.mangle_props) {
+ if (test.mangle) {
U.base54.reset();
output.compute_char_frequency(test.mangle);
- }
- if (test.mangle) {
output.mangle_names(test.mangle);
- }
- if (test.mangle_props) {
- output = U.mangle_properties(output, test.mangle_props);
+ if (test.mangle.properties) {
+ output = U.mangle_properties(output, test.mangle.properties);
+ }
}
output = make_code(output, output_options);
if (expect != output) {