Compare commits
29 Commits
harmony-v3
...
harmony-v3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
945db924fc | ||
|
|
087bce508a | ||
|
|
5e6f26445f | ||
|
|
fc7e33453f | ||
|
|
d052394621 | ||
|
|
4d5aeeddfb | ||
|
|
f0a99125ee | ||
|
|
1e4de2e6d3 | ||
|
|
ad139aa34d | ||
|
|
26be15f111 | ||
|
|
179f33f08a | ||
|
|
d260fe9018 | ||
|
|
96f9b8cba3 | ||
|
|
11afa816e3 | ||
|
|
8b4dcd8f3e | ||
|
|
285401ced8 | ||
|
|
9db4c42380 | ||
|
|
49f3de8397 | ||
|
|
94f93ad82d | ||
|
|
d1f085bce7 | ||
|
|
7b95b63ca1 | ||
|
|
94e5e00c03 | ||
|
|
dc6bcaa18e | ||
|
|
d58b184835 | ||
|
|
137e4c4753 | ||
|
|
b3a57ff019 | ||
|
|
3d5bc08185 | ||
|
|
0692435f01 | ||
|
|
b163b13a0b |
34
README.md
34
README.md
@@ -1,11 +1,11 @@
|
||||
uglify-es
|
||||
=========
|
||||
|
||||
**uglify-es** is an ECMAScript 2015 parser, minifier, compressor and beautifier toolkit.
|
||||
**uglify-es** is an ECMAScript parser, minifier, compressor and beautifier toolkit for ES6+.
|
||||
|
||||
#### Note:
|
||||
- **The `uglify-es` API and CLI is compatible with `uglify-js@3.x`.**
|
||||
- **`uglify-es` is not backwards compatible with the `uglify-js@2.x` API and CLI.**
|
||||
- **`uglify-es` is API/CLI compatible with `uglify-js@3`.**
|
||||
- **`uglify-es` is not backwards compatible with `uglify-js@2`.**
|
||||
|
||||
Install
|
||||
-------
|
||||
@@ -102,6 +102,7 @@ a double dash to prevent input files being used as option arguments:
|
||||
sequences.
|
||||
--config-file <file> Read `minify()` options from JSON file.
|
||||
-d, --define <expr>[=value] Global definitions.
|
||||
--ecma <version> Specifiy ECMAScript release: 5, 6, 7 or 8.
|
||||
--ie8 Support non-standard Internet Explorer 8.
|
||||
Equivalent to setting `ie8: true` in `minify()`
|
||||
for `compress`, `mangle` and `output` options.
|
||||
@@ -433,6 +434,9 @@ if (result.error) throw result.error;
|
||||
|
||||
## Minify options
|
||||
|
||||
- `ecma` (default `undefined`) - pass `5`, `6`, `7` or `8` to override `parse`,
|
||||
`compress` and `output` options.
|
||||
|
||||
- `warnings` (default `false`) — pass `true` to return compressor warnings
|
||||
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
|
||||
|
||||
@@ -464,7 +468,6 @@ if (result.error) throw result.error;
|
||||
|
||||
```javascript
|
||||
{
|
||||
warnings: false,
|
||||
parse: {
|
||||
// parse options
|
||||
},
|
||||
@@ -484,8 +487,10 @@ if (result.error) throw result.error;
|
||||
sourceMap: {
|
||||
// source map options
|
||||
},
|
||||
ecma: 5, // specify one of: 5, 6, 7 or 8
|
||||
toplevel: false,
|
||||
ie8: false,
|
||||
warnings: false,
|
||||
}
|
||||
```
|
||||
|
||||
@@ -539,6 +544,9 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
## Parse options
|
||||
|
||||
- `bare_returns` (default `false`) -- support top level `return` statements
|
||||
- `ecma` (default: `8`) -- specify one of `5`, `6`, `7` or `8`. Note: this setting
|
||||
is not presently enforced except for ES8 optional trailing commas in function
|
||||
parameter lists and calls with `ecma` `8`.
|
||||
- `html5_comments` (default `true`)
|
||||
- `shebang` (default `true`) -- support `#!command` as the first line
|
||||
|
||||
@@ -590,6 +598,10 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
|
||||
- `evaluate` -- attempt to evaluate constant expressions
|
||||
|
||||
- `arrows` (default `true`) -- convert ES5 style anonymous function expressions
|
||||
to arrow functions if permissible by language semantics.
|
||||
Note: `arrows` requires that the `ecma` compress option is set to `6` or greater.
|
||||
|
||||
- `booleans` -- various optimizations for boolean context, for example `!!a
|
||||
? b : c → a ? b : c`
|
||||
|
||||
@@ -677,6 +689,9 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
functions marked as "pure". A function call is marked as "pure" if a comment
|
||||
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
||||
example: `/*@__PURE__*/foo();`
|
||||
|
||||
- `ecma` -- default `5`. Pass `6` or greater to enable `compress` options that
|
||||
will transform ES5 code into smaller ES6+ equivalent forms.
|
||||
|
||||
## Mangle options
|
||||
|
||||
@@ -686,6 +701,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
- `toplevel` (default `false`). Pass `true` to mangle names declared in the
|
||||
top level scope.
|
||||
|
||||
- `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).
|
||||
@@ -749,9 +766,12 @@ can pass additional arguments that control the code output:
|
||||
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
|
||||
comments, `"some"` to preserve some comments, a regular expression string
|
||||
(e.g. `/^!/`) or a function.
|
||||
- `ecma` (default `5`) -- set output printing mode. This will only change the
|
||||
output in direct control of the beautifier. Non-compatible features in the
|
||||
abstract syntax tree will still be outputted as is.
|
||||
- `ecma` (default `5`) -- set output printing mode. Set `ecma` to `6` or
|
||||
greater to emit shorthand object properties - i.e.: `{a}` instead of `{a: a}`.
|
||||
The `ecma` option will only change the output in direct control of the
|
||||
beautifier. Non-compatible features in the abstract syntax tree will still
|
||||
be output as is. For example: an `ecma` setting of `5` will **not** convert
|
||||
ES6+ code to ES5.
|
||||
- `indent_level` (default 4)
|
||||
- `indent_start` (default 0) -- prefix all lines by that many spaces
|
||||
- `inline_script` (default `false`) -- escape the slash in occurrences of
|
||||
|
||||
@@ -44,6 +44,7 @@ program.option("-o, --output <file>", "Output file (default STDOUT).");
|
||||
program.option("--comments [filter]", "Preserve copyright comments in the output.");
|
||||
program.option("--config-file <file>", "Read minify() options from JSON file.");
|
||||
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
|
||||
program.option("--ecma <version>", "Specifiy ECMAScript release: 5, 6, 7 or 8.");
|
||||
program.option("--ie8", "Support non-standard Internet Explorer 8.");
|
||||
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
|
||||
program.option("--name-cache <file>", "File to hold mangled name mappings.");
|
||||
@@ -73,6 +74,10 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
|
||||
options[name] = program[name];
|
||||
}
|
||||
});
|
||||
if ("ecma" in program) {
|
||||
if (program.ecma != (program.ecma | 0)) fatal("ERROR: ecma must be an integer");
|
||||
options.ecma = program.ecma | 0;
|
||||
}
|
||||
if (program.beautify) {
|
||||
options.output = typeof program.beautify == "object" ? program.beautify : {};
|
||||
if (!("beautify" in options.output)) {
|
||||
|
||||
@@ -345,7 +345,7 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||
var AST_Expansion = DEFNODE("Expansion", "expression", {
|
||||
$documentation: "An expandible argument, such as ...rest, a splat, such as [1,2,...all], or an expansion in a variable declaration, such as var [first, ...rest] = list",
|
||||
$propdoc: {
|
||||
expression: "AST_Symbol the thing to be expanded"
|
||||
expression: "[AST_Node] the thing to be expanded"
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
var self = this;
|
||||
@@ -446,7 +446,7 @@ var AST_PrefixedTemplateString = DEFNODE("PrefixedTemplateString", "template_str
|
||||
var AST_TemplateString = DEFNODE("TemplateString", "segments", {
|
||||
$documentation: "A template string literal",
|
||||
$propdoc: {
|
||||
segments: "[AST_TemplateSegment|AST_Expression]* One or more segments, starting with AST_TemplateSegment. AST_Expression may follow AST_TemplateSegment, but each AST_Expression must be followed by AST_TemplateSegment."
|
||||
segments: "[AST_Node*] One or more segments, starting with AST_TemplateSegment. AST_Node may follow AST_TemplateSegment, but each AST_Node must be followed by AST_TemplateSegment."
|
||||
},
|
||||
_walk: function(visitor) {
|
||||
return visitor._visit(this, function(){
|
||||
|
||||
243
lib/compress.js
243
lib/compress.js
@@ -48,6 +48,7 @@ function Compressor(options, false_by_default) {
|
||||
return new Compressor(options, false_by_default);
|
||||
TreeTransformer.call(this, this.before, this.after);
|
||||
this.options = defaults(options, {
|
||||
arrows : !false_by_default,
|
||||
booleans : !false_by_default,
|
||||
cascade : !false_by_default,
|
||||
collapse_vars : !false_by_default,
|
||||
@@ -93,12 +94,9 @@ function Compressor(options, false_by_default) {
|
||||
var global_defs = this.options["global_defs"];
|
||||
if (typeof global_defs == "object") for (var key in global_defs) {
|
||||
if (/^@/.test(key) && HOP(global_defs, key)) {
|
||||
var ast = parse(global_defs[key]);
|
||||
if (ast.body.length == 1 && ast.body[0] instanceof AST_SimpleStatement) {
|
||||
global_defs[key.slice(1)] = ast.body[0].body;
|
||||
} else throw new Error(string_template("Can't handle expression: {value}", {
|
||||
value: global_defs[key]
|
||||
}));
|
||||
global_defs[key.slice(1)] = parse(global_defs[key], {
|
||||
expression: true
|
||||
});
|
||||
}
|
||||
}
|
||||
var pure_funcs = this.options["pure_funcs"];
|
||||
@@ -125,15 +123,13 @@ function Compressor(options, false_by_default) {
|
||||
};
|
||||
}
|
||||
var toplevel = this.options["toplevel"];
|
||||
if (typeof toplevel == "string") {
|
||||
this.toplevel.funcs = /funcs/.test(toplevel);
|
||||
this.toplevel.vars = /vars/.test(toplevel);
|
||||
} else {
|
||||
this.toplevel = toplevel ? function(def) {
|
||||
return !def.export;
|
||||
} : return_false;
|
||||
this.toplevel.funcs = this.toplevel.vars = toplevel;
|
||||
}
|
||||
this.toplevel = typeof toplevel == "string" ? {
|
||||
funcs: /funcs/.test(toplevel),
|
||||
vars: /vars/.test(toplevel)
|
||||
} : {
|
||||
funcs: toplevel,
|
||||
vars: toplevel
|
||||
};
|
||||
var sequences = this.options["sequences"];
|
||||
this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
|
||||
this.warnings_produced = {};
|
||||
@@ -142,12 +138,12 @@ function Compressor(options, false_by_default) {
|
||||
Compressor.prototype = new TreeTransformer;
|
||||
merge(Compressor.prototype, {
|
||||
option: function(key) { return this.options[key] },
|
||||
toplevel: function(def) {
|
||||
if (def.export) return false;
|
||||
for (var i = 0, len = def.orig.length; i < len; i++)
|
||||
exposed: function(def) {
|
||||
if (def.export) return true;
|
||||
if (def.global) for (var i = 0, len = def.orig.length; i < len; i++)
|
||||
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
|
||||
return false;
|
||||
return true;
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
compress: function(node) {
|
||||
if (this.option("expression")) {
|
||||
@@ -283,11 +279,11 @@ merge(Compressor.prototype, {
|
||||
var reduce_vars = rescan && compressor.option("reduce_vars");
|
||||
var safe_ids = Object.create(null);
|
||||
var suppressor = new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Symbol) {
|
||||
var d = node.definition();
|
||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||
d.fixed = false;
|
||||
}
|
||||
if (!(node instanceof AST_Symbol)) return;
|
||||
var d = node.definition();
|
||||
if (!d) return;
|
||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||
d.fixed = false;
|
||||
});
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
node._squeezed = false;
|
||||
@@ -355,7 +351,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (node instanceof AST_Defun) {
|
||||
var d = node.name.definition();
|
||||
if (d.global && !compressor.toplevel(d) || safe_to_read(d)) {
|
||||
if (compressor.exposed(d) || safe_to_read(d)) {
|
||||
d.fixed = false;
|
||||
} else {
|
||||
d.fixed = node;
|
||||
@@ -367,7 +363,7 @@ merge(Compressor.prototype, {
|
||||
safe_ids = save_ids;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Function || node instanceof AST_Arrow) {
|
||||
if (is_func_expr(node)) {
|
||||
push();
|
||||
var iife;
|
||||
if (!node.name
|
||||
@@ -530,7 +526,7 @@ merge(Compressor.prototype, {
|
||||
def.escaped = false;
|
||||
if (def.scope.uses_eval) {
|
||||
def.fixed = false;
|
||||
} else if (!def.global || def.orig[0] instanceof AST_SymbolConst || compressor.toplevel(def)) {
|
||||
} else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) {
|
||||
def.fixed = undefined;
|
||||
} else {
|
||||
def.fixed = false;
|
||||
@@ -560,8 +556,29 @@ merge(Compressor.prototype, {
|
||||
return fixed();
|
||||
});
|
||||
|
||||
AST_SymbolRef.DEFMETHOD("is_immutable", function() {
|
||||
var orig = this.definition().orig;
|
||||
return orig.length == 1 && orig[0] instanceof AST_SymbolLambda;
|
||||
});
|
||||
|
||||
function is_func_expr(node) {
|
||||
return node instanceof AST_Arrow || node instanceof AST_Function;
|
||||
}
|
||||
|
||||
function is_lhs_read_only(lhs) {
|
||||
return lhs instanceof AST_SymbolRef && lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
||||
if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
|
||||
if (lhs instanceof AST_PropAccess) {
|
||||
lhs = lhs.expression;
|
||||
if (lhs instanceof AST_SymbolRef) {
|
||||
if (lhs.is_immutable()) return false;
|
||||
lhs = lhs.fixed_value();
|
||||
}
|
||||
if (!lhs) return true;
|
||||
if (lhs instanceof AST_RegExp) return false;
|
||||
if (lhs instanceof AST_Constant) return true;
|
||||
return is_lhs_read_only(lhs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function is_ref_of(ref, type) {
|
||||
@@ -691,7 +708,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
function is_iife_call(node) {
|
||||
if (node instanceof AST_Call && !(node instanceof AST_New)) {
|
||||
return node.expression instanceof AST_Function || is_iife_call(node.expression);
|
||||
return is_func_expr(node.expression) || is_iife_call(node.expression);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -782,7 +799,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (candidate instanceof AST_VarDef) {
|
||||
var def = candidate.name.definition();
|
||||
if (def.references.length == 1 && (!def.global || compressor.toplevel(def))) {
|
||||
if (def.references.length == 1 && !compressor.exposed(def)) {
|
||||
return maintain_this_binding(parent, node, candidate.value);
|
||||
}
|
||||
return make_node(AST_Assign, candidate, {
|
||||
@@ -844,7 +861,7 @@ merge(Compressor.prototype, {
|
||||
if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) {
|
||||
var def = expr.name.definition();
|
||||
if (def.orig.length > 1
|
||||
|| def.references.length == 1 && (!def.global || compressor.toplevel(def))) {
|
||||
|| def.references.length == 1 && !compressor.exposed(def)) {
|
||||
return make_node(AST_SymbolRef, expr.name, expr.name);
|
||||
}
|
||||
} else {
|
||||
@@ -1304,6 +1321,7 @@ merge(Compressor.prototype, {
|
||||
return false;
|
||||
});
|
||||
def(AST_Function, return_false);
|
||||
def(AST_Arrow, return_false);
|
||||
def(AST_UnaryPostfix, return_false);
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "void";
|
||||
@@ -1333,6 +1351,7 @@ merge(Compressor.prototype, {
|
||||
def(AST_SymbolRef, function(pure_getters) {
|
||||
if (this.is_undefined) return true;
|
||||
if (!is_strict(pure_getters)) return false;
|
||||
if (this.is_immutable()) return false;
|
||||
var fixed = this.fixed_value();
|
||||
return !fixed || fixed._throw_on_access(pure_getters);
|
||||
});
|
||||
@@ -1576,9 +1595,6 @@ merge(Compressor.prototype, {
|
||||
def(AST_Lambda, function(){
|
||||
throw def;
|
||||
});
|
||||
def(AST_Arrow, function() {
|
||||
throw def;
|
||||
});
|
||||
def(AST_Class, function() {
|
||||
throw def;
|
||||
});
|
||||
@@ -1632,8 +1648,7 @@ merge(Compressor.prototype, {
|
||||
case "typeof":
|
||||
// Function would be evaluated to an array and so typeof would
|
||||
// incorrectly return 'object'. Hence making is a special case.
|
||||
if (e instanceof AST_Function ||
|
||||
e instanceof AST_Arrow) return typeof function(){};
|
||||
if (is_func_expr(e)) return typeof function(){};
|
||||
|
||||
e = ev(e, compressor);
|
||||
|
||||
@@ -1805,6 +1820,9 @@ merge(Compressor.prototype, {
|
||||
def(AST_Function, function(){
|
||||
return basic_negation(this);
|
||||
});
|
||||
def(AST_Arrow, function(){
|
||||
return basic_negation(this);
|
||||
});
|
||||
def(AST_UnaryPrefix, function(){
|
||||
if (this.operator == "!")
|
||||
return this.expression;
|
||||
@@ -2047,7 +2065,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_Block, function(self, compressor){
|
||||
if (!(self.body instanceof AST_Node)) tighten_body(self.body, compressor);
|
||||
tighten_body(self.body, compressor);
|
||||
return self;
|
||||
});
|
||||
|
||||
@@ -2086,7 +2104,6 @@ merge(Compressor.prototype, {
|
||||
var var_defs_by_id = new Dictionary();
|
||||
var initializations = new Dictionary();
|
||||
var destructuring_value = null;
|
||||
var in_definition = false;
|
||||
// pass 1: find out which symbols are directly used in
|
||||
// this scope (not in nested scopes).
|
||||
var scope = this;
|
||||
@@ -2125,9 +2142,7 @@ merge(Compressor.prototype, {
|
||||
if (def.name instanceof AST_Destructuring) {
|
||||
var destructuring_cache = destructuring_value;
|
||||
destructuring_value = def.value;
|
||||
in_definition = true;
|
||||
def.walk(tw);
|
||||
in_definition = false;
|
||||
destructuring_value = destructuring_cache;
|
||||
} else {
|
||||
initializations.add(def.name.name, def.value);
|
||||
@@ -2163,46 +2178,8 @@ merge(Compressor.prototype, {
|
||||
scope = save_scope;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Destructuring) {
|
||||
if (!in_definition) {
|
||||
return true;
|
||||
}
|
||||
for (var i = 0; i < node.names.length; i++) {
|
||||
if (node.names[i] instanceof AST_Destructuring) {
|
||||
node.names[i].walk(tw);
|
||||
}
|
||||
else if (node.names[i] instanceof AST_Expansion) {
|
||||
if (node.names[i].expression instanceof AST_Symbol) {
|
||||
initializations.add(node.names[i].expression.name, destructuring_value);
|
||||
} else if (node.names[i].expression instanceof AST_Destructuring) {
|
||||
node.names[i].expression.walk(tw);
|
||||
} else {
|
||||
throw new Error(string_template("Can't handle expansion of type: {type}", {
|
||||
type: Object.getPrototypeOf(node.names[i].expression).TYPE
|
||||
}));
|
||||
}
|
||||
}
|
||||
else if (node.names[i] instanceof AST_ObjectKeyVal) {
|
||||
if (typeof node.names[i].key === "string") {
|
||||
initializations.add(node.names[i].key, destructuring_value);
|
||||
}
|
||||
}
|
||||
else if (node.names[i] instanceof AST_Symbol) {
|
||||
initializations.add(node.names[i].name, destructuring_value);
|
||||
}
|
||||
else if (node.names[i] instanceof AST_DefaultAssign) {
|
||||
continue;
|
||||
}
|
||||
else if (node.names[i] instanceof AST_Hole) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
throw new Error(string_template("Unknown destructuring element of type: {type}", {
|
||||
type: Object.getPrototypeOf(node.names[i]).TYPE
|
||||
}));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (node.destructuring && destructuring_value) {
|
||||
initializations.add(node.name, destructuring_value);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -2592,7 +2569,7 @@ merge(Compressor.prototype, {
|
||||
def(AST_This, return_null);
|
||||
def(AST_Call, function(compressor, first_in_statement){
|
||||
if (!this.has_pure_annotation(compressor) && compressor.pure_funcs(this)) {
|
||||
if (this.expression instanceof AST_Function
|
||||
if (is_func_expr(this.expression)
|
||||
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
|
||||
var node = this.clone();
|
||||
node.expression.process_expression(false, compressor);
|
||||
@@ -2696,6 +2673,9 @@ merge(Compressor.prototype, {
|
||||
if (expr) merge_sequence(expressions, expr);
|
||||
return make_sequence(this, expressions);
|
||||
});
|
||||
def(AST_Expansion, function(compressor, first_in_statement){
|
||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
});
|
||||
})(function(node, func){
|
||||
node.DEFMETHOD("drop_side_effect_free", func);
|
||||
});
|
||||
@@ -3116,10 +3096,10 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
if (compressor.option("unused")
|
||||
&& simple_args
|
||||
&& (fn instanceof AST_Function
|
||||
&& (is_func_expr(fn)
|
||||
|| compressor.option("reduce_vars")
|
||||
&& fn instanceof AST_SymbolRef
|
||||
&& (fn = fn.fixed_value()) instanceof AST_Function)
|
||||
&& is_func_expr(fn = fn.fixed_value()))
|
||||
&& !fn.uses_arguments
|
||||
&& !fn.uses_eval) {
|
||||
var pos = 0, last = 0;
|
||||
@@ -3293,7 +3273,7 @@ merge(Compressor.prototype, {
|
||||
if (self.args.length == 0) return make_node(AST_Function, self, {
|
||||
argnames: [],
|
||||
body: []
|
||||
});
|
||||
}).optimize(compressor);
|
||||
if (all(self.args, function(x) {
|
||||
return x instanceof AST_String;
|
||||
})) {
|
||||
@@ -3301,7 +3281,7 @@ merge(Compressor.prototype, {
|
||||
// https://github.com/mishoo/UglifyJS2/issues/203
|
||||
// if the code argument is a constant, then we can minify it.
|
||||
try {
|
||||
var code = "NaN(function(" + self.args.slice(0, -1).map(function(arg) {
|
||||
var code = "n(function(" + self.args.slice(0, -1).map(function(arg) {
|
||||
return arg.value;
|
||||
}).join(",") + "){" + self.args[self.args.length - 1].value + "})";
|
||||
var ast = parse(code);
|
||||
@@ -3310,27 +3290,36 @@ merge(Compressor.prototype, {
|
||||
var comp = new Compressor(compressor.options);
|
||||
ast = ast.transform(comp);
|
||||
ast.figure_out_scope(mangle);
|
||||
ast.mangle_names();
|
||||
base54.reset();
|
||||
ast.compute_char_frequency(mangle);
|
||||
ast.mangle_names(mangle);
|
||||
var fun;
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (fun) return true;
|
||||
if (node instanceof AST_Lambda) {
|
||||
if (is_func_expr(node)) {
|
||||
fun = node;
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
var args = fun.argnames.map(function(arg, i) {
|
||||
return make_node(AST_String, self.args[i], {
|
||||
value: arg.print_to_string()
|
||||
});
|
||||
});
|
||||
if (fun.body instanceof AST_Node) {
|
||||
fun.body = [
|
||||
make_node(AST_Return, fun.body, {
|
||||
value: fun.body
|
||||
})
|
||||
];
|
||||
}
|
||||
var code = OutputStream();
|
||||
AST_BlockStatement.prototype._codegen.call(fun, fun, code);
|
||||
code = code.toString().replace(/^\{|\}$/g, "");
|
||||
args.push(make_node(AST_String, self.args[self.args.length - 1], {
|
||||
value: code
|
||||
}));
|
||||
self.args = args;
|
||||
self.args = [
|
||||
make_node(AST_String, self, {
|
||||
value: fun.argnames.map(function(arg) {
|
||||
return arg.print_to_string();
|
||||
}).join(",")
|
||||
}),
|
||||
make_node(AST_String, self.args[self.args.length - 1], {
|
||||
value: code.get().replace(/^\{|\}$/g, "")
|
||||
})
|
||||
];
|
||||
return self;
|
||||
} catch (ex) {
|
||||
if (ex instanceof JS_Parse_Error) {
|
||||
@@ -3342,7 +3331,14 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
}
|
||||
var stat = fn instanceof AST_Function && fn.body[0];
|
||||
var stat = is_func_expr(fn) && fn.body;
|
||||
if (stat instanceof AST_Node) {
|
||||
stat = make_node(AST_Return, stat, {
|
||||
value: stat
|
||||
});
|
||||
} else if (stat) {
|
||||
stat = stat[0];
|
||||
}
|
||||
if (compressor.option("inline") && stat instanceof AST_Return) {
|
||||
var value = stat.value;
|
||||
if (!value || value.is_constant_expression()) {
|
||||
@@ -3350,10 +3346,10 @@ merge(Compressor.prototype, {
|
||||
return make_sequence(self, args).transform(compressor);
|
||||
}
|
||||
}
|
||||
if (exp instanceof AST_Function && !exp.is_generator && !exp.async) {
|
||||
if (is_func_expr(exp) && !exp.is_generator && !exp.async) {
|
||||
if (compressor.option("inline")
|
||||
&& !exp.name
|
||||
&& exp.body.length == 1
|
||||
&& (exp.body instanceof AST_Node || exp.body.length == 1)
|
||||
&& !exp.uses_arguments
|
||||
&& !exp.uses_eval
|
||||
&& simple_args
|
||||
@@ -3403,6 +3399,13 @@ merge(Compressor.prototype, {
|
||||
value: value
|
||||
}));
|
||||
var body = fn.transform(compressor).body;
|
||||
if (body instanceof AST_Node) {
|
||||
body = [
|
||||
make_node(AST_Return, body, {
|
||||
value: body
|
||||
})
|
||||
];
|
||||
}
|
||||
if (body.length == 0) return make_node(AST_Undefined, self);
|
||||
if (body.length == 1 && body[0] instanceof AST_Return) {
|
||||
value = body[0].value;
|
||||
@@ -3429,7 +3432,7 @@ merge(Compressor.prototype, {
|
||||
if (value !== self) return value;
|
||||
}
|
||||
}
|
||||
if (compressor.option("side_effects") && all(exp.body, is_empty)) {
|
||||
if (compressor.option("side_effects") && !(exp.body instanceof AST_Node) && all(exp.body, is_empty)) {
|
||||
var args = self.args.concat(make_node(AST_Undefined, self));
|
||||
return make_sequence(self, args).transform(compressor);
|
||||
}
|
||||
@@ -3564,6 +3567,8 @@ merge(Compressor.prototype, {
|
||||
|| cdr instanceof AST_PropAccess
|
||||
|| cdr instanceof AST_Unary && !unary_side_effects(cdr.operator)) {
|
||||
field = "expression";
|
||||
} else if (cdr instanceof AST_Conditional) {
|
||||
field = "condition";
|
||||
} else {
|
||||
expressions[++i] = expressions[j];
|
||||
break;
|
||||
@@ -4098,15 +4103,15 @@ merge(Compressor.prototype, {
|
||||
var d = self.definition();
|
||||
var fixed = self.fixed_value();
|
||||
if (fixed instanceof AST_Defun) {
|
||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed).clone(true);
|
||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
||||
}
|
||||
if (compressor.option("unused")
|
||||
&& fixed instanceof AST_Function
|
||||
&& is_func_expr(fixed)
|
||||
&& d.references.length == 1
|
||||
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
||||
&& !d.scope.uses_eval
|
||||
&& compressor.find_parent(AST_Scope) === fixed.parent_scope) {
|
||||
return fixed;
|
||||
return fixed.clone(true);
|
||||
}
|
||||
if (compressor.option("evaluate") && fixed) {
|
||||
if (d.should_replace === undefined) {
|
||||
@@ -4129,7 +4134,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
var name_length = d.name.length;
|
||||
var overhead = 0;
|
||||
if (compressor.option("unused") && (!d.global || compressor.toplevel(d))) {
|
||||
if (compressor.option("unused") && !compressor.exposed(d)) {
|
||||
overhead = (name_length + 2 + value_length) / d.references.length;
|
||||
}
|
||||
d.should_replace = value_length <= name_length + overhead ? fn : false;
|
||||
@@ -4540,13 +4545,37 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_Arrow, function(self, compressor){
|
||||
if (self.body.length === 1 && self.body[0] instanceof AST_Return) {
|
||||
if (!(self.body instanceof AST_Node)) tighten_body(self.body, compressor);
|
||||
if (compressor.option("arrows")
|
||||
&& self.body.length == 1
|
||||
&& self.body[0] instanceof AST_Return) {
|
||||
var value = self.body[0].value;
|
||||
self.body = value ? value : [];
|
||||
}
|
||||
return self;
|
||||
});
|
||||
|
||||
OPT(AST_Function, function(self, compressor){
|
||||
tighten_body(self.body, compressor);
|
||||
if (compressor.option("arrows")
|
||||
&& compressor.option("ecma") >= 6
|
||||
&& !self.name
|
||||
&& !self.is_generator
|
||||
&& !self.uses_arguments
|
||||
&& !self.uses_eval) {
|
||||
var has_special_symbol = false;
|
||||
self.walk(new TreeWalker(function(node) {
|
||||
if (has_special_symbol) return true;
|
||||
if (node instanceof AST_Symbol && !node.definition()) {
|
||||
has_special_symbol = true;
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
if (!has_special_symbol) return make_node(AST_Arrow, self, self).optimize(compressor);
|
||||
}
|
||||
return self;
|
||||
});
|
||||
|
||||
OPT(AST_Class, function(self, compressor){
|
||||
// HACK to avoid compress failure.
|
||||
// AST_Class is not really an AST_Scope/AST_Block as it lacks a body.
|
||||
|
||||
@@ -32,6 +32,7 @@ function minify(files, options) {
|
||||
try {
|
||||
options = defaults(options, {
|
||||
compress: {},
|
||||
ecma: undefined,
|
||||
ie8: false,
|
||||
keep_fnames: false,
|
||||
mangle: {},
|
||||
@@ -46,6 +47,7 @@ function minify(files, options) {
|
||||
var timings = options.timings && {
|
||||
start: Date.now()
|
||||
};
|
||||
set_shorthand("ecma", options, [ "parse", "compress", "output" ]);
|
||||
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
|
||||
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
||||
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
||||
|
||||
@@ -533,6 +533,7 @@ function OutputStream(options) {
|
||||
use_asm = prev_use_asm;
|
||||
}
|
||||
});
|
||||
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||
|
||||
AST_Node.DEFMETHOD("print_to_string", function(options){
|
||||
var s = OutputStream(options);
|
||||
@@ -978,12 +979,12 @@ function OutputStream(options) {
|
||||
AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){
|
||||
var self = this;
|
||||
if (!nokeyword) {
|
||||
if (this.async) {
|
||||
if (self.async) {
|
||||
output.print("async");
|
||||
output.space();
|
||||
}
|
||||
output.print("function");
|
||||
if (this.is_generator) {
|
||||
if (self.is_generator) {
|
||||
output.star();
|
||||
}
|
||||
if (self.name) {
|
||||
@@ -1038,6 +1039,10 @@ function OutputStream(options) {
|
||||
var needs_parens = parent instanceof AST_Binary ||
|
||||
parent instanceof AST_Unary ||
|
||||
(parent instanceof AST_Call && self === parent.expression);
|
||||
if (self.async) {
|
||||
output.print("async");
|
||||
output.space();
|
||||
}
|
||||
if (needs_parens) { output.print("(") }
|
||||
if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) {
|
||||
self.argnames[0].print(output);
|
||||
@@ -1053,9 +1058,9 @@ function OutputStream(options) {
|
||||
output.print('=>');
|
||||
output.space();
|
||||
if (self.body instanceof AST_Node) {
|
||||
this.body.print(output);
|
||||
self.body.print(output);
|
||||
} else {
|
||||
print_bracketed(this.body, output);
|
||||
print_bracketed(self.body, output);
|
||||
}
|
||||
if (needs_parens) { output.print(")") }
|
||||
});
|
||||
|
||||
151
lib/parse.js
151
lib/parse.js
@@ -509,8 +509,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
}
|
||||
var content = "", raw = "", ch, tok;
|
||||
next(true, true);
|
||||
while ((ch = next(true, true)) !== "`") {
|
||||
if (ch === "$" && peek() === "{") {
|
||||
while ((ch = next(true, true)) != "`") {
|
||||
if (ch == "\r") {
|
||||
if (peek() == "\n") ++S.pos;
|
||||
ch = "\n";
|
||||
} else if (ch == "$" && peek() == "{") {
|
||||
next(true, true);
|
||||
S.brace_counter++;
|
||||
tok = token(begin ? "template_head" : "template_substitution", content);
|
||||
@@ -521,7 +524,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||
}
|
||||
|
||||
raw += ch;
|
||||
if (ch === "\\") {
|
||||
if (ch == "\\") {
|
||||
var tmp = S.pos;
|
||||
ch = read_escaped_char();
|
||||
raw += S.text.substr(tmp, S.pos - tmp);
|
||||
@@ -856,6 +859,7 @@ function parse($TEXT, options) {
|
||||
|
||||
options = defaults(options, {
|
||||
bare_returns : false,
|
||||
ecma : 8,
|
||||
expression : false,
|
||||
filename : null,
|
||||
html5_comments : true,
|
||||
@@ -1229,9 +1233,12 @@ function parse($TEXT, options) {
|
||||
var is_in = is("operator", "in");
|
||||
var is_of = is("name", "of");
|
||||
if (is_in || is_of) {
|
||||
if ((init instanceof AST_Definitions) &&
|
||||
init.definitions.length > 1)
|
||||
croak("Only one variable declaration allowed in for..in loop");
|
||||
if (init instanceof AST_Definitions) {
|
||||
if (init.definitions.length > 1)
|
||||
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||
} else if (!(is_assignable(init) || (init = to_destructuring(init)) instanceof AST_Destructuring)) {
|
||||
croak("Invalid left-hand side in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||
}
|
||||
next();
|
||||
if (is_in) {
|
||||
return for_in(init);
|
||||
@@ -1281,18 +1288,19 @@ function parse($TEXT, options) {
|
||||
});
|
||||
};
|
||||
|
||||
var arrow_function = function(start, argnames) {
|
||||
var arrow_function = function(start, argnames, is_async) {
|
||||
if (S.token.nlb) {
|
||||
croak("Unexpected newline before arrow (=>)");
|
||||
}
|
||||
|
||||
expect_token("arrow", "=>");
|
||||
|
||||
var body = _function_body(is("punc", "{"));
|
||||
var body = _function_body(is("punc", "{"), false, is_async);
|
||||
|
||||
return new AST_Arrow({
|
||||
start : start,
|
||||
end : body.end,
|
||||
async : is_async,
|
||||
argnames : argnames,
|
||||
body : body
|
||||
});
|
||||
@@ -1385,22 +1393,20 @@ function parse($TEXT, options) {
|
||||
|
||||
function parameters() {
|
||||
var start = S.token;
|
||||
var first = true;
|
||||
var params = [];
|
||||
var used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict"));
|
||||
|
||||
expect("(");
|
||||
|
||||
while (!is("punc", ")")) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
expect(",");
|
||||
}
|
||||
|
||||
var param = parameter(used_parameters);
|
||||
params.push(param);
|
||||
|
||||
if (!is("punc", ")")) {
|
||||
expect(",");
|
||||
if (is("punc", ")") && options.ecma < 8) unexpected();
|
||||
}
|
||||
|
||||
if (param instanceof AST_Expansion) {
|
||||
break;
|
||||
}
|
||||
@@ -1616,25 +1622,40 @@ function parse($TEXT, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function params_or_seq_() {
|
||||
var first = true;
|
||||
function params_or_seq_(allow_arrows, maybe_sequence) {
|
||||
var spread_token;
|
||||
var invalid_sequence;
|
||||
var trailing_comma;
|
||||
var a = [];
|
||||
expect("(");
|
||||
while (!is("punc", ")")) {
|
||||
if (first) first = false; else expect(",");
|
||||
if (spread_token) unexpected(spread_token);
|
||||
if (is("expand", "...")) {
|
||||
var spread_token = S.token;
|
||||
spread_token = S.token;
|
||||
if (maybe_sequence) invalid_sequence = S.token;
|
||||
next();
|
||||
a.push(new AST_Expansion({
|
||||
start: prev(),
|
||||
expression: expression(),
|
||||
end: S.token,
|
||||
}));
|
||||
if (!is("punc", ")")) {
|
||||
unexpected(spread_token);
|
||||
}
|
||||
} else {
|
||||
a.push(expression());
|
||||
}
|
||||
if (!is("punc", ")")) {
|
||||
expect(",");
|
||||
if (is("punc", ")")) {
|
||||
if (options.ecma < 8) unexpected();
|
||||
trailing_comma = prev();
|
||||
if (maybe_sequence) invalid_sequence = trailing_comma;
|
||||
}
|
||||
}
|
||||
}
|
||||
expect(")");
|
||||
if (allow_arrows && is("arrow", "=>")) {
|
||||
if (spread_token && trailing_comma) unexpected(trailing_comma);
|
||||
} else if (invalid_sequence) {
|
||||
unexpected(invalid_sequence);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
@@ -1882,7 +1903,7 @@ function parse($TEXT, options) {
|
||||
var newexp = expr_atom(false), args;
|
||||
if (is("punc", "(")) {
|
||||
next();
|
||||
args = expr_list(")");
|
||||
args = expr_list(")", options.ecma >= 8);
|
||||
} else {
|
||||
args = [];
|
||||
}
|
||||
@@ -1989,21 +2010,24 @@ function parse($TEXT, options) {
|
||||
}
|
||||
}
|
||||
|
||||
var expr_atom = function(allow_calls) {
|
||||
var expr_atom = function(allow_calls, allow_arrows) {
|
||||
if (is("operator", "new")) {
|
||||
return new_(allow_calls);
|
||||
}
|
||||
var start = S.token;
|
||||
var async = is("name", "async") && as_atom_node();
|
||||
if (is("punc")) {
|
||||
switch (start.value) {
|
||||
switch (S.token.value) {
|
||||
case "(":
|
||||
next();
|
||||
var exprs = params_or_seq_();
|
||||
expect(")");
|
||||
if (is("arrow", "=>")) {
|
||||
return arrow_function(start, exprs.map(to_fun_args));
|
||||
if (async && !allow_calls) break;
|
||||
var exprs = params_or_seq_(allow_arrows, !async);
|
||||
if (allow_arrows && is("arrow", "=>")) {
|
||||
return arrow_function(start, exprs.map(to_fun_args), !!async);
|
||||
}
|
||||
var ex = exprs.length == 1 ? exprs[0] : new AST_Sequence({
|
||||
var ex = async ? new AST_Call({
|
||||
expression: async,
|
||||
args: exprs
|
||||
}) : exprs.length == 1 ? exprs[0] : new AST_Sequence({
|
||||
expressions: exprs
|
||||
});
|
||||
ex.start = start;
|
||||
@@ -2014,23 +2038,25 @@ function parse($TEXT, options) {
|
||||
case "{":
|
||||
return subscripts(object_or_destructuring_(), allow_calls);
|
||||
}
|
||||
unexpected();
|
||||
if (!async) unexpected();
|
||||
}
|
||||
if (is("name", "async") && is_token(peek(), "keyword", "function")) {
|
||||
if (allow_arrows && is("name") && is_token(peek(), "arrow")) {
|
||||
var param = new AST_SymbolFunarg({
|
||||
name: S.token.value,
|
||||
start: start,
|
||||
end: start,
|
||||
});
|
||||
next();
|
||||
next();
|
||||
var func = function_(AST_Function, false, true);
|
||||
func.start = start;
|
||||
func.end = prev();
|
||||
return subscripts(func, allow_calls);
|
||||
return arrow_function(start, [param], !!async);
|
||||
}
|
||||
if (is("keyword", "function")) {
|
||||
next();
|
||||
var func = function_(AST_Function);
|
||||
var func = function_(AST_Function, false, !!async);
|
||||
func.start = start;
|
||||
func.end = prev();
|
||||
return subscripts(func, allow_calls);
|
||||
}
|
||||
if (async) return subscripts(async, allow_calls);
|
||||
if (is("keyword", "class")) {
|
||||
next();
|
||||
var cls = class_(AST_ClassExpression);
|
||||
@@ -2327,6 +2353,14 @@ function parse($TEXT, options) {
|
||||
}
|
||||
|
||||
function map_name(is_import) {
|
||||
function make_symbol(type) {
|
||||
return new type({
|
||||
name: as_property_name(),
|
||||
start: prev(),
|
||||
end: prev()
|
||||
});
|
||||
}
|
||||
|
||||
var foreign_type = is_import ? AST_SymbolImportForeign : AST_SymbolExportForeign;
|
||||
var type = is_import ? AST_SymbolImport : AST_SymbolExport;
|
||||
var start = S.token;
|
||||
@@ -2334,16 +2368,16 @@ function parse($TEXT, options) {
|
||||
var name;
|
||||
|
||||
if (is_import) {
|
||||
foreign_name = as_symbol(foreign_type);
|
||||
foreign_name = make_symbol(foreign_type);
|
||||
} else {
|
||||
name = as_symbol(type);
|
||||
name = make_symbol(type);
|
||||
}
|
||||
if (is("name", "as")) {
|
||||
next(); // The "as" word
|
||||
if (is_import) {
|
||||
name = as_symbol(type);
|
||||
name = make_symbol(type);
|
||||
} else {
|
||||
foreign_name = as_symbol(foreign_type);
|
||||
foreign_name = make_symbol(foreign_type);
|
||||
}
|
||||
} else if (is_import) {
|
||||
name = new type(foreign_name);
|
||||
@@ -2592,11 +2626,9 @@ function parse($TEXT, options) {
|
||||
return expr;
|
||||
};
|
||||
|
||||
var call_args = embed_tokens(function call_args() {
|
||||
var first = true;
|
||||
var call_args = embed_tokens(function _call_args() {
|
||||
var args = [];
|
||||
while (!is("punc", ")")) {
|
||||
if (first) first = false; else expect(",");
|
||||
if (is("expand", "...")) {
|
||||
next();
|
||||
args.push(new AST_Expansion({
|
||||
@@ -2606,12 +2638,16 @@ function parse($TEXT, options) {
|
||||
} else {
|
||||
args.push(expression(false));
|
||||
}
|
||||
if (!is("punc", ")")) {
|
||||
expect(",");
|
||||
if (is("punc", ")") && options.ecma < 8) unexpected();
|
||||
}
|
||||
}
|
||||
next();
|
||||
return args;
|
||||
});
|
||||
|
||||
var maybe_unary = function(allow_calls) {
|
||||
var maybe_unary = function(allow_calls, allow_arrows) {
|
||||
var start = S.token;
|
||||
if (start.type == "name" && start.value == "await") {
|
||||
if (is_in_async()) {
|
||||
@@ -2629,8 +2665,9 @@ function parse($TEXT, options) {
|
||||
ex.end = prev();
|
||||
return ex;
|
||||
}
|
||||
var val = expr_atom(allow_calls);
|
||||
var val = expr_atom(allow_calls, allow_arrows);
|
||||
while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
|
||||
if (val instanceof AST_Arrow) unexpected();
|
||||
val = make_unary(AST_UnaryPostfix, S.token, val);
|
||||
val.start = start;
|
||||
val.end = S.token;
|
||||
@@ -2678,7 +2715,7 @@ function parse($TEXT, options) {
|
||||
};
|
||||
|
||||
function expr_ops(no_in) {
|
||||
return expr_op(maybe_unary(true), 0, no_in);
|
||||
return expr_op(maybe_unary(true, true), 0, no_in);
|
||||
};
|
||||
|
||||
var maybe_conditional = function(no_in) {
|
||||
@@ -2759,22 +2796,6 @@ function parse($TEXT, options) {
|
||||
}
|
||||
}
|
||||
|
||||
if (start.type == "punc" && start.value == "(" && peek().value == ")") {
|
||||
next();
|
||||
next();
|
||||
return arrow_function(start, []);
|
||||
}
|
||||
|
||||
if (is("name") && is_token(peek(), "arrow")) {
|
||||
var param = new AST_SymbolFunarg({
|
||||
name: start.value,
|
||||
start: start,
|
||||
end: start,
|
||||
});
|
||||
next();
|
||||
return arrow_function(start, [param]);
|
||||
}
|
||||
|
||||
var left = maybe_conditional(no_in);
|
||||
var val = S.token.value;
|
||||
|
||||
|
||||
139
lib/scope.js
139
lib/scope.js
@@ -132,7 +132,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
scope = save_scope;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Destructuring && node.is_array === false) {
|
||||
if (node instanceof AST_Destructuring) {
|
||||
in_destructuring = node; // These don't nest
|
||||
descend();
|
||||
in_destructuring = null;
|
||||
@@ -263,8 +263,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
s.uses_eval = true;
|
||||
}
|
||||
}
|
||||
var sym = node.scope.find_variable(name);
|
||||
if (!sym) {
|
||||
var sym;
|
||||
if (tw.parent() instanceof AST_NameMapping && tw.parent(1).module_name
|
||||
|| !(sym = node.scope.find_variable(name))) {
|
||||
sym = self.def_global(node);
|
||||
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
|
||||
sym.scope.uses_arguments = true;
|
||||
@@ -449,7 +450,7 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
||||
|
||||
AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
||||
var def = this.definition();
|
||||
return def && def.unmangleable(options);
|
||||
return !def || def.unmangleable(options);
|
||||
});
|
||||
|
||||
// labels are always mangleable
|
||||
@@ -554,113 +555,69 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
||||
|
||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
||||
options = this._default_mangler_options(options);
|
||||
var tw = new TreeWalker(function(node){
|
||||
if (node instanceof AST_Constant)
|
||||
base54.consider(node.print_to_string());
|
||||
else if (node instanceof AST_Return)
|
||||
base54.consider("return");
|
||||
else if (node instanceof AST_Throw)
|
||||
base54.consider("throw");
|
||||
else if (node instanceof AST_Continue)
|
||||
base54.consider("continue");
|
||||
else if (node instanceof AST_Break)
|
||||
base54.consider("break");
|
||||
else if (node instanceof AST_Debugger)
|
||||
base54.consider("debugger");
|
||||
else if (node instanceof AST_Directive)
|
||||
base54.consider(node.value);
|
||||
else if (node instanceof AST_While)
|
||||
base54.consider("while");
|
||||
else if (node instanceof AST_Do)
|
||||
base54.consider("do while");
|
||||
else if (node instanceof AST_If) {
|
||||
base54.consider("if");
|
||||
if (node.alternative) base54.consider("else");
|
||||
}
|
||||
else if (node instanceof AST_Var)
|
||||
base54.consider("var");
|
||||
else if (node instanceof AST_Const)
|
||||
base54.consider("const");
|
||||
else if (node instanceof AST_Lambda)
|
||||
base54.consider("function");
|
||||
else if (node instanceof AST_For)
|
||||
base54.consider("for");
|
||||
else if (node instanceof AST_ForIn)
|
||||
base54.consider("for in");
|
||||
else if (node instanceof AST_Switch)
|
||||
base54.consider("switch");
|
||||
else if (node instanceof AST_Case)
|
||||
base54.consider("case");
|
||||
else if (node instanceof AST_Default)
|
||||
base54.consider("default");
|
||||
else if (node instanceof AST_With)
|
||||
base54.consider("with");
|
||||
else if (node instanceof AST_ObjectSetter)
|
||||
base54.consider("set" + (typeof node.key === "string" ? node.key : ""));
|
||||
else if (node instanceof AST_ObjectGetter)
|
||||
base54.consider("get" + (typeof node.key === "string" ? node.key : ""));
|
||||
else if (node instanceof AST_ObjectKeyVal && typeof node.key === "string")
|
||||
base54.consider(node.key);
|
||||
else if (node instanceof AST_ConciseMethod && typeof node.key === "string")
|
||||
base54.consider(node.key);
|
||||
else if (node instanceof AST_New)
|
||||
base54.consider("new");
|
||||
else if (node instanceof AST_This)
|
||||
base54.consider("this");
|
||||
else if (node instanceof AST_Super)
|
||||
base54.consider("super");
|
||||
else if (node instanceof AST_Try)
|
||||
base54.consider("try");
|
||||
else if (node instanceof AST_Catch)
|
||||
base54.consider("catch");
|
||||
else if (node instanceof AST_Finally)
|
||||
base54.consider("finally");
|
||||
else if (node instanceof AST_Yield)
|
||||
base54.consider("yield");
|
||||
else if (node instanceof AST_Await)
|
||||
base54.consider("await");
|
||||
else if (node instanceof AST_Symbol && node.unmangleable(options))
|
||||
base54.consider(node.name);
|
||||
else if (node instanceof AST_Unary || node instanceof AST_Binary)
|
||||
base54.consider(node.operator);
|
||||
else if (node instanceof AST_Dot)
|
||||
base54.consider(node.property);
|
||||
});
|
||||
this.walk(tw);
|
||||
try {
|
||||
AST_Node.prototype.print = function(stream, force_parens) {
|
||||
this._print(stream, force_parens);
|
||||
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
|
||||
base54.consider(this.name, -1);
|
||||
} else if (options.properties) {
|
||||
if (this instanceof AST_Dot) {
|
||||
base54.consider(this.property, -1);
|
||||
} else if (this instanceof AST_Sub) {
|
||||
skip_string(this.property);
|
||||
}
|
||||
}
|
||||
};
|
||||
base54.consider(this.print_to_string(), 1);
|
||||
} finally {
|
||||
AST_Node.prototype.print = AST_Node.prototype._print;
|
||||
}
|
||||
base54.sort();
|
||||
|
||||
function skip_string(node) {
|
||||
if (node instanceof AST_String) {
|
||||
base54.consider(node.value, -1);
|
||||
} else if (node instanceof AST_Conditional) {
|
||||
skip_string(node.consequent);
|
||||
skip_string(node.alternative);
|
||||
} else if (node instanceof AST_Sequence) {
|
||||
skip_string(node.expressions[node.expressions.length - 1]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var base54 = (function() {
|
||||
var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
|
||||
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
|
||||
var digits = "0123456789".split("");
|
||||
var chars, frequency;
|
||||
function reset() {
|
||||
frequency = Object.create(null);
|
||||
chars = string.split("").map(function(ch){ return ch.charCodeAt(0) });
|
||||
chars.forEach(function(ch){ frequency[ch] = 0 });
|
||||
leading.forEach(function(ch) {
|
||||
frequency[ch] = 0;
|
||||
});
|
||||
digits.forEach(function(ch) {
|
||||
frequency[ch] = 0;
|
||||
});
|
||||
}
|
||||
base54.consider = function(str){
|
||||
base54.consider = function(str, delta) {
|
||||
for (var i = str.length; --i >= 0;) {
|
||||
var code = str.charCodeAt(i);
|
||||
if (code in frequency) ++frequency[code];
|
||||
frequency[str[i]] += delta;
|
||||
}
|
||||
};
|
||||
function compare(a, b) {
|
||||
return frequency[b] - frequency[a];
|
||||
}
|
||||
base54.sort = function() {
|
||||
chars = mergeSort(chars, function(a, b){
|
||||
if (is_digit(a) && !is_digit(b)) return 1;
|
||||
if (is_digit(b) && !is_digit(a)) return -1;
|
||||
return frequency[b] - frequency[a];
|
||||
});
|
||||
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
|
||||
};
|
||||
base54.reset = reset;
|
||||
reset();
|
||||
base54.get = function(){ return chars };
|
||||
base54.freq = function(){ return frequency };
|
||||
function base54(num) {
|
||||
var ret = "", base = 54;
|
||||
num++;
|
||||
do {
|
||||
num--;
|
||||
ret += String.fromCharCode(chars[num % base]);
|
||||
ret += chars[num % base];
|
||||
num = Math.floor(num / base);
|
||||
base = 64;
|
||||
} while (num > 0);
|
||||
|
||||
17
package.json
17
package.json
@@ -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.0.19",
|
||||
"version": "3.0.21",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
@@ -40,5 +40,18 @@
|
||||
"scripts": {
|
||||
"test": "node test/run-tests.js"
|
||||
},
|
||||
"keywords": ["uglify", "uglify-js", "uglify-es", "minify", "minifier", "es5", "es6", "es2015"]
|
||||
"keywords": [
|
||||
"uglify",
|
||||
"uglify-js",
|
||||
"uglify-es",
|
||||
"minify",
|
||||
"minifier",
|
||||
"es5",
|
||||
"es6",
|
||||
"es2015",
|
||||
"es2016",
|
||||
"es2017",
|
||||
"async",
|
||||
"await"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -202,3 +202,339 @@ arrow_unused_toplevel: {
|
||||
expect_stdout: [ "0", "1", "2", "9" ]
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
no_leading_parentheses: {
|
||||
input: {
|
||||
(x,y) => x(y);
|
||||
async (x,y) => await x(y);
|
||||
}
|
||||
expect_exact: "(x,y)=>x(y);async(x,y)=>await x(y);"
|
||||
}
|
||||
|
||||
async_identifiers: {
|
||||
options = {
|
||||
arrows: true,
|
||||
ecma: 6,
|
||||
}
|
||||
input: {
|
||||
var async = function(x){ console.log("async", x); };
|
||||
var await = function(x){ console.log("await", x); };
|
||||
async(1);
|
||||
await(2);
|
||||
}
|
||||
expect: {
|
||||
var async = x => { console.log("async", x); };
|
||||
var await = x => { console.log("await", x); };
|
||||
async(1);
|
||||
await(2);
|
||||
}
|
||||
expect_stdout: [
|
||||
"async 1",
|
||||
"await 2",
|
||||
]
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
async_function_expression: {
|
||||
options = {
|
||||
arrows: true,
|
||||
ecma: 6,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var named = async function foo() {
|
||||
await bar(1 + 0) + (2 + 0);
|
||||
}
|
||||
var anon = async function() {
|
||||
await (1 + 0) + bar(2 + 0);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var named = async function foo() {
|
||||
await bar(1);
|
||||
};
|
||||
var anon = async () => {
|
||||
await 1, bar(2);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
issue_27: {
|
||||
options = {
|
||||
arrows: true,
|
||||
collapse_vars: true,
|
||||
ecma: 6,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(jQuery) {
|
||||
var $;
|
||||
$ = jQuery;
|
||||
$("body").addClass("foo");
|
||||
})(jQuery);
|
||||
}
|
||||
expect: {
|
||||
(jQuery => {
|
||||
jQuery("body").addClass("foo");
|
||||
})(jQuery);
|
||||
}
|
||||
}
|
||||
|
||||
issue_2105_1: {
|
||||
options = {
|
||||
arrows: true,
|
||||
collapse_vars: true,
|
||||
ecma: 6,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
!function(factory) {
|
||||
factory();
|
||||
}( function() {
|
||||
return function(fn) {
|
||||
fn()().prop();
|
||||
}( function() {
|
||||
function bar() {
|
||||
var quux = function() {
|
||||
console.log("PASS");
|
||||
}, foo = function() {
|
||||
console.log;
|
||||
quux();
|
||||
};
|
||||
return { prop: foo };
|
||||
}
|
||||
return bar;
|
||||
} );
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
!void (() => {
|
||||
var quux = () => {
|
||||
console.log("PASS");
|
||||
};
|
||||
return {
|
||||
prop: () => {
|
||||
console.log;
|
||||
quux();
|
||||
}
|
||||
};
|
||||
})().prop();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
issue_2105_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
((factory) => {
|
||||
factory();
|
||||
})( () => {
|
||||
return ((fn) => {
|
||||
fn()().prop();
|
||||
})( () => {
|
||||
let bar = () => {
|
||||
var quux = () => {
|
||||
console.log("PASS");
|
||||
}, foo = () => {
|
||||
console.log;
|
||||
quux();
|
||||
};
|
||||
return { prop: foo };
|
||||
};
|
||||
return bar;
|
||||
} );
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
!void (() => {
|
||||
var quux = () => {
|
||||
console.log("PASS");
|
||||
};
|
||||
return {
|
||||
prop: () => {
|
||||
console.log;
|
||||
quux();
|
||||
}
|
||||
};
|
||||
})().prop();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_2136_2: {
|
||||
options = {
|
||||
arrows: true,
|
||||
collapse_vars: true,
|
||||
ecma: 6,
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(x) {
|
||||
console.log(x);
|
||||
}
|
||||
!function(a, ...b) {
|
||||
f(b[0]);
|
||||
}(1, 2, 3);
|
||||
}
|
||||
expect: {
|
||||
function f(x) {
|
||||
console.log(x);
|
||||
}
|
||||
f([2,3][0]);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_2136_3: {
|
||||
options = {
|
||||
arrows: true,
|
||||
collapse_vars: true,
|
||||
ecma: 6,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(x) {
|
||||
console.log(x);
|
||||
}
|
||||
!function(a, ...b) {
|
||||
f(b[0]);
|
||||
}(1, 2, 3);
|
||||
}
|
||||
expect: {
|
||||
console.log(2);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
call_args: {
|
||||
options = {
|
||||
arrows: true,
|
||||
ecma: 6,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
const a = 1;
|
||||
console.log(a);
|
||||
+function(a) {
|
||||
return a;
|
||||
}(a);
|
||||
}
|
||||
expect: {
|
||||
const a = 1;
|
||||
console.log(1);
|
||||
+(1, 1);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
call_args_drop_param: {
|
||||
options = {
|
||||
arrows: true,
|
||||
ecma: 6,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
const a = 1;
|
||||
console.log(a);
|
||||
+function(a) {
|
||||
return a;
|
||||
}(a, b);
|
||||
}
|
||||
expect: {
|
||||
const a = 1;
|
||||
console.log(1);
|
||||
+(b, 1);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_485_crashing_1530: {
|
||||
options = {
|
||||
arrows: true,
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
ecma: 6,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
if (true) return;
|
||||
var b = 42;
|
||||
})(this);
|
||||
}
|
||||
expect: {
|
||||
this, void 0;
|
||||
}
|
||||
}
|
||||
|
||||
issue_2084: {
|
||||
options = {
|
||||
arrows: true,
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
ecma: 6,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
!function() {
|
||||
!function(c) {
|
||||
c = 1 + c;
|
||||
var c = 0;
|
||||
function f14(a_1) {
|
||||
if (c = 1 + c, 0 !== 23..toString())
|
||||
c = 1 + c, a_1 && (a_1[0] = 0);
|
||||
}
|
||||
f14();
|
||||
}(-1);
|
||||
}();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
!((c) => {
|
||||
c = 1 + c,
|
||||
c = 1 + (c = 0),
|
||||
0 !== 23..toString() && (c = 1 + c);
|
||||
})(-1),
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
@@ -167,14 +167,14 @@ async_inline: {
|
||||
|
||||
async_identifiers: {
|
||||
input: {
|
||||
let async = function(x){ console.log("async", x); };
|
||||
let await = function(x){ console.log("await", x); };
|
||||
var async = function(x){ console.log("async", x); };
|
||||
var await = function(x){ console.log("await", x); };
|
||||
async(1);
|
||||
await(2);
|
||||
}
|
||||
expect: {
|
||||
let async = function(x){ console.log("async", x); };
|
||||
let await = function(x){ console.log("await", x); };
|
||||
var async = function(x){ console.log("async", x); };
|
||||
var await = function(x){ console.log("await", x); };
|
||||
async(1);
|
||||
await(2);
|
||||
}
|
||||
@@ -182,7 +182,6 @@ async_identifiers: {
|
||||
"async 1",
|
||||
"await 2",
|
||||
]
|
||||
node_version: ">=8"
|
||||
}
|
||||
|
||||
async_shorthand_property: {
|
||||
@@ -230,16 +229,26 @@ async_shorthand_property: {
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
/* FIXME: add test when supported by parser
|
||||
async_arrow: {
|
||||
input: {
|
||||
let a1 = async x => await foo(x);
|
||||
let a2 = async () => await bar();
|
||||
let a3 = async (x) => await baz(x);
|
||||
let a4 = async (x, y) => { await far(x, y); }
|
||||
let a5 = async ({x = [1], y: z = 2}) => { await wow(x, y); }
|
||||
let a5 = async ({x = [1], y: z = 2}) => { await wow(x, z); }
|
||||
}
|
||||
expect: {
|
||||
let a1 = async x => await foo(x);
|
||||
let a2 = async () => await bar();
|
||||
let a3 = async (x) => await baz(x);
|
||||
let a4 = async (x, y) => { await far(x, y); }
|
||||
let a5 = async ({x = [1], y: z = 2}) => { await wow(x, z); }
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
async_arrow_wait: {
|
||||
input: {
|
||||
var a = async (x, y) => await x(y);
|
||||
}
|
||||
expect_exact: "var a=async(x,y)=>await x(y);"
|
||||
}
|
||||
|
||||
@@ -104,34 +104,36 @@ regression_block_scope_resolves: {
|
||||
};
|
||||
input: {
|
||||
(function () {
|
||||
if(1) {
|
||||
if (1) {
|
||||
let x;
|
||||
const y;
|
||||
const y = 1;
|
||||
class Zee {};
|
||||
}
|
||||
if(1) {
|
||||
if (1) {
|
||||
let ex;
|
||||
const why;
|
||||
const why = 2;
|
||||
class Zi {};
|
||||
}
|
||||
console.log(x, y, Zee, ex, why, Zi);
|
||||
console.log(typeof x, typeof y, typeof Zee, typeof ex, typeof why, typeof Zi);
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
(function () {
|
||||
if (1) {
|
||||
let o;
|
||||
const n;
|
||||
class c {};
|
||||
let e;
|
||||
const o = 1;
|
||||
class t {};
|
||||
}
|
||||
if (1) {
|
||||
let o;
|
||||
const n;
|
||||
class c {};
|
||||
let e;
|
||||
const o = 2;
|
||||
class t {};
|
||||
}
|
||||
console.log(x, y, Zee, ex, why, Zi);
|
||||
console.log(typeof x, typeof y, typeof Zee, typeof ex, typeof why, typeof Zi);
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined undefined undefined undefined undefined undefined"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
switch_block_scope_mangler: {
|
||||
@@ -153,25 +155,37 @@ switch_block_scope_mangler: {
|
||||
console.log(cat);
|
||||
}
|
||||
};
|
||||
fn(1);
|
||||
fn(2);
|
||||
fn(3);
|
||||
}
|
||||
expect: {
|
||||
var fn = function(o) {
|
||||
switch (o) {
|
||||
var fn = function(e) {
|
||||
switch (e) {
|
||||
case 1:
|
||||
let e = o + 1
|
||||
let c = o + 4;
|
||||
console.log(e, c);
|
||||
let l = e + 1
|
||||
let o = e + 4;
|
||||
console.log(l, o);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
let l = o + 2;
|
||||
console.log(l);
|
||||
let n = e + 2;
|
||||
console.log(n);
|
||||
break;
|
||||
|
||||
default:
|
||||
let a = o + 3;
|
||||
console.log(a);
|
||||
let c = e + 3;
|
||||
console.log(c);
|
||||
}
|
||||
};
|
||||
fn(1);
|
||||
fn(2);
|
||||
fn(3);
|
||||
}
|
||||
expect_stdout: [
|
||||
"2 5",
|
||||
"4",
|
||||
"6",
|
||||
]
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
@@ -425,8 +425,8 @@ mangle_destructuring_decl: {
|
||||
expect: {
|
||||
function test(t) {
|
||||
let e = t.a || { e: 7, n: 8 };
|
||||
let {t: n, e: o, n: s, s: a = 9, o: c, r: l} = e;
|
||||
console.log(n, o, s, a, c, l);
|
||||
let {t: n, e: o, n: s, s: l = 9, o: a, r: c} = e;
|
||||
console.log(n, o, s, l, a, c);
|
||||
}
|
||||
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
||||
test({});
|
||||
@@ -462,15 +462,15 @@ mangle_destructuring_assign_toplevel_true: {
|
||||
test({});
|
||||
}
|
||||
expect: {
|
||||
function n(n) {
|
||||
let t, a, c;
|
||||
let l = n.a || { e: 7, n: 8 };
|
||||
({t: o, e, n: s, s: t = 9, o: a, r: c} = l);
|
||||
console.log(o, e, s, t, a, c);
|
||||
function e(e) {
|
||||
let l, s, a;
|
||||
let c = e.a || { e: 7, n: 8 };
|
||||
({t: n, e: o, n: t, s: l = 9, o: s, r: a} = c);
|
||||
console.log(n, o, t, l, s, a);
|
||||
}
|
||||
let o, e, s;
|
||||
n({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
||||
n({});
|
||||
let n, o, t;
|
||||
e({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
||||
e({});
|
||||
}
|
||||
expect_stdout: [
|
||||
"1 2 3 4 5 6",
|
||||
@@ -504,10 +504,10 @@ mangle_destructuring_assign_toplevel_false: {
|
||||
}
|
||||
expect: {
|
||||
function test(o) {
|
||||
let s, a, c;
|
||||
let l = o.a || { e: 7, n: 8 };
|
||||
({t, e, n, s = 9, o: a, r: c} = l);
|
||||
console.log(t, e, n, s, a, c);
|
||||
let s, l, a;
|
||||
let c = o.a || { e: 7, n: 8 };
|
||||
({t, e, n, s = 9, o: l, r: a} = c);
|
||||
console.log(t, e, n, s, l, a);
|
||||
}
|
||||
let t, e, n;
|
||||
test({ a: { t: 1, e: 2, n: 3, s: 4, o: 5, r: 6 } });
|
||||
@@ -588,8 +588,8 @@ arrow_func_with_destructuring_args: {
|
||||
})({bar: 5 - 0}, [, 6]);
|
||||
}
|
||||
expect: {
|
||||
(({foo: o = 1, bar: n = 2}, [a = 3, b = 4]) => {
|
||||
console.log(o, n, a, b);
|
||||
(({foo: o = 1, bar: a = 2}, [b = 3, l = 4]) => {
|
||||
console.log(o, a, b, l);
|
||||
})({bar: 5}, [, 6]);
|
||||
}
|
||||
expect_stdout: "1 5 3 6"
|
||||
@@ -639,3 +639,23 @@ issue_2044_ecma_6_beautify: {
|
||||
}
|
||||
expect_exact: "({x: a = 1, y = 2 + b, z = 3 - c} = obj);"
|
||||
}
|
||||
|
||||
issue_2140: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
!function() {
|
||||
var t = {};
|
||||
console.log(([t.a] = [42])[0]);
|
||||
}();
|
||||
}
|
||||
expect: {
|
||||
!function() {
|
||||
var t = {};
|
||||
console.log(([t.a] = [42])[0]);
|
||||
}();
|
||||
}
|
||||
expect_stdout: "42"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
@@ -1409,3 +1409,20 @@ issue_2136_3: {
|
||||
expect_stdout: "2"
|
||||
node_version: ">=6"
|
||||
}
|
||||
|
||||
issue_2163: {
|
||||
options = {
|
||||
pure_funcs: [ "pure" ],
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var c;
|
||||
/*@__PURE__*/f(...a);
|
||||
pure(b, ...c);
|
||||
}
|
||||
expect: {
|
||||
var c;
|
||||
a;
|
||||
b;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,10 +33,10 @@ issue_2038_2: {
|
||||
export { LET, CONST, VAR };
|
||||
}
|
||||
expect: {
|
||||
let a = 1;
|
||||
const c = 2;
|
||||
var n = 3;
|
||||
export { a as LET, c as CONST, n as VAR };
|
||||
let t = 1;
|
||||
const e = 2;
|
||||
var o = 3;
|
||||
export { t as LET, e as CONST, o as VAR };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,10 +51,10 @@ issue_2126: {
|
||||
export { dog };
|
||||
}
|
||||
expect: {
|
||||
import { foo as o, cat as f } from "stuff";
|
||||
console.log(o, f);
|
||||
import { foo as o, cat as s } from "stuff";
|
||||
console.log(o, s);
|
||||
export { o as qux };
|
||||
export { f as dog };
|
||||
export { s as dog };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,3 +154,75 @@ issue_2134_2: {
|
||||
Foo.prototype = {};
|
||||
}
|
||||
}
|
||||
|
||||
redirection: {
|
||||
mangle = {
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
let foo = 1, bar = 2;
|
||||
export { foo as delete };
|
||||
export { bar as default };
|
||||
export { foo as var } from "module.js";
|
||||
}
|
||||
expect: {
|
||||
let e = 1, o = 2;
|
||||
export { e as delete };
|
||||
export { o as default };
|
||||
export { foo as var } from "module.js";
|
||||
}
|
||||
}
|
||||
|
||||
keyword_invalid_1: {
|
||||
input: {
|
||||
export { default };
|
||||
}
|
||||
expect: {
|
||||
export { default };
|
||||
}
|
||||
}
|
||||
|
||||
keyword_invalid_2: {
|
||||
input: {
|
||||
export { default as Alias };
|
||||
}
|
||||
expect: {
|
||||
export { default as Alias };
|
||||
}
|
||||
}
|
||||
|
||||
keyword_invalid_3: {
|
||||
input: {
|
||||
export { default as default };
|
||||
}
|
||||
expect: {
|
||||
export { default as default };
|
||||
}
|
||||
}
|
||||
|
||||
keyword_valid_1: {
|
||||
input: {
|
||||
export { default } from "module.js";
|
||||
}
|
||||
expect: {
|
||||
export { default } from "module.js";
|
||||
}
|
||||
}
|
||||
|
||||
keyword_valid_2: {
|
||||
input: {
|
||||
export { default as Alias } from "module.js";
|
||||
}
|
||||
expect: {
|
||||
export { default as Alias } from "module.js";
|
||||
}
|
||||
}
|
||||
|
||||
keyword_valid_3: {
|
||||
input: {
|
||||
export { default as default } from "module.js";
|
||||
}
|
||||
expect: {
|
||||
export { default as default } from "module.js";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ issue_203: {
|
||||
}
|
||||
expect: {
|
||||
var m = {};
|
||||
var fn = Function("a", "b", "b.exports=42");
|
||||
var fn = Function("n,o", "o.exports=42");
|
||||
fn(null, m, m.exports);
|
||||
console.log(m.exports);
|
||||
}
|
||||
|
||||
@@ -174,3 +174,24 @@ issue_1986: {
|
||||
console.log(42);
|
||||
}
|
||||
}
|
||||
|
||||
issue_2167: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
global_defs: {
|
||||
"@isDevMode": "function(){}",
|
||||
},
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
if (isDevMode()) {
|
||||
greetOverlord();
|
||||
}
|
||||
doWork();
|
||||
}
|
||||
expect: {
|
||||
doWork();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,12 @@ typeof_arrow_functions: {
|
||||
evaluate: true
|
||||
}
|
||||
input: {
|
||||
var foo = typeof (x) => null;
|
||||
var foo = typeof (x => null);
|
||||
console.log(foo);
|
||||
}
|
||||
expect_exact: "var foo=\"function\";"
|
||||
expect_exact: "var foo=\"function\";console.log(foo);"
|
||||
expect_stdout: "function"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
classes: {
|
||||
@@ -60,15 +63,15 @@ class_name_can_be_mangled: {
|
||||
function x() {
|
||||
class Foo {
|
||||
}
|
||||
var class1 = Foo
|
||||
var class2 = class Bar {}
|
||||
var class1 = Foo;
|
||||
var class2 = class Bar {};
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function x() {
|
||||
class a { }
|
||||
var n = a
|
||||
var r = class a {}
|
||||
var s = a;
|
||||
var c = class a {};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,12 +290,12 @@ import_statement_mangling: {
|
||||
Whatever();
|
||||
}
|
||||
expect: {
|
||||
import l from "foo";
|
||||
import e, {Food as o} from "lel";
|
||||
import o from "foo";
|
||||
import m, {Food as r} from "lel";
|
||||
import {What as f} from "lel";
|
||||
l();
|
||||
e();
|
||||
o();
|
||||
m();
|
||||
r();
|
||||
f();
|
||||
}
|
||||
}
|
||||
@@ -466,10 +469,10 @@ issue_1898: {
|
||||
expect: {
|
||||
class Foo {
|
||||
bar() {
|
||||
for (const n of [ 6, 5 ])
|
||||
for (const f of [ 6, 5 ])
|
||||
for (let r of [ 4, 3 ])
|
||||
for (var o of [ 2, 1 ])
|
||||
console.log(n, r, o);
|
||||
console.log(f, r, o);
|
||||
}
|
||||
}
|
||||
new Foo().bar();
|
||||
@@ -494,9 +497,9 @@ issue_1753: {
|
||||
expect: {
|
||||
class SomeClass {
|
||||
constructor(r) {
|
||||
let a = [];
|
||||
for (let s = 0; s < 6; s++)
|
||||
a.push({
|
||||
let s = [];
|
||||
for (let a = 0; a < 6; a++)
|
||||
s.push({
|
||||
mainDrawNumbers: [],
|
||||
extraDrawNumbers: []
|
||||
});
|
||||
@@ -523,9 +526,9 @@ issue_1753_disable: {
|
||||
expect: {
|
||||
class SomeClass {
|
||||
constructor(r) {
|
||||
let a = [];
|
||||
let s = [];
|
||||
for (let r = 0; r < 6; r++)
|
||||
a.push({
|
||||
s.push({
|
||||
mainDrawNumbers: [],
|
||||
extraDrawNumbers: []
|
||||
});
|
||||
|
||||
@@ -10,9 +10,9 @@ issue_1321_no_debug: {
|
||||
}
|
||||
expect: {
|
||||
var x = {};
|
||||
x.b = 1;
|
||||
x["a"] = 2 * x.b;
|
||||
console.log(x.b, x["a"]);
|
||||
x.o = 1;
|
||||
x["a"] = 2 * x.o;
|
||||
console.log(x.o, x["a"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
@@ -30,9 +30,9 @@ issue_1321_debug: {
|
||||
}
|
||||
expect: {
|
||||
var x = {};
|
||||
x.a = 1;
|
||||
x["_$foo$_"] = 2 * x.a;
|
||||
console.log(x.a, x["_$foo$_"]);
|
||||
x.o = 1;
|
||||
x["_$foo$_"] = 2 * x.o;
|
||||
console.log(x.o, x["_$foo$_"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
@@ -49,9 +49,9 @@ issue_1321_with_quoted: {
|
||||
}
|
||||
expect: {
|
||||
var x = {};
|
||||
x.a = 1;
|
||||
x["b"] = 2 * x.a;
|
||||
console.log(x.a, x["b"]);
|
||||
x.o = 1;
|
||||
x["x"] = 2 * x.o;
|
||||
console.log(x.o, x["x"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ same_variable_in_multiple_for_loop: {
|
||||
console.log(o, l);
|
||||
for (let o = 0; o < 2; o++) {
|
||||
console.log(o, l);
|
||||
let c = 2;
|
||||
console.log(c);
|
||||
let e = 2;
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,12 +114,12 @@ same_variable_in_multiple_forIn: {
|
||||
}
|
||||
expect: {
|
||||
var test = [ "a", "b", "c" ];
|
||||
for (let o in test) {
|
||||
console.log(o);
|
||||
let e;
|
||||
e = [ "e", "f", "g" ];
|
||||
for (let o in test)
|
||||
console.log(o);
|
||||
for (let e in test) {
|
||||
console.log(e);
|
||||
let t;
|
||||
t = [ "e", "f", "g" ];
|
||||
for (let e in test)
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
@@ -160,8 +160,8 @@ different_variable_in_multiple_for_loop: {
|
||||
console.log(o, l);
|
||||
for (let o = 0; o < 2; o++) {
|
||||
console.log(o, l);
|
||||
let c = 2;
|
||||
console.log(c);
|
||||
let e = 2;
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,12 +241,12 @@ different_variable_in_multiple_forIn: {
|
||||
}
|
||||
expect: {
|
||||
var test = [ "a", "b", "c" ];
|
||||
for (let o in test) {
|
||||
console.log(o);
|
||||
let e;
|
||||
e = [ "e", "f", "g" ];
|
||||
for (let o in test)
|
||||
console.log(o);
|
||||
for (let e in test) {
|
||||
console.log(e);
|
||||
let t;
|
||||
t = [ "e", "f", "g" ];
|
||||
for (let e in test)
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
@@ -281,10 +281,10 @@ more_variable_in_multiple_for: {
|
||||
}
|
||||
expect: {
|
||||
for (let o = 9, l = 0; l < 20; l += o) {
|
||||
let c = o++ + l;
|
||||
console.log(o, c, l);
|
||||
for (let l = c, e = c * c, f = 0; f < 10; f++)
|
||||
console.log(o, c, e, l, f);
|
||||
let e = o++ + l;
|
||||
console.log(o, e, l);
|
||||
for (let l = e, t = e * e, c = 0; c < 10; c++)
|
||||
console.log(o, e, t, l, c);
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
|
||||
@@ -82,7 +82,7 @@ numeric_literal: {
|
||||
' 42: 2,',
|
||||
' "42": 3,',
|
||||
' 37: 4,',
|
||||
' a: 5,',
|
||||
' o: 5,',
|
||||
' 1e42: 6,',
|
||||
' b: 7,',
|
||||
' "1e+42": 8',
|
||||
@@ -92,7 +92,7 @@ numeric_literal: {
|
||||
'',
|
||||
'console.log(obj[42], obj["42"]);',
|
||||
'',
|
||||
'console.log(obj[37], obj["a"], obj[37], obj["37"]);',
|
||||
'console.log(obj[37], obj["o"], obj[37], obj["37"]);',
|
||||
'',
|
||||
'console.log(obj[1e42], obj["b"], obj["1e+42"]);',
|
||||
]
|
||||
|
||||
@@ -159,7 +159,7 @@ export_mangle_1: {
|
||||
return one - two;
|
||||
};
|
||||
}
|
||||
expect_exact: "export function foo(n,o){return n-o};"
|
||||
expect_exact: "export function foo(o,n){return o-n};"
|
||||
}
|
||||
|
||||
export_mangle_2: {
|
||||
@@ -171,7 +171,7 @@ export_mangle_2: {
|
||||
return one - two;
|
||||
};
|
||||
}
|
||||
expect_exact: "export default function foo(n,o){return n-o};"
|
||||
expect_exact: "export default function foo(o,t){return o-t};"
|
||||
}
|
||||
|
||||
export_mangle_3: {
|
||||
@@ -189,7 +189,7 @@ export_mangle_3: {
|
||||
}
|
||||
};
|
||||
}
|
||||
expect_exact: "export class C{go(n,r){return n-r+n}};"
|
||||
expect_exact: "export class C{go(r,e){return r-e+r}};"
|
||||
}
|
||||
|
||||
export_mangle_4: {
|
||||
@@ -207,7 +207,7 @@ export_mangle_4: {
|
||||
}
|
||||
};
|
||||
}
|
||||
expect_exact: "export default class C{go(n,r){return n-r+n}};"
|
||||
expect_exact: "export default class C{go(e,r){return e-r+e}};"
|
||||
}
|
||||
|
||||
export_mangle_5: {
|
||||
@@ -221,7 +221,7 @@ export_mangle_5: {
|
||||
}
|
||||
};
|
||||
}
|
||||
expect_exact: "export default{prop:function(n,r){return n-r}};"
|
||||
expect_exact: "export default{prop:function(r,t){return r-t}};"
|
||||
}
|
||||
|
||||
export_mangle_6: {
|
||||
@@ -232,7 +232,7 @@ export_mangle_6: {
|
||||
var baz = 2;
|
||||
export let foo = 1, bar = baz;
|
||||
}
|
||||
expect_exact: "var a=2;export let foo=1,bar=a;"
|
||||
expect_exact: "var o=2;export let foo=1,bar=o;"
|
||||
}
|
||||
|
||||
export_toplevel_1: {
|
||||
|
||||
@@ -8,7 +8,7 @@ compress_new_function: {
|
||||
new Function("aa, bb", 'return aa;');
|
||||
}
|
||||
expect: {
|
||||
Function("a", "b", "return a");
|
||||
Function("n,r", "return n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,30 @@ compress_new_function_with_destruct: {
|
||||
new Function("[[aa]], [{bb}]", 'return aa;');
|
||||
}
|
||||
expect: {
|
||||
Function("a", "[b]", "return a");
|
||||
Function("a", "{bb:b}", "return a");
|
||||
Function("[[a]]", "[{bb:b}]", 'return a');
|
||||
Function("n,[r]", "return n");
|
||||
Function("n,{bb:b}", "return n");
|
||||
Function("[[n]],[{bb:b}]", "return n");
|
||||
}
|
||||
}
|
||||
|
||||
compress_new_function_with_destruct_arrows: {
|
||||
options = {
|
||||
arrows: true,
|
||||
unsafe: true,
|
||||
unsafe_Func: true,
|
||||
ecma: 6
|
||||
}
|
||||
beautify = {
|
||||
ecma: 6
|
||||
}
|
||||
input: {
|
||||
new Function("aa, [bb]", 'return aa;');
|
||||
new Function("aa, {bb}", 'return aa;');
|
||||
new Function("[[aa]], [{bb}]", 'return aa;');
|
||||
}
|
||||
expect: {
|
||||
Function("n,[a]", "return n");
|
||||
Function("b,{bb:n}", "return b");
|
||||
Function("[[b]],[{bb:n}]", "return b");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,41 @@
|
||||
dont_reuse_prop: {
|
||||
mangle_props = {
|
||||
regex: /asd/
|
||||
};
|
||||
|
||||
}
|
||||
input: {
|
||||
"aaaaaaaaaabbbbb";
|
||||
var obj = {};
|
||||
obj.a = 123;
|
||||
obj.asd = 256;
|
||||
console.log(obj.a);
|
||||
}
|
||||
expect: {
|
||||
"aaaaaaaaaabbbbb";
|
||||
var obj = {};
|
||||
obj.a = 123;
|
||||
obj.b = 256;
|
||||
console.log(obj.a);
|
||||
}
|
||||
expect_stdout: "123"
|
||||
}
|
||||
|
||||
unmangleable_props_should_always_be_reserved: {
|
||||
mangle_props = {
|
||||
regex: /asd/
|
||||
};
|
||||
|
||||
}
|
||||
input: {
|
||||
"aaaaaaaaaabbbbb";
|
||||
var obj = {};
|
||||
obj.asd = 256;
|
||||
obj.a = 123;
|
||||
console.log(obj.a);
|
||||
}
|
||||
expect: {
|
||||
"aaaaaaaaaabbbbb";
|
||||
var obj = {};
|
||||
obj.b = 256;
|
||||
obj.a = 123;
|
||||
console.log(obj.a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "123"
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ getter_setter_mangler: {
|
||||
};
|
||||
}
|
||||
}
|
||||
expect_exact: "function f(n,t){return{get:n,set:t,get g(){},set s(n){},c,a:1,m(){}}}"
|
||||
expect_exact: "function f(t,e){return{get:t,set:e,get g(){},set s(t){},c,a:1,m(){}}}"
|
||||
}
|
||||
|
||||
use_shorthand_opportunity: {
|
||||
@@ -297,7 +297,7 @@ concise_methods_and_mangle_props: {
|
||||
expect: {
|
||||
function x() {
|
||||
obj = {
|
||||
a() { return 1; }
|
||||
o() { return 1; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
arrow_functions: {
|
||||
options = {
|
||||
arrows: true,
|
||||
}
|
||||
input: {
|
||||
(a) => b; // 1 args
|
||||
(a, b) => c; // n args
|
||||
@@ -13,6 +16,9 @@ arrow_functions: {
|
||||
}
|
||||
|
||||
arrow_return: {
|
||||
options = {
|
||||
arrows: true,
|
||||
}
|
||||
input: {
|
||||
() => {};
|
||||
() => { return; };
|
||||
|
||||
@@ -135,11 +135,11 @@ mangle_properties: {
|
||||
a['run']({color: "blue", foo: "baz"});
|
||||
}
|
||||
expect: {
|
||||
a["a"] = "bar";
|
||||
a.b = "red";
|
||||
x = {c: 10};
|
||||
a.d(x.c, a.a);
|
||||
a['d']({b: "blue", a: "baz"});
|
||||
a["o"] = "bar";
|
||||
a.a = "red";
|
||||
x = {r: 10};
|
||||
a.b(x.r, a.o);
|
||||
a['b']({a: "blue", o: "baz"});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,16 +178,16 @@ mangle_unquoted_properties: {
|
||||
function f1() {
|
||||
a["foo"] = "bar";
|
||||
a.color = "red";
|
||||
a.b = 2;
|
||||
x = {"bar": 10, c: 7};
|
||||
a.c = 9;
|
||||
a.o = 2;
|
||||
x = {"bar": 10, f: 7};
|
||||
a.f = 9;
|
||||
}
|
||||
function f2() {
|
||||
a.foo = "bar";
|
||||
a['color'] = "red";
|
||||
x = {bar: 10, c: 7};
|
||||
a.c = 9;
|
||||
a.b = 3;
|
||||
x = {bar: 10, f: 7};
|
||||
a.f = 9;
|
||||
a.o = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,3 +241,147 @@ issue_2110_2: {
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
set_immutable_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
1..foo += "";
|
||||
if (1..foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
set_immutable_2: {
|
||||
options = {
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
set_immutable_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
var a = 1;
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
1..foo += "";
|
||||
if (1..foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
set_immutable_4: {
|
||||
options = {
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
var a = 1;
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var a = 1;
|
||||
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
set_mutable_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
!function a() {
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("PASS");
|
||||
else console.log("FAIL");
|
||||
}();
|
||||
}
|
||||
expect: {
|
||||
!function a() {
|
||||
if (a.foo += "") console.log("PASS");
|
||||
else console.log("FAIL");
|
||||
}();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
set_mutable_2: {
|
||||
options = {
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
!function a() {
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("PASS");
|
||||
else console.log("FAIL");
|
||||
}();
|
||||
}
|
||||
expect: {
|
||||
!function a() {
|
||||
(a.foo += "") ? console.log("PASS") : console.log("FAIL");
|
||||
}();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -2625,3 +2625,28 @@ issue_2090_2: {
|
||||
expect_stdout: "1"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
for_in_prop: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = {
|
||||
foo: function() {
|
||||
for (this.b in [1, 2]);
|
||||
}
|
||||
};
|
||||
a.foo();
|
||||
console.log(a.b);
|
||||
}
|
||||
expect: {
|
||||
var a = {
|
||||
foo: function() {
|
||||
for (this.b in [1, 2]);
|
||||
}
|
||||
};
|
||||
a.foo();
|
||||
console.log(a.b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
4
test/input/invalid/for-in_1.js
Normal file
4
test/input/invalid/for-in_1.js
Normal file
@@ -0,0 +1,4 @@
|
||||
var a, b = [1, 2];
|
||||
for (1, 2, a in b) {
|
||||
console.log(a, b[a]);
|
||||
}
|
||||
4
test/input/invalid/for-in_2.js
Normal file
4
test/input/invalid/for-in_2.js
Normal file
@@ -0,0 +1,4 @@
|
||||
var c = [1, 2];
|
||||
for (var a, b in c) {
|
||||
console.log(a, c[a]);
|
||||
}
|
||||
1
test/input/invalid/sequence.js
Normal file
1
test/input/invalid/sequence.js
Normal file
@@ -0,0 +1 @@
|
||||
(a, ...b);
|
||||
@@ -62,23 +62,20 @@ describe("Arrow functions", function() {
|
||||
}
|
||||
});
|
||||
it("Should not accept arrow functions in the middle or end of an expression", function() {
|
||||
var tests = [
|
||||
[
|
||||
"0 + x => 0",
|
||||
"0 + async x => 0",
|
||||
"typeof x => 0",
|
||||
"0 + x => 0"
|
||||
];
|
||||
var test = function(code) {
|
||||
return function() {
|
||||
"typeof async x => 0",
|
||||
"typeof (x) => null",
|
||||
"typeof async (x) => null",
|
||||
].forEach(function(code) {
|
||||
assert.throws(function() {
|
||||
uglify.parse(code);
|
||||
}
|
||||
}
|
||||
var error = function(e) {
|
||||
return e instanceof uglify.JS_Parse_Error &&
|
||||
e.message === "Unexpected token: arrow (=>)";
|
||||
}
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.throws(test(tests[i]), error);
|
||||
}
|
||||
}, function(e) {
|
||||
return e instanceof uglify.JS_Parse_Error && /^Unexpected /.test(e.message);
|
||||
}, code);
|
||||
});
|
||||
});
|
||||
|
||||
it("Should parse a function containing default assignment correctly", function() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var assert = require("assert");
|
||||
var exec = require("child_process").exec;
|
||||
var readFileSync = require("fs").readFileSync;
|
||||
var semver = require("semver");
|
||||
|
||||
function read(path) {
|
||||
return readFileSync(path, "utf8");
|
||||
@@ -9,9 +10,11 @@ function read(path) {
|
||||
describe("bin/uglifyjs", function () {
|
||||
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
|
||||
it("should produce a functional build when using --self", function (done) {
|
||||
this.timeout(30000);
|
||||
this.timeout(60000);
|
||||
|
||||
var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS';
|
||||
var command = uglifyjscmd + ' --self -mc ecma=';
|
||||
command += semver.satisfies(process.version, ">=4") ? "6" : "5";
|
||||
command += ',passes=3,keep_fargs=false,unsafe --wrap WrappedUglifyJS';
|
||||
|
||||
exec(command, function (err, stdout) {
|
||||
if (err) throw err;
|
||||
@@ -593,6 +596,51 @@ describe("bin/uglifyjs", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (spread in sequence)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/sequence.js';
|
||||
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||
"Parse error at test/input/invalid/sequence.js:1,4",
|
||||
"(a, ...b);",
|
||||
" ^",
|
||||
"ERROR: Unexpected token: expand (...)"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (for-in init)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/for-in_1.js';
|
||||
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||
"Parse error at test/input/invalid/for-in_1.js:2,5",
|
||||
"for (1, 2, a in b) {",
|
||||
" ^",
|
||||
"ERROR: Invalid left-hand side in for..in loop"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (for-in var)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/for-in_2.js';
|
||||
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||
"Parse error at test/input/invalid/for-in_2.js:2,5",
|
||||
"for (var a, b in c) {",
|
||||
" ^",
|
||||
"ERROR: Only one variable declaration allowed in for..in loop"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should handle literal string as source map input", function(done) {
|
||||
var command = [
|
||||
uglifyjscmd,
|
||||
|
||||
@@ -191,15 +191,51 @@ describe("Function", function() {
|
||||
];
|
||||
var test = function(code) {
|
||||
return function() {
|
||||
uglify.parse(code);
|
||||
uglify.parse(code, { ecma: 5 });
|
||||
}
|
||||
}
|
||||
var error = function(e) {
|
||||
return e instanceof uglify.JS_Parse_Error &&
|
||||
e.message === "Invalid function parameter";
|
||||
return e instanceof uglify.JS_Parse_Error;
|
||||
}
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.throws(test(tests[i]), error);
|
||||
assert.throws(test(tests[i]), error, tests[i]);
|
||||
}
|
||||
});
|
||||
it("Should accept trailing commas only for ES8", function() {
|
||||
[
|
||||
"new Foo(a, );",
|
||||
"async(...[1, 2], );",
|
||||
"console.log(...[1, 2], );",
|
||||
"!function(a, b, ){ console.log(a + b); }(3, 4, );",
|
||||
].forEach(function(code) {
|
||||
uglify.parse(code, { ecma: 8 });
|
||||
assert.throws(function() {
|
||||
uglify.parse(code, { ecma: 6 });
|
||||
}, function(e) {
|
||||
return e instanceof uglify.JS_Parse_Error;
|
||||
}, code);
|
||||
});
|
||||
});
|
||||
it("Should not accept invalid trailing commas", function() {
|
||||
var tests = [
|
||||
"f(, );",
|
||||
"(, ) => {};",
|
||||
"(...p, ) => {};",
|
||||
"function f(, ) {}",
|
||||
"function f(...p, ) {}",
|
||||
"function foo(a, b, , ) {}",
|
||||
'console.log("hello", , );',
|
||||
];
|
||||
var test = function(code) {
|
||||
return function() {
|
||||
uglify.parse(code, { ecma: 8 });
|
||||
}
|
||||
}
|
||||
var error = function(e) {
|
||||
return e instanceof uglify.JS_Parse_Error;
|
||||
}
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.throws(test(tests[i]), error, tests[i]);
|
||||
}
|
||||
});
|
||||
it("Should not accept an initializer when parameter is a rest parameter", function() {
|
||||
|
||||
@@ -2,29 +2,37 @@ var Uglify = require('../../');
|
||||
var assert = require("assert");
|
||||
|
||||
describe("let", function() {
|
||||
it("Should not produce `let` as a variable name in mangle", function(done) {
|
||||
it("Should not produce reserved keywords as variable name in mangle", function(done) {
|
||||
this.timeout(10000);
|
||||
|
||||
// Produce a lot of variables in a function and run it through mangle.
|
||||
var s = '"use strict"; function foo() {';
|
||||
for (var i = 0; i < 21000; ++i) {
|
||||
var s = '"dddddeeeeelllllooooottttt"; function foo() {';
|
||||
for (var i = 0; i < 18000; i++) {
|
||||
s += "var v" + i + "=0;";
|
||||
}
|
||||
s += '}';
|
||||
var result = Uglify.minify(s, {compress: false});
|
||||
|
||||
// Verify that select keywords and reserved keywords not produced
|
||||
assert.strictEqual(result.code.indexOf("var let="), -1);
|
||||
assert.strictEqual(result.code.indexOf("var do="), -1);
|
||||
assert.strictEqual(result.code.indexOf("var var="), -1);
|
||||
[
|
||||
"do",
|
||||
"let",
|
||||
"var",
|
||||
].forEach(function(name) {
|
||||
assert.strictEqual(result.code.indexOf("var " + name + "="), -1);
|
||||
});
|
||||
|
||||
// Verify that the variable names that appeared immediately before
|
||||
// and after the erroneously generated `let` variable name still exist
|
||||
// and after the erroneously generated variable name still exist
|
||||
// to show the test generated enough symbols.
|
||||
assert(result.code.indexOf("var ket=") >= 0);
|
||||
assert(result.code.indexOf("var met=") >= 0);
|
||||
[
|
||||
"to", "eo",
|
||||
"eet", "fet",
|
||||
"rar", "oar",
|
||||
].forEach(function(name) {
|
||||
assert.ok(result.code.indexOf("var " + name + "=") >= 0);
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ describe("minify", function() {
|
||||
});
|
||||
var err = result.error;
|
||||
assert.ok(err instanceof Error);
|
||||
assert.strictEqual(err.stack.split(/\n/)[0], "Error: Can't handle expression: debugger");
|
||||
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token: keyword (debugger)");
|
||||
});
|
||||
it("should skip inherited properties", function() {
|
||||
var foo = Object.create({ skip: this });
|
||||
|
||||
@@ -30,4 +30,13 @@ describe("Template string", function() {
|
||||
assert.throws(exec(tests[i]), fail, tests[i]);
|
||||
}
|
||||
});
|
||||
it("Should process all line terminators as LF", function() {
|
||||
[
|
||||
"`a\rb`",
|
||||
"`a\nb`",
|
||||
"`a\r\nb`",
|
||||
].forEach(function(code) {
|
||||
assert.strictEqual(uglify.parse(code).print_to_string(), "`a\\nb`;");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,7 +86,6 @@ function run_compress_tests() {
|
||||
log_start_file(file);
|
||||
function test_case(test) {
|
||||
log_test(test.name);
|
||||
U.base54.reset();
|
||||
var output_options = test.beautify || {};
|
||||
var expect;
|
||||
if (test.expect) {
|
||||
@@ -101,9 +100,6 @@ function run_compress_tests() {
|
||||
quote_style: 3,
|
||||
keep_quoted_props: true
|
||||
});
|
||||
if (test.mangle_props) {
|
||||
input = U.mangle_properties(input, test.mangle_props);
|
||||
}
|
||||
var options = U.defaults(test.options, {
|
||||
warnings: false
|
||||
});
|
||||
@@ -118,10 +114,16 @@ function run_compress_tests() {
|
||||
var cmp = new U.Compressor(options, true);
|
||||
var output = cmp.compress(input);
|
||||
output.figure_out_scope(test.mangle);
|
||||
if (test.mangle) {
|
||||
if (test.mangle || test.mangle_props) {
|
||||
U.base54.reset();
|
||||
output.compute_char_frequency(test.mangle);
|
||||
}
|
||||
if (test.mangle) {
|
||||
output.mangle_names(test.mangle);
|
||||
}
|
||||
if (test.mangle_props) {
|
||||
output = U.mangle_properties(output, test.mangle_props);
|
||||
}
|
||||
output = make_code(output, output_options);
|
||||
if (expect != output) {
|
||||
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
|
||||
|
||||
Reference in New Issue
Block a user