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.
|
||||
--verbose Print diagnostic 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
|
||||
“exports” and “global” variables available. You
|
||||
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
|
||||
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
|
||||
|
||||
```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_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)
|
||||
|
||||
- `webkit` (default `false`) -- enable workarounds for WebKit bugs.
|
||||
PhantomJS users should set this option to `true`.
|
||||
- `v8` (default `false`) -- enable workarounds for Chrome & Node.js bugs
|
||||
|
||||
- `width` (default `80`) -- only takes effect when beautification is on, this
|
||||
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 });
|
||||
```
|
||||
|
||||
#### Source maps and debugging
|
||||
### Source maps and debugging
|
||||
|
||||
Various `compress` transforms that simplify, rearrange, inline and remove code
|
||||
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:
|
||||
|
||||
- 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
|
||||
objects they have not been overridden.
|
||||
- `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";
|
||||
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.",
|
||||
" --verbose Print diagnostic messages.",
|
||||
" --warn Print warning messages.",
|
||||
" --webkit Support non-standard Safari/Webkit.",
|
||||
" --wrap <name> Embed everything as a function with “exports” corresponding to “name” globally.",
|
||||
" --reduce-test Reduce a standalone test case (assumes cloned repository).",
|
||||
].join("\n"));
|
||||
@@ -142,6 +143,7 @@ function process_option(name, no_value) {
|
||||
case "timings":
|
||||
case "toplevel":
|
||||
case "validate":
|
||||
case "webkit":
|
||||
options[name] = true;
|
||||
break;
|
||||
case "keep-fnames":
|
||||
@@ -276,7 +278,9 @@ function convert_ast(fn) {
|
||||
function run() {
|
||||
var content = options.sourceMap && options.sourceMap.content;
|
||||
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);
|
||||
}
|
||||
try {
|
||||
|
||||
171
lib/ast.js
171
lib/ast.js
@@ -137,17 +137,17 @@ var AST_Node = DEFNODE("Node", "start end", {
|
||||
}, null);
|
||||
|
||||
(AST_Node.log_function = function(fn, verbose) {
|
||||
var printed = Object.create(null);
|
||||
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 {
|
||||
if (!fn) {
|
||||
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) {
|
||||
if (printed[msg]) return;
|
||||
@@ -414,8 +414,12 @@ var AST_ForIn = DEFNODE("ForIn", "init object", {
|
||||
_validate: function() {
|
||||
if (this.init instanceof AST_Definitions) {
|
||||
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)) {
|
||||
throw new Error("init must be assignable");
|
||||
} else {
|
||||
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");
|
||||
},
|
||||
@@ -496,12 +500,24 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||
}
|
||||
}, 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",
|
||||
$propdoc: {
|
||||
name: "[AST_SymbolDeclaration?] the name of this function",
|
||||
argnames: "[AST_SymbolFunarg*] array of function arguments",
|
||||
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
|
||||
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",
|
||||
},
|
||||
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) {
|
||||
var node = this;
|
||||
@@ -515,7 +531,9 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments length_read", {
|
||||
},
|
||||
_validate: function() {
|
||||
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);
|
||||
@@ -748,8 +766,10 @@ var AST_Const = DEFNODE("Const", null, {
|
||||
_validate: function() {
|
||||
this.definitions.forEach(function(node) {
|
||||
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");
|
||||
must_be_expression(node, "value");
|
||||
validate_destructured(node.name, function(node) {
|
||||
if (!(node instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
|
||||
});
|
||||
if (node.value != null) must_be_expression(node, "value");
|
||||
});
|
||||
},
|
||||
}, AST_Definitions);
|
||||
@@ -759,7 +779,9 @@ var AST_Let = DEFNODE("Let", null, {
|
||||
_validate: function() {
|
||||
this.definitions.forEach(function(node) {
|
||||
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");
|
||||
});
|
||||
},
|
||||
@@ -770,7 +792,9 @@ var AST_Var = DEFNODE("Var", null, {
|
||||
_validate: function() {
|
||||
this.definitions.forEach(function(node) {
|
||||
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");
|
||||
});
|
||||
},
|
||||
@@ -969,6 +993,14 @@ var AST_Assign = DEFNODE("Assign", null, {
|
||||
$documentation: "An assignment expression — `a = b + 5`",
|
||||
_validate: function() {
|
||||
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);
|
||||
|
||||
@@ -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", {
|
||||
$documentation: "An object literal",
|
||||
$propdoc: {
|
||||
@@ -1015,24 +1118,28 @@ var AST_Object = DEFNODE("Object", "properties", {
|
||||
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
||||
$documentation: "Base class for literal object properties",
|
||||
$propdoc: {
|
||||
key: "[string|AST_SymbolAccessor] property name. For ObjectKeyVal this is a string. For getters and setters this is an AST_SymbolAccessor.",
|
||||
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
|
||||
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.",
|
||||
},
|
||||
walk: function(visitor) {
|
||||
var node = this;
|
||||
visitor.visit(node, function() {
|
||||
if (node.key instanceof AST_Node) node.key.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() {
|
||||
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");
|
||||
},
|
||||
}, AST_ObjectProperty);
|
||||
@@ -1040,7 +1147,6 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
||||
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||
$documentation: "An object setter property",
|
||||
_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");
|
||||
},
|
||||
}, AST_ObjectProperty);
|
||||
@@ -1048,7 +1154,6 @@ var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
|
||||
$documentation: "An object getter property",
|
||||
_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");
|
||||
},
|
||||
}, 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", {
|
||||
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
|
||||
}, 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]);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
@@ -87,6 +89,7 @@ function minify(files, options) {
|
||||
toplevel: false,
|
||||
validate: false,
|
||||
warnings: false,
|
||||
webkit: false,
|
||||
wrap: false,
|
||||
}, true);
|
||||
if (options.validate) AST_Node.enable_validation();
|
||||
@@ -99,6 +102,7 @@ function minify(files, options) {
|
||||
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
|
||||
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
||||
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
||||
set_shorthand("webkit", options, [ "mangle", "output" ]);
|
||||
var quoted_props;
|
||||
if (options.mangle) {
|
||||
options.mangle = defaults(options.mangle, {
|
||||
@@ -109,6 +113,7 @@ function minify(files, options) {
|
||||
properties: false,
|
||||
reserved: [],
|
||||
toplevel: false,
|
||||
webkit: false,
|
||||
}, true);
|
||||
if (options.mangle.properties) {
|
||||
if (typeof options.mangle.properties != "object") {
|
||||
@@ -258,6 +263,7 @@ function minify(files, options) {
|
||||
} catch (ex) {
|
||||
return { error: ex };
|
||||
} finally {
|
||||
AST_Node.log_function();
|
||||
AST_Node.disable_validation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,9 +115,6 @@
|
||||
value : from_moz(M.value)
|
||||
};
|
||||
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
||||
args.key = new AST_SymbolAccessor({
|
||||
name: args.key
|
||||
});
|
||||
args.value = new AST_Accessor(args.value);
|
||||
if (M.kind == "get") return new AST_ObjectGetter(args);
|
||||
if (M.kind == "set") return new AST_ObjectSetter(args);
|
||||
@@ -385,7 +382,7 @@
|
||||
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
||||
var key = {
|
||||
type: "Literal",
|
||||
value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
|
||||
value: M.key
|
||||
};
|
||||
var kind;
|
||||
if (M instanceof AST_ObjectKeyVal) {
|
||||
|
||||
138
lib/output.js
138
lib/output.js
@@ -56,6 +56,7 @@ function OutputStream(options) {
|
||||
beautify : false,
|
||||
braces : false,
|
||||
comments : false,
|
||||
galio : false,
|
||||
ie8 : false,
|
||||
indent_level : 4,
|
||||
indent_start : 0,
|
||||
@@ -69,6 +70,7 @@ function OutputStream(options) {
|
||||
semicolons : true,
|
||||
shebang : true,
|
||||
source_map : null,
|
||||
v8 : false,
|
||||
webkit : false,
|
||||
width : 80,
|
||||
wrap_iife : false,
|
||||
@@ -499,11 +501,11 @@ function OutputStream(options) {
|
||||
}
|
||||
}
|
||||
if (/comment[134]/.test(c.type)) {
|
||||
print("//" + c.value.replace(/[@#]__PURE__/g, ' ') + "\n");
|
||||
print("//" + c.value.replace(/[@#]__PURE__/g, " ") + "\n");
|
||||
indent();
|
||||
last_nlb = true;
|
||||
} else if (c.type == "comment2") {
|
||||
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
|
||||
print("/*" + c.value.replace(/[@#]__PURE__/g, " ") + "*/");
|
||||
last_nlb = false;
|
||||
}
|
||||
});
|
||||
@@ -557,10 +559,10 @@ function OutputStream(options) {
|
||||
space();
|
||||
}
|
||||
if (/comment[134]/.test(c.type)) {
|
||||
print("//" + c.value.replace(/[@#]__PURE__/g, ' '));
|
||||
print("//" + c.value.replace(/[@#]__PURE__/g, " "));
|
||||
need_newline_indented = true;
|
||||
} else if (c.type == "comment2") {
|
||||
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
|
||||
print("/*" + c.value.replace(/[@#]__PURE__/g, " ") + "*/");
|
||||
need_space = true;
|
||||
}
|
||||
});
|
||||
@@ -610,7 +612,7 @@ function OutputStream(options) {
|
||||
},
|
||||
parent : function(n) {
|
||||
return stack[stack.length - 2 - (n || 0)];
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -652,13 +654,7 @@ function OutputStream(options) {
|
||||
/* -----[ PARENTHESES ]----- */
|
||||
|
||||
function PARENS(nodetype, func) {
|
||||
if (Array.isArray(nodetype)) {
|
||||
nodetype.forEach(function(nodetype) {
|
||||
PARENS(nodetype, func);
|
||||
});
|
||||
} else {
|
||||
nodetype.DEFMETHOD("needs_parens", func);
|
||||
}
|
||||
nodetype.DEFMETHOD("needs_parens", func);
|
||||
}
|
||||
|
||||
PARENS(AST_Node, return_false);
|
||||
@@ -667,11 +663,11 @@ function OutputStream(options) {
|
||||
// the first token to appear in a statement.
|
||||
PARENS(AST_Function, function(output) {
|
||||
if (!output.has_parens() && first_in_statement(output)) return true;
|
||||
if (output.option('webkit')) {
|
||||
if (output.option("webkit")) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_PropAccess && p.expression === this) return true;
|
||||
}
|
||||
if (output.option('wrap_iife')) {
|
||||
if (output.option("wrap_iife")) {
|
||||
var p = output.parent();
|
||||
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
|
||||
// interpreted as a block of code.
|
||||
PARENS(AST_Object, function(output) {
|
||||
function needs_parens_obj(output) {
|
||||
return !output.has_parens() && first_in_statement(output);
|
||||
});
|
||||
}
|
||||
PARENS(AST_Object, needs_parens_obj);
|
||||
|
||||
PARENS(AST_Unary, function(output) {
|
||||
var p = output.parent();
|
||||
@@ -699,7 +696,9 @@ function OutputStream(options) {
|
||||
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||
// ==> 20 (side effect, set a := 10 and b := 20)
|
||||
|| p instanceof AST_Conditional
|
||||
// { [(1, 2)]: 3 }[2] ==> 3
|
||||
// { foo: (1, 2) }.foo ==> 2
|
||||
|| p instanceof AST_DestructuredKeyVal
|
||||
|| p instanceof AST_ObjectProperty
|
||||
// (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||
|| p instanceof AST_PropAccess && p.expression === this
|
||||
@@ -746,7 +745,7 @@ function OutputStream(options) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_New) return p.expression === this;
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
||||
if (output.option('webkit')) {
|
||||
if (output.option("webkit")) {
|
||||
var g = output.parent(1);
|
||||
return this.expression instanceof AST_Function
|
||||
&& p instanceof AST_PropAccess
|
||||
@@ -769,24 +768,36 @@ function OutputStream(options) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||
var value = this.value;
|
||||
// https://github.com/mishoo/UglifyJS/issues/115
|
||||
// https://github.com/mishoo/UglifyJS/pull/1009
|
||||
return value < 0 || /^0/.test(make_num(value));
|
||||
// https://github.com/mishoo/UglifyJS/issues/115
|
||||
return value < 0
|
||||
// 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();
|
||||
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
||||
if (p instanceof AST_Binary) return !(p instanceof AST_Assign);
|
||||
// (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
|
||||
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
|
||||
if (p instanceof AST_PropAccess) return p.expression === this;
|
||||
if (p instanceof AST_PropAccess) return p.expression === self;
|
||||
// !(a = false) → 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 ]----- */
|
||||
@@ -1273,6 +1284,38 @@ function OutputStream(options) {
|
||||
output.space();
|
||||
} : 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) {
|
||||
var props = this.properties;
|
||||
if (props.length > 0) output.with_block(function() {
|
||||
@@ -1289,34 +1332,43 @@ function OutputStream(options) {
|
||||
else print_braced_empty(this, output);
|
||||
});
|
||||
|
||||
function print_property_name(key, quote, output) {
|
||||
if (output.option("quote_keys")) {
|
||||
function print_property_key(self, output) {
|
||||
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);
|
||||
} else if ("" + +key == key && key >= 0) {
|
||||
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 {
|
||||
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;
|
||||
print_property_name(self.key, self.quote, output);
|
||||
print_property_key(self, output);
|
||||
output.colon();
|
||||
self.value.print(output);
|
||||
});
|
||||
}
|
||||
DEFPRINT(AST_ObjectKeyVal, print_key_value);
|
||||
function print_accessor(type) {
|
||||
return function(output) {
|
||||
var self = this;
|
||||
output.print(type);
|
||||
output.space();
|
||||
print_property_name(self.key.name, self.quote, output);
|
||||
print_property_key(self, output);
|
||||
self.value._codegen(output, true);
|
||||
};
|
||||
}
|
||||
@@ -1474,6 +1526,7 @@ function OutputStream(options) {
|
||||
AST_Constant,
|
||||
AST_Debugger,
|
||||
AST_Definitions,
|
||||
AST_Destructured,
|
||||
AST_Finally,
|
||||
AST_Jump,
|
||||
AST_Lambda,
|
||||
@@ -1488,14 +1541,7 @@ function OutputStream(options) {
|
||||
output.add_mapping(this.start);
|
||||
});
|
||||
|
||||
DEFMAP([
|
||||
AST_ObjectGetter,
|
||||
AST_ObjectSetter,
|
||||
], function(output) {
|
||||
output.add_mapping(this.start, this.key.name);
|
||||
});
|
||||
|
||||
DEFMAP([ AST_ObjectProperty ], function(output) {
|
||||
output.add_mapping(this.start, this.key);
|
||||
DEFMAP([ AST_DestructuredKeyVal, AST_ObjectProperty ], function(output) {
|
||||
if (typeof this.key == "string") 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();
|
||||
switch (S.token.type) {
|
||||
case "string":
|
||||
@@ -844,9 +844,6 @@ function parse($TEXT, options) {
|
||||
return for_();
|
||||
|
||||
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();
|
||||
return function_(AST_Defun);
|
||||
|
||||
@@ -976,14 +973,16 @@ function parse($TEXT, options) {
|
||||
if (!is("punc", ";")) {
|
||||
init = is("keyword", "const")
|
||||
? (next(), const_(true))
|
||||
: is("keyword", "let")
|
||||
? (next(), let_(true))
|
||||
: is("keyword", "var")
|
||||
? (next(), var_(true))
|
||||
: expression(true, true);
|
||||
if (is("operator", "in")) {
|
||||
if (init instanceof AST_Var) {
|
||||
if (init instanceof AST_Definitions) {
|
||||
if (init.definitions.length > 1)
|
||||
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||
} else if (!is_assignable(init)) {
|
||||
} 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);
|
||||
}
|
||||
next();
|
||||
@@ -1028,7 +1027,7 @@ function parse($TEXT, options) {
|
||||
var argnames = [];
|
||||
for (var first = true; !is("punc", ")");) {
|
||||
if (first) first = false; else expect(",");
|
||||
argnames.push(as_symbol(AST_SymbolFunarg));
|
||||
argnames.push(maybe_destructured(AST_SymbolFunarg));
|
||||
}
|
||||
next();
|
||||
var loop = S.in_loop;
|
||||
@@ -1038,7 +1037,7 @@ function parse($TEXT, options) {
|
||||
S.input.push_directives_stack();
|
||||
S.in_loop = 0;
|
||||
S.labels = [];
|
||||
var body = block_(true);
|
||||
var body = block_();
|
||||
if (S.input.has_directive("use strict")) {
|
||||
if (name) strict_verify_symbol(name);
|
||||
argnames.forEach(strict_verify_symbol);
|
||||
@@ -1067,12 +1066,12 @@ function parse($TEXT, options) {
|
||||
});
|
||||
}
|
||||
|
||||
function block_(strict_defun) {
|
||||
function block_() {
|
||||
expect("{");
|
||||
var a = [];
|
||||
while (!is("punc", "}")) {
|
||||
if (is("eof")) expect_token("punc", "}");
|
||||
a.push(statement(strict_defun));
|
||||
a.push(statement());
|
||||
}
|
||||
next();
|
||||
return a;
|
||||
@@ -1149,16 +1148,16 @@ function parse($TEXT, options) {
|
||||
});
|
||||
}
|
||||
|
||||
function vardefs(type, no_in, must_init) {
|
||||
function vardefs(type, no_in) {
|
||||
var a = [];
|
||||
for (;;) {
|
||||
var start = S.token;
|
||||
var name = as_symbol(type);
|
||||
var name = maybe_destructured(type);
|
||||
var value = null;
|
||||
if (is("operator", "=")) {
|
||||
next();
|
||||
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");
|
||||
}
|
||||
a.push(new AST_VarDef({
|
||||
@@ -1177,7 +1176,7 @@ function parse($TEXT, options) {
|
||||
var const_ = function(no_in) {
|
||||
return new AST_Const({
|
||||
start : prev(),
|
||||
definitions : vardefs(AST_SymbolConst, no_in, true),
|
||||
definitions : vardefs(AST_SymbolConst, no_in),
|
||||
end : prev()
|
||||
});
|
||||
};
|
||||
@@ -1222,7 +1221,7 @@ function parse($TEXT, options) {
|
||||
var tok = S.token, ret;
|
||||
switch (tok.type) {
|
||||
case "name":
|
||||
ret = _make_symbol(AST_SymbolRef);
|
||||
ret = _make_symbol(AST_SymbolRef, tok);
|
||||
break;
|
||||
case "num":
|
||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
||||
@@ -1309,7 +1308,8 @@ function parse($TEXT, options) {
|
||||
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 = [];
|
||||
while (!is("punc", closing)) {
|
||||
if (first) first = false; else expect(",");
|
||||
@@ -1317,7 +1317,7 @@ function parse($TEXT, options) {
|
||||
if (is("punc", ",") && allow_empty) {
|
||||
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||
} else {
|
||||
a.push(expression(false));
|
||||
a.push(parser());
|
||||
}
|
||||
}
|
||||
next();
|
||||
@@ -1340,51 +1340,62 @@ function parse($TEXT, options) {
|
||||
var first = true, a = [];
|
||||
while (!is("punc", "}")) {
|
||||
if (first) first = false; else expect(",");
|
||||
if (!options.strict && is("punc", "}"))
|
||||
// allow trailing comma
|
||||
break;
|
||||
// allow trailing comma
|
||||
if (!options.strict && is("punc", "}")) break;
|
||||
var start = S.token;
|
||||
var type = start.type;
|
||||
var name = as_property_name();
|
||||
if (type == "name" && !is("punc", ":")) {
|
||||
var key = new AST_SymbolAccessor({
|
||||
start: S.token,
|
||||
name: "" + as_property_name(),
|
||||
end: prev()
|
||||
});
|
||||
if (name == "get") {
|
||||
a.push(new AST_ObjectGetter({
|
||||
start : start,
|
||||
key : key,
|
||||
value : create_accessor(),
|
||||
end : prev()
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (name == "set") {
|
||||
a.push(new AST_ObjectSetter({
|
||||
start : start,
|
||||
key : key,
|
||||
value : create_accessor(),
|
||||
end : prev()
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
var key = as_property_key();
|
||||
if (is("punc", "(")) {
|
||||
var func_start = S.token;
|
||||
var func = function_(AST_Function);
|
||||
func.start = func_start;
|
||||
func.end = prev();
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start: start,
|
||||
key: key,
|
||||
value: func,
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
}
|
||||
if (!is("punc", ":") && start.type == "name") switch (key) {
|
||||
case "get":
|
||||
a.push(new AST_ObjectGetter({
|
||||
start: start,
|
||||
key: as_property_key(),
|
||||
value: create_accessor(),
|
||||
end: prev(),
|
||||
}));
|
||||
continue;
|
||||
case "set":
|
||||
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(":");
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
start : start,
|
||||
quote : start.quote,
|
||||
key : "" + name,
|
||||
value : expression(false),
|
||||
end : prev()
|
||||
start: start,
|
||||
key: key,
|
||||
value: expression(false),
|
||||
end: prev(),
|
||||
}));
|
||||
}
|
||||
next();
|
||||
return new AST_Object({ properties: a });
|
||||
});
|
||||
|
||||
function as_property_name() {
|
||||
function as_property_key() {
|
||||
var tmp = S.token;
|
||||
switch (tmp.type) {
|
||||
case "operator":
|
||||
@@ -1395,7 +1406,13 @@ function parse($TEXT, options) {
|
||||
case "keyword":
|
||||
case "atom":
|
||||
next();
|
||||
return tmp.value;
|
||||
return "" + tmp.value;
|
||||
case "punc":
|
||||
if (tmp.value != "[") unexpected();
|
||||
next();
|
||||
var key = expression(false);
|
||||
expect("]");
|
||||
return key;
|
||||
default:
|
||||
unexpected();
|
||||
}
|
||||
@@ -1408,12 +1425,12 @@ function parse($TEXT, options) {
|
||||
return name;
|
||||
}
|
||||
|
||||
function _make_symbol(type) {
|
||||
var name = S.token.value;
|
||||
return new (name == "this" ? AST_This : type)({
|
||||
name : String(name),
|
||||
start : S.token,
|
||||
end : S.token
|
||||
function _make_symbol(type, token) {
|
||||
var name = token.value;
|
||||
return new (name === "this" ? AST_This : type)({
|
||||
name: "" + name,
|
||||
start: token,
|
||||
end: token,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1427,7 +1444,7 @@ function parse($TEXT, options) {
|
||||
if (!noerror) croak("Name expected");
|
||||
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) {
|
||||
strict_verify_symbol(sym);
|
||||
}
|
||||
@@ -1435,6 +1452,54 @@ function parse($TEXT, options) {
|
||||
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) {
|
||||
var start = call.start;
|
||||
var comments = start.comments_before;
|
||||
@@ -1564,11 +1629,43 @@ function parse($TEXT, options) {
|
||||
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 start = S.token;
|
||||
var left = maybe_conditional(no_in), val = S.token.value;
|
||||
if (is("operator") && ASSIGNMENT[val]) {
|
||||
if (is_assignable(left)) {
|
||||
if (is_assignable(left) || val == "=" && (left = to_destructured(left)) instanceof AST_Destructured) {
|
||||
next();
|
||||
return new AST_Assign({
|
||||
start : start,
|
||||
@@ -1616,7 +1713,7 @@ function parse($TEXT, options) {
|
||||
var body = [];
|
||||
S.input.push_directives_stack();
|
||||
while (!is("eof"))
|
||||
body.push(statement(true));
|
||||
body.push(statement());
|
||||
S.input.pop_directives_stack();
|
||||
var end = prev();
|
||||
var toplevel = options.toplevel;
|
||||
|
||||
@@ -81,8 +81,8 @@ var builtins = function() {
|
||||
|
||||
function reserve_quoted_keys(ast, reserved) {
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_ObjectKeyVal) {
|
||||
if (node.quote) add(node.key);
|
||||
if (node instanceof AST_ObjectProperty) {
|
||||
if (node.start && node.start.quote) add(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
@@ -165,11 +165,8 @@ function mangle_properties(ast, options) {
|
||||
}
|
||||
} else if (node instanceof AST_Dot) {
|
||||
add(node.property);
|
||||
} else if (node instanceof AST_ObjectKeyVal) {
|
||||
add(node.key);
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
// setter or getter, since KeyVal is handled above
|
||||
add(node.key.name);
|
||||
if (typeof node.key == "string") add(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
@@ -198,11 +195,8 @@ function mangle_properties(ast, options) {
|
||||
}
|
||||
} else if (node instanceof AST_Dot) {
|
||||
node.property = mangle(node.property);
|
||||
} else if (node instanceof AST_ObjectKeyVal) {
|
||||
node.key = mangle(node.key);
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
// setter or getter
|
||||
node.key.name = mangle(node.key.name);
|
||||
if (typeof node.key == "string") node.key = mangle(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
if (!options.keep_quoted) mangleStrings(node.property);
|
||||
}
|
||||
|
||||
67
lib/scope.js
67
lib/scope.js
@@ -72,7 +72,7 @@ SymbolDef.prototype = {
|
||||
if (def) {
|
||||
this.mangled_name = def.mangled_name || def.name;
|
||||
} else {
|
||||
this.mangled_name = next_mangled_name(this.scope, options, this);
|
||||
this.mangled_name = next_mangled_name(this, options);
|
||||
}
|
||||
if (this.global && cache) {
|
||||
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
|
||||
self.globals = new Dictionary();
|
||||
var in_arg = [];
|
||||
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.label) node.label.thedef.references.push(node);
|
||||
return true;
|
||||
@@ -212,10 +222,24 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var name = node.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) {
|
||||
sym = self.def_global(node);
|
||||
} 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") {
|
||||
var parent = tw.parent();
|
||||
@@ -408,7 +432,8 @@ function names_in_use(scope, options) {
|
||||
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 holes = scope.cname_holes;
|
||||
var names = Object.create(null);
|
||||
@@ -461,6 +486,7 @@ function _default_mangler_options(options) {
|
||||
keep_fnames : false,
|
||||
reserved : [],
|
||||
toplevel : false,
|
||||
webkit : false,
|
||||
});
|
||||
if (!Array.isArray(options.reserved)) options.reserved = [];
|
||||
// Never mangle arguments
|
||||
@@ -495,9 +521,24 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
return true;
|
||||
}
|
||||
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) {
|
||||
if (!defer_redef(def)) to_mangle.push(def);
|
||||
if (!defer_redef(def)) node.to_mangle.push(def);
|
||||
});
|
||||
descend();
|
||||
if (options.cache && node instanceof AST_Toplevel) {
|
||||
@@ -508,7 +549,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
sym.scope = node;
|
||||
sym.reference(options);
|
||||
}
|
||||
to_mangle.forEach(mangle);
|
||||
node.to_mangle.forEach(mangle);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Label) {
|
||||
@@ -528,13 +569,19 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
def.mangle(options);
|
||||
}
|
||||
|
||||
function defer_redef(def, node) {
|
||||
function defer_redef(def) {
|
||||
var sym = def.orig[0];
|
||||
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);
|
||||
def.references.forEach(reference);
|
||||
var node = def.orig[0];
|
||||
if (node instanceof AST_SymbolCatch || node instanceof AST_SymbolConst) reference(node);
|
||||
if (sym instanceof AST_SymbolCatch || sym instanceof AST_SymbolConst) reference(sym);
|
||||
return true;
|
||||
|
||||
function reference(sym) {
|
||||
|
||||
@@ -160,10 +160,21 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
DEF(AST_Array, function(self, 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) {
|
||||
self.properties = do_list(self.properties, 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);
|
||||
});
|
||||
})(function(node, descend) {
|
||||
|
||||
@@ -143,8 +143,9 @@ function push_uniq(array, el) {
|
||||
}
|
||||
|
||||
function string_template(text, props) {
|
||||
return text.replace(/\{(.+?)\}/g, function(str, p) {
|
||||
return props && props[p];
|
||||
return text.replace(/\{([^}]+)\}/g, function(str, 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",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.11.4",
|
||||
"version": "3.12.0",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -63,7 +63,6 @@ function make_code(ast, options) {
|
||||
|
||||
function parse_test(file) {
|
||||
var script = fs.readFileSync(file, "utf8");
|
||||
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS/issues/348
|
||||
try {
|
||||
var ast = U.parse(script, {
|
||||
filename: file
|
||||
@@ -315,6 +314,7 @@ function test_case(test) {
|
||||
if (test.mangle.properties) U.mangle_properties(output, test.mangle.properties);
|
||||
}
|
||||
var output_code = make_code(output, output_options);
|
||||
U.AST_Node.log_function();
|
||||
if (expect != output_code) {
|
||||
log([
|
||||
"!!! failed",
|
||||
@@ -386,7 +386,7 @@ function test_case(test) {
|
||||
mangle: test.mangle
|
||||
});
|
||||
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;
|
||||
}
|
||||
if (!sandbox.same_stdout(test.expect_stdout, actual)) {
|
||||
|
||||
@@ -807,3 +807,47 @@ issue_4200: {
|
||||
}
|
||||
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"
|
||||
}
|
||||
|
||||
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 always false [test/compress/conditionals.js:3,12]",
|
||||
"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: Boolean || 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: 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: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 = {}
|
||||
input: {
|
||||
@@ -11,8 +53,8 @@ mangle_catch_1: {
|
||||
expect: {
|
||||
try {
|
||||
throw "eeeee";
|
||||
} catch (e) {
|
||||
const o = typeof d;
|
||||
} catch (o) {
|
||||
const e = typeof d;
|
||||
}
|
||||
console.log(typeof a, typeof b);
|
||||
}
|
||||
@@ -57,6 +99,23 @@ retain_block: {
|
||||
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: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
@@ -1084,3 +1143,207 @@ issue_4231: {
|
||||
}
|
||||
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_warnings: [
|
||||
"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"
|
||||
}
|
||||
@@ -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: Boolean || always true [test/compress/dead-code.js:1,16]",
|
||||
"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 && always false [test/compress/dead-code.js:6,28]",
|
||||
"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: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"
|
||||
}
|
||||
|
||||
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 = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
@@ -556,9 +556,10 @@ issue_2531_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
@@ -2081,7 +2082,7 @@ issue_3016_1: {
|
||||
var b = 1;
|
||||
do {
|
||||
3[b];
|
||||
} while(0);
|
||||
} while (0);
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
@@ -2112,7 +2113,7 @@ issue_3016_2: {
|
||||
do {
|
||||
a = 3,
|
||||
a[b];
|
||||
} while(0);
|
||||
} while (0);
|
||||
var a;
|
||||
console.log(b);
|
||||
}
|
||||
@@ -2145,7 +2146,7 @@ issue_3016_2_ie8: {
|
||||
do {
|
||||
a = 3,
|
||||
a[b];
|
||||
} while(0);
|
||||
} while (0);
|
||||
var a;
|
||||
console.log(b);
|
||||
}
|
||||
@@ -2175,7 +2176,7 @@ issue_3016_3: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||
} while(b--);
|
||||
} while (b--);
|
||||
var a;
|
||||
}
|
||||
expect_stdout: [
|
||||
@@ -2208,7 +2209,7 @@ issue_3016_3_ie8: {
|
||||
var b = 1;
|
||||
do {
|
||||
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
|
||||
} while(b--);
|
||||
} while (b--);
|
||||
var a;
|
||||
}
|
||||
expect_stdout: [
|
||||
@@ -5115,3 +5116,102 @@ issue_4233: {
|
||||
}
|
||||
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"
|
||||
}
|
||||
|
||||
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: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
|
||||
@@ -2877,3 +2877,30 @@ issue_4235: {
|
||||
}
|
||||
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:7,16]",
|
||||
"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: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,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 initialization 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 unused variable a [test/compress/issue-1034.js:4,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
||||
"INFO: pass 0: last_count: Infinity, count: 35",
|
||||
"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 initialization in unreachable code [test/compress/issue-1034.js:9,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 c [test/compress/issue-1034.js:9,16]",
|
||||
@@ -138,10 +135,7 @@ non_hoisted_function_after_return_2b: {
|
||||
}
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
|
||||
"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 initialization in unreachable code [test/compress/issue-1034.js:8,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_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,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 initialization 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 unused variable a [test/compress/issue-1034.js:5,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
||||
"INFO: pass 0: last_count: Infinity, count: 46",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:10,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 c [test/compress/issue-1034.js:10,16]",
|
||||
@@ -301,10 +292,7 @@ non_hoisted_function_after_return_2b_strict: {
|
||||
}
|
||||
expect_stdout: "5 6"
|
||||
expect_warnings: [
|
||||
"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 unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping initialization in unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -20,6 +20,26 @@ retain_block: {
|
||||
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: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
@@ -893,3 +913,318 @@ issue_4231: {
|
||||
expect_stdout: "function"
|
||||
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"
|
||||
}
|
||||
|
||||
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: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
(-2);
|
||||
(-2).toFixed(0);
|
||||
(function() {
|
||||
console.log((-2));
|
||||
console.log((-2).toFixed(0));
|
||||
|
||||
(2);
|
||||
(2).toFixed(0);
|
||||
console.log((2));
|
||||
console.log((2).toFixed(0));
|
||||
|
||||
(0.2);
|
||||
(0.2).toFixed(0);
|
||||
console.log((0.2));
|
||||
console.log((0.2).toFixed(0));
|
||||
|
||||
(2.34e20);
|
||||
(2.34e20).toFixed(0);
|
||||
console.log((2.34e20));
|
||||
console.log((2.34e20).toFixed(0));
|
||||
|
||||
(0.00000002);
|
||||
(0.00000002).toFixed(0);
|
||||
console.log((0.00000002));
|
||||
console.log((0.00000002).toFixed(0));
|
||||
|
||||
(1000000000000000128);
|
||||
(1000000000000000128).toFixed(0);
|
||||
console.log((1000000000000000128));
|
||||
console.log((1000000000000000128).toFixed(0));
|
||||
|
||||
(-1000000000000000128);
|
||||
(-1000000000000000128).toFixed(0);
|
||||
}
|
||||
console.log((-1000000000000000128));
|
||||
console.log((-1000000000000000128).toFixed(0));
|
||||
})();
|
||||
}
|
||||
expect_exact: [
|
||||
"function f() {",
|
||||
" -2;",
|
||||
" (-2).toFixed(0);",
|
||||
" 2;",
|
||||
" 2..toFixed(0);",
|
||||
" .2;",
|
||||
" .2.toFixed(0);",
|
||||
" 234e18;",
|
||||
" 234e18.toFixed(0);",
|
||||
" 2e-8;",
|
||||
" 2e-8.toFixed(0);",
|
||||
" 0xde0b6b3a7640080;",
|
||||
" (0xde0b6b3a7640080).toFixed(0);",
|
||||
" -0xde0b6b3a7640080;",
|
||||
" (-0xde0b6b3a7640080).toFixed(0);",
|
||||
"}",
|
||||
"(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
|
||||
}
|
||||
|
||||
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: {
|
||||
|
||||
@@ -221,3 +221,142 @@ numeric_literal: {
|
||||
"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;
|
||||
function g(){};
|
||||
b = 2;
|
||||
x(b);
|
||||
x(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,3 +234,178 @@ issue_4191_let: {
|
||||
expect_stdout: "function undefined"
|
||||
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() {
|
||||
// location 0 1 2 3 4
|
||||
// 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
|
||||
var found = false;
|
||||
ast.walk(new UglifyJS.TreeWalker(function(node) {
|
||||
@@ -13,9 +13,9 @@ describe("tokens", function() {
|
||||
found = true;
|
||||
assert.equal(node.start.pos, 12);
|
||||
assert.equal(node.end.endpos, 46);
|
||||
assert(node.key instanceof UglifyJS.AST_SymbolAccessor);
|
||||
assert.equal(node.key.start.pos, 16);
|
||||
assert.equal(node.key.end.endpos, 22);
|
||||
assert(node.key instanceof UglifyJS.AST_SymbolRef);
|
||||
assert.equal(node.key.start.pos, 17);
|
||||
assert.equal(node.key.end.endpos, 21);
|
||||
assert(node.value instanceof UglifyJS.AST_Accessor);
|
||||
assert.equal(node.value.start.pos, 22);
|
||||
assert.equal(node.value.end.endpos, 46);
|
||||
|
||||
@@ -95,6 +95,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
|
||||
// quick ignores
|
||||
if (node instanceof U.AST_Accessor) return;
|
||||
if (node instanceof U.AST_Destructured) return;
|
||||
if (node instanceof U.AST_Directive) return;
|
||||
if (!in_list && node instanceof U.AST_EmptyStatement) return;
|
||||
if (node instanceof U.AST_Label) return;
|
||||
@@ -114,6 +115,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
|
||||
// ignore lvalues
|
||||
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) {
|
||||
case "++":
|
||||
case "--":
|
||||
@@ -250,13 +253,23 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_ForIn) {
|
||||
var expr = [
|
||||
node.init,
|
||||
node.object,
|
||||
node.body,
|
||||
][ (node.start._permute * steps | 0) % 3 ];
|
||||
var expr;
|
||||
switch ((node.start._permute * steps | 0) % 3) {
|
||||
case 0:
|
||||
if (!(node.init instanceof U.AST_Definitions
|
||||
&& 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;
|
||||
if (expr && (expr !== node.body || !has_loopcontrol(expr, node, parent))) {
|
||||
if (expr) {
|
||||
CHANGED = true;
|
||||
return to_statement(expr);
|
||||
}
|
||||
@@ -389,6 +402,13 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
CHANGED = true;
|
||||
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
|
||||
@@ -593,7 +613,7 @@ function is_error(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) {
|
||||
|
||||
@@ -276,6 +276,7 @@ var NO_DEFUN = false;
|
||||
var DEFUN_OK = true;
|
||||
var DONT_STORE = true;
|
||||
var NO_CONST = true;
|
||||
var NO_DUPLICATE = true;
|
||||
|
||||
var VAR_NAMES = [
|
||||
"a",
|
||||
@@ -356,11 +357,15 @@ function createFunctions(n, recurmax, allowDefun, canThrow, stmtDepth) {
|
||||
return s;
|
||||
}
|
||||
|
||||
function createParams() {
|
||||
function createParams(noDuplicate) {
|
||||
var len = unique_vars.length;
|
||||
var params = [];
|
||||
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(", ");
|
||||
}
|
||||
|
||||
@@ -372,6 +377,118 @@ function createArgs(recurmax, stmtDepth, canThrow) {
|
||||
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) {
|
||||
if (!generate_directive && !s[1] && /\("/.test(s[2])) s[2] = ";" + s[2];
|
||||
return s;
|
||||
@@ -410,11 +527,37 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
||||
return names.indexOf(name) < 0;
|
||||
});
|
||||
var len = VAR_NAMES.length;
|
||||
var s = type + " " + names.map(function(name) {
|
||||
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||
VAR_NAMES.push(name);
|
||||
return name + " = " + value;
|
||||
}).join(", ") + ";";
|
||||
var s = type + " ";
|
||||
switch (rng(10)) {
|
||||
case 0:
|
||||
while (!rng(10)) names.splice(rng(names.length + 1), 0, "");
|
||||
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));
|
||||
return s;
|
||||
}
|
||||
@@ -424,9 +567,9 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||
if (--recurmax < 0) { return ";"; }
|
||||
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
||||
var s = [];
|
||||
var name;
|
||||
var name, args;
|
||||
var varNames = VAR_NAMES.slice();
|
||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||
var namesLenBefore = VAR_NAMES.length;
|
||||
if (allowDefun || rng(5) > 0) {
|
||||
name = "f" + funcs++;
|
||||
} else {
|
||||
@@ -434,7 +577,16 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||
name = createVarName(MANDATORY, !allowDefun);
|
||||
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());
|
||||
if (rng(5) === 0) {
|
||||
// functions with functions. lower the recursion to prevent a mess.
|
||||
@@ -445,17 +597,16 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||
}
|
||||
s.push("}", "");
|
||||
s = filterDirective(s).join("\n");
|
||||
|
||||
VAR_NAMES.length = namesLenBefore;
|
||||
});
|
||||
VAR_NAMES = varNames;
|
||||
|
||||
if (!allowDefun) {
|
||||
// avoid "function statements" (decl inside statements)
|
||||
s = "var " + createVarName(MANDATORY) + " = " + s;
|
||||
s += "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||
} else if (!(name in called) || rng(3) > 0) {
|
||||
s += "(" + (args || createArgs(recurmax, stmtDepth, canThrow)) + ")";
|
||||
} else if (!(name in called) || args || rng(3)) {
|
||||
s += "var " + createVarName(MANDATORY) + " = " + name;
|
||||
s += "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||
s += "(" + (args || createArgs(recurmax, stmtDepth, canThrow)) + ")";
|
||||
}
|
||||
|
||||
return s + ";";
|
||||
@@ -556,8 +707,9 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
||||
return [
|
||||
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||
label.target + " for (",
|
||||
/^key/.test(key) ? "var " : "",
|
||||
key + " in expr" + loop + ") {",
|
||||
!/^key/.test(key) ? rng(10) ? "" : "var " : rng(10) ? "var " : rng(2) ? "let " : "const ",
|
||||
rng(10) ? key : rng(5) ? "[ " + key + " ]" : "{ length: " + key + " }",
|
||||
" in expr" + loop + ") {",
|
||||
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
||||
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
|
||||
return "switch (" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") { " + createSwitchParts(recurmax, 4, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
||||
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:
|
||||
unique_vars.push("c");
|
||||
var name = createVarName(MANDATORY);
|
||||
@@ -714,7 +871,28 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
case p++:
|
||||
return getVarName();
|
||||
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++:
|
||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||
case p++:
|
||||
@@ -859,7 +1037,10 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
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;
|
||||
return "typeof " + name + ' == "function" && --_calls_ >= 0 && ' + name + "(" + createArgs(recurmax, stmtDepth, canThrow) + ")";
|
||||
}
|
||||
@@ -908,21 +1089,27 @@ function getDotKey(assign) {
|
||||
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 s;
|
||||
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||
var prop1 = getDotKey();
|
||||
if (rng(2) == 0) {
|
||||
switch (rng(3)) {
|
||||
case 0:
|
||||
s = [
|
||||
"get " + prop1 + "(){",
|
||||
"get " + createObjectKey(recurmax, stmtDepth, canThrow) + "(){",
|
||||
strictMode(),
|
||||
defns(),
|
||||
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||
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;
|
||||
do {
|
||||
prop2 = getDotKey();
|
||||
@@ -933,8 +1120,18 @@ function createAccessor(recurmax, stmtDepth, canThrow) {
|
||||
defns(),
|
||||
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||
"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;
|
||||
@@ -944,13 +1141,16 @@ function createAccessor(recurmax, stmtDepth, canThrow) {
|
||||
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
|
||||
recurmax--;
|
||||
var obj = ["({"];
|
||||
for (var i = rng(6); --i >= 0;) {
|
||||
if (rng(20) == 0) {
|
||||
obj.push(createAccessor(recurmax, stmtDepth, canThrow));
|
||||
} else {
|
||||
var key = KEYS[rng(KEYS.length)];
|
||||
obj.push(key + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
|
||||
}
|
||||
for (var i = rng(6); --i >= 0;) switch (rng(30)) {
|
||||
case 0:
|
||||
obj.push(createObjectFunction(recurmax, stmtDepth, canThrow));
|
||||
break;
|
||||
case 1:
|
||||
obj.push(getVarName() + ",");
|
||||
break;
|
||||
default:
|
||||
obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
|
||||
break;
|
||||
}
|
||||
obj.push("})");
|
||||
return obj.join("\n");
|
||||
@@ -978,13 +1178,77 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
||||
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||
case 3:
|
||||
assignee = getVarName();
|
||||
expr = "(" + assignee + "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow)
|
||||
+ "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||
switch (rng(20)) {
|
||||
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 + ")";
|
||||
case 4:
|
||||
assignee = getVarName();
|
||||
expr = "(" + assignee + "." + getDotKey(true) + createAssignment()
|
||||
+ _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||
switch (rng(20)) {
|
||||
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 + ")";
|
||||
default:
|
||||
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 uglify_code, uglify_result, ok;
|
||||
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
|
||||
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 depth of termination caused by infinite recursion
|
||||
if (!ok) {
|
||||
|
||||
Reference in New Issue
Block a user