Compare commits

...

10 Commits

Author SHA1 Message Date
Alex Lam S.L
067d52b6ba harmony-v3.0.28 2017-08-20 01:19:06 +08:00
alexlamsl
e0e009ace2 Merge branch 'master' into harmony-v3.0.28 2017-08-20 00:35:46 +08:00
Alex Lam S.L
f81ff10a9b v3.0.28 2017-08-20 00:27:01 +08:00
kzc
ae0f117da6 Introduce new compress option unsafe_arrows (#2278)
* Not always safe to convert a function expression to an arrow
  function when code depends on the function prototype existing.

Fixes #2271
2017-08-16 22:51:26 +08:00
Alex Lam S.L
a5461e0adc prohibit let/const redeclaration (#2277)
fixes #2270
2017-08-14 12:31:12 +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
2bf8216e50 fix pure_getters on spread of objects (#2275) 2017-08-13 22:08:33 +08:00
kzc
2ed3f8db44 fix output of spread of a sequence (#2268)
fixes #2267
2017-08-03 00:40:19 +08:00
kzc
4700c14855 implement object rest/spread (#2265)
- improve parse errors for destructuring spread elements
- `unsafe` for object literals with rest elements

Miscellaneous
- increase mocha unicode surrogate test timeout
2017-08-02 13:47:58 +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
19 changed files with 436 additions and 55 deletions

View File

@@ -646,9 +646,16 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `evaluate` -- attempt to evaluate constant expressions - `evaluate` -- attempt to evaluate constant expressions
- `arrows` (default `true`) -- convert ES5 style anonymous function expressions - `arrows` (default `true`) -- Converts `()=>{return x}` to `()=>x`. Class
to arrow functions if permissible by language semantics. and object literal methods will also be converted to arrow expressions if
Note: `arrows` requires that the `ecma` compress option is set to `6` or greater. the resultant code is shorter: `m(){return x}` becomes `m:()=>x`.
This transform requires that the `ecma` compress option is set to `6` or greater.
- `unsafe_arrows` (default `false`) -- Convert ES5 style anonymous function
expressions to arrow functions if the function body does not reference `this`.
Note: it is not always safe to perform this conversion if code relies on the
the function having a `prototype`, which arrow functions lack.
This transform requires that the `ecma` compress option is set to `6` or greater.
- `booleans` -- various optimizations for boolean context, for example `!!a - `booleans` -- various optimizations for boolean context, for example `!!a
? b : c → a ? b : c` ? b : c → a ? b : c`

View File

@@ -84,6 +84,7 @@ function Compressor(options, false_by_default) {
toplevel : !!(options && options["top_retain"]), toplevel : !!(options && options["top_retain"]),
typeofs : !false_by_default, typeofs : !false_by_default,
unsafe : false, unsafe : false,
unsafe_arrows : false,
unsafe_comps : false, unsafe_comps : false,
unsafe_Func : false, unsafe_Func : false,
unsafe_math : false, unsafe_math : false,
@@ -1427,9 +1428,14 @@ merge(Compressor.prototype, {
def(AST_Object, function(compressor) { def(AST_Object, function(compressor) {
if (!is_strict(compressor)) return false; if (!is_strict(compressor)) return false;
for (var i = this.properties.length; --i >=0;) for (var i = this.properties.length; --i >=0;)
if (this.properties[i].value instanceof AST_Accessor) return true; if (this.properties[i]._dot_throw(compressor)) return true;
return false; return false;
}); });
def(AST_ObjectProperty, return_false);
def(AST_ObjectGetter, return_true);
def(AST_Expansion, function(compressor) {
return this.expression._dot_throw(compressor);
});
def(AST_Function, return_false); def(AST_Function, return_false);
def(AST_Arrow, return_false); def(AST_Arrow, return_false);
def(AST_UnaryPostfix, return_false); def(AST_UnaryPostfix, return_false);
@@ -1731,6 +1737,7 @@ merge(Compressor.prototype, {
var val = {}; var val = {};
for (var i = 0, len = this.properties.length; i < len; i++) { for (var i = 0, len = this.properties.length; i < len; i++) {
var prop = this.properties[i]; var prop = this.properties[i];
if (prop instanceof AST_Expansion) return this;
var key = prop.key; var key = prop.key;
if (key instanceof AST_Symbol) { if (key instanceof AST_Symbol) {
key = key.name; key = key.name;
@@ -4742,7 +4749,7 @@ merge(Compressor.prototype, {
OPT(AST_Function, function(self, compressor){ OPT(AST_Function, function(self, compressor){
tighten_body(self.body, compressor); tighten_body(self.body, compressor);
if (compressor.option("arrows") if (compressor.option("unsafe_arrows")
&& compressor.option("ecma") >= 6 && compressor.option("ecma") >= 6
&& !self.name && !self.name
&& !self.is_generator && !self.is_generator

View File

@@ -157,7 +157,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(get_full_char(str, i+1)) ? "\\x00" : "\\0"; return /[0-9]/.test(get_full_char(str, i+1)) ? "\\x00" : "\\0";
} }
return s; return s;
}); });
@@ -689,6 +689,7 @@ function OutputStream(options) {
* ==> 20 (side effect, set a := 10 and b := 20) */ * ==> 20 (side effect, set a := 10 and b := 20) */
|| p instanceof AST_Arrow // x => (x, x) || p instanceof AST_Arrow // x => (x, x)
|| p instanceof AST_DefaultAssign // x => (x = (0, function(){})) || p instanceof AST_DefaultAssign // x => (x = (0, function(){}))
|| p instanceof AST_Expansion // [...(a, b)]
; ;
}); });

View File

@@ -1522,7 +1522,7 @@ function parse($TEXT, options) {
} }
if (is_expand) { if (is_expand) {
if (!is("punc", "]")) { if (!is("punc", "]")) {
unexpected(); // Must be last element croak("Rest element must be last element");
} }
elements[elements.length - 1] = new AST_Expansion({ elements[elements.length - 1] = new AST_Expansion({
start: expand_token, start: expand_token,
@@ -1547,18 +1547,33 @@ function parse($TEXT, options) {
} else { } else {
expect(","); expect(",");
} }
if (is("expand", "...")) {
is_expand = true;
expand_token = S.token;
used_parameters.mark_spread(S.token);
next();
}
if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].indexOf(peek().value) !== -1) { if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].indexOf(peek().value) !== -1) {
used_parameters.add_parameter(S.token); used_parameters.add_parameter(S.token);
elements.push(new AST_ObjectKeyVal({ var value = new symbol_type({
start: prev(), start: S.token,
key: S.token.value, name: S.token.value,
value: new symbol_type({ end: S.token,
start: S.token, });
name: S.token.value, if (is_expand) {
end: S.token elements.push(new AST_Expansion({
}), start: expand_token,
end: prev() expression: value,
})); end: value.end,
}));
} else {
elements.push(new AST_ObjectKeyVal({
start: prev(),
key: S.token.value,
value: value,
end: value.end,
}));
}
next(); next();
} else if (is("punc", "}")) { } else if (is("punc", "}")) {
continue; // Allow trailing hole continue; // Allow trailing hole
@@ -1589,7 +1604,12 @@ function parse($TEXT, options) {
})); }));
} }
} }
if (is("operator", "=")) { if (is_expand) {
if (!is("punc", "}")) {
croak("Rest element must be last element");
}
}
else if (is("operator", "=")) {
used_parameters.mark_default_assignment(S.token); used_parameters.mark_default_assignment(S.token);
next(); next();
elements[elements.length - 1].value = new AST_DefaultAssign({ elements[elements.length - 1].value = new AST_DefaultAssign({
@@ -2143,7 +2163,18 @@ function parse($TEXT, options) {
if (!options.strict && is("punc", "}")) if (!options.strict && is("punc", "}"))
// allow trailing comma // allow trailing comma
break; break;
start = S.token; start = S.token;
if (start.type == "expand") {
next();
a.push(new AST_Expansion({
start: start,
expression: expression(false),
end: prev(),
}));
continue;
}
var name = as_property_name(); var name = as_property_name();
var value; var value;

View File

@@ -203,6 +203,21 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|| node instanceof AST_SymbolLet || node instanceof AST_SymbolLet
|| node instanceof AST_SymbolConst) { || node instanceof AST_SymbolConst) {
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node); var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node);
if (!all(def.orig, function(sym) {
if (sym === node) return true;
if (node instanceof AST_SymbolBlockDeclaration) {
return sym instanceof AST_SymbolLambda;
}
return !(sym instanceof AST_SymbolLet || sym instanceof AST_SymbolConst);
})) {
js_error(
node.name + " redeclared",
node.start.file,
node.start.line,
node.start.col,
node.start.pos
);
}
if (!(node instanceof AST_SymbolFunarg)) mark_export(def, 2); if (!(node instanceof AST_SymbolFunarg)) mark_export(def, 2);
def.destructuring = in_destructuring; def.destructuring = in_destructuring;
if (defun !== scope) { if (defun !== scope) {
@@ -300,6 +315,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;
} }
})); }));
@@ -357,7 +373,7 @@ AST_IterationStatement.DEFMETHOD("is_block_scope", return_true);
AST_Lambda.DEFMETHOD("init_scope_vars", function(){ AST_Lambda.DEFMETHOD("init_scope_vars", function(){
AST_Scope.prototype.init_scope_vars.apply(this, arguments); AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false; this.uses_arguments = false;
this.def_variable(new AST_SymbolConst({ this.def_variable(new AST_SymbolFunarg({
name: "arguments", name: "arguments",
start: this.start, start: this.start,
end: this.end end: this.end

View File

@@ -4,7 +4,7 @@
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony", "homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"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.27", "version": "3.0.28",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },

View File

@@ -213,7 +213,7 @@ no_leading_parentheses: {
async_identifiers: { async_identifiers: {
options = { options = {
arrows: true, unsafe_arrows: true,
ecma: 6, ecma: 6,
} }
input: { input: {
@@ -237,7 +237,7 @@ async_identifiers: {
async_function_expression: { async_function_expression: {
options = { options = {
arrows: true, unsafe_arrows: true,
ecma: 6, ecma: 6,
evaluate: true, evaluate: true,
side_effects: true, side_effects: true,
@@ -262,7 +262,7 @@ async_function_expression: {
issue_27: { issue_27: {
options = { options = {
arrows: true, unsafe_arrows: true,
collapse_vars: true, collapse_vars: true,
ecma: 6, ecma: 6,
unused: true, unused: true,
@@ -283,7 +283,7 @@ issue_27: {
issue_2105_1: { issue_2105_1: {
options = { options = {
arrows: true, unsafe_arrows: true,
collapse_vars: true, collapse_vars: true,
ecma: 6, ecma: 6,
inline: true, inline: true,
@@ -501,7 +501,7 @@ issue_485_crashing_1530: {
issue_2084: { issue_2084: {
options = { options = {
arrows: true, unsafe_arrows: true,
collapse_vars: true, collapse_vars: true,
conditionals: true, conditionals: true,
ecma: 6, ecma: 6,
@@ -577,6 +577,7 @@ concise_methods_with_computed_property2: {
async_object_literal: { async_object_literal: {
options = { options = {
arrows: true, arrows: true,
unsafe_arrows: true,
ecma: 6, ecma: 6,
evaluate: true, evaluate: true,
} }
@@ -597,3 +598,35 @@ async_object_literal: {
}; };
} }
} }
issue_2271: {
options = {
arrows: true,
ecma: 6,
evaluate: true,
unsafe_arrows: false,
}
input: {
var Foo = function() {};
Foo.prototype.set = function(value) {
this.value = value;
return this;
}
Foo.prototype.print = function() {
console.log(this.value);
}
new Foo().set("PASS").print();
}
expect: {
var Foo = function() {};
Foo.prototype.set = function(value) {
this.value = value;
return this;
}
Foo.prototype.print = function() {
console.log(this.value);
}
new Foo().set("PASS").print();
}
expect_stdout: "PASS"
}

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

@@ -65,10 +65,10 @@ nested_destructuring_objects: {
} }
input: { input: {
const [{a},b] = c; const [{a},b] = c;
let [{a},b] = c; let [{d},e] = f;
var [{a},b] = c; var [{g},h] = i;
} }
expect_exact: 'const[{a},b]=c;let[{a},b]=c;var[{a},b]=c;'; expect_exact: 'const[{a},b]=c;let[{d},e]=f;var[{g},h]=i;';
} }
destructuring_constdef_in_loops: { destructuring_constdef_in_loops: {
@@ -274,8 +274,8 @@ reduce_vars: {
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}}; var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}}); ({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}});
const [{a},b] = c; const [{a},b] = c;
let [{a},b] = c; let [{d},e] = f;
var [{a},b] = c; var [{g},h] = i;
[{a},b] = c; [{a},b] = c;
for (const [x,y] in pairs); for (const [x,y] in pairs);
for (let [x,y] in pairs); for (let [x,y] in pairs);
@@ -292,8 +292,8 @@ reduce_vars: {
var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}}; var {aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}};
({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}}); ({aa, bb: {cc, dd}} = {aa:1, bb: {cc:2, dd: 3}});
const [{a},b] = c; const [{a},b] = c;
let [{a},b] = c; let [{d},e] = f;
var [{a},b] = c; var [{g},h] = i;
[{a},b] = c; [{a},b] = c;
for (const [x,y] in pairs); for (const [x,y] in pairs);
for (let [x,y] in pairs); for (let [x,y] in pairs);

View File

@@ -211,13 +211,13 @@ export_statement: {
} }
input: { input: {
export default 1 + 2; export default 1 + 2;
export var foo = 4; export var a = 4;
export let foo = 6; export let b = 6;
export const foo = 6; export const c = 6;
export function foo() {}; export function d() {};
export class foo { }; export class e {};
} }
expect_exact: "export default 3;export var foo=4;export let foo=6;export const foo=6;export function foo(){};export class foo{};" expect_exact: "export default 3;export var a=4;export let b=6;export const c=6;export function d(){};export class e{};"
} }
export_default_object_expression: { export_default_object_expression: {
@@ -695,3 +695,112 @@ export_default_class_decl: {
} }
expect_exact: "export default class Car{};export class Cab{};" expect_exact: "export default class Car{};export class Cab{};"
} }
object_rest_spread: {
mangle = {
toplevel: true,
}
input: {
var { w: w1, ...V } = { w: 7, x: 1, y: 2 }; console.log(w1, V);
let { w: w2, ...L } = { w: 8, x: 3, y: 4 }; console.log(w2, L);
const { w: w3, ...C } = { w: 9, x: 5, y: 6 }; console.log(w3, C);
let b;
({ b, ...V } = { a: 1, b: 2, c: 3 }); console.log(V);
({ b, ...L } = { a: 4, b: 5, c: 6 }); console.log(L);
(function({ y, ...p }){ console.log(p); })({ x: 1, y: 2, z: 3 });
(({ y, ...p }) => { console.log(p); })({ x: 4, y: 5, z: 6 });
const T = { a: 1, b: 2 }; console.log({ ...T, w: 0, ...{}, ...L, ...{K: 9} });
}
expect: {
var { w: o, ...l } = { w: 7, x: 1, y: 2 }; console.log(o, l);
let { w: c, ...n } = { w: 8, x: 3, y: 4 }; console.log(c, n);
const { w: e, ...s } = { w: 9, x: 5, y: 6 }; console.log(e, s);
let g;
({ b: g, ...l } = { a: 1, b: 2, c: 3 }); console.log(l);
({ b: g, ...n } = { a: 4, b: 5, c: 6 }); console.log(n);
(function({ y: o, ...l }) { console.log(l); })({ x: 1, y: 2, z: 3 });
(({ y: o, ...l }) => { console.log(l); })({ x: 4, y: 5, z: 6 });
const w = { a: 1, b: 2 }; console.log({ ...w, w: 0, ...{}, ...n, ...{ K: 9 } });
}
}
object_spread_unsafe: {
options = {
collapse_vars: true,
evaluate: true,
join_vars: true,
passes: 3,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
mangle = {
toplevel: true,
}
input: {
var o1 = { x: 1, y: 2 };
var o2 = { x: 3, z: 4 };
var cloned = { ...o1 };
var merged = { ...o1, ...o2 };
console.log(cloned, merged);
}
expect: {
var o = { x: 1, y: 2 }, l = { ...o }, x = { ...o, ...{ x: 3, z: 4 } };
console.log(l, x);
}
}
array_spread_of_sequence: {
mangle = {
toplevel: true,
}
input: {
var a = [1];
console.log([...(a, a)]);
console.log([...a, a]);
console.log([...(a || a)]);
console.log([...a || a]);
}
expect: {
var o = [1];
console.log([...(o, o)]);
console.log([...o, o]);
console.log([...o || o]);
console.log([...o || o]);
}
expect_stdout: [
"[ 1 ]",
"[ 1, [ 1 ] ]",
"[ 1 ]",
"[ 1 ]",
]
node_version: ">=6"
}
object_spread_of_sequence: {
mangle = {
toplevel: true,
}
input: {
var a = {x: 1};
console.log({ ...(a, a) });
console.log({ ...a, a });
console.log({ ...(a || a) });
console.log({ ...a || a });
}
expect: {
var o = { x: 1 };
console.log({ ...(o, o) });
console.log({ ...o, a: o });
console.log({ ...o || o });
console.log({ ...o || o });
}
}

View File

@@ -36,9 +36,10 @@ compress_new_function_with_destruct: {
compress_new_function_with_destruct_arrows: { compress_new_function_with_destruct_arrows: {
options = { options = {
arrows: true, arrows: true,
unsafe_arrows: true,
unsafe: true, unsafe: true,
unsafe_Func: true, unsafe_Func: true,
ecma: 6 ecma: 6,
} }
beautify = { beautify = {
ecma: 6 ecma: 6

View File

@@ -142,11 +142,11 @@ destructuring_arguments_3: {
} }
input: { input: {
function fn3({x: {y: {z: {} = 42}}}) {} function fn3({x: {y: {z: {} = 42}}}) {}
const { cover = (function () {}), xCover = (0, function() {}) } = {}; const { a = (function () {}), b = (0, function() {}) } = {};
let { cover = (function () {}), xCover = (0, function() {}) } = {}; let { c = (function () {}), d = (0, function() {}) } = {};
var { cover = (function () {}), xCover = (0, function() {}) } = {}; var { e = (function () {}), f = (0, function() {}) } = {};
} }
expect_exact: "function fn3({x:{y:{z:{}=42}}}){}const{cover=function(){},xCover=(0,function(){})}={};let{cover=function(){},xCover=(0,function(){})}={};var{cover=function(){},xCover=(0,function(){})}={};" expect_exact: "function fn3({x:{y:{z:{}=42}}}){}const{a=function(){},b=(0,function(){})}={};let{c=function(){},d=(0,function(){})}={};var{e=function(){},f=(0,function(){})}={};"
} }
default_arguments: { default_arguments: {

View File

@@ -385,3 +385,76 @@ set_mutable_2: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_2265_1: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
({ ...{} }).p;
({ ...g }).p;
}
expect: {
({ ...g }).p;
}
}
issue_2265_2: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = {
get b() {
throw 0;
}
};
({...a}).b;
}
expect: {
var a = {
get b() {
throw 0;
}
};
({...a}).b;
}
}
issue_2265_3: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = {
set b() {
throw 0;
}
};
({...a}).b;
}
expect: {}
}
issue_2265_4: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = { b: 1 };
({...a}).b;
}
expect: {}
}

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

@@ -253,13 +253,19 @@ describe("Left-hand side expressions", function () {
// Multiple spreads are not allowed in destructuring array // Multiple spreads are not allowed in destructuring array
expect("[...a, ...b] = [1, 2, 3, 4]", "Spread must the be last element in destructuring array"); expect("[...a, ...b] = [1, 2, 3, 4]", "Spread must the be last element in destructuring array");
// Spread in obvious object pattern // Array spread must be last in destructuring declaration
expect("({...a} = foo)", "Unexpected token: expand (...)"); expect("let [ ...x, a ] = o;", "Rest element must be last element");
// Only one spread per destructuring array declaration
expect("let [ a, ...x, ...y ] = o;", "Rest element must be last element");
// Spread in block should not be allowed // Spread in block should not be allowed
expect("{...a} = foo", "Unexpected token: expand (...)"); expect("{...a} = foo", "Unexpected token: expand (...)");
// Not in standard yet // Object spread must be last in destructuring declaration
expect("let foo = {bar: 42}, bar; bar = {...foo}", "Unexpected token: expand (...)"); expect("let { ...x, a } = o;", "Rest element must be last element");
// Only one spread per destructuring declaration
expect("let { a, ...x, ...y } = o;", "Rest element must be last element");
}); });
}); });

View File

@@ -291,4 +291,34 @@ describe("minify", function() {
assert.strictEqual(result.code, "alert({bar:42});"); assert.strictEqual(result.code, "alert({bar:42});");
}); });
}); });
describe("duplicated block-scoped declarations", function() {
[
"let a=1;let a=2;",
"let a=1;var a=2;",
"var a=1;let a=2;",
"let[a]=[1];var a=2;",
"let a=1;var[a]=[2];",
"let[a]=[1];var[a]=[2];",
"const a=1;const a=2;",
"const a=1;var a=2;",
"var a=1;const a=2;",
"const[a]=[1];var a=2;",
"const a=1;var[a]=[2];",
"const[a]=[1];var[a]=[2];",
].forEach(function(code) {
it(code, function() {
var result = Uglify.minify(code, {
compress: false,
mangle: false
});
assert.strictEqual(result.error, undefined);
assert.strictEqual(result.code, code);
result = Uglify.minify(code);
var err = result.error;
assert.ok(err instanceof Error);
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: a redeclared");
});
});
});
}); });

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,8 +75,8 @@ 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() { it("Should not unescape unpaired surrogates", function() {

View File

@@ -146,6 +146,7 @@ describe("Unicode", function() {
if (semver.satisfies(process.version, ">=4")) { if (semver.satisfies(process.version, ">=4")) {
it("Should not unescape unpaired surrogates", function() { it("Should not unescape unpaired surrogates", function() {
this.timeout(5000);
var code = []; var code = [];
for (var i = 0; i <= 0x20001; i++) { for (var i = 0; i <= 0x20001; i++) {
code.push("\\u{" + i.toString(16) + "}"); code.push("\\u{" + i.toString(16) + "}");