Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8d10b7cde | ||
|
|
7caab39e26 | ||
|
|
eff45eac0e | ||
|
|
1e787c556b | ||
|
|
df47632ecc | ||
|
|
eb08fed120 | ||
|
|
8b0c836515 | ||
|
|
5d4e6e3bdc | ||
|
|
d2a45ba441 | ||
|
|
de376c3d33 | ||
|
|
4a19575e74 | ||
|
|
e0695ef549 | ||
|
|
d6152e6a76 | ||
|
|
d930c705f6 | ||
|
|
254937754c | ||
|
|
ae4dbcb5b9 | ||
|
|
e13615549e | ||
|
|
a7698f8845 | ||
|
|
bbed9b13b1 | ||
|
|
2cff7c94e8 | ||
|
|
7576048118 | ||
|
|
3c1898fd65 | ||
|
|
e04429350f | ||
|
|
60f3b55156 | ||
|
|
689f8f504d | ||
|
|
ae51f76ba7 | ||
|
|
7eef86ed05 | ||
|
|
b1cfa71131 |
2
.github/workflows/ufuzz.yml
vendored
2
.github/workflows/ufuzz.yml
vendored
@@ -2,7 +2,7 @@ name: Fuzzing
|
|||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '*/5 * * * *'
|
- cron: '*/15 * * * *'
|
||||||
env:
|
env:
|
||||||
BASE_URL: https://api.github.com/repos/${{ github.repository }}
|
BASE_URL: https://api.github.com/repos/${{ github.repository }}
|
||||||
CAUSE: ${{ github.event_name }}
|
CAUSE: ${{ github.event_name }}
|
||||||
|
|||||||
27
README.md
27
README.md
@@ -1327,3 +1327,30 @@ To allow for better optimizations, the compiler makes various assumptions:
|
|||||||
// SyntaxError: The left-hand side of a for-of loop may not be 'async'.
|
// SyntaxError: The left-hand side of a for-of loop may not be 'async'.
|
||||||
```
|
```
|
||||||
UglifyJS may modify the input which in turn may suppress those errors.
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
- Later versions of Chrome and Node.js will give incorrect results with the
|
||||||
|
following:
|
||||||
|
```javascript
|
||||||
|
console.log({
|
||||||
|
...console,
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
[42]: "PASS",
|
||||||
|
}[42]);
|
||||||
|
// Expected: "PASS"
|
||||||
|
// Actual: "FAIL"
|
||||||
|
```
|
||||||
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
- Earlier versions of JavaScript will throw `TypeError` with the following:
|
||||||
|
```javascript
|
||||||
|
(function() {
|
||||||
|
{
|
||||||
|
const a = "foo";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const a = "bar";
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
// TypeError: const 'a' has already been declared
|
||||||
|
```
|
||||||
|
UglifyJS may modify the input which in turn may suppress those errors.
|
||||||
|
|||||||
@@ -1692,7 +1692,7 @@ var AST_ObjectMethod = DEFNODE("ObjectMethod", null, {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (!(this.value instanceof AST_LambdaExpression)) throw new Error("value must be AST_LambdaExpression");
|
if (!(this.value instanceof AST_LambdaExpression)) throw new Error("value must be AST_LambdaExpression");
|
||||||
if (is_arrow(this.value)) throw new Error("value cannot be AST_Arrow or AST_AsyncArrow");
|
if (is_arrow(this.value)) throw new Error("value cannot be AST_Arrow or AST_AsyncArrow");
|
||||||
if (this.value.name != null) throw new Error("name of class method's lambda must be null");
|
if (this.value.name != null) throw new Error("name of object method's lambda must be null");
|
||||||
},
|
},
|
||||||
}, AST_ObjectKeyVal);
|
}, AST_ObjectKeyVal);
|
||||||
|
|
||||||
|
|||||||
228
lib/compress.js
228
lib/compress.js
@@ -136,11 +136,23 @@ function Compressor(options, false_by_default) {
|
|||||||
this.pure_funcs = pure_funcs;
|
this.pure_funcs = pure_funcs;
|
||||||
} else if (typeof pure_funcs == "string") {
|
} else if (typeof pure_funcs == "string") {
|
||||||
this.pure_funcs = function(node) {
|
this.pure_funcs = function(node) {
|
||||||
return pure_funcs !== node.expression.print_to_string();
|
var expr;
|
||||||
|
if (node instanceof AST_Call) {
|
||||||
|
expr = node.expression;
|
||||||
|
} else if (node instanceof AST_Template) {
|
||||||
|
expr = node.tag;
|
||||||
|
}
|
||||||
|
return !(expr && pure_funcs === expr.print_to_string());
|
||||||
};
|
};
|
||||||
} else if (Array.isArray(pure_funcs)) {
|
} else if (Array.isArray(pure_funcs)) {
|
||||||
this.pure_funcs = function(node) {
|
this.pure_funcs = function(node) {
|
||||||
return !member(node.expression.print_to_string(), pure_funcs);
|
var expr;
|
||||||
|
if (node instanceof AST_Call) {
|
||||||
|
expr = node.expression;
|
||||||
|
} else if (node instanceof AST_Template) {
|
||||||
|
expr = node.tag;
|
||||||
|
}
|
||||||
|
return !(expr && member(expr.print_to_string(), pure_funcs));
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
this.pure_funcs = return_true;
|
this.pure_funcs = return_true;
|
||||||
@@ -568,9 +580,12 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function safe_to_assign(tw, def, declare) {
|
function safe_to_assign(tw, def, declare) {
|
||||||
if (!(declare || all(def.orig, function(sym) {
|
if (!declare) {
|
||||||
|
if (is_funarg(def) && def.scope.uses_arguments && !tw.has_directive("use strict")) return false;
|
||||||
|
if (!all(def.orig, function(sym) {
|
||||||
return !(sym instanceof AST_SymbolConst);
|
return !(sym instanceof AST_SymbolConst);
|
||||||
}))) return false;
|
})) return false;
|
||||||
|
}
|
||||||
if (def.fixed === undefined) return declare || all(def.orig, function(sym) {
|
if (def.fixed === undefined) return declare || all(def.orig, function(sym) {
|
||||||
return !(sym instanceof AST_SymbolLet);
|
return !(sym instanceof AST_SymbolLet);
|
||||||
});
|
});
|
||||||
@@ -1143,7 +1158,7 @@ merge(Compressor.prototype, {
|
|||||||
var parent = tw.parent();
|
var parent = tw.parent();
|
||||||
if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false;
|
if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false;
|
||||||
if (tw.defun_visited[def.id]) return true;
|
if (tw.defun_visited[def.id]) return true;
|
||||||
if (tw.defun_ids[def.id] !== tw.safe_ids) return true;
|
if (def.init === fn && tw.defun_ids[def.id] !== tw.safe_ids) return true;
|
||||||
tw.defun_visited[def.id] = true;
|
tw.defun_visited[def.id] = true;
|
||||||
fn.inlined = false;
|
fn.inlined = false;
|
||||||
push(tw);
|
push(tw);
|
||||||
@@ -1194,11 +1209,20 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_SymbolRef, function(tw, descend, compressor) {
|
def(AST_SymbolRef, function(tw, descend, compressor) {
|
||||||
var d = this.definition();
|
var d = this.definition();
|
||||||
push_ref(d, this);
|
push_ref(d, this);
|
||||||
if (d.references.length == 1
|
if (d.references.length == 1 && !d.fixed && d.orig[0] instanceof AST_SymbolDefun) {
|
||||||
&& !d.fixed
|
|
||||||
&& d.orig[0] instanceof AST_SymbolDefun) {
|
|
||||||
tw.loop_ids[d.id] = tw.in_loop;
|
tw.loop_ids[d.id] = tw.in_loop;
|
||||||
}
|
}
|
||||||
|
var recursive = recursive_ref(tw, d);
|
||||||
|
if (recursive) recursive.enclosed.forEach(function(def) {
|
||||||
|
if (d === def) return;
|
||||||
|
if (def.scope === recursive) return;
|
||||||
|
var assigns = def.fixed && def.fixed.assigns;
|
||||||
|
if (!assigns) return;
|
||||||
|
if (assigns[assigns.length - 1] instanceof AST_VarDef) return;
|
||||||
|
var safe = tw.safe_ids[def.id];
|
||||||
|
if (!safe) return;
|
||||||
|
safe.assign = true;
|
||||||
|
});
|
||||||
if (d.fixed === false) {
|
if (d.fixed === false) {
|
||||||
var redef = d.redefined();
|
var redef = d.redefined();
|
||||||
if (redef && cross_scope(d.scope, this.scope)) redef.single_use = false;
|
if (redef && cross_scope(d.scope, this.scope)) redef.single_use = false;
|
||||||
@@ -1207,7 +1231,6 @@ merge(Compressor.prototype, {
|
|||||||
} else if (d.fixed) {
|
} else if (d.fixed) {
|
||||||
if (this.in_arg && d.orig[0] instanceof AST_SymbolLambda) this.fixed = d.scope;
|
if (this.in_arg && d.orig[0] instanceof AST_SymbolLambda) this.fixed = d.scope;
|
||||||
var value = this.fixed_value();
|
var value = this.fixed_value();
|
||||||
var recursive = recursive_ref(tw, d);
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
d.recursive_refs++;
|
d.recursive_refs++;
|
||||||
} else if (value && ref_once(compressor, d)) {
|
} else if (value && ref_once(compressor, d)) {
|
||||||
@@ -1228,9 +1251,7 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (d.fixed && tw.loop_ids[d.id] !== tw.in_loop) {
|
if (d.fixed && tw.loop_ids[d.id] !== tw.in_loop) d.cross_loop = true;
|
||||||
d.cross_loop = true;
|
|
||||||
}
|
|
||||||
mark_escaped(tw, d, this.scope, this, value, 0, 1);
|
mark_escaped(tw, d, this.scope, this, value, 0, 1);
|
||||||
}
|
}
|
||||||
if (!this.fixed) this.fixed = d.fixed;
|
if (!this.fixed) this.fixed = d.fixed;
|
||||||
@@ -1905,7 +1926,8 @@ merge(Compressor.prototype, {
|
|||||||
if (!--replaced) abort = true;
|
if (!--replaced) abort = true;
|
||||||
if (is_lhs(node, multi_replacer.parent())) return node;
|
if (is_lhs(node, multi_replacer.parent())) return node;
|
||||||
var ref = rvalue.clone();
|
var ref = rvalue.clone();
|
||||||
value_def.references.push(ref);
|
ref.scope = node.scope;
|
||||||
|
ref.reference();
|
||||||
if (replaced == assign_pos) {
|
if (replaced == assign_pos) {
|
||||||
abort = true;
|
abort = true;
|
||||||
return make_node(AST_Assign, candidate, {
|
return make_node(AST_Assign, candidate, {
|
||||||
@@ -1982,6 +2004,7 @@ merge(Compressor.prototype, {
|
|||||||
force_single = true;
|
force_single = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (replaced == assign_pos) assign_used = true;
|
||||||
var def = lhs.definition();
|
var def = lhs.definition();
|
||||||
abort = false;
|
abort = false;
|
||||||
hit_index = 0;
|
hit_index = 0;
|
||||||
@@ -2107,7 +2130,7 @@ merge(Compressor.prototype, {
|
|||||||
def = fn.definition();
|
def = fn.definition();
|
||||||
fn = fn.fixed_value();
|
fn = fn.fixed_value();
|
||||||
}
|
}
|
||||||
if (!(fn instanceof AST_Lambda)) return true;
|
if (!(fn instanceof AST_Lambda)) return !node.is_expr_pure(compressor);
|
||||||
if (def && recursive_ref(compressor, def)) return true;
|
if (def && recursive_ref(compressor, def)) return true;
|
||||||
if (fn.collapse_scanning) return false;
|
if (fn.collapse_scanning) return false;
|
||||||
fn.collapse_scanning = true;
|
fn.collapse_scanning = true;
|
||||||
@@ -2167,7 +2190,7 @@ merge(Compressor.prototype, {
|
|||||||
var def = node.definition();
|
var def = node.definition();
|
||||||
return (in_try || def.scope.resolve() !== scope) && !can_drop_symbol(node);
|
return (in_try || def.scope.resolve() !== scope) && !can_drop_symbol(node);
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Template) return node.tag && !is_raw_tag(compressor, node.tag);
|
if (node instanceof AST_Template) return !node.is_expr_pure(compressor);
|
||||||
if (node instanceof AST_VarDef) {
|
if (node instanceof AST_VarDef) {
|
||||||
if (check_destructured(node.name)) return true;
|
if (check_destructured(node.name)) return true;
|
||||||
return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) {
|
return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) {
|
||||||
@@ -3775,7 +3798,8 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Null, return_true);
|
def(AST_Null, return_true);
|
||||||
def(AST_Object, function(compressor, force) {
|
def(AST_Object, function(compressor, force) {
|
||||||
return is_strict(compressor, force) && !all(this.properties, function(prop) {
|
return is_strict(compressor, force) && !all(this.properties, function(prop) {
|
||||||
return prop instanceof AST_ObjectKeyVal;
|
if (!(prop instanceof AST_ObjectKeyVal)) return false;
|
||||||
|
return !(prop.key == "__proto__" && prop.value._dot_throw(compressor, force));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
def(AST_ObjectIdentity, function(compressor, force) {
|
def(AST_ObjectIdentity, function(compressor, force) {
|
||||||
@@ -4266,6 +4290,7 @@ merge(Compressor.prototype, {
|
|||||||
],
|
],
|
||||||
String: [
|
String: [
|
||||||
"fromCharCode",
|
"fromCharCode",
|
||||||
|
"raw",
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -4899,6 +4924,19 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return compressor.option("annotations") && this.pure || !compressor.pure_funcs(this);
|
return compressor.option("annotations") && this.pure || !compressor.pure_funcs(this);
|
||||||
});
|
});
|
||||||
|
AST_Template.DEFMETHOD("is_expr_pure", function(compressor) {
|
||||||
|
var tag = this.tag;
|
||||||
|
if (!tag) return true;
|
||||||
|
if (compressor.option("unsafe")) {
|
||||||
|
if (is_undeclared_ref(tag) && global_pure_fns[tag.name]) return true;
|
||||||
|
if (tag instanceof AST_Dot && is_undeclared_ref(tag.expression)) {
|
||||||
|
var static_fn = static_fns[tag.expression.name];
|
||||||
|
return static_fn && (static_fn[tag.property]
|
||||||
|
|| tag.expression.name == "Math" && tag.property == "random");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !compressor.pure_funcs(this);
|
||||||
|
});
|
||||||
AST_Node.DEFMETHOD("is_call_pure", return_false);
|
AST_Node.DEFMETHOD("is_call_pure", return_false);
|
||||||
AST_Call.DEFMETHOD("is_call_pure", function(compressor) {
|
AST_Call.DEFMETHOD("is_call_pure", function(compressor) {
|
||||||
if (!compressor.option("unsafe")) return false;
|
if (!compressor.option("unsafe")) return false;
|
||||||
@@ -5063,7 +5101,7 @@ merge(Compressor.prototype, {
|
|||||||
return !this.is_declared(compressor) || !can_drop_symbol(this, compressor);
|
return !this.is_declared(compressor) || !can_drop_symbol(this, compressor);
|
||||||
});
|
});
|
||||||
def(AST_Template, function(compressor) {
|
def(AST_Template, function(compressor) {
|
||||||
return this.tag && !is_raw_tag(compressor, this.tag) || any(this.expressions, compressor);
|
return !this.is_expr_pure(compressor) || any(this.expressions, compressor);
|
||||||
});
|
});
|
||||||
def(AST_Try, function(compressor) {
|
def(AST_Try, function(compressor) {
|
||||||
return any(this.body, compressor)
|
return any(this.body, compressor)
|
||||||
@@ -5243,7 +5281,7 @@ merge(Compressor.prototype, {
|
|||||||
if (member(def.scope, scopes)) return true;
|
if (member(def.scope, scopes)) return true;
|
||||||
if (scope && !def.redefined()) {
|
if (scope && !def.redefined()) {
|
||||||
var scope_def = scope.find_variable(node.name);
|
var scope_def = scope.find_variable(node.name);
|
||||||
if (def.undeclared ? !scope_def : scope_def === def) {
|
if (scope_def ? scope_def === def : def.undeclared) {
|
||||||
result = "f";
|
result = "f";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -5751,7 +5789,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!tail_refs) continue;
|
if (!tail_refs) continue;
|
||||||
if (head_refs.start.block !== tail_refs.start.block
|
if (head_refs.start.block !== tail_refs.start.block
|
||||||
|| !mergeable(head_refs, tail_refs)
|
|| !mergeable(head_refs, tail_refs)
|
||||||
|| head_refs.start.loop && !mergeable(tail_refs, head_refs)
|
|| (head_refs.start.loop || !same_scope(def)) && !mergeable(tail_refs, head_refs)
|
||||||
|| !all(tail_refs, function(sym) {
|
|| !all(tail_refs, function(sym) {
|
||||||
return sym.scope.find_variable(def.name) === def;
|
return sym.scope.find_variable(def.name) === def;
|
||||||
})) {
|
})) {
|
||||||
@@ -6057,7 +6095,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!side_effects) {
|
if (!side_effects) {
|
||||||
initializations.add(def.id, value);
|
initializations.add(def.id, value);
|
||||||
} else if (shared) {
|
} else if (shared) {
|
||||||
verify_safe_usage(def, true, value_modified[def.id]);
|
verify_safe_usage(def, name, value_modified[def.id]);
|
||||||
}
|
}
|
||||||
assignments.add(def.id, defn);
|
assignments.add(def.id, defn);
|
||||||
}
|
}
|
||||||
@@ -6092,6 +6130,30 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
tw.directives = Object.create(compressor.directives);
|
tw.directives = Object.create(compressor.directives);
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
var drop_fn_name = compressor.option("keep_fnames") ? return_false : compressor.option("ie8") ? function(def) {
|
||||||
|
return !compressor.exposed(def) && def.references.length == def.replaced;
|
||||||
|
} : function(def) {
|
||||||
|
if (!(def.id in in_use_ids)) return true;
|
||||||
|
if (def.orig.length - def.eliminated < 2) return false;
|
||||||
|
// function argument will always overshadow its name
|
||||||
|
if (def.orig[1] instanceof AST_SymbolFunarg) return true;
|
||||||
|
// retain if referenced within destructured object of argument
|
||||||
|
return all(def.references, function(ref) {
|
||||||
|
return !ref.in_arg;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (compressor.option("ie8")) initializations.each(function(init, id) {
|
||||||
|
if (id in in_use_ids) return;
|
||||||
|
init.forEach(function(init) {
|
||||||
|
init.walk(new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_Function && node.name && !drop_fn_name(node.name.definition())) {
|
||||||
|
node.walk(tw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Scope) return true;
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
// pass 2: for every used symbol we need to walk its
|
// pass 2: for every used symbol we need to walk its
|
||||||
// initialization code to figure out if it uses other
|
// initialization code to figure out if it uses other
|
||||||
// symbols (that may not be in_use).
|
// symbols (that may not be in_use).
|
||||||
@@ -6129,18 +6191,6 @@ merge(Compressor.prototype, {
|
|||||||
delete assign_in_use[id];
|
delete assign_in_use[id];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var drop_fn_name = compressor.option("keep_fnames") ? return_false : compressor.option("ie8") ? function(def) {
|
|
||||||
return !compressor.exposed(def) && def.references.length == def.replaced;
|
|
||||||
} : function(def) {
|
|
||||||
if (!(def.id in in_use_ids)) return true;
|
|
||||||
if (def.orig.length < 2) return false;
|
|
||||||
// function argument will always overshadow its name
|
|
||||||
if (def.orig[1] instanceof AST_SymbolFunarg) return true;
|
|
||||||
// retain if referenced within destructured object of argument
|
|
||||||
return all(def.references, function(ref) {
|
|
||||||
return !ref.in_arg;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// pass 3: we should drop declarations not in_use
|
// pass 3: we should drop declarations not in_use
|
||||||
var trim_defns = [];
|
var trim_defns = [];
|
||||||
var unused_fn_names = [];
|
var unused_fn_names = [];
|
||||||
@@ -6200,19 +6250,13 @@ merge(Compressor.prototype, {
|
|||||||
if (drop_vars) {
|
if (drop_vars) {
|
||||||
var props = [], sym = assign_as_unused(node, props);
|
var props = [], sym = assign_as_unused(node, props);
|
||||||
if (sym) {
|
if (sym) {
|
||||||
var def = sym.definition();
|
|
||||||
var in_use = def.id in in_use_ids;
|
|
||||||
var value;
|
var value;
|
||||||
|
if (can_drop_lhs(sym, node)) {
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
if (!in_use || node.left === sym && indexOf_assign(def, node) < 0) {
|
|
||||||
value = get_rhs(node);
|
value = get_rhs(node);
|
||||||
if (node.write_only === true) {
|
if (node.write_only === true) value = value.drop_side_effect_free(compressor);
|
||||||
value = value.drop_side_effect_free(compressor)
|
|
||||||
|| make_node(AST_Number, node, { value: 0 });
|
|
||||||
}
|
}
|
||||||
}
|
if (!value) value = make_node(AST_Number, node, { value: 0 });
|
||||||
} else if (!in_use || node.expression === sym && indexOf_assign(def, node) < 0) {
|
|
||||||
value = make_node(AST_Number, node, { value: 0 });
|
|
||||||
}
|
}
|
||||||
if (value) {
|
if (value) {
|
||||||
if (props.assign) {
|
if (props.assign) {
|
||||||
@@ -6705,7 +6749,7 @@ merge(Compressor.prototype, {
|
|||||||
function verify_safe_usage(def, read, modified) {
|
function verify_safe_usage(def, read, modified) {
|
||||||
if (def.id in in_use_ids) return;
|
if (def.id in in_use_ids) return;
|
||||||
if (read && modified) {
|
if (read && modified) {
|
||||||
in_use_ids[def.id] = true;
|
in_use_ids[def.id] = read;
|
||||||
in_use.push(def);
|
in_use.push(def);
|
||||||
} else {
|
} else {
|
||||||
value_read[def.id] = read;
|
value_read[def.id] = read;
|
||||||
@@ -6713,6 +6757,14 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function can_drop_lhs(sym, node) {
|
||||||
|
var def = sym.definition();
|
||||||
|
var in_use = in_use_ids[def.id];
|
||||||
|
if (!in_use) return true;
|
||||||
|
if (node[node instanceof AST_Assign ? "left" : "expression"] !== sym) return false;
|
||||||
|
return in_use === sym && def.references.length - def.replaced == 1 || indexOf_assign(def, node) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
function get_rhs(assign) {
|
function get_rhs(assign) {
|
||||||
var rhs = assign.right;
|
var rhs = assign.right;
|
||||||
if (!assign.write_only) return rhs;
|
if (!assign.write_only) return rhs;
|
||||||
@@ -6775,7 +6827,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node.left === sym) {
|
if (node.left === sym) {
|
||||||
if (!node.write_only || shared) {
|
if (!node.write_only || shared) {
|
||||||
verify_safe_usage(node_def, true, value_modified[node_def.id]);
|
verify_safe_usage(node_def, sym, value_modified[node_def.id]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var fixed = sym.fixed_value();
|
var fixed = sym.fixed_value();
|
||||||
@@ -7413,9 +7465,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (left.has_side_effects(compressor)) return this;
|
if (left.has_side_effects(compressor)) return this;
|
||||||
var right = this.right;
|
var right = this.right;
|
||||||
if (lazy_op[this.operator.slice(0, -1)]) {
|
if (!lazy_op[this.operator.slice(0, -1)]) {
|
||||||
this.write_only = !right.has_side_effects(compressor);
|
|
||||||
} else {
|
|
||||||
this.write_only = true;
|
this.write_only = true;
|
||||||
if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
|
if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) {
|
||||||
return right.drop_side_effect_free(compressor);
|
return right.drop_side_effect_free(compressor);
|
||||||
@@ -7464,27 +7514,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!rhs) return lhs;
|
if (!rhs) return lhs;
|
||||||
return make_sequence(this, [ lhs, rhs ]);
|
return make_sequence(this, [ lhs, rhs ]);
|
||||||
});
|
});
|
||||||
def(AST_Call, function(compressor, first_in_statement) {
|
function drop_returns(compressor, exp) {
|
||||||
var self = this;
|
|
||||||
if (self.is_expr_pure(compressor)) {
|
|
||||||
if (self.pure) AST_Node.warn("Dropping __PURE__ call [{file}:{line},{col}]", self.start);
|
|
||||||
var args = trim(self.args, compressor, first_in_statement, array_spread);
|
|
||||||
return args && make_sequence(self, args.map(convert_spread));
|
|
||||||
}
|
|
||||||
var exp = self.expression;
|
|
||||||
if (self.is_call_pure(compressor)) {
|
|
||||||
var exprs = self.args.slice();
|
|
||||||
exprs.unshift(exp.expression);
|
|
||||||
exprs = trim(exprs, compressor, first_in_statement, array_spread);
|
|
||||||
return exprs && make_sequence(self, exprs.map(convert_spread));
|
|
||||||
}
|
|
||||||
if (compressor.option("yields") && is_generator(exp)) {
|
|
||||||
var call = self.clone();
|
|
||||||
call.expression = make_node(AST_Function, exp, exp);
|
|
||||||
call.expression.body = [];
|
|
||||||
var opt = call.transform(compressor);
|
|
||||||
if (opt !== call) return opt.drop_side_effect_free(compressor, first_in_statement);
|
|
||||||
}
|
|
||||||
var drop_body = false;
|
var drop_body = false;
|
||||||
if (compressor.option("arrows") && is_arrow(exp)) {
|
if (compressor.option("arrows") && is_arrow(exp)) {
|
||||||
if (!exp.value) {
|
if (!exp.value) {
|
||||||
@@ -7518,6 +7548,31 @@ merge(Compressor.prototype, {
|
|||||||
node.value = value.drop_side_effect_free(compressor);
|
node.value = value.drop_side_effect_free(compressor);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
return drop_body;
|
||||||
|
}
|
||||||
|
def(AST_Call, function(compressor, first_in_statement) {
|
||||||
|
var self = this;
|
||||||
|
if (self.is_expr_pure(compressor)) {
|
||||||
|
if (self.pure) AST_Node.warn("Dropping __PURE__ call [{file}:{line},{col}]", self.start);
|
||||||
|
var args = trim(self.args, compressor, first_in_statement, array_spread);
|
||||||
|
return args && make_sequence(self, args.map(convert_spread));
|
||||||
|
}
|
||||||
|
var exp = self.expression;
|
||||||
|
if (self.is_call_pure(compressor)) {
|
||||||
|
var exprs = self.args.slice();
|
||||||
|
exprs.unshift(exp.expression);
|
||||||
|
exprs = trim(exprs, compressor, first_in_statement, array_spread);
|
||||||
|
return exprs && make_sequence(self, exprs.map(convert_spread));
|
||||||
|
}
|
||||||
|
if (compressor.option("yields") && is_generator(exp)) {
|
||||||
|
var call = self.clone();
|
||||||
|
call.expression = make_node(AST_Function, exp, exp);
|
||||||
|
call.expression.body = [];
|
||||||
|
var opt = call.transform(compressor);
|
||||||
|
if (opt !== call) return opt.drop_side_effect_free(compressor, first_in_statement);
|
||||||
|
}
|
||||||
|
if (drop_returns(compressor, exp)) {
|
||||||
// always shallow clone to ensure stripping of negated IIFEs
|
// always shallow clone to ensure stripping of negated IIFEs
|
||||||
self = self.clone();
|
self = self.clone();
|
||||||
self.expression = exp.clone();
|
self.expression = exp.clone();
|
||||||
@@ -7582,7 +7637,6 @@ merge(Compressor.prototype, {
|
|||||||
}).init_vars(node),
|
}).init_vars(node),
|
||||||
}));
|
}));
|
||||||
exprs = [ node ];
|
exprs = [ node ];
|
||||||
|
|
||||||
}
|
}
|
||||||
if (values) exprs.push(make_node(AST_Call, this, {
|
if (values) exprs.push(make_node(AST_Call, this, {
|
||||||
expression: make_node(AST_Arrow, this, {
|
expression: make_node(AST_Arrow, this, {
|
||||||
@@ -7713,10 +7767,21 @@ merge(Compressor.prototype, {
|
|||||||
return this.is_declared(compressor) && can_drop_symbol(this, compressor) ? null : this;
|
return this.is_declared(compressor) && can_drop_symbol(this, compressor) ? null : this;
|
||||||
});
|
});
|
||||||
def(AST_Template, function(compressor, first_in_statement) {
|
def(AST_Template, function(compressor, first_in_statement) {
|
||||||
if (this.tag && !is_raw_tag(compressor, this.tag)) return this;
|
var self = this;
|
||||||
var expressions = this.expressions;
|
if (self.is_expr_pure(compressor)) {
|
||||||
|
var expressions = self.expressions;
|
||||||
if (expressions.length == 0) return null;
|
if (expressions.length == 0) return null;
|
||||||
return make_sequence(this, expressions).drop_side_effect_free(compressor, first_in_statement);
|
return make_sequence(self, expressions).drop_side_effect_free(compressor, first_in_statement);
|
||||||
|
}
|
||||||
|
var tag = self.tag;
|
||||||
|
if (drop_returns(compressor, tag)) {
|
||||||
|
// always shallow clone to signal internal changes
|
||||||
|
self = self.clone();
|
||||||
|
self.tag = tag.clone();
|
||||||
|
// avoid extraneous traversal
|
||||||
|
if (tag._squeezed) self.tag._squeezed = true;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
});
|
});
|
||||||
def(AST_Unary, function(compressor, first_in_statement) {
|
def(AST_Unary, function(compressor, first_in_statement) {
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
@@ -8538,8 +8603,10 @@ merge(Compressor.prototype, {
|
|||||||
if (def.scope === scope) return;
|
if (def.scope === scope) return;
|
||||||
def.scope = scope;
|
def.scope = scope;
|
||||||
scope.variables.set(def.name, def);
|
scope.variables.set(def.name, def);
|
||||||
|
scope.enclosed.push(def);
|
||||||
|
scope.var_names()[def.name] = true;
|
||||||
}),
|
}),
|
||||||
value: defn.value
|
value: defn.value,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -10660,6 +10727,14 @@ merge(Compressor.prototype, {
|
|||||||
lambda_def.recursive_refs = def.recursive_refs;
|
lambda_def.recursive_refs = def.recursive_refs;
|
||||||
}
|
}
|
||||||
value.walk(new TreeWalker(function(node) {
|
value.walk(new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_SymbolDeclaration) {
|
||||||
|
if (node !== name) {
|
||||||
|
var def = node.definition();
|
||||||
|
def.orig.push(node);
|
||||||
|
def.eliminated++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!(node instanceof AST_SymbolRef)) return;
|
if (!(node instanceof AST_SymbolRef)) return;
|
||||||
var def = node.definition();
|
var def = node.definition();
|
||||||
if (def === defun_def) {
|
if (def === defun_def) {
|
||||||
@@ -10766,7 +10841,8 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
OPT(AST_Template, function(self, compressor) {
|
OPT(AST_Template, function(self, compressor) {
|
||||||
if (!compressor.option("templates")) return self;
|
if (!compressor.option("templates")) return self;
|
||||||
if (!self.tag || is_raw_tag(compressor, self.tag)) {
|
var tag = self.tag;
|
||||||
|
if (!tag || is_raw_tag(compressor, tag)) {
|
||||||
var exprs = self.expressions.slice();
|
var exprs = self.expressions.slice();
|
||||||
var strs = self.strings.slice();
|
var strs = self.strings.slice();
|
||||||
var CHANGED = false;
|
var CHANGED = false;
|
||||||
@@ -10774,6 +10850,7 @@ merge(Compressor.prototype, {
|
|||||||
var node = exprs[i];
|
var node = exprs[i];
|
||||||
var ev = node.evaluate(compressor);
|
var ev = node.evaluate(compressor);
|
||||||
if (ev === node) continue;
|
if (ev === node) continue;
|
||||||
|
if (tag && /\r|\\|`/.test(ev)) continue;
|
||||||
ev = ("" + ev).replace(/\r|\\|`/g, function(s) {
|
ev = ("" + ev).replace(/\r|\\|`/g, function(s) {
|
||||||
return "\\" + (s == "\r" ? "r" : s);
|
return "\\" + (s == "\r" ? "r" : s);
|
||||||
});
|
});
|
||||||
@@ -10782,11 +10859,11 @@ merge(Compressor.prototype, {
|
|||||||
if (typeof make_node(AST_Template, self, {
|
if (typeof make_node(AST_Template, self, {
|
||||||
expressions: [],
|
expressions: [],
|
||||||
strings: [ combined ],
|
strings: [ combined ],
|
||||||
tag: self.tag,
|
tag: tag,
|
||||||
}).evaluate(compressor) != typeof make_node(AST_Template, self, {
|
}).evaluate(compressor) != typeof make_node(AST_Template, self, {
|
||||||
expressions: [ node ],
|
expressions: [ node ],
|
||||||
strings: strs.slice(i, i + 2),
|
strings: strs.slice(i, i + 2),
|
||||||
tag: self.tag,
|
tag: tag,
|
||||||
}).evaluate(compressor)) continue;
|
}).evaluate(compressor)) continue;
|
||||||
exprs.splice(i, 1);
|
exprs.splice(i, 1);
|
||||||
strs.splice(i, 2, combined);
|
strs.splice(i, 2, combined);
|
||||||
@@ -11339,6 +11416,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function is_tail_equivalent(consequent, alternative) {
|
function is_tail_equivalent(consequent, alternative) {
|
||||||
if (consequent.TYPE != alternative.TYPE) return;
|
if (consequent.TYPE != alternative.TYPE) return;
|
||||||
|
if (consequent.optional != alternative.optional) return;
|
||||||
if (consequent instanceof AST_Call) {
|
if (consequent instanceof AST_Call) {
|
||||||
if (arg_diff(consequent, alternative) != -1) return;
|
if (arg_diff(consequent, alternative) != -1) return;
|
||||||
return consequent.TYPE != "Call"
|
return consequent.TYPE != "Call"
|
||||||
|
|||||||
@@ -790,10 +790,23 @@ function OutputStream(options) {
|
|||||||
if (p instanceof AST_Unary) return true;
|
if (p instanceof AST_Unary) return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function lhs_has_optional(node, output) {
|
||||||
|
var p = output.parent();
|
||||||
|
if (p instanceof AST_PropAccess && p.expression === node && is_lhs(p, output.parent(1))) {
|
||||||
|
// ++(foo?.bar).baz
|
||||||
|
// (foo?.()).bar = baz
|
||||||
|
do {
|
||||||
|
if (node.optional) return true;
|
||||||
|
node = node.expression;
|
||||||
|
} while (node.TYPE == "Call" || node instanceof AST_PropAccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PARENS(AST_PropAccess, function(output) {
|
PARENS(AST_PropAccess, function(output) {
|
||||||
var node = this;
|
var node = this;
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_New && p.expression === node) {
|
if (p instanceof AST_New) {
|
||||||
|
if (p.expression !== node) return false;
|
||||||
// i.e. new (foo().bar)
|
// i.e. new (foo().bar)
|
||||||
//
|
//
|
||||||
// if there's one call into this subtree, then we need
|
// if there's one call into this subtree, then we need
|
||||||
@@ -805,20 +818,22 @@ function OutputStream(options) {
|
|||||||
} while (node instanceof AST_PropAccess);
|
} while (node instanceof AST_PropAccess);
|
||||||
return node.TYPE == "Call";
|
return node.TYPE == "Call";
|
||||||
}
|
}
|
||||||
|
return lhs_has_optional(node, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Call, function(output) {
|
PARENS(AST_Call, function(output) {
|
||||||
|
var node = this;
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_New) return p.expression === this;
|
if (p instanceof AST_New) return p.expression === node;
|
||||||
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
||||||
if (output.option("webkit")) {
|
if (output.option("webkit")
|
||||||
var g = output.parent(1);
|
&& node.expression instanceof AST_Function
|
||||||
return this.expression instanceof AST_Function
|
|
||||||
&& p instanceof AST_PropAccess
|
&& p instanceof AST_PropAccess
|
||||||
&& p.expression === this
|
&& p.expression === node) {
|
||||||
&& g instanceof AST_Assign
|
var g = output.parent(1);
|
||||||
&& g.left === p;
|
if (g instanceof AST_Assign && g.left === p) return true;
|
||||||
}
|
}
|
||||||
|
return lhs_has_optional(node, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_New, function(output) {
|
PARENS(AST_New, function(output) {
|
||||||
@@ -1920,7 +1935,11 @@ function OutputStream(options) {
|
|||||||
output.add_mapping(this.start);
|
output.add_mapping(this.start);
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFMAP([ AST_DestructuredKeyVal, AST_ObjectProperty ], function(output) {
|
DEFMAP([
|
||||||
|
AST_ClassProperty,
|
||||||
|
AST_DestructuredKeyVal,
|
||||||
|
AST_ObjectProperty,
|
||||||
|
], function(output) {
|
||||||
if (typeof this.key == "string") output.add_mapping(this.start, this.key);
|
if (typeof this.key == "string") output.add_mapping(this.start, this.key);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ var PUNC_AFTER_EXPRESSION = PUNC_SEPARATORS + PUNC_CLOSERS;
|
|||||||
var PUNC_BEFORE_EXPRESSION = PUNC_OPENERS + PUNC_SEPARATORS;
|
var PUNC_BEFORE_EXPRESSION = PUNC_OPENERS + PUNC_SEPARATORS;
|
||||||
var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + "`" + PUNC_CLOSERS;
|
var PUNC_CHARS = PUNC_BEFORE_EXPRESSION + "`" + PUNC_CLOSERS;
|
||||||
var WHITESPACE_CHARS = NEWLINE_CHARS + " \u00a0\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF";
|
var WHITESPACE_CHARS = NEWLINE_CHARS + " \u00a0\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF";
|
||||||
var NON_IDENTIFIER_CHARS = makePredicate(characters("./'\"" + OPERATOR_CHARS + PUNC_CHARS + WHITESPACE_CHARS));
|
var NON_IDENTIFIER_CHARS = makePredicate(characters("./'\"#" + OPERATOR_CHARS + PUNC_CHARS + WHITESPACE_CHARS));
|
||||||
|
|
||||||
NEWLINE_CHARS = makePredicate(characters(NEWLINE_CHARS));
|
NEWLINE_CHARS = makePredicate(characters(NEWLINE_CHARS));
|
||||||
OPERATOR_CHARS = makePredicate(characters(OPERATOR_CHARS));
|
OPERATOR_CHARS = makePredicate(characters(OPERATOR_CHARS));
|
||||||
@@ -468,7 +468,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function read_name() {
|
function read_name() {
|
||||||
var backslash = false, name = "", ch, escaped = false, hex;
|
var backslash = false, ch, escaped = false, name = peek() == "#" ? next() : "";
|
||||||
while (ch = peek()) {
|
while (ch = peek()) {
|
||||||
if (!backslash) {
|
if (!backslash) {
|
||||||
if (ch == "\\") escaped = backslash = true, next();
|
if (ch == "\\") escaped = backslash = true, next();
|
||||||
@@ -483,7 +483,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (KEYWORDS[name] && escaped) {
|
if (KEYWORDS[name] && escaped) {
|
||||||
hex = name.charCodeAt(0).toString(16).toUpperCase();
|
var hex = name.charCodeAt(0).toString(16).toUpperCase();
|
||||||
name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
|
name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
@@ -618,7 +618,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
if (PUNC_CHARS[ch]) return token("punc", next());
|
if (PUNC_CHARS[ch]) return token("punc", next());
|
||||||
if (looking_at("=>")) return token("punc", next() + next());
|
if (looking_at("=>")) return token("punc", next() + next());
|
||||||
if (OPERATOR_CHARS[ch]) return read_operator();
|
if (OPERATOR_CHARS[ch]) return read_operator();
|
||||||
if (code == 92 || !NON_IDENTIFIER_CHARS[ch]) return read_word();
|
if (code == 35 || code == 92 || !NON_IDENTIFIER_CHARS[ch]) return read_word();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
parse_error("Unexpected character '" + ch + "'");
|
parse_error("Unexpected character '" + ch + "'");
|
||||||
|
|||||||
27
lib/scope.js
27
lib/scope.js
@@ -80,15 +80,16 @@ SymbolDef.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
redefined: function() {
|
redefined: function() {
|
||||||
var scope = this.defun;
|
var self = this;
|
||||||
|
var scope = self.defun;
|
||||||
if (!scope) return;
|
if (!scope) return;
|
||||||
var name = this.name;
|
var name = self.name;
|
||||||
var def = scope.variables.get(name)
|
var def = scope.variables.get(name)
|
||||||
|| scope instanceof AST_Toplevel && scope.globals.get(name)
|
|| scope instanceof AST_Toplevel && scope.globals.get(name)
|
||||||
|| this.orig[0] instanceof AST_SymbolConst && find_if(function(def) {
|
|| self.orig[0] instanceof AST_SymbolConst && find_if(function(def) {
|
||||||
return def.name == name;
|
return def.name == name;
|
||||||
}, scope.enclosed);
|
}, scope.enclosed);
|
||||||
if (def && def !== this) return def.redefined() || def;
|
if (def && def !== self) return def.redefined() || def;
|
||||||
},
|
},
|
||||||
unmangleable: function(options) {
|
unmangleable: function(options) {
|
||||||
return this.global && !options.toplevel
|
return this.global && !options.toplevel
|
||||||
@@ -396,13 +397,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
} else {
|
} else {
|
||||||
new_def = scope.def_variable(node);
|
new_def = scope.def_variable(node);
|
||||||
}
|
}
|
||||||
|
if (new_def.undeclared) self.variables.set(name, new_def);
|
||||||
|
if (name == "arguments" && is_arguments(old_def) && node instanceof AST_SymbolLambda) return true;
|
||||||
old_def.defun = new_def.scope;
|
old_def.defun = new_def.scope;
|
||||||
old_def.forEach(function(node) {
|
old_def.forEach(function(node) {
|
||||||
node.redef = old_def;
|
node.redef = old_def;
|
||||||
node.thedef = new_def;
|
node.thedef = new_def;
|
||||||
node.reference(options);
|
node.reference(options);
|
||||||
});
|
});
|
||||||
if (new_def.undeclared) self.variables.set(name, new_def);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -800,6 +802,7 @@ var base54 = (function() {
|
|||||||
var leading = init("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_");
|
var leading = init("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_");
|
||||||
var chars, frequency;
|
var chars, frequency;
|
||||||
function reset() {
|
function reset() {
|
||||||
|
chars = null;
|
||||||
frequency = Object.create(freq);
|
frequency = Object.create(freq);
|
||||||
}
|
}
|
||||||
base54.consider = function(str, delta) {
|
base54.consider = function(str, delta) {
|
||||||
@@ -811,19 +814,15 @@ var base54 = (function() {
|
|||||||
return frequency[b] - frequency[a];
|
return frequency[b] - frequency[a];
|
||||||
}
|
}
|
||||||
base54.sort = function() {
|
base54.sort = function() {
|
||||||
chars = leading.sort(compare).concat(digits.sort(compare));
|
chars = leading.sort(compare).concat(digits).sort(compare);
|
||||||
};
|
};
|
||||||
base54.reset = reset;
|
base54.reset = reset;
|
||||||
reset();
|
reset();
|
||||||
function base54(num) {
|
function base54(num) {
|
||||||
var ret = "", base = 54;
|
var ret = leading[num % 54];
|
||||||
num++;
|
for (num = Math.floor(num / 54); --num >= 0; num >>= 6) {
|
||||||
do {
|
ret += chars[num & 0x3F];
|
||||||
num--;
|
}
|
||||||
ret += chars[num % base];
|
|
||||||
num = Math.floor(num / base);
|
|
||||||
base = 64;
|
|
||||||
} while (num > 0);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return base54;
|
return base54;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"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.13.6",
|
"version": "3.13.8",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -701,3 +701,48 @@ issue_4876: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=15"
|
node_version: ">=15"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4924_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
console.log("PASS");
|
||||||
|
a = function() {};
|
||||||
|
b = function() {}(b ||= a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var b;
|
||||||
|
console.log("PASS");
|
||||||
|
b = void (b ||= function() {});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=15"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4924_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
dead_code: true,
|
||||||
|
passes: 2,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
console.log("PASS");
|
||||||
|
a = function() {};
|
||||||
|
b = function() {}(b ||= a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=15"
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ fields: {
|
|||||||
console.log(k, o[k]);
|
console.log(k, o[k]);
|
||||||
console.log(o.q);
|
console.log(o.q);
|
||||||
}
|
}
|
||||||
expect_exact: 'var o=new class A{"#p";static #p="PASS";async;get q(){return A.#p}[6*7]=console?"foo":"bar"};for(var k in o)console.log(k,o[k]);console.log(o.q);'
|
expect_exact: 'var o=new class A{"#p";static#p="PASS";async;get q(){return A.#p}[6*7]=console?"foo":"bar"};for(var k in o)console.log(k,o[k]);console.log(o.q);'
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
"42 foo",
|
"42 foo",
|
||||||
"#p undefined",
|
"#p undefined",
|
||||||
@@ -136,7 +136,7 @@ private_methods: {
|
|||||||
}
|
}
|
||||||
}().q.then(console.log);
|
}().q.then(console.log);
|
||||||
}
|
}
|
||||||
expect_exact: "(new class A{static*#f(){yield 3*A.#p}async #g(){for(var a of A.#f())return a*await 2}static get #p(){return 7}get q(){return this.#g()}}).q.then(console.log);"
|
expect_exact: "(new class A{static*#f(){yield 3*A.#p}async#g(){for(var a of A.#f())return a*await 2}static get#p(){return 7}get q(){return this.#g()}}).q.then(console.log);"
|
||||||
expect_stdout: "42"
|
expect_stdout: "42"
|
||||||
node_version: ">=14.6"
|
node_version: ">=14.6"
|
||||||
}
|
}
|
||||||
@@ -1563,3 +1563,83 @@ drop_unused_self_reference: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4951_1: {
|
||||||
|
input: {
|
||||||
|
class A {
|
||||||
|
static#p = console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_exact: 'class A{static#p=console.log("PASS")}'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=12"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4951_2: {
|
||||||
|
input: {
|
||||||
|
new class {
|
||||||
|
constructor() {
|
||||||
|
this.#f().then(console.log);
|
||||||
|
}
|
||||||
|
async#f() {
|
||||||
|
return await "PASS";
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_exact: 'new class{constructor(){this.#f().then(console.log)}async#f(){return await"PASS"}};'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=14.6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4962_1: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
function f() {
|
||||||
|
while (console.log(typeof g));
|
||||||
|
}
|
||||||
|
class A {
|
||||||
|
static p = f();
|
||||||
|
}
|
||||||
|
})(function g() {});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function g() {}),
|
||||||
|
void function() {
|
||||||
|
while (console.log(typeof g));
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=12"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4962_2: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {}(function g() {
|
||||||
|
function h() {
|
||||||
|
f;
|
||||||
|
}
|
||||||
|
class A {
|
||||||
|
static p = h();
|
||||||
|
}
|
||||||
|
}, typeof g));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f() {}(function g() {
|
||||||
|
f;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=12"
|
||||||
|
}
|
||||||
|
|||||||
@@ -9220,3 +9220,62 @@ issue_4920: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4935: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
var b;
|
||||||
|
var c = b = a;
|
||||||
|
console || c(a++);
|
||||||
|
--b;
|
||||||
|
console.log(a, b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
var b;
|
||||||
|
var c = b = a;
|
||||||
|
console || a(a++);
|
||||||
|
--b;
|
||||||
|
console.log(a, b);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 0"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_throw: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
inline: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
(function() {
|
||||||
|
return function(a) {
|
||||||
|
return function(b) {
|
||||||
|
throw b;
|
||||||
|
}(a);
|
||||||
|
};
|
||||||
|
})()("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
(function(a) {
|
||||||
|
return function() {
|
||||||
|
throw a;
|
||||||
|
}();
|
||||||
|
})("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1535,3 +1535,160 @@ issue_4848: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4954_1: {
|
||||||
|
rename = true
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
(function() {
|
||||||
|
{
|
||||||
|
const a = "foo";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const a = "bar";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
(function() {
|
||||||
|
{
|
||||||
|
const a = "foo";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const b = "bar";
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4954_2: {
|
||||||
|
mangle = {}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
const a = null;
|
||||||
|
(function(b) {
|
||||||
|
for (const a in null);
|
||||||
|
for (const a in b)
|
||||||
|
console.log("PASS");
|
||||||
|
})([ null ]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
const a = null;
|
||||||
|
(function(o) {
|
||||||
|
for (const n in null);
|
||||||
|
for (const n in o)
|
||||||
|
console.log("PASS");
|
||||||
|
})([ null ]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4960: {
|
||||||
|
mangle = {}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
var a;
|
||||||
|
(function() {
|
||||||
|
{
|
||||||
|
const a = console.log("PASS");
|
||||||
|
}
|
||||||
|
try {} catch (e) {
|
||||||
|
const a = console.log("FAIL");
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
var a;
|
||||||
|
(function() {
|
||||||
|
{
|
||||||
|
const o = console.log("PASS");
|
||||||
|
}
|
||||||
|
try {} catch (o) {
|
||||||
|
const c = console.log("FAIL");
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4965_1: {
|
||||||
|
mangle = {}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
c;
|
||||||
|
} catch (a) {
|
||||||
|
{
|
||||||
|
const a = 1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const a = console.log(typeof c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
c;
|
||||||
|
} catch (t) {
|
||||||
|
{
|
||||||
|
const c = 1;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const t = console.log(typeof c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4965_2: {
|
||||||
|
mangle = {}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
throw 1;
|
||||||
|
} catch (e) {
|
||||||
|
try {
|
||||||
|
{
|
||||||
|
const e = 2;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
const e = 3;
|
||||||
|
console.log(typeof t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
throw 1;
|
||||||
|
} catch (o) {
|
||||||
|
try {
|
||||||
|
{
|
||||||
|
const t = 2;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
const o = 3;
|
||||||
|
console.log(typeof t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -3080,11 +3080,9 @@ issue_4235: {
|
|||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(function() {
|
void function() {
|
||||||
f = console.log(f),
|
var f = console.log(f);
|
||||||
void 0;
|
}();
|
||||||
var f;
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
}
|
}
|
||||||
@@ -3436,7 +3434,7 @@ issue_4912_2: {
|
|||||||
console.log(function() {
|
console.log(function() {
|
||||||
var g, f = function() {};
|
var g, f = function() {};
|
||||||
f.p = {};
|
f.p = {};
|
||||||
(g = f.p.q = function() {}).r = "PASS";
|
(f.p.q = function() {}).r = "PASS";
|
||||||
return f;
|
return f;
|
||||||
}().p.q.r);
|
}().p.q.r);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2947,3 +2947,73 @@ issue_4729: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4928_1: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = function f() {
|
||||||
|
f(a);
|
||||||
|
};
|
||||||
|
console.log(typeof f);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = function f() {
|
||||||
|
f(a);
|
||||||
|
};
|
||||||
|
console.log(typeof f);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4928_2: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
switch (42) {
|
||||||
|
case console:
|
||||||
|
var a = function f() {
|
||||||
|
f(a);
|
||||||
|
};
|
||||||
|
case 42:
|
||||||
|
var a = console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
switch (42) {
|
||||||
|
case console:
|
||||||
|
var a = function f() {
|
||||||
|
f(a);
|
||||||
|
};
|
||||||
|
case 42:
|
||||||
|
a = console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4958: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
ie8: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function arguments(a) {
|
||||||
|
a = 21;
|
||||||
|
return arguments[0] + 21;
|
||||||
|
}("FAIL"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function arguments(a) {
|
||||||
|
a = 21;
|
||||||
|
return arguments[0] + 21;
|
||||||
|
}("FAIL"));
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|||||||
@@ -3301,3 +3301,80 @@ issue_4761: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4956_1: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f(c) {
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
a = { p: 42 };
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
b = a.p;
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f(0);
|
||||||
|
f(1);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f(c) {
|
||||||
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
a = { p: 42 };
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
b = a.p;
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f(0);
|
||||||
|
f(1);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"42",
|
||||||
|
"42",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4956_2: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b;
|
||||||
|
function f(c) {
|
||||||
|
if (0 == c) {
|
||||||
|
console;
|
||||||
|
a = { p: 42 };
|
||||||
|
}
|
||||||
|
b = a.p;
|
||||||
|
if (1 == c)
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
f(0);
|
||||||
|
f(1);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b;
|
||||||
|
function f(c) {
|
||||||
|
if (0 == c) {
|
||||||
|
console;
|
||||||
|
a = { p: 42 };
|
||||||
|
}
|
||||||
|
b = a.p;
|
||||||
|
if (1 == c)
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
f(0);
|
||||||
|
f(1);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,6 +43,48 @@ ternary_decimal: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assign_parentheses_call: {
|
||||||
|
input: {
|
||||||
|
var o = {};
|
||||||
|
((() => o)?.()).p = "PASS";
|
||||||
|
console.log(o.p);
|
||||||
|
}
|
||||||
|
expect_exact: 'var o={};((()=>o)?.()).p="PASS";console.log(o.p);'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=14"
|
||||||
|
}
|
||||||
|
|
||||||
|
assign_parentheses_dot: {
|
||||||
|
input: {
|
||||||
|
(console?.log).name.p = console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_exact: '(console?.log.name).p=console.log("PASS");'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=14"
|
||||||
|
}
|
||||||
|
|
||||||
|
assign_no_parentheses: {
|
||||||
|
input: {
|
||||||
|
console[console.log?.("PASS")] = 42;
|
||||||
|
}
|
||||||
|
expect_exact: 'console[console.log?.("PASS")]=42;'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=14"
|
||||||
|
}
|
||||||
|
|
||||||
|
unary_parentheses: {
|
||||||
|
input: {
|
||||||
|
var o = { p: 41 };
|
||||||
|
(function() {
|
||||||
|
return o;
|
||||||
|
}?.()).p++;
|
||||||
|
console.log(o.p);
|
||||||
|
}
|
||||||
|
expect_exact: "var o={p:41};(function(){return o}?.()).p++;console.log(o.p);"
|
||||||
|
expect_stdout: "42"
|
||||||
|
node_version: ">=14"
|
||||||
|
}
|
||||||
|
|
||||||
collapse_vars_1: {
|
collapse_vars_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
@@ -211,3 +253,55 @@ issue_4906: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=14"
|
node_version: ">=14"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4928: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = a?.[function f() {
|
||||||
|
f(a);
|
||||||
|
}];
|
||||||
|
console.log(typeof f);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = a?.[function f() {
|
||||||
|
f(a);
|
||||||
|
}];
|
||||||
|
console.log(typeof f);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=14"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4947_1: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(console.foo ? 42..p : console.bar?.p);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(console.foo ? 42..p : console.bar?.p);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
node_version: ">=14"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4947_2: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var log = console.log, fail;
|
||||||
|
log("PASS") ? log(42) : fail?.(42);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var log = console.log, fail;
|
||||||
|
log("PASS") ? log(42) : fail?.(42);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=14"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1638,3 +1638,29 @@ nested_property_assignments_3: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4939: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
__proto__: {
|
||||||
|
get p() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).p;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({
|
||||||
|
__proto__: {
|
||||||
|
get p() {
|
||||||
|
console.log("PASS");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).p;
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -7631,3 +7631,114 @@ issue_4568: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4937: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
function g() {
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
} while (!g);
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
function g() {
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
} while (!g);
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4943_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b = 1;
|
||||||
|
(function f() {
|
||||||
|
a = "foo";
|
||||||
|
b-- && f();
|
||||||
|
console.log(a);
|
||||||
|
a = "bar";
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b = 1;
|
||||||
|
(function f() {
|
||||||
|
a = "foo";
|
||||||
|
b-- && f();
|
||||||
|
console.log(a);
|
||||||
|
a = "bar";
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4943_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a, b = 1;
|
||||||
|
(function f() {
|
||||||
|
a = "foo";
|
||||||
|
b-- && f();
|
||||||
|
console.log(a);
|
||||||
|
a = "bar";
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a, b = 1;
|
||||||
|
(function f() {
|
||||||
|
a = "foo";
|
||||||
|
b-- && f();
|
||||||
|
console.log(a);
|
||||||
|
a = "bar";
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4949: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function f(a) {
|
||||||
|
a = 0;
|
||||||
|
console.log(a++, arguments[0]);
|
||||||
|
})(0);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
a = 0;
|
||||||
|
console.log(a++, arguments[0]);
|
||||||
|
})(0);
|
||||||
|
}
|
||||||
|
expect_stdout: "0 1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -315,6 +315,21 @@ unsafe_side_effects: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pure_funcs: {
|
||||||
|
options = {
|
||||||
|
pure_funcs: "Math.random",
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
Math.random`${console.log("PASS")}`;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
issue_4604: {
|
issue_4604: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
@@ -398,3 +413,24 @@ issue_4676: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4931: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
templates: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(String.raw`${typeof A} ${"\r"}`);
|
||||||
|
console.log(String.raw`${"\\"} ${"`"}`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(String.raw`${typeof A} ${"\r"}`);
|
||||||
|
console.log("\\ `");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"undefined \r",
|
||||||
|
"\\ `",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -523,3 +523,93 @@ default_init: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4933_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(f());
|
||||||
|
function f() {
|
||||||
|
var a;
|
||||||
|
for (console in a = [ f ]) {
|
||||||
|
const b = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f() {
|
||||||
|
var a;
|
||||||
|
for (console in a = [ f ]) {
|
||||||
|
const b = a;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4933_2: {
|
||||||
|
options = {
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(f());
|
||||||
|
function f() {
|
||||||
|
var a;
|
||||||
|
for (console in a = [ f ]) {
|
||||||
|
const b = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f() {
|
||||||
|
for (console in [ f ]);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4954: {
|
||||||
|
options = {
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
(function() {
|
||||||
|
{
|
||||||
|
let a = console;
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let a = function() {};
|
||||||
|
a && console.log(typeof a);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
(function() {
|
||||||
|
var a = console;
|
||||||
|
console.log(typeof a);
|
||||||
|
{
|
||||||
|
let a = function() {};
|
||||||
|
a && console.log(typeof a);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"object",
|
||||||
|
"function",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ describe("let", function() {
|
|||||||
// Produce a lot of variables in a function and run it through mangle.
|
// Produce a lot of variables in a function and run it through mangle.
|
||||||
var s = '"dddddeeeeelllllooooottttt"; function foo() {';
|
var s = '"dddddeeeeelllllooooottttt"; function foo() {';
|
||||||
for (var i = 0; i < 18000; i++) {
|
for (var i = 0; i < 18000; i++) {
|
||||||
s += "var v" + i + "=0;";
|
s += "var v" + i + "=[];";
|
||||||
}
|
}
|
||||||
s += '}';
|
s += '}';
|
||||||
var result = UglifyJS.minify(s, {
|
var result = UglifyJS.minify(s, {
|
||||||
compress: false
|
compress: false,
|
||||||
}).code;
|
}).code;
|
||||||
|
|
||||||
// Verify that select keywords and reserved keywords not produced
|
// Verify that select keywords and reserved keywords not produced
|
||||||
|
|||||||
@@ -101,6 +101,19 @@ describe("sourcemaps", function() {
|
|||||||
var map = JSON.parse(result.map);
|
var map = JSON.parse(result.map);
|
||||||
assert.deepEqual(map.names, []);
|
assert.deepEqual(map.names, []);
|
||||||
});
|
});
|
||||||
|
it("Should mark class properties", function() {
|
||||||
|
var result = UglifyJS.minify([
|
||||||
|
"class A {",
|
||||||
|
" static P = 42",
|
||||||
|
" set #q(v) {}",
|
||||||
|
"}",
|
||||||
|
].join("\n"), {
|
||||||
|
sourceMap: true,
|
||||||
|
});
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
assert.strictEqual(result.code, "class A{static P=42;set#q(s){}}");
|
||||||
|
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["A","P","#q","v"],"mappings":"MAAMA,EACFC,SAAW,GACXC,MAAOC"}');
|
||||||
|
});
|
||||||
it("Should mark array/object literals", function() {
|
it("Should mark array/object literals", function() {
|
||||||
var result = UglifyJS.minify([
|
var result = UglifyJS.minify([
|
||||||
"var obj = {};",
|
"var obj = {};",
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
if (verbose) {
|
if (verbose) {
|
||||||
log("// Node.js " + process.version + " on " + os.platform() + " " + os.arch());
|
log("// Node.js " + process.version + " on " + os.platform() + " " + os.arch());
|
||||||
}
|
}
|
||||||
if (differs.error && [ "DefaultsError", "SyntaxError" ].indexOf(differs.error.name) < 0) {
|
if (differs && differs.error && [ "DefaultsError", "SyntaxError" ].indexOf(differs.error.name) < 0) {
|
||||||
test_for_diff = test_minify;
|
test_for_diff = test_minify;
|
||||||
differs = test_for_diff(testcase, minify_options, result_cache, max_timeout);
|
differs = test_for_diff(testcase, minify_options, result_cache, max_timeout);
|
||||||
}
|
}
|
||||||
@@ -132,6 +132,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (parent instanceof U.AST_VarDef && parent.name === node) return;
|
if (parent instanceof U.AST_VarDef && parent.name === node) return;
|
||||||
|
// preserve class methods
|
||||||
|
if (parent instanceof U.AST_ClassMethod && parent.value === node) return;
|
||||||
// preserve exports
|
// preserve exports
|
||||||
if (parent instanceof U.AST_ExportDeclaration) return;
|
if (parent instanceof U.AST_ExportDeclaration) return;
|
||||||
if (parent instanceof U.AST_ExportDefault) return;
|
if (parent instanceof U.AST_ExportDefault) return;
|
||||||
@@ -147,6 +149,9 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node;
|
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node;
|
||||||
// preserve for (xxx in/of ...)
|
// preserve for (xxx in/of ...)
|
||||||
if (parent instanceof U.AST_ForEnumeration && parent.init === node) return node;
|
if (parent instanceof U.AST_ForEnumeration && parent.init === node) return node;
|
||||||
|
// preserve super(...)
|
||||||
|
if (node.TYPE == "Call" && node.expression instanceof U.AST_Super) return;
|
||||||
|
if (node instanceof U.AST_Super && parent.TYPE == "Call" && parent.expression === node) return node;
|
||||||
|
|
||||||
// node specific permutations with no parent logic
|
// node specific permutations with no parent logic
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ exports.run_code = semver.satisfies(process.version, "0.8") ? function(code, top
|
|||||||
} : semver.satisfies(process.version, "<0.12") ? run_code_vm : function(code, toplevel, timeout) {
|
} : semver.satisfies(process.version, "<0.12") ? run_code_vm : function(code, toplevel, timeout) {
|
||||||
if ([
|
if ([
|
||||||
/\basync[ \t]*\([\s\S]*?\)[ \t]*=>/,
|
/\basync[ \t]*\([\s\S]*?\)[ \t]*=>/,
|
||||||
/\b(async[ \t]+function|setImmediate|setInterval|setTimeout)\b/,
|
/\b(async[ \t]+function|Promise|setImmediate|setInterval|setTimeout)\b/,
|
||||||
/\basync([ \t]+|[ \t]*\*[ \t]*)[^\s()[\]{},.&|!~=*%/+-]+(\s*\(|[ \t]*=>)/,
|
/\basync([ \t]+|[ \t]*#|[ \t]*\*[ \t]*)[^\s()[\]{},.&|!~=*%/+-]+(\s*\(|[ \t]*=>)/,
|
||||||
].some(function(pattern) {
|
].some(function(pattern) {
|
||||||
return pattern.test(code);
|
return pattern.test(code);
|
||||||
})) {
|
})) {
|
||||||
|
|||||||
@@ -356,6 +356,7 @@ var block_vars = [];
|
|||||||
var lambda_vars = [];
|
var lambda_vars = [];
|
||||||
var unique_vars = [];
|
var unique_vars = [];
|
||||||
var classes = [];
|
var classes = [];
|
||||||
|
var allow_this = true;
|
||||||
var async = false;
|
var async = false;
|
||||||
var has_await = false;
|
var has_await = false;
|
||||||
var export_default = false;
|
var export_default = false;
|
||||||
@@ -402,6 +403,7 @@ function createTopLevelCode() {
|
|||||||
lambda_vars.length = 0;
|
lambda_vars.length = 0;
|
||||||
unique_vars.length = 0;
|
unique_vars.length = 0;
|
||||||
classes.length = 0;
|
classes.length = 0;
|
||||||
|
allow_this = true;
|
||||||
async = false;
|
async = false;
|
||||||
has_await = false;
|
has_await = false;
|
||||||
export_default = false;
|
export_default = false;
|
||||||
@@ -1731,6 +1733,8 @@ function createObjectFunction(recurmax, stmtDepth, canThrow, internal, isClazz)
|
|||||||
fn = function(defns) {
|
fn = function(defns) {
|
||||||
if (generator) name = "*" + name;
|
if (generator) name = "*" + name;
|
||||||
if (async) name = "async "+ name;
|
if (async) name = "async "+ name;
|
||||||
|
var save_allow = allow_this;
|
||||||
|
if (internal == "super") allow_this = false;
|
||||||
s = [
|
s = [
|
||||||
name + "(" + createParams(save_async, save_generator, NO_DUPLICATE) + "){",
|
name + "(" + createParams(save_async, save_generator, NO_DUPLICATE) + "){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
@@ -1738,6 +1742,7 @@ function createObjectFunction(recurmax, stmtDepth, canThrow, internal, isClazz)
|
|||||||
];
|
];
|
||||||
s.push(_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, stmtDepth));
|
s.push(_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, stmtDepth));
|
||||||
if (internal == "super") s.push("super" + createArgs(recurmax, stmtDepth, canThrow, NO_TEMPLATE) + ";");
|
if (internal == "super") s.push("super" + createArgs(recurmax, stmtDepth, canThrow, NO_TEMPLATE) + ";");
|
||||||
|
allow_this = save_allow;
|
||||||
if (/^(constructor|super)$/.test(internal) || rng(10) == 0) for (var i = rng(4); --i >= 0;) {
|
if (/^(constructor|super)$/.test(internal) || rng(10) == 0) for (var i = rng(4); --i >= 0;) {
|
||||||
s.push(rng(2) ? createSuperAssignment(recurmax, stmtDepth, canThrow) : createThisAssignment(recurmax, stmtDepth, canThrow));
|
s.push(rng(2) ? createSuperAssignment(recurmax, stmtDepth, canThrow) : createThisAssignment(recurmax, stmtDepth, canThrow));
|
||||||
}
|
}
|
||||||
@@ -1974,7 +1979,7 @@ function createValue() {
|
|||||||
var v;
|
var v;
|
||||||
do {
|
do {
|
||||||
v = VALUES[rng(VALUES.length)];
|
v = VALUES[rng(VALUES.length)];
|
||||||
} while (v == "new.target" && rng(200));
|
} while (v == "new.target" && rng(200) || !allow_this && v == "this");
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2298,7 +2303,7 @@ function is_error_in(ex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function is_error_spread(ex) {
|
function is_error_spread(ex) {
|
||||||
return ex.name == "TypeError" && /Found non-callable @@iterator| is not iterable| is not a function/.test(ex.message);
|
return ex.name == "TypeError" && /Found non-callable @@iterator| is not iterable| not a function/.test(ex.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_error_recursion(ex) {
|
function is_error_recursion(ex) {
|
||||||
|
|||||||
Reference in New Issue
Block a user