Compare commits

...

15 Commits

Author SHA1 Message Date
Alex Lam S.L
44352eb26a harmony-v3.1.5 2017-10-22 01:49:55 +08:00
alexlamsl
9f1c72ae28 update test
Sub-optimal result due to block scope.
2017-10-22 00:38:16 +08:00
alexlamsl
c60fa67827 Merge branch 'master' into harmony-v3.1.5 2017-10-22 00:35:00 +08:00
Alex Lam S.L
96439ca246 v3.1.5 2017-10-22 00:27:26 +08:00
Thomas Sauer
f9c57dfee0 Allow 'yield' as method name (#2382)
fixes #2381
2017-10-21 14:22:39 +08:00
Alex Lam S.L
c927cea632 unsafe fix-ups for #2351 (#2379) 2017-10-21 04:08:26 +08:00
Alex Lam S.L
9f4b98f8e4 backport #2374 (#2376) 2017-10-19 23:02:27 +08:00
Alex Lam S.L
0f2ef3367c enhance collapse_vars around lazy operations (#2369) 2017-10-19 04:52:00 +08:00
kzc
6bf5fea008 option formatting in docs (#2374)
- reintroduce compress documentation for keep_fnames and unsafe_methods
- reintroduce keep_fnames in mangle option docs
- order compress & mangle options
2017-10-18 05:23:53 +08:00
Alex Lam S.L
7e5b5cac97 fix AST_PropAccess in collapse_vars (take 3) (#2375)
Suppress scanning beyond assignment to `a.b`
2017-10-18 02:54:51 +08:00
Alex Lam S.L
c1346e06b7 clean up lazy operator detection (#2373) 2017-10-17 23:25:45 +08:00
Alex Lam S.L
0d2fe8e3ef fix AST_PropAccess in collapse_vars (take 2) (#2372)
fixes #2364
2017-10-17 22:59:15 +08:00
Alex Lam S.L
f2b9c11e2a fix AST_PropAccess in collapse_vars (#2370)
fixes #2364
2017-10-17 18:33:03 +08:00
Alex Lam S.L
b6a7ca292e deduplicate AST_Super & AST_This logic (#2366) 2017-10-17 04:19:53 +08:00
Alex Lam S.L
fe647b083e account for side-effects from AST_This in collapse_vars (#2365) 2017-10-17 01:18:55 +08:00
10 changed files with 598 additions and 82 deletions

View File

@@ -604,7 +604,7 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
## Compress options
- `arrows` (default `true`) -- Converts `()=>{return x}` to `()=>x`. Class
- `arrows` (default: `true`) -- Converts `()=>{return x}` to `()=>x`. Class
and object literal methods will also be converted to arrow expressions if
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.
@@ -622,8 +622,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
`!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
- `computed_props` -- default `true`. Transforms constant computed properties
into regular ones: `{["computed"]: 1}` is converted into `{computed: 1}`.
- `computed_props` (default: `true`) -- Transforms constant computed properties
into regular ones: `{["computed"]: 1}` is converted to `{computed: 1}`.
- `conditionals` (default: `true`) -- apply optimizations for `if`-s and conditional
expressions
@@ -637,7 +637,7 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `drop_debugger` (default: `true`) -- remove `debugger;` statements
- `ecma` -- default `5`. Pass `6` or greater to enable `compress` options that
- `ecma` (default: `5`) -- Pass `6` or greater to enable `compress` options that
will transform ES5 code into smaller ES6+ equivalent forms.
- `evaluate` (default: `true`) -- attempt to evaluate constant expressions
@@ -662,6 +662,10 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
compressor from discarding unused function arguments. You need this
for code which relies on `Function.length`.
- `keep_fnames` (default: `false`) -- Pass `true` to prevent the
compressor from discarding function names. Useful for code relying on
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
- `keep_infinity` (default: `false`) -- default `false`. Pass `true` to prevent `Infinity` from
being compressed into `1/0`, which may cause performance issues on Chrome.
@@ -726,7 +730,9 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
earlier versions due to known issues.
- `unsafe_arrows` (default `false`) -- Convert ES5 style anonymous function
- `unsafe` (default: `false`) -- apply "unsafe" transformations (discussion below)
- `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.
@@ -739,14 +745,19 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
comparison are switching. Compression only works if both `comparisons` and
`unsafe_comps` are both set to true.
- `unsafe` (default: `false`) -- apply "unsafe" transformations (discussion below)
- `unsafe_Func` (default: `false`) -- compress and mangle `Function(args, code)`
when both `args` and `code` are string literals.
- `unsafe_math` (default: `false`) -- optimize numerical expressions like
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
- `unsafe_methods` (default: false) -- Converts `{ m: function(){} }` to
`{ m(){} }`. `ecma` must be set to `6` or greater to enable this transform.
If `unsafe_methods` is a RegExp then key/value pairs with keys matching the
RegExp will be converted to concise methods.
Note: if enabled there is a risk of getting a "`<method name>` is not a
constructor" TypeError should any code try to `new` the former function.
- `unsafe_proto` (default: `false`) -- optimize expressions like
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
@@ -761,17 +772,21 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
## Mangle options
- `eval` (default `false`). Pass `true` to mangle names visible in scopes
where `eval` or `with` are used.
- `keep_classnames` (default `false`). Pass `true` to not mangle class names.
- `keep_fnames` (default `false`). Pass `true` to not mangle function names.
Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames`
[compress option](#compress-options).
- `reserved` (default `[]`). Pass an array of identifiers that should be
excluded from mangling. Example: `["foo", "bar"]`.
- `toplevel` (default `false`). Pass `true` to mangle names declared in the
top level scope.
- `eval` (default `false`). Pass `true` to mangle names visible in scopes
where `eval` or `with` are used.
- `safari10` (default `false`). Pass `true` to work around the Safari 10 loop
iterator [bug](https://bugs.webkit.org/show_bug.cgi?id=171041)
"Cannot declare a let variable twice".

View File

@@ -1042,7 +1042,7 @@ var AST_This = DEFNODE("This", null, {
var AST_Super = DEFNODE("Super", null, {
$documentation: "The `super` symbol",
}, AST_Symbol);
}, AST_This);
var AST_Constant = DEFNODE("Constant", null, {
$documentation: "Base class for all constants",

View File

@@ -157,7 +157,7 @@ merge(Compressor.prototype, {
var last_count = 1 / 0;
for (var pass = 0; pass < passes; pass++) {
if (pass > 0 || this.option("reduce_vars"))
node.reset_opt_flags(this, true);
node.reset_opt_flags(this);
node = node.transform(this);
if (passes > 1) {
var count = 0;
@@ -289,8 +289,9 @@ merge(Compressor.prototype, {
self.transform(tt);
});
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) {
var reduce_vars = rescan && compressor.option("reduce_vars");
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor) {
var reduce_vars = compressor.option("reduce_vars");
var unused = compressor.option("unused");
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
// properly assigned before use:
// - `push()` & `pop()` when visiting conditional branches
@@ -315,16 +316,31 @@ merge(Compressor.prototype, {
if (node instanceof AST_SymbolRef) {
var d = node.definition();
d.references.push(node);
if (d.fixed === undefined || !safe_to_read(d)
|| is_modified(node, 0, is_immutable(node))) {
if (d.fixed === undefined || !safe_to_read(d) || d.single_use == "m") {
d.fixed = false;
} else {
var parent = tw.parent();
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|| parent instanceof AST_Call && node !== parent.expression
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|| parent instanceof AST_VarDef && node === parent.value) {
d.escaped = true;
var value = node.fixed_value();
if (unused) {
d.single_use = value
&& d.references.length == 1
&& loop_ids[d.id] === in_loop
&& d.scope === node.scope
&& value.is_constant_expression();
}
if (is_modified(node, 0, is_immutable(value))) {
if (d.single_use) {
d.single_use = "m";
} else {
d.fixed = false;
}
} else {
var parent = tw.parent();
if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
|| parent instanceof AST_Call && node !== parent.expression
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|| parent instanceof AST_VarDef && node === parent.value) {
d.escaped = true;
}
}
}
}
@@ -419,8 +435,7 @@ merge(Compressor.prototype, {
pop();
return true;
}
if (node instanceof AST_Binary
&& (node.operator == "&&" || node.operator == "||")) {
if (node instanceof AST_Binary && lazy_op(node.operator)) {
node.left.walk(tw);
push();
node.right.walk(tw);
@@ -567,20 +582,8 @@ merge(Compressor.prototype, {
def.single_use = undefined;
}
function is_immutable(node) {
var value = node.fixed_value();
if (!value) return false;
if (value.is_constant()) return true;
if (compressor.option("unused")) {
var d = node.definition();
if (d.single_use === undefined) {
d.single_use = loop_ids[d.id] === in_loop
&& d.scope === node.scope
&& value.is_constant_expression();
}
if (d.references.length == 1 && d.single_use) return true;
}
return value instanceof AST_Lambda;
function is_immutable(value) {
return value && (value.is_constant() || value instanceof AST_Lambda);
}
function is_modified(node, level, immutable) {
@@ -610,7 +613,6 @@ merge(Compressor.prototype, {
}
function is_lhs_read_only(lhs) {
if (lhs instanceof AST_Super) return true;
if (lhs instanceof AST_This) return true;
if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
if (lhs instanceof AST_PropAccess) {
@@ -819,6 +821,7 @@ merge(Compressor.prototype, {
// Locate symbols which may execute code outside of scanning range
var lvalues = get_lvalues(candidate);
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
var one_off = lhs instanceof AST_Symbol && lhs.definition().references.length == 1;
var side_effects = value_has_side_effects(candidate);
var hit = candidate.name instanceof AST_SymbolFunarg;
var abort = false, replaced = false;
@@ -880,17 +883,18 @@ merge(Compressor.prototype, {
var sym;
if (node instanceof AST_Call
|| node instanceof AST_Exit
|| node instanceof AST_PropAccess && node.has_side_effects(compressor)
|| node instanceof AST_PropAccess
&& (side_effects || node.expression.may_throw_on_access(compressor))
|| node instanceof AST_SymbolRef
&& (lvalues[node.name]
|| side_effects && !references_in_scope(node.definition()))
|| (sym = lhs_or_def(node)) && get_symbol(sym).name in lvalues
|| parent instanceof AST_Binary
&& (parent.operator == "&&" || parent.operator == "||")
|| parent instanceof AST_Case
|| parent instanceof AST_Conditional
|| parent instanceof AST_For
|| parent instanceof AST_If) {
|| (sym = lhs_or_def(node))
&& (sym instanceof AST_PropAccess || sym.name in lvalues)
|| (side_effects || !one_off)
&& (parent instanceof AST_Binary && lazy_op(parent.operator)
|| parent instanceof AST_Case
|| parent instanceof AST_Conditional
|| parent instanceof AST_If)) {
if (!(node instanceof AST_Scope)) descend(node, tt);
abort = true;
return node;
@@ -1003,27 +1007,14 @@ merge(Compressor.prototype, {
}
}
function get_symbol(node) {
while (node instanceof AST_PropAccess) node = node.expression;
return node;
}
function get_lvalues(expr) {
var lvalues = Object.create(null);
if (expr instanceof AST_Unary) return lvalues;
var scope;
var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_Scope) {
var save_scope = scope;
descend();
scope = save_scope;
return true;
}
if (node instanceof AST_SymbolRef || node instanceof AST_PropAccess) {
var sym = get_symbol(node);
if (sym instanceof AST_SymbolRef) {
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
}
var sym = node;
while (sym instanceof AST_PropAccess) sym = sym.expression;
if (sym instanceof AST_SymbolRef || sym instanceof AST_This) {
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
}
});
expr[expr instanceof AST_Assign ? "right" : "value"].walk(tw);
@@ -1522,9 +1513,10 @@ merge(Compressor.prototype, {
return member(this.operator, unary_bool);
});
def(AST_Binary, function(){
return member(this.operator, binary_bool) ||
( (this.operator == "&&" || this.operator == "||") &&
this.left.is_boolean() && this.right.is_boolean() );
return member(this.operator, binary_bool)
|| lazy_op(this.operator)
&& this.left.is_boolean()
&& this.right.is_boolean();
});
def(AST_Conditional, function(){
return this.consequent.is_boolean() && this.alternative.is_boolean();
@@ -1596,6 +1588,7 @@ merge(Compressor.prototype, {
node.DEFMETHOD("is_string", func);
});
var lazy_op = makePredicate("&& ||");
var unary_side_effects = makePredicate("delete ++ --");
function is_lhs(node, parent) {
@@ -2143,7 +2136,6 @@ merge(Compressor.prototype, {
def(AST_EmptyStatement, return_false);
def(AST_Constant, return_false);
def(AST_Super, return_false);
def(AST_This, return_false);
def(AST_Call, function(compressor){
@@ -2838,7 +2830,6 @@ merge(Compressor.prototype, {
def(AST_Node, return_this);
def(AST_Constant, return_null);
def(AST_Super, return_null);
def(AST_This, return_null);
def(AST_Call, function(compressor, first_in_statement){
if (!this.is_expr_pure(compressor)) {
@@ -2864,14 +2855,12 @@ merge(Compressor.prototype, {
def(AST_Binary, function(compressor, first_in_statement){
var right = this.right.drop_side_effect_free(compressor);
if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
switch (this.operator) {
case "&&":
case "||":
if (lazy_op(this.operator)) {
if (right === this.right) return this;
var node = this.clone();
node.right = right;
return node;
default:
} else {
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement);
return make_sequence(this, [ left, right ]);
@@ -3795,7 +3784,7 @@ merge(Compressor.prototype, {
}
if (cdr instanceof AST_Binary && !(cdr instanceof AST_Assign)) {
if (cdr.left.is_constant()) {
if (cdr.operator == "||" || cdr.operator == "&&") {
if (lazy_op(cdr.operator)) {
expressions[++i] = expressions[j];
break;
}
@@ -4295,8 +4284,7 @@ merge(Compressor.prototype, {
// "x" + (y + "z")==> "x" + y + "z"
if (self.right instanceof AST_Binary
&& self.right.operator == self.operator
&& (self.operator == "&&"
|| self.operator == "||"
&& (lazy_op(self.operator)
|| (self.operator == "+"
&& (self.right.left.is_string(compressor)
|| (self.left.is_string(compressor)
@@ -4348,6 +4336,7 @@ merge(Compressor.prototype, {
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
}
if (compressor.option("unused")
&& fixed
&& d.references.length == 1
&& (d.single_use || is_func_expr(fixed)
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
@@ -4832,7 +4821,7 @@ merge(Compressor.prototype, {
var has_special_symbol = false;
self.walk(new TreeWalker(function(node) {
if (has_special_symbol) return true;
if (node instanceof AST_Super || node instanceof AST_This) {
if (node instanceof AST_This) {
has_special_symbol = true;
return true;
}

View File

@@ -1685,9 +1685,6 @@ function OutputStream(options) {
DEFPRINT(AST_Symbol, function (self, output) {
self._do_print(output);
});
DEFPRINT(AST_SymbolDeclaration, function(self, output){
self._do_print(output);
});
DEFPRINT(AST_Hole, noop);
DEFPRINT(AST_This, function(self, output){
output.print("this");

View File

@@ -2565,7 +2565,7 @@ function parse($TEXT, options) {
unexpected(tmp);
}
case "name":
if (tmp.value == "yield" && !is_token(peek(), "punc", ":")
if (tmp.value == "yield" && !is_token(peek(), "punc", ":") && !is_token(peek(), "punc", "(")
&& S.input.has_directive("use strict") && !is_in_generator()) {
token_error(tmp, "Unexpected yield identifier inside strict mode");
}

View File

@@ -4,7 +4,7 @@
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.1.4",
"version": "3.1.5",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -631,3 +631,31 @@ issue_2271: {
}
expect_stdout: "PASS"
}
concise_method_with_super: {
options = {
arrows: true,
}
input: {
var o = {
f: "FAIL",
g() {
return super.f;
}
}
Object.setPrototypeOf(o, { f: "PASS" });
console.log(o.g());
}
expect: {
var o = {
f: "FAIL",
g() {
return super.f;
}
}
Object.setPrototypeOf(o, { f: "PASS" });
console.log(o.g());
}
expect_stdout: "PASS"
node_version: ">=4"
}

View File

@@ -2874,3 +2874,419 @@ prop_side_effects_2: {
"2",
]
}
issue_2365: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
console.log(function(a) {
var b = a.f;
a.f++;
return b;
}({ f: 1 }));
console.log(function() {
var a = { f: 1 }, b = a.f;
a.f++;
return b;
}());
console.log({
f: 1,
g: function() {
var b = this.f;
this.f++;
return b;
}
}.g());
}
expect: {
console.log(function(a) {
var b = a.f;
a.f++;
return b;
}({ f: 1 }));
console.log(function() {
var a = { f: 1 }, b = a.f;
a.f++;
return b;
}());
console.log({
f: 1,
g: function() {
var b = this.f;
this.f++;
return b;
}
}.g());
}
expect_stdout: [
"1",
"1",
"1",
]
}
issue_2364_1: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
function inc(obj) {
return obj.count++;
}
function foo() {
var first = arguments[0];
var result = inc(first);
return foo.amount = first.count, result;
}
var data = {
count: 0,
};
var answer = foo(data);
console.log(foo.amount, answer);
}
expect: {
function inc(obj) {
return obj.count++;
}
function foo() {
var first = arguments[0];
var result = inc(first);
return foo.amount = first.count, result;
}
var data = {
count: 0
};
var answer = foo(data);
console.log(foo.amount, answer);
}
expect_stdout: "1 0"
}
issue_2364_2: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
function callValidate() {
var validate = compilation.validate;
var result = validate.apply(null, arguments);
return callValidate.errors = validate.errors, result;
}
}
expect: {
function callValidate() {
var validate = compilation.validate;
var result = validate.apply(null, arguments);
return callValidate.errors = validate.errors, result;
}
}
}
issue_2364_3: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
function inc(obj) {
return obj.count++;
}
function foo(bar) {
var result = inc(bar);
return foo.amount = bar.count, result;
}
var data = {
count: 0,
};
var answer = foo(data);
console.log(foo.amount, answer);
}
expect: {
function inc(obj) {
return obj.count++;
}
function foo(bar) {
var result = inc(bar);
return foo.amount = bar.count, result;
}
var data = {
count: 0,
};
var answer = foo(data);
console.log(foo.amount, answer);
}
expect_stdout: "1 0"
}
issue_2364_4: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
function inc(obj) {
return obj.count++;
}
function foo(bar, baz) {
var result = inc(bar);
return foo.amount = baz.count, result;
}
var data = {
count: 0,
};
var answer = foo(data, data);
console.log(foo.amount, answer);
}
expect: {
function inc(obj) {
return obj.count++;
}
function foo(bar, baz) {
var result = inc(bar);
return foo.amount = baz.count, result;
}
var data = {
count: 0,
};
var answer = foo(data, data);
console.log(foo.amount, answer);
}
expect_stdout: "1 0"
}
issue_2364_5: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: true,
properties: true,
reduce_vars: true,
unused: true,
}
input: {
function f0(o, a, h) {
var b = 3 - a;
var obj = o;
var seven = 7;
var prop = 'run';
var t = obj[prop](b)[seven] = h;
return t;
}
}
expect: {
function f0(o, a, h) {
return o.run(3 - a)[7] = h;
}
}
}
issue_2364_6: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
function f(a, b) {
var c = a.p;
b.p = "FAIL";
return c;
}
var o = {
p: "PASS"
}
console.log(f(o, o));
}
expect: {
function f(a, b) {
var c = a.p;
b.p = "FAIL";
return c;
}
var o = {
p: "PASS"
}
console.log(f(o, o));
}
expect_stdout: "PASS"
}
issue_2364_7: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
function f(a, b) {
var c = a.p;
b.f();
return c;
}
var o = {
p: "PASS",
f: function() {
this.p = "FAIL";
}
}
console.log(f(o, o));
}
expect: {
function f(a, b) {
var c = a.p;
b.f();
return c;
}
var o = {
p: "PASS",
f: function() {
this.p = "FAIL";
}
}
console.log(f(o, o));
}
expect_stdout: "PASS"
}
issue_2364_8: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
function f(a, b, c) {
var d = a[b.f = function() {
return "PASS";
}];
return c.f(d);
}
var o = {
f: function() {
return "FAIL";
}
};
console.log(f({}, o, o));
}
expect: {
function f(a, b, c) {
var d = a[b.f = function() {
return "PASS";
}];
return c.f(d);
}
var o = {
f: function() {
return "FAIL";
}
};
console.log(f({}, o, o));
}
expect_stdout: "PASS"
}
issue_2364_9: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
function f(a, b) {
var d = a();
return b.f(d);
}
var o = {
f: function() {
return "FAIL";
}
};
console.log(f(function() {
o.f = function() {
return "PASS";
};
}, o));
}
expect: {
function f(a, b) {
var d = a();
return b.f(d);
}
var o = {
f: function() {
return "FAIL";
}
};
console.log(f(function() {
o.f = function() {
return "PASS";
};
}, o));
}
expect_stdout: "PASS"
}
pure_getters_chain: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
function o(t, r) {
var a = t[1], s = t[2], o = t[3], i = t[5];
return a <= 23 && s <= 59 && o <= 59 && (!r || i);
}
console.log(o([ , 23, 59, 59, , 42], 1));
}
expect: {
function o(t, r) {
return t[1] <= 23 && t[2] <= 59 && t[3] <= 59 && (!r || t[5]);
}
console.log(o([ , 23, 59, 59, , 42], 1));
}
expect_stdout: "42"
}
conditional_1: {
options = {
collapse_vars: true,
}
input: {
function f(a, b) {
var c = "";
var d = b ? ">" : "<";
if (a) c += "=";
return c += d;
}
console.log(f(0, 0), f(0, 1), f(1, 0), f(1, 1));
}
expect: {
function f(a, b) {
var c = "";
if (a) c += "=";
return c += b ? ">" : "<";
}
console.log(f(0, 0), f(0, 1), f(1, 0), f(1, 1));
}
expect_stdout: "< > =< =>"
}
conditional_2: {
options = {
collapse_vars: true,
}
input: {
function f(a, b) {
var c = a + 1, d = a + 2;
return b ? c : d;
}
console.log(f(3, 0), f(4, 1));
}
expect: {
function f(a, b) {
return b ? a + 1 : a + 2;
}
console.log(f(3, 0), f(4, 1));
}
expect_stdout: "5 5"
}

View File

@@ -3051,3 +3051,63 @@ array_forof_2: {
expect_stdout: "3"
node_version: ">=0.12"
}
const_expr_1: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2
};
o.a++;
console.log(o.a, o.b);
}
expect: {
var o = {
a: 1,
b: 2
};
o.a++;
console.log(o.a, o.b);
}
expect_stdout: "2 2"
}
const_expr_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
Object.prototype.c = function() {
this.a++;
};
var o = {
a: 1,
b: 2
};
o.c();
console.log(o.a, o.b);
}
expect: {
Object.prototype.c = function() {
this.a++;
};
var o = {
a: 1,
b: 2
};
o.c();
console.log(o.a, o.b);
}
expect_stdout: "2 2"
}

View File

@@ -102,4 +102,15 @@ describe("Yield", function() {
assert.throws(test(tests[i]), fail, tests[i]);
}
});
it("Should allow yield to be used as class/object property name", function() {
var input = [
'"use strict";',
"({yield:42});",
"({yield(){}});",
"(class{yield(){}});",
"class C{yield(){}}",
].join("");
assert.strictEqual(UglifyJS.minify(input, { compress: false }).code, input);
});
});