Compare commits

..

9 Commits

Author SHA1 Message Date
Alex Lam S.L
f81ff10a9b v3.0.28 2017-08-20 00:27:01 +08:00
Erik Desjardins
16d40915b4 don't escape null characters as \0 when followed by any digit (#2273)
fixes #2272
2017-08-14 12:30:08 +08:00
Alex Lam S.L
e7c21e87e3 fix ie8 mangling of top-level AST_SymbolCatch (#2263)
fixes #2254
2017-08-01 02:38:32 +08:00
Alex Lam S.L
c4c2ef44d0 v3.0.27 2017-07-30 01:50:42 +08:00
Alex Lam S.L
a845897758 improve mangle.properties (#2261)
- include dead code when `keep_quoted`
- unify `keep_quoted` & `reserved`
- make `test/run-tests.js` consistent with `minify()`

fixes #2256
2017-07-29 23:02:04 +08:00
kzc
32ea2c5530 issue template: describe acceptable JS input (#2255) 2017-07-27 21:38:36 +08:00
Alex Lam S.L
bc61deeca9 v3.0.26 2017-07-23 12:39:36 +08:00
Alex Lam S.L
6a5e74b44e unescape surrogate pairs only (#2246)
fixes #2242
2017-07-23 12:38:21 +08:00
Alex Lam S.L
54446341ee update dependencies (#2241)
- acorn@5.1.1
- commander@2.11.0
- mocha@3.4.2
2017-07-16 16:20:40 +08:00
18 changed files with 343 additions and 141 deletions

View File

@@ -8,7 +8,14 @@
**Uglify version (`uglifyjs -V`)** **Uglify version (`uglifyjs -V`)**
**JavaScript input** <!-- ideally as small as possible --> **JavaScript input**
<!--
A complete parsable JS program exhibiting the issue with
UglifyJS alone - without third party tools or libraries.
Ideally the input should be as small as possible.
Post a link to a gist if necessary.
-->
**The `uglifyjs` CLI command executed or `minify()` options used.** **The `uglifyjs` CLI command executed or `minify()` options used.**

View File

@@ -68,6 +68,7 @@ function minify(files, options) {
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]); set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]); set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]); set_shorthand("warnings", options, [ "compress" ]);
var quoted_props;
if (options.mangle) { if (options.mangle) {
options.mangle = defaults(options.mangle, { options.mangle = defaults(options.mangle, {
cache: options.nameCache && (options.nameCache.vars || {}), cache: options.nameCache && (options.nameCache.vars || {}),
@@ -78,11 +79,16 @@ function minify(files, options) {
reserved: [], reserved: [],
toplevel: false, toplevel: false,
}, true); }, true);
if (options.nameCache && options.mangle.properties) { if (options.mangle.properties) {
if (typeof options.mangle.properties != "object") { if (typeof options.mangle.properties != "object") {
options.mangle.properties = {}; 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 || {}; options.mangle.properties.cache = options.nameCache.props || {};
} }
} }
@@ -125,6 +131,9 @@ function minify(files, options) {
} }
toplevel = options.parse.toplevel; toplevel = options.parse.toplevel;
} }
if (quoted_props) {
reserve_quoted_keys(toplevel, quoted_props);
}
if (options.wrap) { if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap); toplevel = toplevel.wrap_commonjs(options.wrap);
} }

View File

