Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f67866147 | ||
|
|
645d5a348b | ||
|
|
cf120c7cea | ||
|
|
8d30902ba9 | ||
|
|
02459cddf9 | ||
|
|
1b579779be | ||
|
|
b18b70f63b | ||
|
|
641406d491 | ||
|
|
134ef0b1eb | ||
|
|
db87dcf13e | ||
|
|
aecbabc587 | ||
|
|
fd6544b340 | ||
|
|
f6a83f7944 | ||
|
|
35283e5dd1 | ||
|
|
7a51c17ff0 | ||
|
|
aff842f2f9 | ||
|
|
0bedd031da | ||
|
|
caa92aea5d | ||
|
|
383163afa6 | ||
|
|
8a83c8dd46 | ||
|
|
2a612fd472 | ||
|
|
b9798a01a8 | ||
|
|
6dbacb5e3f | ||
|
|
e5f80afc53 | ||
|
|
42e34c870a | ||
|
|
e390e7e124 | ||
|
|
6fd5b5b371 | ||
|
|
fba27bfb71 | ||
|
|
41310e6404 | ||
|
|
91fc1c82b5 | ||
|
|
810cd40356 | ||
|
|
1cbd07e789 | ||
|
|
b82de04775 | ||
|
|
4bbeb09f7c | ||
|
|
c2f6fd5fde | ||
|
|
af4ea3ff69 | ||
|
|
e7643248a3 | ||
|
|
68091dbf69 | ||
|
|
cbf7269296 | ||
|
|
d8563caba7 | ||
|
|
2e0ad40fe6 | ||
|
|
5d12abc41b | ||
|
|
79e5c3f564 | ||
|
|
607f87c5cd |
22
README.md
22
README.md
@@ -135,6 +135,10 @@ a double dash to prevent input files being used as option arguments:
|
|||||||
--toplevel Compress and/or mangle variables in top level scope.
|
--toplevel Compress and/or mangle variables in top level scope.
|
||||||
--verbose Print diagnostic messages.
|
--verbose Print diagnostic messages.
|
||||||
--warn Print warning messages.
|
--warn Print warning messages.
|
||||||
|
--webkit Support non-standard Safari/Webkit.
|
||||||
|
Equivalent to setting `webkit: true` in `minify()`
|
||||||
|
for `mangle` and `output` options.
|
||||||
|
By default UglifyJS will not try to be Safari-proof.
|
||||||
--wrap <name> Embed everything in a big function, making the
|
--wrap <name> Embed everything in a big function, making the
|
||||||
“exports” and “global” variables available. You
|
“exports” and “global” variables available. You
|
||||||
need to pass an argument to this option to
|
need to pass an argument to this option to
|
||||||
@@ -519,6 +523,9 @@ if (result.error) throw result.error;
|
|||||||
- `warnings` (default `false`) — pass `true` to return compressor warnings
|
- `warnings` (default `false`) — pass `true` to return compressor warnings
|
||||||
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
|
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
|
||||||
|
|
||||||
|
- `webkit` (default `false`) -- enable workarounds for Safari/WebKit bugs.
|
||||||
|
PhantomJS users should set this option to `true`.
|
||||||
|
|
||||||
## Minify options structure
|
## Minify options structure
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@@ -868,6 +875,8 @@ can pass additional arguments that control the code output:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- `galio` (default `false`) -- enable workarounds for ANT Galio bugs
|
||||||
|
|
||||||
- `indent_level` (default `4`)
|
- `indent_level` (default `4`)
|
||||||
|
|
||||||
- `indent_start` (default `0`) -- prefix all lines by that many spaces
|
- `indent_start` (default `0`) -- prefix all lines by that many spaces
|
||||||
@@ -906,8 +915,7 @@ can pass additional arguments that control the code output:
|
|||||||
|
|
||||||
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
||||||
|
|
||||||
- `webkit` (default `false`) -- enable workarounds for WebKit bugs.
|
- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs
|
||||||
PhantomJS users should set this option to `true`.
|
|
||||||
|
|
||||||
- `width` (default `80`) -- only takes effect when beautification is on, this
|
- `width` (default `80`) -- only takes effect when beautification is on, this
|
||||||
specifies an (orientative) line width that the beautifier will try to
|
specifies an (orientative) line width that the beautifier will try to
|
||||||
@@ -1138,7 +1146,7 @@ To enable fast minify mode with the API use:
|
|||||||
UglifyJS.minify(code, { compress: false, mangle: true });
|
UglifyJS.minify(code, { compress: false, mangle: true });
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Source maps and debugging
|
### Source maps and debugging
|
||||||
|
|
||||||
Various `compress` transforms that simplify, rearrange, inline and remove code
|
Various `compress` transforms that simplify, rearrange, inline and remove code
|
||||||
are known to have an adverse effect on debugging with source maps. This is
|
are known to have an adverse effect on debugging with source maps. This is
|
||||||
@@ -1150,6 +1158,10 @@ disable the Uglify `compress` option and just use `mangle`.
|
|||||||
|
|
||||||
To allow for better optimizations, the compiler makes various assumptions:
|
To allow for better optimizations, the compiler makes various assumptions:
|
||||||
|
|
||||||
|
- The code does not rely on preserving its runtime performance characteristics.
|
||||||
|
Typically uglified code will run faster due to less instructions and easier
|
||||||
|
inlining, but may be slower on rare occasions for a specific platform, e.g.
|
||||||
|
see [`reduce_funcs`](#compress-options).
|
||||||
- `.toString()` and `.valueOf()` don't have side effects, and for built-in
|
- `.toString()` and `.valueOf()` don't have side effects, and for built-in
|
||||||
objects they have not been overridden.
|
objects they have not been overridden.
|
||||||
- `undefined`, `NaN` and `Infinity` have not been externally redefined.
|
- `undefined`, `NaN` and `Infinity` have not been externally redefined.
|
||||||
@@ -1177,3 +1189,7 @@ To allow for better optimizations, the compiler makes various assumptions:
|
|||||||
top.B = "PASS";
|
top.B = "PASS";
|
||||||
console.log(B);
|
console.log(B);
|
||||||
```
|
```
|
||||||
|
- Use of `arguments` alongside destructuring as function parameters, e.g.
|
||||||
|
`function({}, arguments) {}` will result in `SyntaxError` in earlier versions
|
||||||
|
of Chrome and Node.js - UglifyJS may modify the input which in turn may
|
||||||
|
suppress those errors.
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ function process_option(name, no_value) {
|
|||||||
" --validate Perform validation during AST manipulations.",
|
" --validate Perform validation during AST manipulations.",
|
||||||
" --verbose Print diagnostic messages.",
|
" --verbose Print diagnostic messages.",
|
||||||
" --warn Print warning messages.",
|
" --warn Print warning messages.",
|
||||||
|
" --webkit Support non-standard Safari/Webkit.",
|
||||||
" --wrap <name> Embed everything as a function with “exports” corresponding to “name” globally.",
|
" --wrap <name> Embed everything as a function with “exports” corresponding to “name” globally.",
|
||||||
" --reduce-test Reduce a standalone test case (assumes cloned repository).",
|
" --reduce-test Reduce a standalone test case (assumes cloned repository).",
|
||||||
].join("\n"));
|
].join("\n"));
|
||||||
@@ -142,6 +143,7 @@ function process_option(name, no_value) {
|
|||||||
case "timings":
|
case "timings":
|
||||||
case "toplevel":
|
case "toplevel":
|
||||||
case "validate":
|
case "validate":
|
||||||
|
case "webkit":
|
||||||
options[name] = true;
|
options[name] = true;
|
||||||
break;
|
break;
|
||||||
case "keep-fnames":
|
case "keep-fnames":
|
||||||
@@ -276,7 +278,9 @@ function convert_ast(fn) {
|
|||||||
function run() {
|
function run() {
|
||||||
var content = options.sourceMap && options.sourceMap.content;
|
var content = options.sourceMap && options.sourceMap.content;
|
||||||
if (content && content != "inline") {
|
if (content && content != "inline") {
|
||||||
UglifyJS.AST_Node.info("Using input source map: " + content);
|
UglifyJS.AST_Node.info("Using input source map: {content}", {
|
||||||
|
content : content,
|
||||||
|
});
|
||||||
options.sourceMap.content = read_file(content, content);
|
options.sourceMap.content = read_file(content, content);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|||||||
171
lib/ast.js
171
lib/ast.js
@@ -137,17 +137,17 @@ var AST_Node = DEFNODE("Node", "start end", {
|
|||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
(AST_Node.log_function = function(fn, verbose) {
|
(AST_Node.log_function = function(fn, verbose) {
|
||||||
var printed = Object.create(null);
|
if (!fn) {
|
||||||
if (fn) {
|
|
||||||
AST_Node.info = verbose ? function(text, props) {
|
|
||||||
log("INFO: " + string_template(text, props));
|
|
||||||
} : noop;
|
|
||||||
AST_Node.warn = function(text, props) {
|
|
||||||
log("WARN: " + string_template(text, props));
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
AST_Node.info = AST_Node.warn = noop;
|
AST_Node.info = AST_Node.warn = noop;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
var printed = Object.create(null);
|
||||||
|
AST_Node.info = verbose ? function(text, props) {
|
||||||
|
log("INFO: " + string_template(text, props));
|
||||||
|
} : noop;
|
||||||
|
AST_Node.warn = function(text, props) {
|
||||||
|
log("WARN: " + string_template(text, props));
|
||||||
|
};
|
||||||
|
|
||||||
function log(msg) {
|
function log(msg) {
|
||||||
if (printed[msg]) return;
|
if (printed[msg]) return;
|
||||||
@@ -414,8 +414,12 @@ var AST_ForIn = DEFNODE("ForIn", "init object", {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (this.init instanceof AST_Definitions) {
|
if (this.init instanceof AST_Definitions) {
|
||||||
if (this.init.definitions.length != 1) throw new Error("init must have single declaration");
|
if (this.init.definitions.length != 1) throw new Error("init must have single declaration");
|
||||||
} else if (!(this.init instanceof AST_PropAccess || this.init instanceof AST_SymbolRef)) {
|
} else {
|
||||||
throw new Error("init must be assignable");
|
validate_destructured(this.init, function(node) {
|
||||||
|
if (!(node instanceof AST_PropAccess || node instanceof AST_SymbolRef)) {
|
||||||
|
throw new Error("init must be assignable: " + node.TYPE);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
must_be_expression(this, "object");
|
must_be_expression(this, "object");
|
||||||
},
|
},
|
||||||
@@ -496,12 +500,24 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
|||||||
}
|
}
|
||||||
}, AST_Scope);
|
}, AST_Scope);
|
||||||
|
|
||||||
var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
|
var AST_Lambda = DEFNODE("Lambda", "name argnames length_read uses_arguments", {
|
||||||
$documentation: "Base class for functions",
|
$documentation: "Base class for functions",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[AST_SymbolDeclaration?] the name of this function",
|
name: "[AST_SymbolDeclaration?] the name of this function",
|
||||||
argnames: "[AST_SymbolFunarg*] array of function arguments",
|
argnames: "[(AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
|
||||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
|
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
|
||||||
|
},
|
||||||
|
each_argname: function(visit) {
|
||||||
|
var tw = new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_DestructuredKeyVal) {
|
||||||
|
node.value.walk(tw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_SymbolFunarg) visit(node);
|
||||||
|
});
|
||||||
|
this.argnames.forEach(function(argname) {
|
||||||
|
argname.walk(tw);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
@@ -515,7 +531,9 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
|
|||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.argnames.forEach(function(node) {
|
this.argnames.forEach(function(node) {
|
||||||
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
validate_destructured(node, function(node) {
|
||||||
|
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Scope);
|
}, AST_Scope);
|
||||||
@@ -748,8 +766,10 @@ var AST_Const = DEFNODE("Const", null, {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.definitions.forEach(function(node) {
|
this.definitions.forEach(function(node) {
|
||||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||||
if (!(node.name instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
|
validate_destructured(node.name, function(node) {
|
||||||
must_be_expression(node, "value");
|
if (!(node instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
|
||||||
|
});
|
||||||
|
if (node.value != null) must_be_expression(node, "value");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Definitions);
|
}, AST_Definitions);
|
||||||
@@ -759,7 +779,9 @@ var AST_Let = DEFNODE("Let", null, {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.definitions.forEach(function(node) {
|
this.definitions.forEach(function(node) {
|
||||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||||
if (!(node.name instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
|
validate_destructured(node.name, function(node) {
|
||||||
|
if (!(node instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
|
||||||
|
});
|
||||||
if (node.value != null) must_be_expression(node, "value");
|
if (node.value != null) must_be_expression(node, "value");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -770,7 +792,9 @@ var AST_Var = DEFNODE("Var", null, {
|
|||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.definitions.forEach(function(node) {
|
this.definitions.forEach(function(node) {
|
||||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||||
if (!(node.name instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
validate_destructured(node.name, function(node) {
|
||||||
|
if (!(node instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
||||||
|
});
|
||||||
if (node.value != null) must_be_expression(node, "value");
|
if (node.value != null) must_be_expression(node, "value");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -969,6 +993,14 @@ var AST_Assign = DEFNODE("Assign", null, {
|
|||||||
$documentation: "An assignment expression — `a = b + 5`",
|
$documentation: "An assignment expression — `a = b + 5`",
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (this.operator.indexOf("=") < 0) throw new Error('operator must contain "="');
|
if (this.operator.indexOf("=") < 0) throw new Error('operator must contain "="');
|
||||||
|
if (this.left instanceof AST_Destructured) {
|
||||||
|
if (this.operator != "=") throw new Error("invalid destructuring operator: " + this.operator);
|
||||||
|
validate_destructured(this.left, function(node) {
|
||||||
|
if (!(node instanceof AST_PropAccess || node instanceof AST_SymbolRef)) {
|
||||||
|
throw new Error("left must be assignable: " + node.TYPE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}, AST_Binary);
|
}, AST_Binary);
|
||||||
|
|
||||||
@@ -992,6 +1024,77 @@ var AST_Array = DEFNODE("Array", "elements", {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var AST_Destructured = DEFNODE("Destructured", null, {
|
||||||
|
$documentation: "Base class for destructured literal",
|
||||||
|
});
|
||||||
|
|
||||||
|
function validate_destructured(node, check) {
|
||||||
|
if (node instanceof AST_DestructuredArray) return node.elements.forEach(function(node) {
|
||||||
|
if (!(node instanceof AST_Hole)) validate_destructured(node, check);
|
||||||
|
});
|
||||||
|
if (node instanceof AST_DestructuredObject) return node.properties.forEach(function(prop) {
|
||||||
|
validate_destructured(prop.value, check);
|
||||||
|
});
|
||||||
|
check(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
var AST_DestructuredArray = DEFNODE("DestructuredArray", "elements", {
|
||||||
|
$documentation: "A destructured array literal",
|
||||||
|
$propdoc: {
|
||||||
|
elements: "[AST_Node*] array of elements",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
node.elements.forEach(function(element) {
|
||||||
|
element.walk(visitor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, AST_Destructured);
|
||||||
|
|
||||||
|
var AST_DestructuredKeyVal = DEFNODE("DestructuredKeyVal", "key value", {
|
||||||
|
$documentation: "A key: value destructured property",
|
||||||
|
$propdoc: {
|
||||||
|
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
|
||||||
|
value: "[AST_Node] property value",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
if (node.key instanceof AST_Node) node.key.walk(visitor);
|
||||||
|
node.value.walk(visitor);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (typeof this.key != "string") {
|
||||||
|
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
|
||||||
|
must_be_expression(this, "key");
|
||||||
|
}
|
||||||
|
must_be_expression(this, "value");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var AST_DestructuredObject = DEFNODE("DestructuredObject", "properties", {
|
||||||
|
$documentation: "A destructured object literal",
|
||||||
|
$propdoc: {
|
||||||
|
properties: "[AST_DestructuredKeyVal*] array of properties",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
node.properties.forEach(function(prop) {
|
||||||
|
prop.walk(visitor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
this.properties.forEach(function(node) {
|
||||||
|
if (!(node instanceof AST_DestructuredKeyVal)) throw new Error("properties must be AST_DestructuredKeyVal[]");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, AST_Destructured);
|
||||||
|
|
||||||
var AST_Object = DEFNODE("Object", "properties", {
|
var AST_Object = DEFNODE("Object", "properties", {
|
||||||
$documentation: "An object literal",
|
$documentation: "An object literal",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
@@ -1015,24 +1118,28 @@ var AST_Object = DEFNODE("Object", "properties", {
|
|||||||
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
||||||
$documentation: "Base class for literal object properties",
|
$documentation: "Base class for literal object properties",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
key: "[string|AST_SymbolAccessor] property name. For ObjectKeyVal this is a string. For getters and setters this is an AST_SymbolAccessor.",
|
key: "[string|AST_Node] property name. For computed property this is an AST_Node.",
|
||||||
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
|
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor.",
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
visitor.visit(node, function() {
|
visitor.visit(node, function() {
|
||||||
|
if (node.key instanceof AST_Node) node.key.walk(visitor);
|
||||||
node.value.walk(visitor);
|
node.value.walk(visitor);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
|
||||||
$documentation: "A key: value object property",
|
|
||||||
$propdoc: {
|
|
||||||
quote: "[string] the original quote character"
|
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (typeof this.key != "string") throw new Error("key must be string");
|
if (typeof this.key != "string") {
|
||||||
|
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
|
||||||
|
must_be_expression(this, "key");
|
||||||
|
}
|
||||||
|
if (!(this.value instanceof AST_Node)) throw new Error("value must be AST_Node");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
|
||||||
|
$documentation: "A key: value object property",
|
||||||
|
_validate: function() {
|
||||||
must_be_expression(this, "value");
|
must_be_expression(this, "value");
|
||||||
},
|
},
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
@@ -1040,7 +1147,6 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
|||||||
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||||
$documentation: "An object setter property",
|
$documentation: "An object setter property",
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
|
|
||||||
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
||||||
},
|
},
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
@@ -1048,7 +1154,6 @@ var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
|||||||
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
|
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
|
||||||
$documentation: "An object getter property",
|
$documentation: "An object getter property",
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
|
|
||||||
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
|
||||||
},
|
},
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
@@ -1065,10 +1170,6 @@ var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
|
|
||||||
$documentation: "The name of a property accessor (setter/getter function)"
|
|
||||||
}, AST_Symbol);
|
|
||||||
|
|
||||||
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
|
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
|
||||||
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
|
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|||||||
1303
lib/compress.js
1303
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,9 @@ function read_source_map(name, toplevel) {
|
|||||||
return to_ascii(match[2]);
|
return to_ascii(match[2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AST_Node.warn("inline source map not found: " + name);
|
AST_Node.warn("inline source map not found: {name}", {
|
||||||
|
name: name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function parse_source_map(content) {
|
function parse_source_map(content) {
|
||||||
@@ -87,6 +89,7 @@ function minify(files, options) {
|
|||||||
toplevel: false,
|
toplevel: false,
|
||||||
validate: false,
|
validate: false,
|
||||||
warnings: false,
|
warnings: false,
|
||||||
|
webkit: false,
|
||||||
wrap: false,
|
wrap: false,
|
||||||
}, true);
|
}, true);
|
||||||
if (options.validate) AST_Node.enable_validation();
|
if (options.validate) AST_Node.enable_validation();
|
||||||
@@ -99,6 +102,7 @@ function minify(files, options) {
|
|||||||
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
|
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
|
||||||
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
||||||
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
||||||
|
set_shorthand("webkit", options, [ "mangle", "output" ]);
|
||||||
var quoted_props;
|
var quoted_props;
|
||||||
if (options.mangle) {
|
if (options.mangle) {
|
||||||
options.mangle = defaults(options.mangle, {
|
options.mangle = defaults(options.mangle, {
|
||||||
@@ -109,6 +113,7 @@ function minify(files, options) {
|
|||||||
properties: false,
|
properties: false,
|
||||||
reserved: [],
|
reserved: [],
|
||||||
toplevel: false,
|
toplevel: false,
|
||||||
|
webkit: false,
|
||||||
}, true);
|
}, true);
|
||||||
if (options.mangle.properties) {
|
if (options.mangle.properties) {
|
||||||
if (typeof options.mangle.properties != "object") {
|
if (typeof options.mangle.properties != "object") {
|
||||||
@@ -258,6 +263,7 @@ function minify(files, options) {
|
|||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
return { error: ex };
|
return { error: ex };
|
||||||
} finally {
|
} finally {
|
||||||
|
AST_Node.log_function();
|
||||||
AST_Node.disable_validation();
|
AST_Node.disable_validation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,9 +115,6 @@
|
|||||||
value : from_moz(M.value)
|
value : from_moz(M.value)
|
||||||
};
|
};
|
||||||
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
||||||
args.key = new AST_SymbolAccessor({
|
|
||||||
name: args.key
|
|
||||||
});
|
|
||||||
args.value = new AST_Accessor(args.value);
|
args.value = new AST_Accessor(args.value);
|
||||||
if (M.kind == "get") return new AST_ObjectGetter(args);
|
if (M.kind == "get") return new AST_ObjectGetter(args);
|
||||||
if (M.kind == "set") return new AST_ObjectSetter(args);
|
if (M.kind == "set") return new AST_ObjectSetter(args);
|
||||||
@@ -385,7 +382,7 @@
|
|||||||
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
||||||
var key = {
|
var key = {
|
||||||
type: "Literal",
|
type: "Literal",
|
||||||
value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
|
value: M.key
|
||||||
};
|
};
|
||||||
var kind;
|
var kind;
|
||||||
if (M instanceof AST_ObjectKeyVal) {
|
if (M instanceof AST_ObjectKeyVal) {
|
||||||
|
|||||||
138
lib/output.js
138
lib/output.js
@@ -56,6 +56,7 @@ function OutputStream(options) {
|
|||||||
beautify : false,
|
beautify : false,
|
||||||
braces : false,
|
braces : false,
|
||||||
comments : false,
|
comments : false,
|
||||||
|
galio : false,
|
||||||
ie8 : false,
|
ie8 : false,
|
||||||
indent_level : 4,
|
indent_level : 4,
|
||||||
indent_start : 0,
|
indent_start : 0,
|
||||||
@@ -69,6 +70,7 @@ function OutputStream(options) {
|
|||||||
semicolons : true,
|
semicolons : true,
|
||||||
shebang : true,
|
shebang : true,
|
||||||
source_map : null,
|
source_map : null,
|
||||||
|
v8 : false,
|
||||||
webkit : false,
|
webkit : false,
|
||||||
width : 80,
|
width : 80,
|
||||||
wrap_iife : false,
|
wrap_iife : false,
|
||||||
@@ -499,11 +501,11 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (/comment[134]/.test(c.type)) {
|
if (/comment[134]/.test(c.type)) {
|
||||||
print("//" + c.value.replace(/[@#]__PURE__/g, ' ') + "\n");
|
print("//" + c.value.replace(/[@#]__PURE__/g, " ") + "\n");
|
||||||
indent();
|
indent();
|
||||||
last_nlb = true;
|
last_nlb = true;
|
||||||
} else if (c.type == "comment2") {
|
} else if (c.type == "comment2") {
|
||||||
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
|
print("/*" + c.value.replace(/[@#]__PURE__/g, " ") + "*/");
|
||||||
last_nlb = false;
|
last_nlb = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -557,10 +559,10 @@ function OutputStream(options) {
|
|||||||
space();
|
space();
|
||||||
}
|
}
|
||||||
if (/comment[134]/.test(c.type)) {
|
if (/comment[134]/.test(c.type)) {
|
||||||
print("//" + c.value.replace(/[@#]__PURE__/g, ' '));
|
print("//" + c.value.replace(/[@#]__PURE__/g, " "));
|
||||||
need_newline_indented = true;
|
need_newline_indented = true;
|
||||||
} else if (c.type == "comment2") {
|
} else if (c.type == "comment2") {
|
||||||
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
|
print("/*" + c.value.replace(/[@#]__PURE__/g, " ") + "*/");
|
||||||
need_space = true;
|
need_space = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -610,7 +612,7 @@ function OutputStream(options) {
|
|||||||
},
|
},
|
||||||
parent : function(n) {
|
parent : function(n) {
|
||||||
return stack[stack.length - 2 - (n || 0)];
|
return stack[stack.length - 2 - (n || 0)];
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,13 +654,7 @@ function OutputStream(options) {
|
|||||||
/* -----[ PARENTHESES ]----- */
|
/* -----[ PARENTHESES ]----- */
|
||||||
|
|
||||||
function PARENS(nodetype, func) {
|
function PARENS(nodetype, func) {
|
||||||
if (Array.isArray(nodetype)) {
|
nodetype.DEFMETHOD("needs_parens", func);
|
||||||
nodetype.forEach(function(nodetype) {
|
|
||||||
PARENS(nodetype, func);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
nodetype.DEFMETHOD("needs_parens", func);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PARENS(AST_Node, return_false);
|
PARENS(AST_Node, return_false);
|
||||||
@@ -667,11 +663,11 @@ function OutputStream(options) {
|
|||||||
// the first token to appear in a statement.
|
// the first token to appear in a statement.
|
||||||
PARENS(AST_Function, function(output) {
|
PARENS(AST_Function, function(output) {
|
||||||
if (!output.has_parens() && first_in_statement(output)) return true;
|
if (!output.has_parens() && first_in_statement(output)) return true;
|
||||||
if (output.option('webkit')) {
|
if (output.option("webkit")) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_PropAccess && p.expression === this) return true;
|
if (p instanceof AST_PropAccess && p.expression === this) return true;
|
||||||
}
|
}
|
||||||
if (output.option('wrap_iife')) {
|
if (output.option("wrap_iife")) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_Call && p.expression === this) return true;
|
if (p instanceof AST_Call && p.expression === this) return true;
|
||||||
}
|
}
|
||||||
@@ -679,9 +675,10 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
// same goes for an object literal, because otherwise it would be
|
// same goes for an object literal, because otherwise it would be
|
||||||
// interpreted as a block of code.
|
// interpreted as a block of code.
|
||||||
PARENS(AST_Object, function(output) {
|
function needs_parens_obj(output) {
|
||||||
return !output.has_parens() && first_in_statement(output);
|
return !output.has_parens() && first_in_statement(output);
|
||||||
});
|
}
|
||||||
|
PARENS(AST_Object, needs_parens_obj);
|
||||||
|
|
||||||
PARENS(AST_Unary, function(output) {
|
PARENS(AST_Unary, function(output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
@@ -699,7 +696,9 @@ function OutputStream(options) {
|
|||||||
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||||
// ==> 20 (side effect, set a := 10 and b := 20)
|
// ==> 20 (side effect, set a := 10 and b := 20)
|
||||||
|| p instanceof AST_Conditional
|
|| p instanceof AST_Conditional
|
||||||
|
// { [(1, 2)]: 3 }[2] ==> 3
|
||||||
// { foo: (1, 2) }.foo ==> 2
|
// { foo: (1, 2) }.foo ==> 2
|
||||||
|
|| p instanceof AST_DestructuredKeyVal
|
||||||
|| p instanceof AST_ObjectProperty
|
|| p instanceof AST_ObjectProperty
|
||||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||||
|| p instanceof AST_PropAccess && p.expression === this
|
|| p instanceof AST_PropAccess && p.expression === this
|
||||||
@@ -746,7 +745,7 @@ function OutputStream(options) {
|
|||||||
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 === this;
|
||||||
// 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);
|
var g = output.parent(1);
|
||||||
return this.expression instanceof AST_Function
|
return this.expression instanceof AST_Function
|
||||||
&& p instanceof AST_PropAccess
|
&& p instanceof AST_PropAccess
|
||||||
@@ -769,24 +768,36 @@ function OutputStream(options) {
|
|||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_PropAccess && p.expression === this) {
|
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||||
var value = this.value;
|
var value = this.value;
|
||||||
// https://github.com/mishoo/UglifyJS/issues/115
|
// https://github.com/mishoo/UglifyJS/issues/115
|
||||||
// https://github.com/mishoo/UglifyJS/pull/1009
|
return value < 0
|
||||||
return value < 0 || /^0/.test(make_num(value));
|
// https://github.com/mishoo/UglifyJS/pull/1009
|
||||||
|
|| output.option("galio") && /^0/.test(make_num(value));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS([ AST_Assign, AST_Conditional ], function(output) {
|
function needs_parens_assign_cond(self, output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
||||||
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
||||||
// (a = func)() —or— new (a = Object)()
|
// (a = func)() —or— new (a = Object)()
|
||||||
if (p instanceof AST_Call) return p.expression === this;
|
if (p instanceof AST_Call) return p.expression === self;
|
||||||
// (a = foo) ? bar : baz
|
// (a = foo) ? bar : baz
|
||||||
if (p instanceof AST_Conditional) return p.condition === this;
|
if (p instanceof AST_Conditional) return p.condition === self;
|
||||||
// (a = foo)["prop"] —or— (a = foo).prop
|
// (a = foo)["prop"] —or— (a = foo).prop
|
||||||
if (p instanceof AST_PropAccess) return p.expression === this;
|
if (p instanceof AST_PropAccess) return p.expression === self;
|
||||||
// !(a = false) → true
|
// !(a = false) → true
|
||||||
if (p instanceof AST_Unary) return true;
|
if (p instanceof AST_Unary) return true;
|
||||||
|
}
|
||||||
|
PARENS(AST_Assign, function(output) {
|
||||||
|
if (needs_parens_assign_cond(this, output)) return true;
|
||||||
|
// v8 parser bug => workaround
|
||||||
|
// f([1], [a] = []) => f([1], ([a] = []))
|
||||||
|
if (output.option("v8")) return this.left instanceof AST_Destructured;
|
||||||
|
// ({ p: a } = o);
|
||||||
|
if (this.left instanceof AST_DestructuredObject) return needs_parens_obj(output);
|
||||||
|
});
|
||||||
|
PARENS(AST_Conditional, function(output) {
|
||||||
|
return needs_parens_assign_cond(this, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ PRINTERS ]----- */
|
/* -----[ PRINTERS ]----- */
|
||||||
@@ -1273,6 +1284,38 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
} : noop);
|
} : noop);
|
||||||
});
|
});
|
||||||
|
DEFPRINT(AST_DestructuredArray, function(output) {
|
||||||
|
var a = this.elements, len = a.length;
|
||||||
|
output.with_square(len > 0 ? function() {
|
||||||
|
output.space();
|
||||||
|
a.forEach(function(exp, i) {
|
||||||
|
if (i) output.comma();
|
||||||
|
exp.print(output);
|
||||||
|
// If the final element is a hole, we need to make sure it
|
||||||
|
// doesn't look like a trailing comma, by inserting an actual
|
||||||
|
// trailing comma.
|
||||||
|
if (i === len - 1 && exp instanceof AST_Hole)
|
||||||
|
output.comma();
|
||||||
|
});
|
||||||
|
output.space();
|
||||||
|
} : noop);
|
||||||
|
});
|
||||||
|
DEFPRINT(AST_DestructuredKeyVal, print_key_value);
|
||||||
|
DEFPRINT(AST_DestructuredObject, function(output) {
|
||||||
|
var props = this.properties;
|
||||||
|
if (props.length > 0) output.with_block(function() {
|
||||||
|
props.forEach(function(prop, i) {
|
||||||
|
if (i) {
|
||||||
|
output.print(",");
|
||||||
|
output.newline();
|
||||||
|
}
|
||||||
|
output.indent();
|
||||||
|
prop.print(output);
|
||||||
|
});
|
||||||
|
output.newline();
|
||||||
|
});
|
||||||
|
else print_braced_empty(this, output);
|
||||||
|
});
|
||||||
DEFPRINT(AST_Object, function(output) {
|
DEFPRINT(AST_Object, function(output) {
|
||||||
var props = this.properties;
|
var props = this.properties;
|
||||||
if (props.length > 0) output.with_block(function() {
|
if (props.length > 0) output.with_block(function() {
|
||||||
@@ -1289,34 +1332,43 @@ function OutputStream(options) {
|
|||||||
else print_braced_empty(this, output);
|
else print_braced_empty(this, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
function print_property_name(key, quote, output) {
|
function print_property_key(self, output) {
|
||||||
if (output.option("quote_keys")) {
|
var key = self.key;
|
||||||
|
if (key instanceof AST_Node) {
|
||||||
|
output.with_square(function() {
|
||||||
|
key.print(output);
|
||||||
|
});
|
||||||
|
} else if (output.option("quote_keys")) {
|
||||||
output.print_string(key);
|
output.print_string(key);
|
||||||
} else if ("" + +key == key && key >= 0) {
|
} else if ("" + +key == key && key >= 0) {
|
||||||
output.print(make_num(key));
|
output.print(make_num(key));
|
||||||
} else if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
|
|
||||||
if (quote && output.option("keep_quoted_props")) {
|
|
||||||
output.print_string(key, quote);
|
|
||||||
} else {
|
|
||||||
output.print_name(key);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
output.print_string(key, quote);
|
var quote = self.start && self.start.quote;
|
||||||
|
if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
|
||||||
|
if (quote && output.option("keep_quoted_props")) {
|
||||||
|
output.print_string(key, quote);
|
||||||
|
} else {
|
||||||
|
output.print_name(key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output.print_string(key, quote);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFPRINT(AST_ObjectKeyVal, function(output) {
|
function print_key_value(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
print_property_name(self.key, self.quote, output);
|
print_property_key(self, output);
|
||||||
output.colon();
|
output.colon();
|
||||||
self.value.print(output);
|
self.value.print(output);
|
||||||
});
|
}
|
||||||
|
DEFPRINT(AST_ObjectKeyVal, print_key_value);
|
||||||
function print_accessor(type) {
|
function print_accessor(type) {
|
||||||
return function(output) {
|
return function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
output.print(type);
|
output.print(type);
|
||||||
output.space();
|
output.space();
|
||||||
print_property_name(self.key.name, self.quote, output);
|
print_property_key(self, output);
|
||||||
self.value._codegen(output, true);
|
self.value._codegen(output, true);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1474,6 +1526,7 @@ function OutputStream(options) {
|
|||||||
AST_Constant,
|
AST_Constant,
|
||||||
AST_Debugger,
|
AST_Debugger,
|
||||||
AST_Definitions,
|
AST_Definitions,
|
||||||
|
AST_Destructured,
|
||||||
AST_Finally,
|
AST_Finally,
|
||||||
AST_Jump,
|
AST_Jump,
|
||||||
AST_Lambda,
|
AST_Lambda,
|
||||||
@@ -1488,14 +1541,7 @@ function OutputStream(options) {
|
|||||||
output.add_mapping(this.start);
|
output.add_mapping(this.start);
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFMAP([
|
DEFMAP([ AST_DestructuredKeyVal, AST_ObjectProperty ], function(output) {
|
||||||
AST_ObjectGetter,
|
if (typeof this.key == "string") output.add_mapping(this.start, this.key);
|
||||||
AST_ObjectSetter,
|
|
||||||
], function(output) {
|
|
||||||
output.add_mapping(this.start, this.key.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
DEFMAP([ AST_ObjectProperty ], function(output) {
|
|
||||||
output.add_mapping(this.start, this.key);
|
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
221
lib/parse.js
221
lib/parse.js
@@ -753,7 +753,7 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var statement = embed_tokens(function(strict_defun) {
|
var statement = embed_tokens(function() {
|
||||||
handle_regexp();
|
handle_regexp();
|
||||||
switch (S.token.type) {
|
switch (S.token.type) {
|
||||||
case "string":
|
case "string":
|
||||||
@@ -844,9 +844,6 @@ function parse($TEXT, options) {
|
|||||||
return for_();
|
return for_();
|
||||||
|
|
||||||
case "function":
|
case "function":
|
||||||
if (!strict_defun && S.input.has_directive("use strict")) {
|
|
||||||
croak("In strict mode code, functions can only be declared at top level or immediately within another function.");
|
|
||||||
}
|
|
||||||
next();
|
next();
|
||||||
return function_(AST_Defun);
|
return function_(AST_Defun);
|
||||||
|
|
||||||
@@ -976,14 +973,16 @@ function parse($TEXT, options) {
|
|||||||
if (!is("punc", ";")) {
|
if (!is("punc", ";")) {
|
||||||
init = is("keyword", "const")
|
init = is("keyword", "const")
|
||||||
? (next(), const_(true))
|
? (next(), const_(true))
|
||||||
|
: is("keyword", "let")
|
||||||
|
? (next(), let_(true))
|
||||||
: is("keyword", "var")
|
: is("keyword", "var")
|
||||||
? (next(), var_(true))
|
? (next(), var_(true))
|
||||||
: expression(true, true);
|
: expression(true, true);
|
||||||
if (is("operator", "in")) {
|
if (is("operator", "in")) {
|
||||||
if (init instanceof AST_Var) {
|
if (init instanceof AST_Definitions) {
|
||||||
if (init.definitions.length > 1)
|
if (init.definitions.length > 1)
|
||||||
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||||
} else if (!is_assignable(init)) {
|
} else if (!(is_assignable(init) || (init = to_destructured(init)) instanceof AST_Destructured)) {
|
||||||
croak("Invalid left-hand side in for..in loop", init.start.line, init.start.col, init.start.pos);
|
croak("Invalid left-hand side in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
@@ -1028,7 +1027,7 @@ function parse($TEXT, options) {
|
|||||||
var argnames = [];
|
var argnames = [];
|
||||||
for (var first = true; !is("punc", ")");) {
|
for (var first = true; !is("punc", ")");) {
|
||||||
if (first) first = false; else expect(",");
|
if (first) first = false; else expect(",");
|
||||||
argnames.push(as_symbol(AST_SymbolFunarg));
|
argnames.push(maybe_destructured(AST_SymbolFunarg));
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
var loop = S.in_loop;
|
var loop = S.in_loop;
|
||||||
@@ -1038,7 +1037,7 @@ function parse($TEXT, options) {
|
|||||||
S.input.push_directives_stack();
|
S.input.push_directives_stack();
|
||||||
S.in_loop = 0;
|
S.in_loop = 0;
|
||||||
S.labels = [];
|
S.labels = [];
|
||||||
var body = block_(true);
|
var body = block_();
|
||||||
if (S.input.has_directive("use strict")) {
|
if (S.input.has_directive("use strict")) {
|
||||||
if (name) strict_verify_symbol(name);
|
if (name) strict_verify_symbol(name);
|
||||||
argnames.forEach(strict_verify_symbol);
|
argnames.forEach(strict_verify_symbol);
|
||||||
@@ -1067,12 +1066,12 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function block_(strict_defun) {
|
function block_() {
|
||||||
expect("{");
|
expect("{");
|
||||||
var a = [];
|
var a = [];
|
||||||
while (!is("punc", "}")) {
|
while (!is("punc", "}")) {
|
||||||
if (is("eof")) expect_token("punc", "}");
|
if (is("eof")) expect_token("punc", "}");
|
||||||
a.push(statement(strict_defun));
|
a.push(statement());
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return a;
|
return a;
|
||||||
@@ -1149,16 +1148,16 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function vardefs(type, no_in, must_init) {
|
function vardefs(type, no_in) {
|
||||||
var a = [];
|
var a = [];
|
||||||
for (;;) {
|
for (;;) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var name = as_symbol(type);
|
var name = maybe_destructured(type);
|
||||||
var value = null;
|
var value = null;
|
||||||
if (is("operator", "=")) {
|
if (is("operator", "=")) {
|
||||||
next();
|
next();
|
||||||
value = expression(false, no_in);
|
value = expression(false, no_in);
|
||||||
} else if (must_init) {
|
} else if (!no_in && (type === AST_SymbolConst || name instanceof AST_Destructured)) {
|
||||||
croak("Missing initializer in declaration");
|
croak("Missing initializer in declaration");
|
||||||
}
|
}
|
||||||
a.push(new AST_VarDef({
|
a.push(new AST_VarDef({
|
||||||
@@ -1177,7 +1176,7 @@ function parse($TEXT, options) {
|
|||||||
var const_ = function(no_in) {
|
var const_ = function(no_in) {
|
||||||
return new AST_Const({
|
return new AST_Const({
|
||||||
start : prev(),
|
start : prev(),
|
||||||
definitions : vardefs(AST_SymbolConst, no_in, true),
|
definitions : vardefs(AST_SymbolConst, no_in),
|
||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1222,7 +1221,7 @@ function parse($TEXT, options) {
|
|||||||
var tok = S.token, ret;
|
var tok = S.token, ret;
|
||||||
switch (tok.type) {
|
switch (tok.type) {
|
||||||
case "name":
|
case "name":
|
||||||
ret = _make_symbol(AST_SymbolRef);
|
ret = _make_symbol(AST_SymbolRef, tok);
|
||||||
break;
|
break;
|
||||||
case "num":
|
case "num":
|
||||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
||||||
@@ -1309,7 +1308,8 @@ function parse($TEXT, options) {
|
|||||||
unexpected();
|
unexpected();
|
||||||
};
|
};
|
||||||
|
|
||||||
function expr_list(closing, allow_trailing_comma, allow_empty) {
|
function expr_list(closing, allow_trailing_comma, allow_empty, parser) {
|
||||||
|
if (!parser) parser = expression;
|
||||||
var first = true, a = [];
|
var first = true, a = [];
|
||||||
while (!is("punc", closing)) {
|
while (!is("punc", closing)) {
|
||||||
if (first) first = false; else expect(",");
|
if (first) first = false; else expect(",");
|
||||||
@@ -1317,7 +1317,7 @@ function parse($TEXT, options) {
|
|||||||
if (is("punc", ",") && allow_empty) {
|
if (is("punc", ",") && allow_empty) {
|
||||||
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||||
} else {
|
} else {
|
||||||
a.push(expression(false));
|
a.push(parser());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
@@ -1340,51 +1340,62 @@ function parse($TEXT, options) {
|
|||||||
var first = true, a = [];
|
var first = true, a = [];
|
||||||
while (!is("punc", "}")) {
|
while (!is("punc", "}")) {
|
||||||
if (first) first = false; else expect(",");
|
if (first) first = false; else expect(",");
|
||||||
if (!options.strict && is("punc", "}"))
|
// allow trailing comma
|
||||||
// allow trailing comma
|
if (!options.strict && is("punc", "}")) break;
|
||||||
break;
|
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var type = start.type;
|
var key = as_property_key();
|
||||||
var name = as_property_name();
|
if (is("punc", "(")) {
|
||||||
if (type == "name" && !is("punc", ":")) {
|
var func_start = S.token;
|
||||||
var key = new AST_SymbolAccessor({
|
var func = function_(AST_Function);
|
||||||
start: S.token,
|
func.start = func_start;
|
||||||
name: "" + as_property_name(),
|
func.end = prev();
|
||||||
end: prev()
|
a.push(new AST_ObjectKeyVal({
|
||||||
});
|
start: start,
|
||||||
if (name == "get") {
|
key: key,
|
||||||
a.push(new AST_ObjectGetter({
|
value: func,
|
||||||
start : start,
|
end: prev(),
|
||||||
key : key,
|
}));
|
||||||
value : create_accessor(),
|
continue;
|
||||||
end : prev()
|
}
|
||||||
}));
|
if (!is("punc", ":") && start.type == "name") switch (key) {
|
||||||
continue;
|
case "get":
|
||||||
}
|
a.push(new AST_ObjectGetter({
|
||||||
if (name == "set") {
|
start: start,
|
||||||
a.push(new AST_ObjectSetter({
|
key: as_property_key(),
|
||||||
start : start,
|
value: create_accessor(),
|
||||||
key : key,
|
end: prev(),
|
||||||
value : create_accessor(),
|
}));
|
||||||
end : prev()
|
continue;
|
||||||
}));
|
case "set":
|
||||||
continue;
|
a.push(new AST_ObjectSetter({
|
||||||
}
|
start: start,
|
||||||
|
key: as_property_key(),
|
||||||
|
value: create_accessor(),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start: start,
|
||||||
|
key: key,
|
||||||
|
value: _make_symbol(AST_SymbolRef, start),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
expect(":");
|
expect(":");
|
||||||
a.push(new AST_ObjectKeyVal({
|
a.push(new AST_ObjectKeyVal({
|
||||||
start : start,
|
start: start,
|
||||||
quote : start.quote,
|
key: key,
|
||||||
key : "" + name,
|
value: expression(false),
|
||||||
value : expression(false),
|
end: prev(),
|
||||||
end : prev()
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return new AST_Object({ properties: a });
|
return new AST_Object({ properties: a });
|
||||||
});
|
});
|
||||||
|
|
||||||
function as_property_name() {
|
function as_property_key() {
|
||||||
var tmp = S.token;
|
var tmp = S.token;
|
||||||
switch (tmp.type) {
|
switch (tmp.type) {
|
||||||
case "operator":
|
case "operator":
|
||||||
@@ -1395,7 +1406,13 @@ function parse($TEXT, options) {
|
|||||||
case "keyword":
|
case "keyword":
|
||||||
case "atom":
|
case "atom":
|
||||||
next();
|
next();
|
||||||
return tmp.value;
|
return "" + tmp.value;
|
||||||
|
case "punc":
|
||||||
|
if (tmp.value != "[") unexpected();
|
||||||
|
next();
|
||||||
|
var key = expression(false);
|
||||||
|
expect("]");
|
||||||
|
return key;
|
||||||
default:
|
default:
|
||||||
unexpected();
|
unexpected();
|
||||||
}
|
}
|
||||||
@@ -1408,12 +1425,12 @@ function parse($TEXT, options) {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _make_symbol(type) {
|
function _make_symbol(type, token) {
|
||||||
var name = S.token.value;
|
var name = token.value;
|
||||||
return new (name == "this" ? AST_This : type)({
|
return new (name === "this" ? AST_This : type)({
|
||||||
name : String(name),
|
name: "" + name,
|
||||||
start : S.token,
|
start: token,
|
||||||
end : S.token
|
end: token,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1427,7 +1444,7 @@ function parse($TEXT, options) {
|
|||||||
if (!noerror) croak("Name expected");
|
if (!noerror) croak("Name expected");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var sym = _make_symbol(type);
|
var sym = _make_symbol(type, S.token);
|
||||||
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
|
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
|
||||||
strict_verify_symbol(sym);
|
strict_verify_symbol(sym);
|
||||||
}
|
}
|
||||||
@@ -1435,6 +1452,54 @@ function parse($TEXT, options) {
|
|||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybe_destructured(type) {
|
||||||
|
var start = S.token;
|
||||||
|
if (is("punc", "[")) {
|
||||||
|
next();
|
||||||
|
return new AST_DestructuredArray({
|
||||||
|
start: start,
|
||||||
|
elements: expr_list("]", !options.strict, true, function() {
|
||||||
|
return maybe_destructured(type);
|
||||||
|
}),
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (is("punc", "{")) {
|
||||||
|
next();
|
||||||
|
var first = true, a = [];
|
||||||
|
while (!is("punc", "}")) {
|
||||||
|
if (first) first = false; else expect(",");
|
||||||
|
// allow trailing comma
|
||||||
|
if (!options.strict && is("punc", "}")) break;
|
||||||
|
var key_start = S.token;
|
||||||
|
var key = as_property_key();
|
||||||
|
if (!is("punc", ":") && key_start.type == "name") {
|
||||||
|
a.push(new AST_DestructuredKeyVal({
|
||||||
|
start: key_start,
|
||||||
|
key: key,
|
||||||
|
value: _make_symbol(type, key_start),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
expect(":");
|
||||||
|
a.push(new AST_DestructuredKeyVal({
|
||||||
|
start: key_start,
|
||||||
|
key: key,
|
||||||
|
value: maybe_destructured(type),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
return new AST_DestructuredObject({
|
||||||
|
start: start,
|
||||||
|
properties: a,
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return as_symbol(type);
|
||||||
|
}
|
||||||
|
|
||||||
function mark_pure(call) {
|
function mark_pure(call) {
|
||||||
var start = call.start;
|
var start = call.start;
|
||||||
var comments = start.comments_before;
|
var comments = start.comments_before;
|
||||||
@@ -1564,11 +1629,43 @@ function parse($TEXT, options) {
|
|||||||
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
|
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function to_destructured(node) {
|
||||||
|
if (node instanceof AST_Array) {
|
||||||
|
var elements = node.elements.map(to_destructured);
|
||||||
|
return all(elements, function(node) {
|
||||||
|
return node instanceof AST_Destructured || node instanceof AST_Hole || is_assignable(node);
|
||||||
|
}) ? new AST_DestructuredArray({
|
||||||
|
start: node.start,
|
||||||
|
elements: elements,
|
||||||
|
end: node.end,
|
||||||
|
}) : node;
|
||||||
|
}
|
||||||
|
if (!(node instanceof AST_Object)) return node;
|
||||||
|
var props = [];
|
||||||
|
for (var i = 0; i < node.properties.length; i++) {
|
||||||
|
var prop = node.properties[i];
|
||||||
|
if (!(prop instanceof AST_ObjectKeyVal)) return node;
|
||||||
|
var value = to_destructured(prop.value);
|
||||||
|
if (!(value instanceof AST_Destructured || is_assignable(value))) return node;
|
||||||
|
props.push(new AST_DestructuredKeyVal({
|
||||||
|
start: prop.start,
|
||||||
|
key: prop.key,
|
||||||
|
value: value,
|
||||||
|
end: prop.end,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return new AST_DestructuredObject({
|
||||||
|
start: node.start,
|
||||||
|
properties: props,
|
||||||
|
end: node.end,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var maybe_assign = function(no_in) {
|
var maybe_assign = function(no_in) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var left = maybe_conditional(no_in), val = S.token.value;
|
var left = maybe_conditional(no_in), val = S.token.value;
|
||||||
if (is("operator") && ASSIGNMENT[val]) {
|
if (is("operator") && ASSIGNMENT[val]) {
|
||||||
if (is_assignable(left)) {
|
if (is_assignable(left) || val == "=" && (left = to_destructured(left)) instanceof AST_Destructured) {
|
||||||
next();
|
next();
|
||||||
return new AST_Assign({
|
return new AST_Assign({
|
||||||
start : start,
|
start : start,
|
||||||
@@ -1616,7 +1713,7 @@ function parse($TEXT, options) {
|
|||||||
var body = [];
|
var body = [];
|
||||||
S.input.push_directives_stack();
|
S.input.push_directives_stack();
|
||||||
while (!is("eof"))
|
while (!is("eof"))
|
||||||
body.push(statement(true));
|
body.push(statement());
|
||||||
S.input.pop_directives_stack();
|
S.input.pop_directives_stack();
|
||||||
var end = prev();
|
var end = prev();
|
||||||
var toplevel = options.toplevel;
|
var toplevel = options.toplevel;
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ var builtins = function() {
|
|||||||
|
|
||||||
function reserve_quoted_keys(ast, reserved) {
|
function reserve_quoted_keys(ast, reserved) {
|
||||||
ast.walk(new TreeWalker(function(node) {
|
ast.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectProperty) {
|
||||||
if (node.quote) add(node.key);
|
if (node.start && node.start.quote) add(node.key);
|
||||||
} else if (node instanceof AST_Sub) {
|
} else if (node instanceof AST_Sub) {
|
||||||
addStrings(node.property, add);
|
addStrings(node.property, add);
|
||||||
}
|
}
|
||||||
@@ -165,11 +165,8 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
} else if (node instanceof AST_Dot) {
|
} else if (node instanceof AST_Dot) {
|
||||||
add(node.property);
|
add(node.property);
|
||||||
} else if (node instanceof AST_ObjectKeyVal) {
|
|
||||||
add(node.key);
|
|
||||||
} else if (node instanceof AST_ObjectProperty) {
|
} else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter, since KeyVal is handled above
|
if (typeof node.key == "string") add(node.key);
|
||||||
add(node.key.name);
|
|
||||||
} else if (node instanceof AST_Sub) {
|
} else if (node instanceof AST_Sub) {
|
||||||
addStrings(node.property, add);
|
addStrings(node.property, add);
|
||||||
}
|
}
|
||||||
@@ -198,11 +195,8 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
} else if (node instanceof AST_Dot) {
|
} else if (node instanceof AST_Dot) {
|
||||||
node.property = mangle(node.property);
|
node.property = mangle(node.property);
|
||||||
} else if (node instanceof AST_ObjectKeyVal) {
|
|
||||||
node.key = mangle(node.key);
|
|
||||||
} else if (node instanceof AST_ObjectProperty) {
|
} else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter
|
if (typeof node.key == "string") node.key = mangle(node.key);
|
||||||
node.key.name = mangle(node.key.name);
|
|
||||||
} else if (node instanceof AST_Sub) {
|
} else if (node instanceof AST_Sub) {
|
||||||
if (!options.keep_quoted) mangleStrings(node.property);
|
if (!options.keep_quoted) mangleStrings(node.property);
|
||||||
}
|
}
|
||||||
|
|||||||
67
lib/scope.js
67
lib/scope.js
@@ -72,7 +72,7 @@ SymbolDef.prototype = {
|
|||||||
if (def) {
|
if (def) {
|
||||||
this.mangled_name = def.mangled_name || def.name;
|
this.mangled_name = def.mangled_name || def.name;
|
||||||
} else {
|
} else {
|
||||||
this.mangled_name = next_mangled_name(this.scope, options, this);
|
this.mangled_name = next_mangled_name(this, options);
|
||||||
}
|
}
|
||||||
if (this.global && cache) {
|
if (this.global && cache) {
|
||||||
cache.set(this.name, this.mangled_name);
|
cache.set(this.name, this.mangled_name);
|
||||||
@@ -204,7 +204,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
|
|
||||||
// pass 2: find back references and eval
|
// pass 2: find back references and eval
|
||||||
self.globals = new Dictionary();
|
self.globals = new Dictionary();
|
||||||
|
var in_arg = [];
|
||||||
var tw = new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_Lambda) {
|
||||||
|
in_arg.push(node);
|
||||||
|
node.argnames.forEach(function(argname) {
|
||||||
|
argname.walk(tw);
|
||||||
|
});
|
||||||
|
in_arg.pop();
|
||||||
|
walk_body(node, tw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_LoopControl) {
|
if (node instanceof AST_LoopControl) {
|
||||||
if (node.label) node.label.thedef.references.push(node);
|
if (node.label) node.label.thedef.references.push(node);
|
||||||
return true;
|
return true;
|
||||||
@@ -212,10 +222,24 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var name = node.name;
|
var name = node.name;
|
||||||
var sym = node.scope.find_variable(name);
|
var sym = node.scope.find_variable(name);
|
||||||
|
for (var i = in_arg.length; i > 0 && sym;) {
|
||||||
|
i = in_arg.lastIndexOf(sym.scope, i - 1);
|
||||||
|
if (i < 0) break;
|
||||||
|
var decl = sym.orig[0];
|
||||||
|
if (decl instanceof AST_SymbolFunarg || decl instanceof AST_SymbolLambda) {
|
||||||
|
node.in_arg = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sym = sym.scope.parent_scope.find_variable(name);
|
||||||
|
}
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
sym = self.def_global(node);
|
sym = self.def_global(node);
|
||||||
} else if (name == "arguments" && sym.scope instanceof AST_Lambda) {
|
} else if (name == "arguments" && sym.scope instanceof AST_Lambda) {
|
||||||
sym.scope.uses_arguments = true;
|
if (!(tw.parent() instanceof AST_PropAccess)) {
|
||||||
|
sym.scope.uses_arguments = "d";
|
||||||
|
} else if (!sym.scope.uses_arguments) {
|
||||||
|
sym.scope.uses_arguments = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (name == "eval") {
|
if (name == "eval") {
|
||||||
var parent = tw.parent();
|
var parent = tw.parent();
|
||||||
@@ -408,7 +432,8 @@ function names_in_use(scope, options) {
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
function next_mangled_name(scope, options, def) {
|
function next_mangled_name(def, options) {
|
||||||
|
var scope = def.scope;
|
||||||
var in_use = names_in_use(scope, options);
|
var in_use = names_in_use(scope, options);
|
||||||
var holes = scope.cname_holes;
|
var holes = scope.cname_holes;
|
||||||
var names = Object.create(null);
|
var names = Object.create(null);
|
||||||
@@ -461,6 +486,7 @@ function _default_mangler_options(options) {
|
|||||||
keep_fnames : false,
|
keep_fnames : false,
|
||||||
reserved : [],
|
reserved : [],
|
||||||
toplevel : false,
|
toplevel : false,
|
||||||
|
webkit : false,
|
||||||
});
|
});
|
||||||
if (!Array.isArray(options.reserved)) options.reserved = [];
|
if (!Array.isArray(options.reserved)) options.reserved = [];
|
||||||
// Never mangle arguments
|
// Never mangle arguments
|
||||||
@@ -495,9 +521,24 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_BlockScope) {
|
if (node instanceof AST_BlockScope) {
|
||||||
var to_mangle = [];
|
if (options.webkit && node instanceof AST_IterationStatement && node.init instanceof AST_Let) {
|
||||||
|
node.init.definitions.forEach(function(defn) {
|
||||||
|
defn.name.match_symbol(function(sym) {
|
||||||
|
if (!(sym instanceof AST_SymbolLet)) return;
|
||||||
|
var def = sym.definition();
|
||||||
|
var scope = sym.scope.parent_scope;
|
||||||
|
var redef = scope.def_variable(sym);
|
||||||
|
sym.thedef = def;
|
||||||
|
scope.to_mangle.push(redef);
|
||||||
|
def.redefined = function() {
|
||||||
|
return redef;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
node.to_mangle = [];
|
||||||
node.variables.each(function(def) {
|
node.variables.each(function(def) {
|
||||||
if (!defer_redef(def)) to_mangle.push(def);
|
if (!defer_redef(def)) node.to_mangle.push(def);
|
||||||
});
|
});
|
||||||
descend();
|
descend();
|
||||||
if (options.cache && node instanceof AST_Toplevel) {
|
if (options.cache && node instanceof AST_Toplevel) {
|
||||||
@@ -508,7 +549,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
sym.scope = node;
|
sym.scope = node;
|
||||||
sym.reference(options);
|
sym.reference(options);
|
||||||
}
|
}
|
||||||
to_mangle.forEach(mangle);
|
node.to_mangle.forEach(mangle);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Label) {
|
if (node instanceof AST_Label) {
|
||||||
@@ -528,13 +569,19 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
def.mangle(options);
|
def.mangle(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
function defer_redef(def, node) {
|
function defer_redef(def) {
|
||||||
|
var sym = def.orig[0];
|
||||||
var redef = def.redefined();
|
var redef = def.redefined();
|
||||||
if (!redef) return false;
|
if (!redef) {
|
||||||
|
if (!(sym instanceof AST_SymbolConst)) return false;
|
||||||
|
var scope = def.scope.resolve();
|
||||||
|
if (def.scope === scope) return false;
|
||||||
|
redef = scope.def_variable(sym);
|
||||||
|
scope.to_mangle.push(redef);
|
||||||
|
}
|
||||||
redefined.push(def);
|
redefined.push(def);
|
||||||
def.references.forEach(reference);
|
def.references.forEach(reference);
|
||||||
var node = def.orig[0];
|
if (sym instanceof AST_SymbolCatch || sym instanceof AST_SymbolConst) reference(sym);
|
||||||
if (node instanceof AST_SymbolCatch || node instanceof AST_SymbolConst) reference(node);
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
function reference(sym) {
|
function reference(sym) {
|
||||||
|
|||||||
@@ -160,10 +160,21 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
DEF(AST_Array, function(self, tw) {
|
DEF(AST_Array, function(self, tw) {
|
||||||
self.elements = do_list(self.elements, tw);
|
self.elements = do_list(self.elements, tw);
|
||||||
});
|
});
|
||||||
|
DEF(AST_DestructuredArray, function(self, tw) {
|
||||||
|
self.elements = do_list(self.elements, tw);
|
||||||
|
});
|
||||||
|
DEF(AST_DestructuredKeyVal, function(self, tw) {
|
||||||
|
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
|
||||||
|
self.value = self.value.transform(tw);
|
||||||
|
});
|
||||||
|
DEF(AST_DestructuredObject, function(self, tw) {
|
||||||
|
self.properties = do_list(self.properties, tw);
|
||||||
|
});
|
||||||
DEF(AST_Object, function(self, tw) {
|
DEF(AST_Object, function(self, tw) {
|
||||||
self.properties = do_list(self.properties, tw);
|
self.properties = do_list(self.properties, tw);
|
||||||
});
|
});
|
||||||
DEF(AST_ObjectProperty, function(self, tw) {
|
DEF(AST_ObjectProperty, function(self, tw) {
|
||||||
|
if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
|
||||||
self.value = self.value.transform(tw);
|
self.value = self.value.transform(tw);
|
||||||
});
|
});
|
||||||
})(function(node, descend) {
|
})(function(node, descend) {
|
||||||
|
|||||||
@@ -143,8 +143,9 @@ function push_uniq(array, el) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function string_template(text, props) {
|
function string_template(text, props) {
|
||||||
return text.replace(/\{(.+?)\}/g, function(str, p) {
|
return text.replace(/\{([^}]+)\}/g, function(str, p) {
|
||||||
return props && props[p];
|
var value = props[p];
|
||||||
|
return value instanceof AST_Node ? value.print_to_string() : value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.11.4",
|
"version": "3.12.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ function make_code(ast, options) {
|
|||||||
|
|
||||||
function parse_test(file) {
|
function parse_test(file) {
|
||||||
var script = fs.readFileSync(file, "utf8");
|
var script = fs.readFileSync(file, "utf8");
|
||||||
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS/issues/348
|
|
||||||
try {
|
try {
|
||||||
var ast = U.parse(script, {
|
var ast = U.parse(script, {
|
||||||
filename: file
|
filename: file
|
||||||
@@ -315,6 +314,7 @@ function test_case(test) {
|
|||||||
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
|
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
|
||||||
}
|
}
|
||||||
var output_code = make_code(output, output_options);
|
var output_code = make_code(output, output_options);
|
||||||
|
U.AST_Node.log_function();
|
||||||
if (expect != output_code) {
|
if (expect != output_code) {
|
||||||
log([
|
log([
|
||||||
"!!! failed",
|
"!!! failed",
|
||||||
@@ -386,7 +386,7 @@ function test_case(test) {
|
|||||||
mangle: test.mangle
|
mangle: test.mangle
|
||||||
});
|
});
|
||||||
var actual = stdout[toplevel ? 1 : 0];
|
var actual = stdout[toplevel ? 1 : 0];
|
||||||
if (test.expect_stdout === true) {
|
if (test.expect_stdout === true || test.expect_stdout instanceof Error && test.expect_stdout.name === actual.name) {
|
||||||
test.expect_stdout = actual;
|
test.expect_stdout = actual;
|
||||||
}
|
}
|
||||||
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
||||||
|
|||||||
@@ -807,3 +807,47 @@ issue_4200: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4291_1: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
arguments[0] = "PASS";
|
||||||
|
return arguments;
|
||||||
|
}()[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
arguments[0] = "PASS";
|
||||||
|
return arguments;
|
||||||
|
}()[0]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4291_2: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
keep_fargs: "strict",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = function() {
|
||||||
|
if (arguments[0])
|
||||||
|
arguments[1] = "PASS";
|
||||||
|
return arguments;
|
||||||
|
}(42);
|
||||||
|
console.log(a[1], a[0], a.length);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = function(argument_0) {
|
||||||
|
if (argument_0)
|
||||||
|
arguments[1] = "PASS";
|
||||||
|
return arguments;
|
||||||
|
}(42);
|
||||||
|
console.log(a[1], a[0], a.length);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS 42 1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -8577,3 +8577,28 @@ issue_4242: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4248: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
try {
|
||||||
|
a = 1;
|
||||||
|
b[1];
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
try {
|
||||||
|
a = 1;
|
||||||
|
b[1];
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -83,13 +83,11 @@ ifs_3_should_warn: {
|
|||||||
"WARN: Condition left of && always false [test/compress/conditionals.js:3,12]",
|
"WARN: Condition left of && always false [test/compress/conditionals.js:3,12]",
|
||||||
"WARN: Condition always false [test/compress/conditionals.js:3,12]",
|
"WARN: Condition always false [test/compress/conditionals.js:3,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/conditionals.js:3,34]",
|
"WARN: Dropping unreachable code [test/compress/conditionals.js:3,34]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/conditionals.js:4,12]",
|
|
||||||
"WARN: + in boolean context always true [test/compress/conditionals.js:10,19]",
|
"WARN: + in boolean context always true [test/compress/conditionals.js:10,19]",
|
||||||
"WARN: Boolean || always true [test/compress/conditionals.js:10,12]",
|
"WARN: Boolean || always true [test/compress/conditionals.js:10,12]",
|
||||||
"WARN: Condition left of || always true [test/compress/conditionals.js:10,12]",
|
"WARN: Condition left of || always true [test/compress/conditionals.js:10,12]",
|
||||||
"WARN: Condition always true [test/compress/conditionals.js:10,12]",
|
"WARN: Condition always true [test/compress/conditionals.js:10,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/conditionals.js:12,15]",
|
"WARN: Dropping unreachable code [test/compress/conditionals.js:12,15]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/conditionals.js:13,12]",
|
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:3,12]",
|
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:3,12]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:10,12]",
|
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:10,12]",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,3 +1,45 @@
|
|||||||
|
mangle_block: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = "PASS";
|
||||||
|
{
|
||||||
|
const a = "FAIL";
|
||||||
|
}
|
||||||
|
console.log(o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = "PASS";
|
||||||
|
{
|
||||||
|
const a = "FAIL";
|
||||||
|
}
|
||||||
|
console.log(o);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_block_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = "PASS";
|
||||||
|
{
|
||||||
|
const a = "FAIL";
|
||||||
|
}
|
||||||
|
console.log(o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = "PASS";
|
||||||
|
{
|
||||||
|
const c = "FAIL";
|
||||||
|
}
|
||||||
|
console.log(o);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
mangle_catch_1: {
|
mangle_catch_1: {
|
||||||
mangle = {}
|
mangle = {}
|
||||||
input: {
|
input: {
|
||||||
@@ -11,8 +53,8 @@ mangle_catch_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
try {
|
try {
|
||||||
throw "eeeee";
|
throw "eeeee";
|
||||||
} catch (e) {
|
} catch (o) {
|
||||||
const o = typeof d;
|
const e = typeof d;
|
||||||
}
|
}
|
||||||
console.log(typeof a, typeof b);
|
console.log(typeof a, typeof b);
|
||||||
}
|
}
|
||||||
@@ -57,6 +99,23 @@ retain_block: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retain_catch: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {} catch (a) {
|
||||||
|
const a = "aa";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {} catch (a) {
|
||||||
|
const a = "aa";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
if_dead_branch: {
|
if_dead_branch: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
@@ -1084,3 +1143,207 @@ issue_4231: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "function"
|
expect_stdout: "function"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4245: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const a = f();
|
||||||
|
function f() {
|
||||||
|
typeof a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const a = f();
|
||||||
|
function f() {
|
||||||
|
a,
|
||||||
|
1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4248: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
(function() {
|
||||||
|
a = "PASS";
|
||||||
|
b[a];
|
||||||
|
const b = 0;
|
||||||
|
})();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
(function() {
|
||||||
|
a = "PASS";
|
||||||
|
b[a];
|
||||||
|
const b = 0;
|
||||||
|
})();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4261: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const a = 42;
|
||||||
|
(function() {
|
||||||
|
function f() {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
while (f());
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
while (g());
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
{
|
||||||
|
const a = 42;
|
||||||
|
(function() {
|
||||||
|
function g() {
|
||||||
|
while (void console.log(a));
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
while (g());
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4274_1: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (;;) {
|
||||||
|
if (console.log("PASS")) {
|
||||||
|
const a = 0;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (; console.log("PASS");) {
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
}
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4274_2: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (;;) {
|
||||||
|
if (!console.log("PASS")) {
|
||||||
|
break;
|
||||||
|
var a;
|
||||||
|
} else {
|
||||||
|
const a = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (; console.log("PASS");) {
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
}
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4290_1: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4305_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
const arguments = function() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
};
|
||||||
|
arguments();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
const arguments = function() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
};
|
||||||
|
arguments();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4305_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
const a = function() {
|
||||||
|
while (console.log("aaaaa"));
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
const a = function() {
|
||||||
|
while (console.log("aaaaa"));
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
@@ -61,8 +61,6 @@ dead_code_2_should_warn: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:8,12]",
|
"WARN: Dropping unreachable code [test/compress/dead-code.js:8,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/dead-code.js:10,16]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:10,16]",
|
|
||||||
]
|
]
|
||||||
node_version: "<=4"
|
node_version: "<=4"
|
||||||
}
|
}
|
||||||
@@ -103,11 +101,9 @@ dead_code_constant_boolean_should_warn_more: {
|
|||||||
"WARN: + in boolean context always true [test/compress/dead-code.js:1,33]",
|
"WARN: + in boolean context always true [test/compress/dead-code.js:1,33]",
|
||||||
"WARN: Boolean || always true [test/compress/dead-code.js:1,16]",
|
"WARN: Boolean || always true [test/compress/dead-code.js:1,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:1,45]",
|
"WARN: Dropping unreachable code [test/compress/dead-code.js:1,45]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/dead-code.js:3,12]",
|
|
||||||
"WARN: Boolean expression always true [test/compress/dead-code.js:6,47]",
|
"WARN: Boolean expression always true [test/compress/dead-code.js:6,47]",
|
||||||
"WARN: Boolean && always false [test/compress/dead-code.js:6,28]",
|
"WARN: Boolean && always false [test/compress/dead-code.js:6,28]",
|
||||||
"WARN: Dropping unreachable code [test/compress/dead-code.js:6,63]",
|
"WARN: Dropping unreachable code [test/compress/dead-code.js:6,63]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/dead-code.js:9,12]",
|
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:1,15]",
|
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:1,15]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:6,28]",
|
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:6,28]",
|
||||||
]
|
]
|
||||||
|
|||||||
1649
test/compress/destructured.js
Normal file
1649
test/compress/destructured.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3047,3 +3047,30 @@ issue_4214: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "NaN"
|
expect_stdout: "NaN"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4271: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
p: null,
|
||||||
|
q: (console.log("foo"), 42),
|
||||||
|
p: function() {}
|
||||||
|
})[console.log("bar"), "p"] && console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({
|
||||||
|
p: null,
|
||||||
|
q: (console.log("foo"), 42),
|
||||||
|
p: function() {}
|
||||||
|
})[console.log("bar"), "p"],
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -521,7 +521,7 @@ issue_2531_2: {
|
|||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
passes: 3,
|
passes: 2,
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -556,9 +556,10 @@ issue_2531_3: {
|
|||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
passes: 3,
|
passes: 2,
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
@@ -2081,7 +2082,7 @@ issue_3016_1: {
|
|||||||
var b = 1;
|
var b = 1;
|
||||||
do {
|
do {
|
||||||
3[b];
|
3[b];
|
||||||
} while(0);
|
} while (0);
|
||||||
console.log(b);
|
console.log(b);
|
||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
@@ -2112,7 +2113,7 @@ issue_3016_2: {
|
|||||||
do {
|
do {
|
||||||
a = 3,
|
a = 3,
|
||||||
a[b];
|
a[b];
|
||||||
} while(0);
|
} while (0);
|
||||||
var a;
|
var a;
|
||||||
console.log(b);
|
console.log(b);
|
||||||
}
|
}
|
||||||
@@ -2145,7 +2146,7 @@ issue_3016_2_ie8: {
|
|||||||
do {
|
do {
|
||||||
a = 3,
|
a = 3,
|
||||||
a[b];
|
a[b];
|
||||||
} while(0);
|
} while (0);
|
||||||
var a;
|
var a;
|
||||||
console.log(b);
|
console.log(b);
|
||||||
}
|
}
|
||||||
@@ -2175,7 +2176,7 @@ issue_3016_3: {
|
|||||||
var b = 1;
|
var b = 1;
|
||||||
do {
|
do {
|
||||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||||
} while(b--);
|
} while (b--);
|
||||||
var a;
|
var a;
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
@@ -2208,7 +2209,7 @@ issue_3016_3_ie8: {
|
|||||||
var b = 1;
|
var b = 1;
|
||||||
do {
|
do {
|
||||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||||
} while(b--);
|
} while (b--);
|
||||||
var a;
|
var a;
|
||||||
}
|
}
|
||||||
expect_stdout: [
|
expect_stdout: [
|
||||||
@@ -5115,3 +5116,102 @@ issue_4233: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "number"
|
expect_stdout: "number"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4259: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
functions: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = function b() {
|
||||||
|
var c = b;
|
||||||
|
for (b in c);
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function a() {
|
||||||
|
for (a in a);
|
||||||
|
}
|
||||||
|
a();
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4261: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (e) {
|
||||||
|
(function() {
|
||||||
|
function f() {
|
||||||
|
e.p;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
while (f());
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
while (console.log(g()));
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw 42;
|
||||||
|
} catch (e) {
|
||||||
|
(function() {
|
||||||
|
function g() {
|
||||||
|
while (void e.p);
|
||||||
|
}
|
||||||
|
(function() {
|
||||||
|
while (console.log(g()));
|
||||||
|
})();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4265: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
dead_code: true,
|
||||||
|
inline: true,
|
||||||
|
sequences: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
console;
|
||||||
|
if ([ function() {
|
||||||
|
return this + console.log(a);
|
||||||
|
a;
|
||||||
|
var a;
|
||||||
|
}() ]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
return console, function() {
|
||||||
|
return console.log(a);
|
||||||
|
var a;
|
||||||
|
}(), 0;
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|||||||
@@ -297,6 +297,33 @@ name_collision_3: {
|
|||||||
expect_stdout: "true 4 6"
|
expect_stdout: "true 4 6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name_collision_4: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
var o = {
|
||||||
|
p: 0,
|
||||||
|
q: "PASS",
|
||||||
|
};
|
||||||
|
return function(o_p) {
|
||||||
|
if (!o.p) return o_p;
|
||||||
|
}(o.q);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var o_p$0 = 0, o_q = "PASS";
|
||||||
|
return function(o_p) {
|
||||||
|
if (!o_p$0) return o_p;
|
||||||
|
}(o_q);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
contains_this_1: {
|
contains_this_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|||||||
@@ -2877,3 +2877,30 @@ issue_4235: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "undefined"
|
expect_stdout: "undefined"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4250: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
loops: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {
|
||||||
|
(function() {
|
||||||
|
for (f in "f");
|
||||||
|
})();
|
||||||
|
return f;
|
||||||
|
var f;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f() {
|
||||||
|
(function() {
|
||||||
|
for (f in "f");
|
||||||
|
})();
|
||||||
|
return f;
|
||||||
|
var f;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ non_hoisted_function_after_return: {
|
|||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]"
|
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,15 +84,12 @@ non_hoisted_function_after_return_2a: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:4,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:7,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
|
||||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
|
||||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
||||||
"INFO: pass 0: last_count: Infinity, count: 35",
|
"INFO: pass 0: last_count: Infinity, count: 35",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||||
"INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
|
"INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
|
||||||
"INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
|
"INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
|
||||||
@@ -138,10 +135,7 @@ non_hoisted_function_after_return_2b: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:8,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:6,16]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,12]",
|
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,12]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -242,15 +236,12 @@ non_hoisted_function_after_return_2a_strict: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "5 6"
|
expect_stdout: "5 6"
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:5,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:8,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
|
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
|
|
||||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
|
||||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
||||||
"INFO: pass 0: last_count: Infinity, count: 46",
|
"INFO: pass 0: last_count: Infinity, count: 46",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:10,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||||
"INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
|
"INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
|
||||||
"INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
|
"INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
|
||||||
@@ -301,10 +292,7 @@ non_hoisted_function_after_return_2b_strict: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "5 6"
|
expect_stdout: "5 6"
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,26 @@ retain_block: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retain_catch: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
try {} catch (a) {
|
||||||
|
let a = "aa";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
try {} catch (a) {
|
||||||
|
let a = "aa";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
if_dead_branch: {
|
if_dead_branch: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
@@ -893,3 +913,318 @@ issue_4231: {
|
|||||||
expect_stdout: "function"
|
expect_stdout: "function"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4245: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let a = f();
|
||||||
|
function f() {
|
||||||
|
typeof a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let a = f();
|
||||||
|
function f() {
|
||||||
|
a,
|
||||||
|
1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: ReferenceError("a is not defined")
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4248: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
(function() {
|
||||||
|
"use strict";
|
||||||
|
a = "PASS";
|
||||||
|
b[a];
|
||||||
|
let b;
|
||||||
|
})();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "FAIL";
|
||||||
|
try {
|
||||||
|
(function() {
|
||||||
|
"use strict";
|
||||||
|
a = "PASS";
|
||||||
|
b[a];
|
||||||
|
let b;
|
||||||
|
})();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4274_1: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
for (;;) {
|
||||||
|
if (console.log("PASS")) {
|
||||||
|
let a;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
for (; console.log("PASS");) {
|
||||||
|
{
|
||||||
|
let a;
|
||||||
|
}
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4274_2: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
for (;;) {
|
||||||
|
if (!console.log("PASS")) {
|
||||||
|
break;
|
||||||
|
var a;
|
||||||
|
} else {
|
||||||
|
let a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
for (; console.log("PASS");) {
|
||||||
|
{
|
||||||
|
let a;
|
||||||
|
}
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4276_1: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
let a = b, b;
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
let a = b, b;
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4276_2: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
let a = f(), b;
|
||||||
|
console.log("FAIL");
|
||||||
|
function f() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
let a = f(), b;
|
||||||
|
console.log("FAIL");
|
||||||
|
function f() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4290_1: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let a;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let a;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4290_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
console.log(function(a) {
|
||||||
|
a = c;
|
||||||
|
let c;
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
try {
|
||||||
|
console.log(function(a) {
|
||||||
|
a = c;
|
||||||
|
let c;
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4305_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
let arguments = function() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
};
|
||||||
|
arguments();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
let arguments = function() {
|
||||||
|
while (console.log("PASS"));
|
||||||
|
};
|
||||||
|
arguments();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4305_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
(function(a) {
|
||||||
|
let a = function() {
|
||||||
|
while (console.log("aaaaa"));
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
(function(a) {
|
||||||
|
let a = function() {
|
||||||
|
while (console.log("aaaaa"));
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1753: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
webkit: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let i = 0; i < 1; i++)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let i = 0; i < 1; i++)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1753_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
webkit: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let i = 0; i < 1; i++)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let l = null;
|
||||||
|
for (let e = 0; e < 1; e++)
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -3092,3 +3092,94 @@ issue_4237_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_4253: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
switch (0) {
|
||||||
|
default:
|
||||||
|
var a = "FAIL";
|
||||||
|
a = a && a;
|
||||||
|
try {
|
||||||
|
break;
|
||||||
|
} catch (e) {}
|
||||||
|
var b = 42;
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
switch (0) {
|
||||||
|
default:
|
||||||
|
var a = "FAIL";
|
||||||
|
a = a && a;
|
||||||
|
try {
|
||||||
|
break;
|
||||||
|
} catch (e) {}
|
||||||
|
var b = 42;
|
||||||
|
}
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4255: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
loops: true,
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
L: for (var a = 2; --a;)
|
||||||
|
for (var b = 0; console.log(b); --b)
|
||||||
|
break L;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
L: for (var a = 2; --a;) {
|
||||||
|
var b = 0;
|
||||||
|
if (console.log(b))
|
||||||
|
break L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4257: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
switch (--a) {
|
||||||
|
case 0:
|
||||||
|
var b = 0;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
var c = 1 + (0 | (b && A));
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
switch (--a) {
|
||||||
|
case 0:
|
||||||
|
var b = 0;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
var c = 1 + (0 | (b && A));
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,49 +1,100 @@
|
|||||||
hex_numbers_in_parentheses_for_prototype_functions: {
|
parentheses_for_prototype_functions: {
|
||||||
beautify = {
|
beautify = {
|
||||||
beautify: true,
|
beautify: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f() {
|
(function() {
|
||||||
(-2);
|
console.log((-2));
|
||||||
(-2).toFixed(0);
|
console.log((-2).toFixed(0));
|
||||||
|
|
||||||
(2);
|
console.log((2));
|
||||||
(2).toFixed(0);
|
console.log((2).toFixed(0));
|
||||||
|
|
||||||
(0.2);
|
console.log((0.2));
|
||||||
(0.2).toFixed(0);
|
console.log((0.2).toFixed(0));
|
||||||
|
|
||||||
(2.34e20);
|
console.log((2.34e20));
|
||||||
(2.34e20).toFixed(0);
|
console.log((2.34e20).toFixed(0));
|
||||||
|
|
||||||
(0.00000002);
|
console.log((0.00000002));
|
||||||
(0.00000002).toFixed(0);
|
console.log((0.00000002).toFixed(0));
|
||||||
|
|
||||||
(1000000000000000128);
|
console.log((1000000000000000128));
|
||||||
(1000000000000000128).toFixed(0);
|
console.log((1000000000000000128).toFixed(0));
|
||||||
|
|
||||||
(-1000000000000000128);
|
console.log((-1000000000000000128));
|
||||||
(-1000000000000000128).toFixed(0);
|
console.log((-1000000000000000128).toFixed(0));
|
||||||
}
|
})();
|
||||||
}
|
}
|
||||||
expect_exact: [
|
expect_exact: [
|
||||||
"function f() {",
|
"(function() {",
|
||||||
" -2;",
|
" console.log(-2);",
|
||||||
" (-2).toFixed(0);",
|
" console.log((-2).toFixed(0));",
|
||||||
" 2;",
|
" console.log(2);",
|
||||||
" 2..toFixed(0);",
|
" console.log(2..toFixed(0));",
|
||||||
" .2;",
|
" console.log(.2);",
|
||||||
" .2.toFixed(0);",
|
" console.log(.2.toFixed(0));",
|
||||||
" 234e18;",
|
" console.log(234e18);",
|
||||||
" 234e18.toFixed(0);",
|
" console.log(234e18.toFixed(0));",
|
||||||
" 2e-8;",
|
" console.log(2e-8);",
|
||||||
" 2e-8.toFixed(0);",
|
" console.log(2e-8.toFixed(0));",
|
||||||
" 0xde0b6b3a7640080;",
|
" console.log(0xde0b6b3a7640080);",
|
||||||
" (0xde0b6b3a7640080).toFixed(0);",
|
" console.log(0xde0b6b3a7640080.toFixed(0));",
|
||||||
" -0xde0b6b3a7640080;",
|
" console.log(-0xde0b6b3a7640080);",
|
||||||
" (-0xde0b6b3a7640080).toFixed(0);",
|
" console.log((-0xde0b6b3a7640080).toFixed(0));",
|
||||||
"}",
|
"})();",
|
||||||
]
|
]
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
parentheses_for_prototype_functions_galio: {
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
galio: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
console.log((-2));
|
||||||
|
console.log((-2).toFixed(0));
|
||||||
|
|
||||||
|
console.log((2));
|
||||||
|
console.log((2).toFixed(0));
|
||||||
|
|
||||||
|
console.log((0.2));
|
||||||
|
console.log((0.2).toFixed(0));
|
||||||
|
|
||||||
|
console.log((2.34e20));
|
||||||
|
console.log((2.34e20).toFixed(0));
|
||||||
|
|
||||||
|
console.log((0.00000002));
|
||||||
|
console.log((0.00000002).toFixed(0));
|
||||||
|
|
||||||
|
console.log((1000000000000000128));
|
||||||
|
console.log((1000000000000000128).toFixed(0));
|
||||||
|
|
||||||
|
console.log((-1000000000000000128));
|
||||||
|
console.log((-1000000000000000128).toFixed(0));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"(function() {",
|
||||||
|
" console.log(-2);",
|
||||||
|
" console.log((-2).toFixed(0));",
|
||||||
|
" console.log(2);",
|
||||||
|
" console.log(2..toFixed(0));",
|
||||||
|
" console.log(.2);",
|
||||||
|
" console.log(.2.toFixed(0));",
|
||||||
|
" console.log(234e18);",
|
||||||
|
" console.log(234e18.toFixed(0));",
|
||||||
|
" console.log(2e-8);",
|
||||||
|
" console.log(2e-8.toFixed(0));",
|
||||||
|
" console.log(0xde0b6b3a7640080);",
|
||||||
|
" console.log((0xde0b6b3a7640080).toFixed(0));",
|
||||||
|
" console.log(-0xde0b6b3a7640080);",
|
||||||
|
" console.log((-0xde0b6b3a7640080).toFixed(0));",
|
||||||
|
"})();",
|
||||||
|
]
|
||||||
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
comparisons: {
|
comparisons: {
|
||||||
|
|||||||
@@ -221,3 +221,142 @@ numeric_literal: {
|
|||||||
"8 7 8",
|
"8 7 8",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evaluate_computed_key: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
["foo" + "bar"]: "PASS",
|
||||||
|
}.foobar);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
foobar: "PASS",
|
||||||
|
}.foobar);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_computed_key: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
({
|
||||||
|
[console.log("PASS")]: 42,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4269_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
get 0() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
[0]: "PASS",
|
||||||
|
}[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
get 0() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
[0]: "PASS",
|
||||||
|
}[0]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4269_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
get [0]() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
0: "PASS",
|
||||||
|
}[0]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
get [0]() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
0: "PASS",
|
||||||
|
}[0]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4269_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
["foo"]: "bar",
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
42: "PASS",
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
["foo"]: "bar",
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
42: "PASS",
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4269_4: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
objects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log({
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
["foo"]: "bar",
|
||||||
|
42: "PASS",
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
get 42() {
|
||||||
|
return "FAIL";
|
||||||
|
},
|
||||||
|
["foo"]: "bar",
|
||||||
|
42: "PASS",
|
||||||
|
}[42]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1999,7 +1999,7 @@ issue_1606: {
|
|||||||
var a, b;
|
var a, b;
|
||||||
function g(){};
|
function g(){};
|
||||||
b = 2;
|
b = 2;
|
||||||
x(b);
|
x(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,3 +234,178 @@ issue_4191_let: {
|
|||||||
expect_stdout: "function undefined"
|
expect_stdout: "function undefined"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forin_const_1: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const o = {
|
||||||
|
foo: 42,
|
||||||
|
bar: "PASS",
|
||||||
|
};
|
||||||
|
for (const k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
foo: 42,
|
||||||
|
bar: "PASS",
|
||||||
|
};
|
||||||
|
for (const k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
forin_const_2: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const o = {
|
||||||
|
p: 42,
|
||||||
|
q: "PASS",
|
||||||
|
};
|
||||||
|
for (const [ k ] in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
p: 42,
|
||||||
|
q: "PASS",
|
||||||
|
}, k;
|
||||||
|
for ([ k ] in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"p 42",
|
||||||
|
"q PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
forin_let_1: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let o = {
|
||||||
|
foo: 42,
|
||||||
|
bar: "PASS",
|
||||||
|
};
|
||||||
|
for (let k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
var o = {
|
||||||
|
foo: 42,
|
||||||
|
bar: "PASS",
|
||||||
|
}, k;
|
||||||
|
for (k in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo 42",
|
||||||
|
"bar PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
forin_let_2: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
let o = {
|
||||||
|
p: 42,
|
||||||
|
q: "PASS",
|
||||||
|
};
|
||||||
|
for (let [ k ] in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
p: 42,
|
||||||
|
q: "PASS",
|
||||||
|
}, k;
|
||||||
|
for ([ k ] in o)
|
||||||
|
console.log(k, o[k]);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"p 42",
|
||||||
|
"q PASS",
|
||||||
|
]
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4290_1_const: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4290_1_let: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
let a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
let a = 0;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_forin_let: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
varify: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
for (let a in console.log("PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ describe("tokens", function() {
|
|||||||
it("Should give correct positions for accessors", function() {
|
it("Should give correct positions for accessors", function() {
|
||||||
// location 0 1 2 3 4
|
// location 0 1 2 3 4
|
||||||
// 01234567890123456789012345678901234567890123456789
|
// 01234567890123456789012345678901234567890123456789
|
||||||
var ast = UglifyJS.parse("var obj = { get latest() { return undefined; } }");
|
var ast = UglifyJS.parse("var obj = { get [prop]() { return undefined; } }");
|
||||||
// test all AST_ObjectProperty tokens are set as expected
|
// test all AST_ObjectProperty tokens are set as expected
|
||||||
var found = false;
|
var found = false;
|
||||||
ast.walk(new UglifyJS.TreeWalker(function(node) {
|
ast.walk(new UglifyJS.TreeWalker(function(node) {
|
||||||
@@ -13,9 +13,9 @@ describe("tokens", function() {
|
|||||||
found = true;
|
found = true;
|
||||||
assert.equal(node.start.pos, 12);
|
assert.equal(node.start.pos, 12);
|
||||||
assert.equal(node.end.endpos, 46);
|
assert.equal(node.end.endpos, 46);
|
||||||
assert(node.key instanceof UglifyJS.AST_SymbolAccessor);
|
assert(node.key instanceof UglifyJS.AST_SymbolRef);
|
||||||
assert.equal(node.key.start.pos, 16);
|
assert.equal(node.key.start.pos, 17);
|
||||||
assert.equal(node.key.end.endpos, 22);
|
assert.equal(node.key.end.endpos, 21);
|
||||||
assert(node.value instanceof UglifyJS.AST_Accessor);
|
assert(node.value instanceof UglifyJS.AST_Accessor);
|
||||||
assert.equal(node.value.start.pos, 22);
|
assert.equal(node.value.start.pos, 22);
|
||||||
assert.equal(node.value.end.endpos, 46);
|
assert.equal(node.value.end.endpos, 46);
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
|
|
||||||
// quick ignores
|
// quick ignores
|
||||||
if (node instanceof U.AST_Accessor) return;
|
if (node instanceof U.AST_Accessor) return;
|
||||||
|
if (node instanceof U.AST_Destructured) return;
|
||||||
if (node instanceof U.AST_Directive) return;
|
if (node instanceof U.AST_Directive) return;
|
||||||
if (!in_list && node instanceof U.AST_EmptyStatement) return;
|
if (!in_list && node instanceof U.AST_EmptyStatement) return;
|
||||||
if (node instanceof U.AST_Label) return;
|
if (node instanceof U.AST_Label) return;
|
||||||
@@ -114,6 +115,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
|
|
||||||
// ignore lvalues
|
// ignore lvalues
|
||||||
if (parent instanceof U.AST_Assign && parent.left === node) return;
|
if (parent instanceof U.AST_Assign && parent.left === node) return;
|
||||||
|
if (parent instanceof U.AST_DestructuredArray) return;
|
||||||
|
if (parent instanceof U.AST_DestructuredKeyVal && parent.value === node) return;
|
||||||
if (parent instanceof U.AST_Unary && parent.expression === node) switch (parent.operator) {
|
if (parent instanceof U.AST_Unary && parent.expression === node) switch (parent.operator) {
|
||||||
case "++":
|
case "++":
|
||||||
case "--":
|
case "--":
|
||||||
@@ -250,13 +253,23 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (node instanceof U.AST_ForIn) {
|
else if (node instanceof U.AST_ForIn) {
|
||||||
var expr = [
|
var expr;
|
||||||
node.init,
|
switch ((node.start._permute * steps | 0) % 3) {
|
||||||
node.object,
|
case 0:
|
||||||
node.body,
|
if (!(node.init instanceof U.AST_Definitions
|
||||||
][ (node.start._permute * steps | 0) % 3 ];
|
&& node.init.definitions[0].name instanceof U.AST_Destructured)) {
|
||||||
|
expr = node.init;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
expr = node.object;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!has_loopcontrol(node.body, node, parent)) expr = node.body;
|
||||||
|
break;
|
||||||
|
}
|
||||||
node.start._permute += step;
|
node.start._permute += step;
|
||||||
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
|
if (expr) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return to_statement(expr);
|
return to_statement(expr);
|
||||||
}
|
}
|
||||||
@@ -389,6 +402,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return List.skip;
|
return List.skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip element/property from (destructured) array/object
|
||||||
|
if (parent instanceof U.AST_Array || parent instanceof U.AST_Destructured || parent instanceof AST_Object) {
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return List.skip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace this node
|
// replace this node
|
||||||
@@ -593,7 +613,7 @@ function is_error(result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function is_timed_out(result) {
|
function is_timed_out(result) {
|
||||||
return is_error(result) && /timed out/.test(result);
|
return is_error(result) && /timed out/.test(result.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_statement(node) {
|
function is_statement(node) {
|
||||||
|
|||||||
@@ -276,6 +276,7 @@ var NO_DEFUN = false;
|
|||||||
var DEFUN_OK = true;
|
var DEFUN_OK = true;
|
||||||
var DONT_STORE = true;
|
var DONT_STORE = true;
|
||||||
var NO_CONST = true;
|
var NO_CONST = true;
|
||||||
|
var NO_DUPLICATE = true;
|
||||||
|
|
||||||
var VAR_NAMES = [
|
var VAR_NAMES = [
|
||||||
"a",
|
"a",
|
||||||
@@ -356,11 +357,15 @@ function createFunctions(n, recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createParams() {
|
function createParams(noDuplicate) {
|
||||||
|
var len = unique_vars.length;
|
||||||
var params = [];
|
var params = [];
|
||||||
for (var n = rng(4); --n >= 0;) {
|
for (var n = rng(4); --n >= 0;) {
|
||||||
params.push(createVarName(MANDATORY));
|
var name = createVarName(MANDATORY);
|
||||||
|
if (noDuplicate) unique_vars.push(name);
|
||||||
|
params.push(name);
|
||||||
}
|
}
|
||||||
|
unique_vars.length = len;
|
||||||
return params.join(", ");
|
return params.join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,6 +377,118 @@ function createArgs(recurmax, stmtDepth, canThrow) {
|
|||||||
return args.join(", ");
|
return args.join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createAssignmentPairs(recurmax, noComma, stmtDepth, canThrow, varNames, maybe, dontStore) {
|
||||||
|
var avoid = [];
|
||||||
|
var len = unique_vars.length;
|
||||||
|
var pairs = createPairs(recurmax);
|
||||||
|
unique_vars.length = len;
|
||||||
|
return pairs;
|
||||||
|
|
||||||
|
function createAssignmentValue(recurmax) {
|
||||||
|
var current = VAR_NAMES;
|
||||||
|
VAR_NAMES = (varNames || VAR_NAMES).slice();
|
||||||
|
var value = varNames && rng(2) ? createValue() : createExpression(recurmax, noComma, stmtDepth, canThrow);
|
||||||
|
VAR_NAMES = current;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createKey(recurmax, keys) {
|
||||||
|
var save = VAR_NAMES;
|
||||||
|
VAR_NAMES = VAR_NAMES.filter(function(name) {
|
||||||
|
return avoid.indexOf(name) < 0;
|
||||||
|
});
|
||||||
|
var len = VAR_NAMES.length;
|
||||||
|
var key;
|
||||||
|
do {
|
||||||
|
key = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
} while (keys.indexOf(key) >= 0);
|
||||||
|
VAR_NAMES = save.concat(VAR_NAMES.slice(len));
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPairs(recurmax) {
|
||||||
|
var names = [], values = [];
|
||||||
|
var m = rng(4), n = rng(4);
|
||||||
|
if (!varNames) m = Math.max(m, n, 1);
|
||||||
|
for (var i = Math.max(m, n); --i >= 0;) {
|
||||||
|
if (i < m && i < n) {
|
||||||
|
createDestructured(recurmax, names, values);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (i < m) {
|
||||||
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
|
var name = createVarName(maybe, dontStore);
|
||||||
|
unique_vars.length -= 6;
|
||||||
|
avoid.push(name);
|
||||||
|
unique_vars.push(name);
|
||||||
|
names.unshift(name);
|
||||||
|
}
|
||||||
|
if (i < n) {
|
||||||
|
values.unshift(createAssignmentValue(recurmax));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
names: names,
|
||||||
|
values: values,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDestructured(recurmax, names, values) {
|
||||||
|
switch (rng(20)) {
|
||||||
|
case 0:
|
||||||
|
if (--recurmax < 0) {
|
||||||
|
names.unshift("[]");
|
||||||
|
values.unshift('""');
|
||||||
|
} else {
|
||||||
|
var pairs = createPairs(recurmax);
|
||||||
|
while (!rng(10)) {
|
||||||
|
var index = rng(pairs.names.length + 1);
|
||||||
|
pairs.names.splice(index, 0, "");
|
||||||
|
pairs.values.splice(index, 0, rng(2) ? createAssignmentValue(recurmax) : "");
|
||||||
|
}
|
||||||
|
names.unshift("[ " + pairs.names.join(", ") + " ]");
|
||||||
|
values.unshift("[ " + pairs.values.join(", ") + " ]");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (--recurmax < 0) {
|
||||||
|
names.unshift("{}");
|
||||||
|
values.unshift('""');
|
||||||
|
} else {
|
||||||
|
var pairs = createPairs(recurmax);
|
||||||
|
var keys = [];
|
||||||
|
pairs.names.forEach(function(name, index) {
|
||||||
|
if (/^[[{]/.test(name)) {
|
||||||
|
var key;
|
||||||
|
do {
|
||||||
|
key = KEYS[rng(KEYS.length)];
|
||||||
|
} while (keys.indexOf(key) >= 0);
|
||||||
|
keys[index] = key;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
names.unshift("{ " + pairs.names.map(function(name, index) {
|
||||||
|
var key = index in keys ? keys[index] : rng(10) && createKey(recurmax, keys);
|
||||||
|
return key ? key + ": " + name : name;
|
||||||
|
}).join(", ") + " }");
|
||||||
|
values.unshift("{ " + pairs.values.map(function(value, index) {
|
||||||
|
var key = index in keys ? keys[index] : createKey(recurmax, keys);
|
||||||
|
return key + ": " + value;
|
||||||
|
}).join(", ") + " }");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
|
var name = createVarName(maybe, dontStore);
|
||||||
|
unique_vars.length -= 6;
|
||||||
|
avoid.push(name);
|
||||||
|
unique_vars.push(name);
|
||||||
|
names.unshift(name);
|
||||||
|
values.unshift(createAssignmentValue(recurmax));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function filterDirective(s) {
|
function filterDirective(s) {
|
||||||
if (!generate_directive && !s[1] && /\("/.test(s[2])) s[2] = ";" + s[2];
|
if (!generate_directive && !s[1] && /\("/.test(s[2])) s[2] = ";" + s[2];
|
||||||
return s;
|
return s;
|
||||||
@@ -410,11 +527,37 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
|||||||
return names.indexOf(name) < 0;
|
return names.indexOf(name) < 0;
|
||||||
});
|
});
|
||||||
var len = VAR_NAMES.length;
|
var len = VAR_NAMES.length;
|
||||||
var s = type + " " + names.map(function(name) {
|
var s = type + " ";
|
||||||
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
switch (rng(10)) {
|
||||||
VAR_NAMES.push(name);
|
case 0:
|
||||||
return name + " = " + value;
|
while (!rng(10)) names.splice(rng(names.length + 1), 0, "");
|
||||||
}).join(", ") + ";";
|
s += "[ " + names.join(", ") + " ] = [ " + names.map(function() {
|
||||||
|
return rng(10) ? createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) : "";
|
||||||
|
}).join(", ") + " ];";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
var keys = [];
|
||||||
|
s += "{ " + names.map(function(name, i) {
|
||||||
|
var key = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
if (!/\[/.test(key)) keys[i] = key;
|
||||||
|
return key + ": " + name;
|
||||||
|
}).join(", ") + "} = { " + names.map(function(name, i) {
|
||||||
|
var key = i in keys ? keys[i] : createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
return key + ": " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||||
|
}).join(", ") + "};";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s += names.map(function(name, i) {
|
||||||
|
if (type == "let" && !rng(10)) {
|
||||||
|
VAR_NAMES.push(name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||||
|
VAR_NAMES.push(name);
|
||||||
|
return name + " = " + value;
|
||||||
|
}).join(", ") + ";";
|
||||||
|
break;
|
||||||
|
}
|
||||||
VAR_NAMES = save.concat(VAR_NAMES.slice(len));
|
VAR_NAMES = save.concat(VAR_NAMES.slice(len));
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -424,9 +567,9 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
if (--recurmax < 0) { return ";"; }
|
if (--recurmax < 0) { return ";"; }
|
||||||
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
||||||
var s = [];
|
var s = [];
|
||||||
var name;
|
var name, args;
|
||||||
|
var varNames = VAR_NAMES.slice();
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
var namesLenBefore = VAR_NAMES.length;
|
|
||||||
if (allowDefun || rng(5) > 0) {
|
if (allowDefun || rng(5) > 0) {
|
||||||
name = "f" + funcs++;
|
name = "f" + funcs++;
|
||||||
} else {
|
} else {
|
||||||
@@ -434,7 +577,16 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
name = createVarName(MANDATORY, !allowDefun);
|
name = createVarName(MANDATORY, !allowDefun);
|
||||||
unique_vars.length -= 3;
|
unique_vars.length -= 3;
|
||||||
}
|
}
|
||||||
s.push("function " + name + "(" + createParams() + "){", strictMode());
|
var params;
|
||||||
|
if ((!allowDefun || !(name in called)) && rng(2)) {
|
||||||
|
called[name] = false;
|
||||||
|
var pairs = createAssignmentPairs(recurmax, COMMA_OK, stmtDepth, canThrow, varNames, MANDATORY);
|
||||||
|
params = pairs.names.join(", ");
|
||||||
|
args = pairs.values.join(", ");
|
||||||
|
} else {
|
||||||
|
params = createParams();
|
||||||
|
}
|
||||||
|
s.push("function " + name + "(" + params + "){", strictMode());
|
||||||
s.push(defns());
|
s.push(defns());
|
||||||
if (rng(5) === 0) {
|
if (rng(5) === 0) {
|
||||||
// functions with functions. lower the recursion to prevent a mess.
|
// functions with functions. lower the recursion to prevent a mess.
|
||||||
@@ -445,17 +597,16 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
}
|
}
|
||||||
s.push("}", "");
|
s.push("}", "");
|
||||||
s = filterDirective(s).join("\n");
|
s = filterDirective(s).join("\n");
|
||||||
|
|
||||||
VAR_NAMES.length = namesLenBefore;
|
|
||||||
});
|
});
|
||||||
|
VAR_NAMES = varNames;
|
||||||
|
|
||||||
if (!allowDefun) {
|
if (!allowDefun) {
|
||||||
// avoid "function statements" (decl inside statements)
|
// avoid "function statements" (decl inside statements)
|
||||||
s = "var " + createVarName(MANDATORY) + " = " + s;
|
s = "var " + createVarName(MANDATORY) + " = " + s;
|
||||||
s += "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
s += "(" + (args || createArgs(recurmax, stmtDepth, canThrow)) + ")";
|
||||||
} else if (!(name in called) || rng(3) > 0) {
|
} else if (!(name in called) || args || rng(3)) {
|
||||||
s += "var " + createVarName(MANDATORY) + " = " + name;
|
s += "var " + createVarName(MANDATORY) + " = " + name;
|
||||||
s += "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
s += "(" + (args || createArgs(recurmax, stmtDepth, canThrow)) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
return s + ";";
|
return s + ";";
|
||||||
@@ -556,8 +707,9 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
return [
|
return [
|
||||||
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||||
label.target + " for (",
|
label.target + " for (",
|
||||||
/^key/.test(key) ? "var " : "",
|
!/^key/.test(key) ? rng(10) ? "" : "var " : rng(10) ? "var " : rng(2) ? "let " : "const ",
|
||||||
key + " in expr" + loop + ") {",
|
rng(10) ? key : rng(5) ? "[ " + key + " ]" : "{ length: " + key + " }",
|
||||||
|
" in expr" + loop + ") {",
|
||||||
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
||||||
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||||
"}}",
|
"}}",
|
||||||
@@ -571,7 +723,12 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
// note: default does not _need_ to be last
|
// note: default does not _need_ to be last
|
||||||
return "switch (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") { " + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
return "switch (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") { " + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
||||||
case STMT_VAR:
|
case STMT_VAR:
|
||||||
switch (rng(3)) {
|
if (!rng(20)) {
|
||||||
|
var pairs = createAssignmentPairs(recurmax, NO_COMMA, stmtDepth, canThrow, null, MANDATORY);
|
||||||
|
return "var " + pairs.names.map(function(name, index) {
|
||||||
|
return index in pairs.values ? name + " = " + pairs.values[index] : name;
|
||||||
|
}).join(", ") + ";";
|
||||||
|
} else switch (rng(3)) {
|
||||||
case 0:
|
case 0:
|
||||||
unique_vars.push("c");
|
unique_vars.push("c");
|
||||||
var name = createVarName(MANDATORY);
|
var name = createVarName(MANDATORY);
|
||||||
@@ -714,7 +871,28 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
return getVarName();
|
return getVarName();
|
||||||
case p++:
|
case p++:
|
||||||
return getVarName(NO_CONST) + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
switch (rng(20)) {
|
||||||
|
case 0:
|
||||||
|
return [
|
||||||
|
"[ ",
|
||||||
|
new Array(rng(3)).join(","),
|
||||||
|
getVarName(NO_CONST),
|
||||||
|
new Array(rng(3)).join(","),
|
||||||
|
" ] = ",
|
||||||
|
createArrayLiteral(recurmax, stmtDepth, canThrow),
|
||||||
|
].join("");
|
||||||
|
case 1:
|
||||||
|
return [
|
||||||
|
"{ ",
|
||||||
|
rng(2) ? "" : createObjectKey(recurmax, stmtDepth, canThrow) + ": ",
|
||||||
|
getVarName(NO_CONST),
|
||||||
|
" } = ",
|
||||||
|
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow),
|
||||||
|
" || {}",
|
||||||
|
].join("");
|
||||||
|
default:
|
||||||
|
return getVarName(NO_CONST) + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
|
}
|
||||||
case p++:
|
case p++:
|
||||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
@@ -859,7 +1037,10 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
var name = rng(3) == 0 ? getVarName() : "f" + rng(funcs + 2);
|
var name;
|
||||||
|
do {
|
||||||
|
name = rng(3) == 0 ? getVarName() : "f" + rng(funcs + 2);
|
||||||
|
} while (name in called && !called[name]);
|
||||||
called[name] = true;
|
called[name] = true;
|
||||||
return "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
return "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||||
}
|
}
|
||||||
@@ -908,21 +1089,27 @@ function getDotKey(assign) {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAccessor(recurmax, stmtDepth, canThrow) {
|
function createObjectKey(recurmax, stmtDepth, canThrow) {
|
||||||
|
return rng(10) ? KEYS[rng(KEYS.length)] : "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
function createObjectFunction(recurmax, stmtDepth, canThrow) {
|
||||||
var namesLenBefore = VAR_NAMES.length;
|
var namesLenBefore = VAR_NAMES.length;
|
||||||
var s;
|
var s;
|
||||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
var prop1 = getDotKey();
|
switch (rng(3)) {
|
||||||
if (rng(2) == 0) {
|
case 0:
|
||||||
s = [
|
s = [
|
||||||
"get " + prop1 + "(){",
|
"get " + createObjectKey(recurmax, stmtDepth, canThrow) + "(){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
defns(),
|
defns(),
|
||||||
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC),
|
createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC),
|
||||||
"},"
|
"},",
|
||||||
];
|
];
|
||||||
} else {
|
break;
|
||||||
|
case 1:
|
||||||
|
var prop1 = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
var prop2;
|
var prop2;
|
||||||
do {
|
do {
|
||||||
prop2 = getDotKey();
|
prop2 = getDotKey();
|
||||||
@@ -933,8 +1120,18 @@ function createAccessor(recurmax, stmtDepth, canThrow) {
|
|||||||
defns(),
|
defns(),
|
||||||
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
"this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
"this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
||||||
"},"
|
"},",
|
||||||
];
|
];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = [
|
||||||
|
createObjectKey(recurmax, stmtDepth, canThrow) + "(" + createParams(NO_DUPLICATE) + "){",
|
||||||
|
strictMode(),
|
||||||
|
defns(),
|
||||||
|
_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
|
"},",
|
||||||
|
]
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
VAR_NAMES.length = namesLenBefore;
|
VAR_NAMES.length = namesLenBefore;
|
||||||
@@ -944,13 +1141,16 @@ function createAccessor(recurmax, stmtDepth, canThrow) {
|
|||||||
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
|
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
|
||||||
recurmax--;
|
recurmax--;
|
||||||
var obj = ["({"];
|
var obj = ["({"];
|
||||||
for (var i = rng(6); --i >= 0;) {
|
for (var i = rng(6); --i >= 0;) switch (rng(30)) {
|
||||||
if (rng(20) == 0) {
|
case 0:
|
||||||
obj.push(createAccessor(recurmax, stmtDepth, canThrow));
|
obj.push(createObjectFunction(recurmax, stmtDepth, canThrow));
|
||||||
} else {
|
break;
|
||||||
var key = KEYS[rng(KEYS.length)];
|
case 1:
|
||||||
obj.push(key + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
|
obj.push(getVarName() + ",");
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
|
obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
obj.push("})");
|
obj.push("})");
|
||||||
return obj.join("\n");
|
return obj.join("\n");
|
||||||
@@ -978,13 +1178,77 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||||
case 3:
|
case 3:
|
||||||
assignee = getVarName();
|
assignee = getVarName();
|
||||||
expr = "(" + assignee + "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow)
|
switch (rng(20)) {
|
||||||
+ "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
case 0:
|
||||||
|
expr = [
|
||||||
|
"([ ",
|
||||||
|
assignee,
|
||||||
|
"[", createExpression(recurmax, COMMA_OK, stmtDepth, canThrow), "]",
|
||||||
|
" ] = [ ",
|
||||||
|
_createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
" ])",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
var key1 = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
var key2 = /^\[/.test(key1) ? createObjectKey(recurmax, stmtDepth, canThrow) : key1;
|
||||||
|
expr = [
|
||||||
|
"({ ",
|
||||||
|
key1, ": ", assignee,
|
||||||
|
"[", createExpression(recurmax, COMMA_OK, stmtDepth, canThrow), "]",
|
||||||
|
" } = { ",
|
||||||
|
key2, ": ", _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
" })",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
expr = [
|
||||||
|
"(",
|
||||||
|
assignee,
|
||||||
|
"[", createExpression(recurmax, COMMA_OK, stmtDepth, canThrow), "]",
|
||||||
|
createAssignment(),
|
||||||
|
_createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
")",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
return canThrow && rng(10) == 0 ? expr : "(" + assignee + " && " + expr + ")";
|
return canThrow && rng(10) == 0 ? expr : "(" + assignee + " && " + expr + ")";
|
||||||
case 4:
|
case 4:
|
||||||
assignee = getVarName();
|
assignee = getVarName();
|
||||||
expr = "(" + assignee + "." + getDotKey(true) + createAssignment()
|
switch (rng(20)) {
|
||||||
+ _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
case 0:
|
||||||
|
expr = [
|
||||||
|
"([ ",
|
||||||
|
assignee,
|
||||||
|
".", getDotKey(true),
|
||||||
|
" ] = [ ",
|
||||||
|
_createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
" ])",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
var key1 = createObjectKey(recurmax, stmtDepth, canThrow);
|
||||||
|
var key2 = /^\[/.test(key1) ? createObjectKey(recurmax, stmtDepth, canThrow) : key1;
|
||||||
|
expr = [
|
||||||
|
"({ ",
|
||||||
|
key1, ": ", assignee,
|
||||||
|
".", getDotKey(true),
|
||||||
|
" } = { ",
|
||||||
|
key2, ": ", _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
" })",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
expr = [
|
||||||
|
"(",
|
||||||
|
assignee,
|
||||||
|
".", getDotKey(true),
|
||||||
|
createAssignment(),
|
||||||
|
_createBinaryExpr(recurmax, noComma, stmtDepth, canThrow),
|
||||||
|
")",
|
||||||
|
].join("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
return canThrow && rng(10) == 0 ? expr : "(" + assignee + " && " + expr + ")";
|
return canThrow && rng(10) == 0 ? expr : "(" + assignee + " && " + expr + ")";
|
||||||
default:
|
default:
|
||||||
return _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow);
|
return _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow);
|
||||||
@@ -1327,7 +1591,14 @@ function patch_try_catch(orig, toplevel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var minify_options = require("./options.json").map(JSON.stringify);
|
var minify_options = require("./options.json");
|
||||||
|
if (typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") {
|
||||||
|
minify_options.forEach(function(o) {
|
||||||
|
if (!("output" in o)) o.output = {};
|
||||||
|
o.output.v8 = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
minify_options = minify_options.map(JSON.stringify);
|
||||||
var original_code, original_result, errored;
|
var original_code, original_result, errored;
|
||||||
var uglify_code, uglify_result, ok;
|
var uglify_code, uglify_result, ok;
|
||||||
for (var round = 1; round <= num_iterations; round++) {
|
for (var round = 1; round <= num_iterations; round++) {
|
||||||
@@ -1369,7 +1640,12 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ignore difference in error message caused by Temporal Dead Zone
|
// ignore difference in error message caused by Temporal Dead Zone
|
||||||
if (!ok && errored) ok = uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError";
|
if (!ok && errored && uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError") ok = true;
|
||||||
|
// ignore spurious time-outs
|
||||||
|
if (!ok && errored && /timed out/.test(original_result.message) && !/timed out/.test(uglify_result.message)) {
|
||||||
|
if (!orig_result[toplevel ? 3 : 2]) orig_result[toplevel ? 3 : 2] = sandbox.run_code(original_code, toplevel, 10000);
|
||||||
|
ok = sandbox.same_stdout(orig_result[toplevel ? 3 : 2], uglify_result);
|
||||||
|
}
|
||||||
// ignore difference in error message caused by `in`
|
// ignore difference in error message caused by `in`
|
||||||
// ignore difference in depth of termination caused by infinite recursion
|
// ignore difference in depth of termination caused by infinite recursion
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
|
|||||||
Reference in New Issue
Block a user