@@ -109,7 +109,7 @@ function OutputStream(options) {
var current_pos = 0; var current_pos = 0;
var OUTPUT = ""; var OUTPUT = "";
function to_ascii(str, identifier) { var to_utf8 = options.ascii_only ? function(str, identifier) {
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) { return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
var code = ch.charCodeAt(0).toString(16); var code = ch.charCodeAt(0).toString(16);
if (code.length <= 2 && !identifier) { if (code.length <= 2 && !identifier) {
@@ -120,6 +120,12 @@ function OutputStream(options) {
return "\\u" + code; return "\\u" + code;
} }
}); });
} : function(str) {
return str.replace(/[\ud800-\udbff](?![\udc00-\udfff])/g, function(ch) {
return "\\u" + ch.charCodeAt(0).toString(16);
}).replace(/(^|[^\ud800-\udbff])([\udc00-\udfff])/g, function(match, prefix, ch) {
return prefix + "\\u" + ch.charCodeAt(0).toString(16);
});
}; };
function make_string(str, quote) { function make_string(str, quote) {
@@ -140,7 +146,7 @@ function OutputStream(options) {
case "\u2029": return "\\u2029"; case "\u2029": return "\\u2029";
case "\ufeff": return "\\ufeff"; case "\ufeff": return "\\ufeff";
case "\0": case "\0":
return /[0-7]/.test(str.charAt(i+1)) ? "\\x00" : "\\0"; return /[0-9]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
} }
return s; return s;
}); });
@@ -150,7 +156,7 @@ function OutputStream(options) {
function quote_double() { function quote_double() {
return '"' + str.replace(/\x22/g, '\\"') + '"'; return '"' + str.replace(/\x22/g, '\\"') + '"';
} }
if (options.ascii_only) str = to_ascii(str); str = to_utf8(str);
switch (options.quote_style) { switch (options.quote_style) {
case 1: case 1:
return quote_single(); return quote_single();
@@ -175,8 +181,7 @@ function OutputStream(options) {
function make_name(name) { function make_name(name) {
name = name.toString(); name = name.toString();
if (options.ascii_only) name = to_utf8(name, true);
name = to_ascii(name, true);
return name; return name;
}; };
@@ -433,7 +438,7 @@ function OutputStream(options) {
last : function() { return last }, last : function() { return last },
semicolon : semicolon, semicolon : semicolon,
force_semicolon : force_semicolon, force_semicolon : force_semicolon,
to_ascii : to_ascii, to_utf8 : to_utf8,
print_name : function(name) { print(make_name(name)) }, print_name : function(name) { print(make_name(name)) },
print_string : function(str, quote, escape_directive) { print_string : function(str, quote, escape_directive) {
var encoded = encode_string(str, quote); var encoded = encode_string(str, quote);
@@ -1318,9 +1323,7 @@ function OutputStream(options) {
if (regexp.raw_source) { if (regexp.raw_source) {
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/")); str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
} }
if (output.option("ascii_only")) { str = output.to_utf8(str);
str = output.to_ascii(str);
}
output.print(str); output.print(str);
var p = output.parent(); var p = output.parent();
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self) if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)

View File

@@ -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) { function mangle_properties(ast, options) {
options = defaults(options, { options = defaults(options, {
builtins: false, builtins: false,
@@ -91,7 +119,6 @@ function mangle_properties(ast, options) {
} }
var regex = options.regex; 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 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' // 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 names_to_mangle = [];
var unmangleable = []; var unmangleable = [];
var to_keep = {};
// step 1: find candidates to mangle // step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node){ ast.walk(new TreeWalker(function(node){
if (node instanceof AST_ObjectKeyVal) { if (node instanceof AST_ObjectKeyVal) {
add(node.key, keep_quoted && node.quote); add(node.key);
} }
else if (node instanceof AST_ObjectProperty) { else if (node instanceof AST_ObjectProperty) {
// setter or getter, since KeyVal is handled above // setter or getter, since KeyVal is handled above
@@ -119,15 +145,14 @@ function mangle_properties(ast, options) {
add(node.property); add(node.property);
} }
else if (node instanceof AST_Sub) { else if (node instanceof AST_Sub) {
addStrings(node.property, keep_quoted); addStrings(node.property, add);
} }
})); }));
// step 2: transform the tree, renaming properties // step 2: transform the tree, renaming properties
return ast.transform(new TreeTransformer(function(node){ return ast.transform(new TreeTransformer(function(node){
if (node instanceof AST_ObjectKeyVal) { 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) { else if (node instanceof AST_ObjectProperty) {
// setter or getter // setter or getter
@@ -136,22 +161,9 @@ function mangle_properties(ast, options) {
else if (node instanceof AST_Dot) { else if (node instanceof AST_Dot) {
node.property = mangle(node.property); node.property = mangle(node.property);
} }
else if (node instanceof AST_Sub) { else if (!options.keep_quoted && node instanceof AST_Sub) {
if (!keep_quoted) node.property = mangleStrings(node.property);
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 // only function declarations after this line
@@ -167,19 +179,13 @@ function mangle_properties(ast, options) {
} }
function should_mangle(name) { function should_mangle(name) {
if (keep_quoted && name in to_keep) return false;
if (regex && !regex.test(name)) return false; if (regex && !regex.test(name)) return false;
if (reserved.indexOf(name) >= 0) return false; if (reserved.indexOf(name) >= 0) return false;
return cache.props.has(name) return cache.props.has(name)
|| names_to_mangle.indexOf(name) >= 0; || names_to_mangle.indexOf(name) >= 0;
} }
function add(name, keep) { function add(name) {
if (keep) {
to_keep[name] = true;
return;
}
if (can_mangle(name)) if (can_mangle(name))
push_uniq(names_to_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_. // debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_"; 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; mangled = debug_mangled;
} }
} }
// either debug mode is off, or it is on and we could not use the mangled name // either debug mode is off, or it is on and we could not use the mangled name
if (!mangled) { if (!mangled) {
// 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 { do {
mangled = base54(++cache.cname); mangled = base54(++cache.cname);
} while (!can_mangle(mangled) || keep_quoted && mangled in to_keep); } while (!can_mangle(mangled));
} }
cache.props.set(name, mangled); cache.props.set(name, mangled);
@@ -219,32 +222,6 @@ function mangle_properties(ast, options) {
return mangled; 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) { function mangleStrings(node) {
return node.transform(new TreeTransformer(function(node){ return node.transform(new TreeTransformer(function(node){
if (node instanceof AST_Sequence) { if (node instanceof AST_Sequence) {

View File

@@ -235,6 +235,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
ref.reference(options); ref.reference(options);
}); });
node.thedef = def; node.thedef = def;
node.reference(options);
return true; return true;
} }
})); }));

View File

@@ -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.25", "version": "3.0.28",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
@@ -29,12 +29,12 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"commander": "~2.9.0", "commander": "~2.11.0",
"source-map": "~0.5.1" "source-map": "~0.5.1"
}, },
"devDependencies": { "devDependencies": {
"acorn": "~5.0.3", "acorn": "~5.1.1",
"mocha": "~2.3.4", "mocha": "~3.4.2",
"semver": "~5.3.0" "semver": "~5.3.0"
}, },
"scripts": { "scripts": {

View File

@@ -13,7 +13,7 @@ ascii_only_true: {
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"; "\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
} }
} }
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}' expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
} }
ascii_only_false: { ascii_only_false: {
@@ -31,5 +31,5 @@ ascii_only_false: {
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"; "\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
} }
} }
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}' expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
} }

View File

@@ -21,7 +21,7 @@ concat_1: {
var c = 1 + x() + 2 + "boo"; var c = 1 + x() + 2 + "boo";
var d = 1 + x() + 2 + 3 + "boo"; var d = 1 + x() + 2 + 3 + "boo";
var e = 1 + x() + 2 + "X3boo"; var e = 1 + x() + 2 + "X3boo";
var f = "\x00360\08\0"; var f = "\x00360\x008\0";
} }
} }

View File

@@ -1,6 +1,8 @@
issue_1321_no_debug: { issue_1321_no_debug: {
mangle_props = { mangle = {
keep_quoted: true properties: {
keep_quoted: true,
},
} }
input: { input: {
var x = {}; var x = {};
@@ -10,17 +12,19 @@ issue_1321_no_debug: {
} }
expect: { expect: {
var x = {}; var x = {};
x.o = 1; x.x = 1;
x["a"] = 2 * x.o; x["a"] = 2 * x.x;
console.log(x.o, x["a"]); console.log(x.x, x["a"]);
} }
expect_stdout: true expect_stdout: true
} }
issue_1321_debug: { issue_1321_debug: {
mangle_props = { mangle = {
keep_quoted: true, properties: {
debug: "" debug: "",
keep_quoted: true,
},
} }
input: { input: {
var x = {}; var x = {};
@@ -30,16 +34,18 @@ issue_1321_debug: {
} }
expect: { expect: {
var x = {}; var x = {};
x.o = 1; x.x = 1;
x["_$foo$_"] = 2 * x.o; x["_$foo$_"] = 2 * x.x;
console.log(x.o, x["_$foo$_"]); console.log(x.x, x["_$foo$_"]);
} }
expect_stdout: true expect_stdout: true
} }
issue_1321_with_quoted: { issue_1321_with_quoted: {
mangle_props = { mangle = {
keep_quoted: false properties: {
keep_quoted: false,
},
} }
input: { input: {
var x = {}; var x = {};
@@ -49,9 +55,9 @@ issue_1321_with_quoted: {
} }
expect: { expect: {
var x = {}; var x = {};
x.o = 1; x.x = 1;
x["x"] = 2 * x.o; x["o"] = 2 * x.x;
console.log(x.o, x["x"]); console.log(x.x, x["o"]);
} }
expect_stdout: true expect_stdout: true
} }

View File

@@ -1,5 +1,7 @@
mangle_props: { mangle_props: {
mangle_props = {} mangle = {
properties: true,
}
input: { input: {
var obj = { var obj = {
undefined: 1, undefined: 1,
@@ -54,10 +56,12 @@ mangle_props: {
} }
numeric_literal: { numeric_literal: {
mangle = {
properties: true,
}
beautify = { beautify = {
beautify: true, beautify: true,
} }
mangle_props = {}
input: { input: {
var obj = { var obj = {
0: 0, 0: 0,
@@ -105,7 +109,9 @@ numeric_literal: {
} }
identifier: { identifier: {
mangle_props = {} mangle = {
properties: true,
}
input: { input: {
var obj = { var obj = {
abstract: 1, abstract: 1,

View File

@@ -1,6 +1,8 @@
dont_reuse_prop: { dont_reuse_prop: {
mangle_props = { mangle = {
regex: /asd/ properties: {
regex: /asd/,
},
} }
input: { input: {
"aaaaaaaaaabbbbb"; "aaaaaaaaaabbbbb";
@@ -20,8 +22,10 @@ dont_reuse_prop: {
} }
unmangleable_props_should_always_be_reserved: { unmangleable_props_should_always_be_reserved: {
mangle_props = { mangle = {
regex: /asd/ properties: {
regex: /asd/,
},
} }
input: { input: {
"aaaaaaaaaabbbbb"; "aaaaaaaaaabbbbb";

View File

@@ -128,9 +128,11 @@ evaluate_string_length: {
} }
mangle_properties: { mangle_properties: {
mangle_props = { mangle = {
keep_quoted: false properties: {
}; keep_quoted: false,
},
}
input: { input: {
a["foo"] = "bar"; a["foo"] = "bar";
a.color = "red"; a.color = "red";
@@ -139,11 +141,11 @@ mangle_properties: {
a['run']({color: "blue", foo: "baz"}); a['run']({color: "blue", foo: "baz"});
} }
expect: { expect: {
a["o"] = "bar"; a["a"] = "bar";
a.a = "red"; a.b = "red";
x = {r: 10}; x = {o: 10};
a.b(x.r, a.o); a.r(x.o, a.a);
a['b']({a: "blue", o: "baz"}); a['r']({b: "blue", a: "baz"});
} }
} }
@@ -151,8 +153,10 @@ mangle_unquoted_properties: {
options = { options = {
properties: false properties: false
} }
mangle_props = { mangle = {
keep_quoted: true properties: {
keep_quoted: true,
},
} }
beautify = { beautify = {
beautify: false, beautify: false,
@@ -181,24 +185,26 @@ mangle_unquoted_properties: {
function f1() { function f1() {
a["foo"] = "bar"; a["foo"] = "bar";
a.color = "red"; a.color = "red";
a.o = 2; a.r = 2;
x = {"bar": 10, f: 7}; x = {"bar": 10, b: 7};
a.f = 9; a.b = 9;
} }
function f2() { function f2() {
a.foo = "bar"; a.foo = "bar";
a['color'] = "red"; a['color'] = "red";
x = {bar: 10, f: 7}; x = {bar: 10, b: 7};
a.f = 9; a.b = 9;
a.o = 3; a.r = 3;
} }
} }
} }
mangle_debug: { mangle_debug: {
mangle_props = { mangle = {
debug: "" properties: {
}; debug: "",
},
}
input: { input: {
a.foo = "bar"; a.foo = "bar";
x = { baz: "ban" }; x = { baz: "ban" };
@@ -210,9 +216,11 @@ mangle_debug: {
} }
mangle_debug_true: { mangle_debug_true: {
mangle_props = { mangle = {
debug: true properties: {
}; debug: true,
},
}
input: { input: {
a.foo = "bar"; a.foo = "bar";
x = { baz: "ban" }; x = { baz: "ban" };
@@ -224,9 +232,11 @@ mangle_debug_true: {
} }
mangle_debug_suffix: { mangle_debug_suffix: {
mangle_props = { mangle = {
debug: "XYZ" properties: {
}; debug: "XYZ",
},
}
input: { input: {
a.foo = "bar"; a.foo = "bar";
x = { baz: "ban" }; x = { baz: "ban" };
@@ -241,10 +251,12 @@ mangle_debug_suffix_keep_quoted: {
options = { options = {
properties: false properties: false
} }
mangle_props = { mangle = {
keep_quoted: true, properties: {
debug: "XYZ", debug: "XYZ",
reserved: [] keep_quoted: true,
reserved: [],
},
} }
beautify = { beautify = {
beautify: false, beautify: false,
@@ -774,3 +786,21 @@ issue_2208_5: {
} }
expect_stdout: "42" 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;
}
}

View File

@@ -325,3 +325,69 @@ issue_2120_2: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_2254_1: {
mangle = {
ie8: false,
}
input: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(s) {
try {
throw "FAIL";
} catch (e) {
return s;
}
}
}
expect: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(e) {
try {
throw "FAIL";
} catch (t) {
return e;
}
}
}
expect_stdout: "PASS"
}
issue_2254_2: {
mangle = {
ie8: true,
}
input: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(s) {
try {
throw "FAIL";
} catch (e) {
return s;
}
}
}
expect: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(t) {
try {
throw "FAIL";
} catch (e) {
return t;
}
}
}
expect_stdout: "PASS"
}

View File

@@ -15,3 +15,43 @@ unicode_parse_variables: {
var l = 3; var l = 3;
} }
} }
issue_2242_1: {
beautify = {
ascii_only: false,
}
input: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\ud83d\ude00","\\ud83d@\\ude00");'
}
issue_2242_2: {
beautify = {
ascii_only: true,
}
input: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\\ud83d\\ude00","\\ud83d@\\ude00");'
}
issue_2242_3: {
options = {
evaluate: false,
}
input: {
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
}
expect_exact: 'console.log("\\ud83d"+"\\ude00","\\ud83d"+"@"+"\\ude00");'
}
issue_2242_4: {
options = {
evaluate: true,
}
input: {
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
}
expect_exact: 'console.log("\ud83d\ude00","\\ud83d@\\ude00");'
}

View File

@@ -8,6 +8,7 @@ exports["defaults"] = defaults;
exports["mangle_properties"] = mangle_properties; exports["mangle_properties"] = mangle_properties;
exports["minify"] = minify; exports["minify"] = minify;
exports["parse"] = parse; exports["parse"] = parse;
exports["reserve_quoted_keys"] = reserve_quoted_keys;
exports["string_template"] = string_template; exports["string_template"] = string_template;
exports["tokenizer"] = tokenizer; exports["tokenizer"] = tokenizer;
exports["is_identifier"] = is_identifier; exports["is_identifier"] = is_identifier;

View File

@@ -124,6 +124,17 @@ describe("minify", function() {
assert.strictEqual(result.code, assert.strictEqual(result.code,
'a["foo"]="bar",a.a="red",x={"bar":10};'); '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() { describe("inSourceMap", function() {

View File

@@ -61,9 +61,9 @@ describe("String literals", function() {
var tests = [ var tests = [
['"\\76";', ';">";'], ['"\\76";', ';">";'],
['"\\0"', '"\\0";'], ['"\\0"', '"\\0";'],
['"\\08"', '"\\08";'], ['"\\08"', '"\\x008";'],
['"\\008"', '"\\08";'], ['"\\008"', '"\\x008";'],
['"\\0008"', '"\\08";'], ['"\\0008"', '"\\x008";'],
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'], ['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
['"use\\\n strict";\n"\\07";', ';"use strict";"\07";'] ['"use\\\n strict";\n"\\07";', ';"use strict";"\07";']
]; ];
@@ -75,7 +75,44 @@ describe("String literals", function() {
}); });
it("Should not throw error when digit is 8 or 9", function() { it("Should not throw error when digit is 8 or 9", function() {
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\08";'); assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\x008";');
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\09";'); assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\x009";');
});
it("Should not unescape unpaired surrogates", function() {
var code = [];
for (var i = 0; i <= 0xF; i++) {
code.push("\\u000" + i.toString(16));
}
for (;i <= 0xFF; i++) {
code.push("\\u00" + i.toString(16));
}
for (;i <= 0xFFF; i++) {
code.push("\\u0" + i.toString(16));
}
for (; i <= 0xFFFF; i++) {
code.push("\\u" + i.toString(16));
}
code = '"' + code.join() + '"';
var normal = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
ascii_only: false
}
});
if (normal.error) throw normal.error;
assert.ok(code.length > normal.code.length);
assert.strictEqual(eval(code), eval(normal.code));
var ascii = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
ascii_only: false
}
});
if (ascii.error) throw ascii.error;
assert.ok(code.length > ascii.code.length);
assert.strictEqual(eval(code), eval(ascii.code));
}); });
}); });

View File

@@ -111,18 +111,22 @@ function run_compress_tests() {
}; };
if (!options.warnings) options.warnings = true; 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 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 || test.mangle_props) { if (test.mangle) {
U.base54.reset(); 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.properties) {
if (test.mangle_props) { output = U.mangle_properties(output, test.mangle.properties);
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) {