Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7f6b73f4e | ||
|
|
9469c03ac9 | ||
|
|
d57527697f | ||
|
|
f7ca4f2297 | ||
|
|
c076e7b60d | ||
|
|
4a55bb0be5 | ||
|
|
28ecea50a6 | ||
|
|
9a311705f5 | ||
|
|
ee3fe0f4cd | ||
|
|
87f6e1b091 | ||
|
|
c934fc8142 | ||
|
|
257ddc3bdb | ||
|
|
1ddc05725d | ||
|
|
e6b76a4879 | ||
|
|
a0c3836ba0 | ||
|
|
f8a71b56fd | ||
|
|
11e9bdc427 | ||
|
|
a84564d1a8 | ||
|
|
c595b84032 | ||
|
|
7cb1adf455 | ||
|
|
7bea38a05d | ||
|
|
0f910ee25c | ||
|
|
beb9659778 | ||
|
|
f1a833a7aa | ||
|
|
2e41cd6394 | ||
|
|
09f77c7d4d | ||
|
|
fef0bf9ee0 | ||
|
|
ae740b933f | ||
|
|
ec7f37f314 | ||
|
|
eb48a035e7 | ||
|
|
6ab3224c0d | ||
|
|
c909ffb715 | ||
|
|
f71f4905b0 | ||
|
|
fb177a6312 | ||
|
|
65da9acce6 | ||
|
|
67d0237f73 | ||
|
|
984a21704e | ||
|
|
aa3f647656 | ||
|
|
c526da59a1 | ||
|
|
581630e0a7 | ||
|
|
f5952933a0 | ||
|
|
f001e4cb9d | ||
|
|
57ce5bd9e0 | ||
|
|
861a79ac9f | ||
|
|
00996afd2c | ||
|
|
e76fb354eb | ||
|
|
3276740779 | ||
|
|
5509e51098 | ||
|
|
94f84727ce | ||
|
|
8a4f86528f | ||
|
|
adb0e882e9 | ||
|
|
f83d370f57 | ||
|
|
b19aa58cff | ||
|
|
0a65de89b9 | ||
|
|
6e86ee950d | ||
|
|
8ca2401ebe | ||
|
|
491f16c766 | ||
|
|
a30092e20f | ||
|
|
b1abe92e1a | ||
|
|
b454ce667e | ||
|
|
32283a0def | ||
|
|
ac51d4c5a0 | ||
|
|
0432a7abb9 | ||
|
|
f3a1694a41 | ||
|
|
2e0dc97003 | ||
|
|
701035621d | ||
|
|
79334dda10 | ||
|
|
e918748d88 | ||
|
|
6b2f34769a | ||
|
|
48ffbef51d | ||
|
|
c0f3feae9f | ||
|
|
a00040dd93 | ||
|
|
ee95c1b38b | ||
|
|
4bceb85cbf | ||
|
|
30a75049f5 | ||
|
|
a3cc3a9b87 | ||
|
|
96f8befdd7 | ||
|
|
cd58635dcc | ||
|
|
274331d0ea | ||
|
|
0489d6de64 | ||
|
|
fb092839c2 | ||
|
|
b7c112eefe |
8
.github/ISSUE_TEMPLATE.md
vendored
8
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,7 +1,9 @@
|
||||
- Bug report or feature request?
|
||||
- Bug report or feature request? <!-- Note: sub-optimal but correct code is not a bug -->
|
||||
- `uglify-js` version (`uglifyjs -V`)
|
||||
- JavaScript input - ideally as small as possible.
|
||||
- The `uglifyjs` CLI command executed or `minify()` options used.
|
||||
- An example of JavaScript output produced and/or the error or warning.
|
||||
|
||||
Note: the release version of `uglify-js` only supports ES5. Those wishing to minify ES6 should use the experimental [`harmony`](https://github.com/mishoo/UglifyJS2#harmony) branch.
|
||||
<!--
|
||||
Note: the release version of uglify-js only supports ES5. Those wishing
|
||||
to minify ES6 should use the experimental harmony branch.
|
||||
-->
|
||||
|
||||
@@ -5,7 +5,6 @@ node_js:
|
||||
- "0.12"
|
||||
- "4"
|
||||
- "6"
|
||||
- "7"
|
||||
env:
|
||||
- UGLIFYJS_TEST_ALL=1
|
||||
matrix:
|
||||
|
||||
17
README.md
17
README.md
@@ -10,8 +10,10 @@ There's also an
|
||||
[in-browser online demo](http://lisperator.net/uglifyjs/#demo) (for Firefox,
|
||||
Chrome and probably Safari).
|
||||
|
||||
Note: release versions of `uglify-js` only support ECMAScript 5 (ES5). If you wish to minify
|
||||
#### Note:
|
||||
- release versions of `uglify-js` only support ECMAScript 5 (ES5). If you wish to minify
|
||||
ES2015+ (ES6+) code then please use the [harmony](#harmony) development branch.
|
||||
- Node 7 has a known performance regression and runs `uglify-js` twice as slow.
|
||||
|
||||
Install
|
||||
-------
|
||||
@@ -68,7 +70,8 @@ The available options are:
|
||||
--source-map-inline Write base64-encoded source map to the end of js output.
|
||||
--in-source-map Input source map, useful if you're compressing
|
||||
JS that was generated from some other original
|
||||
code.
|
||||
code. Specify "inline" if the source map is included
|
||||
inline with the sources.
|
||||
--screw-ie8 Use this flag if you don't wish to support
|
||||
Internet Explorer 6/7/8.
|
||||
By default UglifyJS will not try to be IE-proof.
|
||||
@@ -200,9 +203,10 @@ compressed JS by mapping every token in the compiled JS to its original
|
||||
location.
|
||||
|
||||
To use this feature you need to pass `--in-source-map
|
||||
/path/to/input/source.map`. Normally the input source map should also point
|
||||
to the file containing the generated JS, so if that's correct you can omit
|
||||
input files from the command line.
|
||||
/path/to/input/source.map` or `--in-source-map inline` if the source map is
|
||||
included inline with the sources. Normally the input source map should also
|
||||
point to the file containing the generated JS, so if that's correct you can
|
||||
omit input files from the command line.
|
||||
|
||||
## Mangler options
|
||||
|
||||
@@ -439,6 +443,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
||||
integer argument larger than 1 to further reduce code size in some cases.
|
||||
Note: raising the number of passes will increase uglify compress time.
|
||||
|
||||
- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
|
||||
being compressed into `1/0`, which may cause performance issues on Chrome.
|
||||
|
||||
### The `unsafe` option
|
||||
|
||||
It enables some transformations that *might* break code logic in certain
|
||||
|
||||
@@ -561,7 +561,7 @@ function getOptions(flag, constants) {
|
||||
|
||||
var ast;
|
||||
try {
|
||||
ast = UglifyJS.parse(x, { expression: true });
|
||||
ast = UglifyJS.parse(x, { cli: true, expression: true });
|
||||
} catch(ex) {
|
||||
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
||||
print_error("Error parsing arguments for flag `" + flag + "': " + x);
|
||||
|
||||
746
lib/compress.js
746
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -53,26 +53,26 @@ function is_some_comments(comment) {
|
||||
function OutputStream(options) {
|
||||
|
||||
options = defaults(options, {
|
||||
indent_start : 0,
|
||||
indent_level : 4,
|
||||
quote_keys : false,
|
||||
space_colon : true,
|
||||
ascii_only : false,
|
||||
unescape_regexps : false,
|
||||
inline_script : false,
|
||||
width : 80,
|
||||
max_line_len : false,
|
||||
beautify : false,
|
||||
source_map : null,
|
||||
bracketize : false,
|
||||
semicolons : true,
|
||||
comments : false,
|
||||
shebang : true,
|
||||
preserve_line : false,
|
||||
screw_ie8 : true,
|
||||
preamble : null,
|
||||
quote_style : 0,
|
||||
indent_level : 4,
|
||||
indent_start : 0,
|
||||
inline_script : false,
|
||||
keep_quoted_props: false,
|
||||
max_line_len : false,
|
||||
preamble : null,
|
||||
preserve_line : false,
|
||||
quote_keys : false,
|
||||
quote_style : 0,
|
||||
screw_ie8 : true,
|
||||
semicolons : true,
|
||||
shebang : true,
|
||||
source_map : null,
|
||||
space_colon : true,
|
||||
unescape_regexps : false,
|
||||
width : 80,
|
||||
wrap_iife : false,
|
||||
}, true);
|
||||
|
||||
@@ -510,8 +510,8 @@ function OutputStream(options) {
|
||||
}));
|
||||
}
|
||||
|
||||
if (comments.length > 0 && output.pos() == 0) {
|
||||
if (output.option("shebang") && comments[0].type == "comment5") {
|
||||
if (output.pos() == 0) {
|
||||
if (comments.length > 0 && output.option("shebang") && comments[0].type == "comment5") {
|
||||
output.print("#!" + comments.shift().value + "\n");
|
||||
output.indent();
|
||||
}
|
||||
@@ -586,7 +586,7 @@ function OutputStream(options) {
|
||||
return first_in_statement(output);
|
||||
});
|
||||
|
||||
PARENS([ AST_Unary, AST_Undefined ], function(output){
|
||||
PARENS(AST_Unary, function(output){
|
||||
var p = output.parent();
|
||||
return p instanceof AST_PropAccess && p.expression === this
|
||||
|| p instanceof AST_Call && p.expression === this;
|
||||
@@ -799,7 +799,7 @@ function OutputStream(options) {
|
||||
output.print("for");
|
||||
output.space();
|
||||
output.with_parens(function(){
|
||||
if (self.init && !(self.init instanceof AST_EmptyStatement)) {
|
||||
if (self.init) {
|
||||
if (self.init instanceof AST_Definitions) {
|
||||
self.init.print(output);
|
||||
} else {
|
||||
@@ -960,24 +960,24 @@ function OutputStream(options) {
|
||||
self.expression.print(output);
|
||||
});
|
||||
output.space();
|
||||
if (self.body.length > 0) output.with_block(function(){
|
||||
self.body.forEach(function(stmt, i){
|
||||
if (i) output.newline();
|
||||
var last = self.body.length - 1;
|
||||
if (last < 0) output.print("{}");
|
||||
else output.with_block(function(){
|
||||
self.body.forEach(function(branch, i){
|
||||
output.indent(true);
|
||||
stmt.print(output);
|
||||
branch.print(output);
|
||||
if (i < last && branch.body.length > 0)
|
||||
output.newline();
|
||||
});
|
||||
});
|
||||
else output.print("{}");
|
||||
});
|
||||
AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){
|
||||
if (this.body.length > 0) {
|
||||
output.newline();
|
||||
this.body.forEach(function(stmt){
|
||||
output.indent();
|
||||
stmt.print(output);
|
||||
output.newline();
|
||||
});
|
||||
}
|
||||
});
|
||||
DEFPRINT(AST_Default, function(self, output){
|
||||
output.print("default:");
|
||||
@@ -1249,16 +1249,7 @@ function OutputStream(options) {
|
||||
var def = self.definition();
|
||||
output.print_name(def ? def.mangled_name || def.name : self.name);
|
||||
});
|
||||
DEFPRINT(AST_Undefined, function(self, output){
|
||||
output.print("void 0");
|
||||
});
|
||||
DEFPRINT(AST_Hole, noop);
|
||||
DEFPRINT(AST_Infinity, function(self, output){
|
||||
output.print("Infinity");
|
||||
});
|
||||
DEFPRINT(AST_NaN, function(self, output){
|
||||
output.print("NaN");
|
||||
});
|
||||
DEFPRINT(AST_This, function(self, output){
|
||||
output.print("this");
|
||||
});
|
||||
|
||||
18
lib/parse.js
18
lib/parse.js
@@ -688,13 +688,14 @@ var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "nam
|
||||
function parse($TEXT, options) {
|
||||
|
||||
options = defaults(options, {
|
||||
strict : false,
|
||||
filename : null,
|
||||
toplevel : null,
|
||||
expression : false,
|
||||
html5_comments : true,
|
||||
bare_returns : false,
|
||||
cli : false,
|
||||
expression : false,
|
||||
filename : null,
|
||||
html5_comments : true,
|
||||
shebang : true,
|
||||
strict : false,
|
||||
toplevel : null,
|
||||
});
|
||||
|
||||
var S = {
|
||||
@@ -1456,7 +1457,7 @@ function parse($TEXT, options) {
|
||||
|
||||
function make_unary(ctor, op, expr) {
|
||||
if ((op == "++" || op == "--") && !is_assignable(expr))
|
||||
croak("Invalid use of " + op + " operator");
|
||||
croak("Invalid use of " + op + " operator", null, ctor === AST_UnaryPrefix ? expr.start.col - 1 : null);
|
||||
return new ctor({ operator: op, expression: expr });
|
||||
};
|
||||
|
||||
@@ -1501,9 +1502,8 @@ function parse($TEXT, options) {
|
||||
};
|
||||
|
||||
function is_assignable(expr) {
|
||||
if (!options.strict) return true;
|
||||
if (expr instanceof AST_This) return false;
|
||||
return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol);
|
||||
if (options.cli) return true;
|
||||
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
|
||||
};
|
||||
|
||||
var maybe_assign = function(no_in) {
|
||||
|
||||
@@ -62,12 +62,12 @@ function find_builtins() {
|
||||
|
||||
function mangle_properties(ast, options) {
|
||||
options = defaults(options, {
|
||||
reserved : null,
|
||||
cache: null,
|
||||
debug: false,
|
||||
ignore_quoted: false,
|
||||
only_cache: false,
|
||||
regex: null,
|
||||
ignore_quoted : false,
|
||||
debug : false
|
||||
reserved: null,
|
||||
});
|
||||
|
||||
var reserved = options.reserved;
|
||||
|
||||
61
lib/scope.js
61
lib/scope.js
@@ -75,8 +75,13 @@ SymbolDef.prototype = {
|
||||
}
|
||||
else if (!this.mangled_name && !this.unmangleable(options)) {
|
||||
var s = this.scope;
|
||||
if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda)
|
||||
var sym = this.orig[0];
|
||||
if (!options.screw_ie8 && sym instanceof AST_SymbolLambda)
|
||||
s = s.parent_scope;
|
||||
var def;
|
||||
if (this.defun && (def = this.defun.variables.get(this.name))) {
|
||||
this.mangled_name = def.mangled_name || def.name;
|
||||
} else
|
||||
this.mangled_name = s.next_mangled(options, this);
|
||||
if (this.global && cache) {
|
||||
cache.set(this.name, this.mangled_name);
|
||||
@@ -87,8 +92,8 @@ SymbolDef.prototype = {
|
||||
|
||||
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
options = defaults(options, {
|
||||
cache: null,
|
||||
screw_ie8: true,
|
||||
cache: null
|
||||
});
|
||||
|
||||
// pass 1: setup scope chaining and handle definitions
|
||||
@@ -100,15 +105,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
if (node instanceof AST_Catch) {
|
||||
var save_scope = scope;
|
||||
scope = new AST_Scope(node);
|
||||
scope.init_scope_vars();
|
||||
scope.parent_scope = save_scope;
|
||||
scope.init_scope_vars(save_scope);
|
||||
descend();
|
||||
scope = save_scope;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Scope) {
|
||||
node.init_scope_vars();
|
||||
var save_scope = node.parent_scope = scope;
|
||||
node.init_scope_vars(scope);
|
||||
var save_scope = scope;
|
||||
var save_defun = defun;
|
||||
var save_labels = labels;
|
||||
defun = scope = node;
|
||||
@@ -155,9 +159,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
else if (node instanceof AST_SymbolVar
|
||||
|| node instanceof AST_SymbolConst) {
|
||||
defun.def_variable(node);
|
||||
if (defun !== scope) {
|
||||
node.mark_enclosed(options);
|
||||
var def = scope.find_variable(node);
|
||||
if (node.thedef !== def) {
|
||||
node.thedef = def;
|
||||
node.reference(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node instanceof AST_SymbolCatch) {
|
||||
scope.def_variable(node);
|
||||
scope.def_variable(node).defun = defun;
|
||||
}
|
||||
else if (node instanceof AST_LabelRef) {
|
||||
var sym = labels.get(node.name);
|
||||
@@ -213,7 +225,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
var name = node.name;
|
||||
var refs = node.thedef.references;
|
||||
var scope = node.thedef.scope.parent_scope;
|
||||
var scope = node.thedef.defun;
|
||||
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
|
||||
refs.forEach(function(ref) {
|
||||
ref.thedef = def;
|
||||
@@ -243,12 +255,12 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
|
||||
}
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("init_scope_vars", function(){
|
||||
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
|
||||
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
||||
this.parent_scope = null; // the parent scope
|
||||
this.parent_scope = parent_scope; // the parent scope
|
||||
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||
this.cname = -1; // the current index for mangling functions/variables
|
||||
});
|
||||
@@ -256,15 +268,15 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(){
|
||||
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||
this.uses_arguments = false;
|
||||
|
||||
var symbol = new AST_VarDef({ name: "arguments", start: this.start, end: this.end });
|
||||
var def = new SymbolDef(this, this.variables.size(), symbol);
|
||||
this.variables.set(symbol.name, def);
|
||||
this.def_variable(new AST_SymbolVar({
|
||||
name: "arguments",
|
||||
start: this.start,
|
||||
end: this.end
|
||||
}));
|
||||
});
|
||||
|
||||
AST_SymbolRef.DEFMETHOD("reference", function(options) {
|
||||
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
||||
var def = this.definition();
|
||||
def.references.push(this);
|
||||
var s = this.scope;
|
||||
while (s) {
|
||||
push_uniq(s.enclosed, def);
|
||||
@@ -278,6 +290,11 @@ AST_SymbolRef.DEFMETHOD("reference", function(options) {
|
||||
}
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("reference", function(options) {
|
||||
this.definition().references.push(this);
|
||||
this.mark_enclosed(options);
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("find_variable", function(name){
|
||||
if (name instanceof AST_Symbol) name = name.name;
|
||||
return this.variables.get(name)
|
||||
@@ -381,12 +398,12 @@ AST_Symbol.DEFMETHOD("global", function(){
|
||||
|
||||
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
|
||||
return defaults(options, {
|
||||
except : [],
|
||||
eval : false,
|
||||
except : [],
|
||||
keep_fnames : false,
|
||||
screw_ie8 : true,
|
||||
sort : false, // Ignored. Flag retained for backwards compatibility.
|
||||
toplevel : false,
|
||||
screw_ie8 : true,
|
||||
keep_fnames : false
|
||||
});
|
||||
});
|
||||
|
||||
@@ -559,12 +576,12 @@ var base54 = (function() {
|
||||
|
||||
AST_Toplevel.DEFMETHOD("scope_warnings", function(options){
|
||||
options = defaults(options, {
|
||||
undeclared : false, // this makes a lot of noise
|
||||
unreferenced : true,
|
||||
assign_to_global : true,
|
||||
eval : true,
|
||||
func_arguments : true,
|
||||
nested_defuns : true,
|
||||
eval : true
|
||||
undeclared : false, // this makes a lot of noise
|
||||
unreferenced : true,
|
||||
});
|
||||
var tw = new TreeWalker(function(node){
|
||||
if (options.undeclared
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": "http://lisperator.net/uglifyjs",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "2.8.13",
|
||||
"version": "2.8.21",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
@@ -30,7 +30,6 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"source-map": "~0.5.1",
|
||||
"uglify-to-browserify": "~1.0.0",
|
||||
"yargs": "~3.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -40,13 +39,15 @@
|
||||
"estraverse": "~1.5.1",
|
||||
"mocha": "~2.3.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"uglify-to-browserify": "~1.0.0"
|
||||
},
|
||||
"browserify": {
|
||||
"transform": [
|
||||
"uglify-to-browserify"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"shrinkwrap": "rm ./npm-shrinkwrap.json; rm -rf ./node_modules; npm i && npm shrinkwrap && npm outdated",
|
||||
"test": "node test/run-tests.js"
|
||||
},
|
||||
"keywords": ["uglify", "uglify-js", "minify", "minifier"]
|
||||
|
||||
@@ -43,6 +43,7 @@ collapse_vars_side_effects_1: {
|
||||
z = i += 4;
|
||||
log(x, z, y, i);
|
||||
}
|
||||
f1(), f2(), f3(), f4();
|
||||
}
|
||||
expect: {
|
||||
function f1() {
|
||||
@@ -73,7 +74,9 @@ collapse_vars_side_effects_1: {
|
||||
y = i += 3;
|
||||
log(x, i += 4, y, i);
|
||||
}
|
||||
f1(), f2(), f3(), f4();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
collapse_vars_side_effects_2: {
|
||||
@@ -823,6 +826,7 @@ collapse_vars_repeated: {
|
||||
console.log(e + "!");
|
||||
})("!");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
collapse_vars_closures: {
|
||||
@@ -890,7 +894,8 @@ collapse_vars_unary: {
|
||||
}
|
||||
expect: {
|
||||
function f0(o, p) {
|
||||
delete o[p];
|
||||
var x = o[p];
|
||||
delete x;
|
||||
}
|
||||
function f1(n) {
|
||||
return n > +!!n
|
||||
@@ -1109,6 +1114,7 @@ collapse_vars_eval_and_with: {
|
||||
return function() { with (o) console.log(a) };
|
||||
})()();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
collapse_vars_constants: {
|
||||
@@ -1168,6 +1174,7 @@ collapse_vars_arguments: {
|
||||
(function(){console.log(arguments);})(7, 1);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
collapse_vars_short_circuit: {
|
||||
@@ -1317,6 +1324,7 @@ collapse_vars_regexp: {
|
||||
console.log(result[0]);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1537: {
|
||||
@@ -1408,3 +1416,178 @@ issue_1605_2: {
|
||||
(new Object).p = 1;
|
||||
}
|
||||
}
|
||||
|
||||
issue_1631_1: {
|
||||
options = {
|
||||
cascade: true,
|
||||
collapse_vars: true,
|
||||
hoist_funs: true,
|
||||
join_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var pc = 0;
|
||||
function f(x) {
|
||||
pc = 200;
|
||||
return 100;
|
||||
}
|
||||
function x() {
|
||||
var t = f();
|
||||
pc += t;
|
||||
return pc;
|
||||
}
|
||||
console.log(x());
|
||||
}
|
||||
expect: {
|
||||
function f(x) {
|
||||
return pc = 200, 100;
|
||||
}
|
||||
function x() {
|
||||
var t = f();
|
||||
return pc += t;
|
||||
}
|
||||
var pc = 0;
|
||||
console.log(x());
|
||||
}
|
||||
expect_stdout: "300"
|
||||
}
|
||||
|
||||
issue_1631_2: {
|
||||
options = {
|
||||
cascade: true,
|
||||
collapse_vars: true,
|
||||
hoist_funs: true,
|
||||
join_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = 1;
|
||||
function f() {
|
||||
a = 2;
|
||||
return 4;
|
||||
}
|
||||
function g() {
|
||||
var t = f();
|
||||
b = a + t;
|
||||
return b;
|
||||
}
|
||||
console.log(g());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return a = 2, 4;
|
||||
}
|
||||
function g() {
|
||||
var t = f();
|
||||
return b = a + t;
|
||||
}
|
||||
var a = 0, b = 1;
|
||||
console.log(g());
|
||||
}
|
||||
expect_stdout: "6"
|
||||
}
|
||||
|
||||
issue_1631_3: {
|
||||
options = {
|
||||
cascade: true,
|
||||
collapse_vars: true,
|
||||
hoist_funs: true,
|
||||
join_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
function g() {
|
||||
var a = 0, b = 1;
|
||||
function f() {
|
||||
a = 2;
|
||||
return 4;
|
||||
}
|
||||
var t = f();
|
||||
b = a + t;
|
||||
return b;
|
||||
}
|
||||
console.log(g());
|
||||
}
|
||||
expect: {
|
||||
function g() {
|
||||
function f() {
|
||||
return a = 2, 4;
|
||||
}
|
||||
var a = 0, b = 1, t = f();
|
||||
return b = a + t;
|
||||
}
|
||||
console.log(g());
|
||||
}
|
||||
expect_stdout: "6"
|
||||
}
|
||||
|
||||
var_side_effects_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var print = console.log.bind(console);
|
||||
function foo(x) {
|
||||
var twice = x * 2;
|
||||
print('Foo:', twice);
|
||||
}
|
||||
foo(10);
|
||||
}
|
||||
expect: {
|
||||
var print = console.log.bind(console);
|
||||
function foo(x) {
|
||||
print('Foo:', 2 * x);
|
||||
}
|
||||
foo(10);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
var_side_effects_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
var print = console.log.bind(console);
|
||||
function foo(x) {
|
||||
var twice = x.y * 2;
|
||||
print('Foo:', twice);
|
||||
}
|
||||
foo({ y: 10 });
|
||||
}
|
||||
expect: {
|
||||
var print = console.log.bind(console);
|
||||
function foo(x) {
|
||||
var twice = 2 * x.y;
|
||||
print('Foo:', twice);
|
||||
}
|
||||
foo({ y: 10 });
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
var_side_effects_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
pure_getters: true,
|
||||
}
|
||||
input: {
|
||||
var print = console.log.bind(console);
|
||||
function foo(x) {
|
||||
var twice = x.y * 2;
|
||||
print('Foo:', twice);
|
||||
}
|
||||
foo({ y: 10 });
|
||||
}
|
||||
expect: {
|
||||
var print = console.log.bind(console);
|
||||
function foo(x) {
|
||||
print('Foo:', 2 * x.y);
|
||||
}
|
||||
foo({ y: 10 });
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ concat_2: {
|
||||
"1" + "2" + "3"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_3: {
|
||||
@@ -79,6 +80,7 @@ concat_3: {
|
||||
1 + 2 + "3" + "4" + "5"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_4: {
|
||||
@@ -107,6 +109,7 @@ concat_4: {
|
||||
1 + "2" + "3" + "4" + "5"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_5: {
|
||||
@@ -135,6 +138,7 @@ concat_5: {
|
||||
"1" + 2 + "3" + "4" + "5"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_6: {
|
||||
@@ -163,6 +167,7 @@ concat_6: {
|
||||
"1" + "2" + "3" + "4" + "5"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_7: {
|
||||
@@ -188,6 +193,7 @@ concat_7: {
|
||||
x += "foo"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
concat_8: {
|
||||
@@ -213,4 +219,5 @@ concat_8: {
|
||||
x += "foo"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -797,3 +797,168 @@ no_evaluate: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
equality_conditionals_false: {
|
||||
options = {
|
||||
conditionals: false,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, b, c) {
|
||||
console.log(
|
||||
a == (b ? a : a),
|
||||
a == (b ? a : c),
|
||||
a != (b ? a : a),
|
||||
a != (b ? a : c),
|
||||
a === (b ? a : a),
|
||||
a === (b ? a : c),
|
||||
a !== (b ? a : a),
|
||||
a !== (b ? a : c)
|
||||
);
|
||||
}
|
||||
f(0, 0, 0);
|
||||
f(0, true, 0);
|
||||
f(1, 2, 3);
|
||||
f(1, null, 3);
|
||||
f(NaN);
|
||||
f(NaN, "foo");
|
||||
}
|
||||
expect: {
|
||||
function f(a, b, c) {
|
||||
console.log(
|
||||
a == (b ? a : a),
|
||||
a == (b ? a : c),
|
||||
a != (b ? a : a),
|
||||
a != (b ? a : c),
|
||||
a === (b ? a : a),
|
||||
a === (b ? a : c),
|
||||
a !== (b ? a : a),
|
||||
a !== (b ? a : c)
|
||||
);
|
||||
}
|
||||
f(0, 0, 0),
|
||||
f(0, true, 0),
|
||||
f(1, 2, 3),
|
||||
f(1, null, 3),
|
||||
f(NaN),
|
||||
f(NaN, "foo");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
equality_conditionals_true: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
function f(a, b, c) {
|
||||
console.log(
|
||||
a == (b ? a : a),
|
||||
a == (b ? a : c),
|
||||
a != (b ? a : a),
|
||||
a != (b ? a : c),
|
||||
a === (b ? a : a),
|
||||
a === (b ? a : c),
|
||||
a !== (b ? a : a),
|
||||
a !== (b ? a : c)
|
||||
);
|
||||
}
|
||||
f(0, 0, 0);
|
||||
f(0, true, 0);
|
||||
f(1, 2, 3);
|
||||
f(1, null, 3);
|
||||
f(NaN);
|
||||
f(NaN, "foo");
|
||||
}
|
||||
expect: {
|
||||
function f(a, b, c) {
|
||||
console.log(
|
||||
(b, a == a),
|
||||
a == (b ? a : c),
|
||||
(b, a != a),
|
||||
a != (b ? a : c),
|
||||
(b, a === a),
|
||||
a === (b ? a : c),
|
||||
(b, a !== a),
|
||||
a !== (b ? a : c)
|
||||
);
|
||||
}
|
||||
f(0, 0, 0),
|
||||
f(0, true, 0),
|
||||
f(1, 2, 3),
|
||||
f(1, null, 3),
|
||||
f(NaN),
|
||||
f(NaN, "foo");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1645_1: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
(b = a) ? a++ + (b += a) ? b += a : b += a : b ^= a;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 100, b = 10;
|
||||
(b = a) ? (a++ + (b += a), b += a) : b ^= a;
|
||||
console.log(a,b);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1645_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
function f() {
|
||||
return a++;
|
||||
}
|
||||
f() ? a += 2 : a += 4;
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
function f(){
|
||||
return a++;
|
||||
}
|
||||
f() ? a += 2 : a += 4;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
condition_symbol_matches_consequent: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
function foo(x, y) {
|
||||
return x ? x : y;
|
||||
}
|
||||
function bar() {
|
||||
return g ? g : h;
|
||||
}
|
||||
var g = 4;
|
||||
var h = 5;
|
||||
console.log(foo(3, null), foo(0, 7), foo(true, false), bar());
|
||||
}
|
||||
expect: {
|
||||
function foo(x, y) {
|
||||
return x || y;
|
||||
}
|
||||
function bar() {
|
||||
return g || h;
|
||||
}
|
||||
var g = 4;
|
||||
var h = 5;
|
||||
console.log(foo(3, null), foo(0, 7), foo(true, false), bar());
|
||||
}
|
||||
expect_stdout: "3 7 true 4"
|
||||
}
|
||||
|
||||
@@ -162,4 +162,5 @@ regexp_literal_not_const: {
|
||||
while (result = REGEXP_LITERAL.exec("acdabcdeabbb")) console.log(result[0]);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ dead_code_constant_boolean_should_warn_more: {
|
||||
var x = 10, y;
|
||||
var moo;
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
dead_code_const_declaration: {
|
||||
@@ -113,6 +114,7 @@ dead_code_const_declaration: {
|
||||
var moo;
|
||||
function bar() {}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
dead_code_const_annotation: {
|
||||
@@ -140,6 +142,7 @@ dead_code_const_annotation: {
|
||||
var moo;
|
||||
function bar() {}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
dead_code_const_annotation_regex: {
|
||||
@@ -163,6 +166,7 @@ dead_code_const_annotation_regex: {
|
||||
var CONST_FOO_ANN = !1;
|
||||
CONST_FOO_ANN && console.log('reachable');
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
dead_code_const_annotation_complex_scope: {
|
||||
@@ -208,4 +212,47 @@ dead_code_const_annotation_complex_scope: {
|
||||
var meat = 'beef';
|
||||
var pork = 'bad';
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
try_catch_finally: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
!function() {
|
||||
try {
|
||||
if (false) throw x;
|
||||
} catch (a) {
|
||||
var a = 2;
|
||||
console.log("FAIL");
|
||||
} finally {
|
||||
a = 3;
|
||||
console.log("PASS");
|
||||
}
|
||||
}();
|
||||
try {
|
||||
console.log(a);
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
!function() {
|
||||
var a;
|
||||
a = 3;
|
||||
console.log("PASS");
|
||||
}();
|
||||
try {
|
||||
console.log(a);
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"1",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -791,3 +791,186 @@ issue_1583: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_1656: {
|
||||
options = {
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
input: {
|
||||
for(var a=0;;);
|
||||
}
|
||||
expect_exact: "for (;;) ;"
|
||||
}
|
||||
|
||||
issue_1709: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
function x() {
|
||||
var x = 1;
|
||||
return x;
|
||||
}(),
|
||||
function y() {
|
||||
const y = 2;
|
||||
return y;
|
||||
}(),
|
||||
function z() {
|
||||
function z() {}
|
||||
return z;
|
||||
}()
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
console.log(
|
||||
function() {
|
||||
var x = 1;
|
||||
return x;
|
||||
}(),
|
||||
function() {
|
||||
const y = 2;
|
||||
return y;
|
||||
}(),
|
||||
function() {
|
||||
function z() {}
|
||||
return z;
|
||||
}()
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1715_1: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
function f() {
|
||||
a++;
|
||||
try {
|
||||
x();
|
||||
} catch (a) {
|
||||
var a;
|
||||
}
|
||||
}
|
||||
f();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
function f() {
|
||||
a++;
|
||||
try {
|
||||
x();
|
||||
} catch (a) {
|
||||
var a;
|
||||
}
|
||||
}
|
||||
f();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_1715_2: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
function f() {
|
||||
a++;
|
||||
try {
|
||||
x();
|
||||
} catch (a) {
|
||||
var a = 2;
|
||||
}
|
||||
}
|
||||
f();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
function f() {
|
||||
a++;
|
||||
try {
|
||||
x();
|
||||
} catch (a) {
|
||||
var a;
|
||||
}
|
||||
}
|
||||
f();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_1715_3: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
function f() {
|
||||
a++;
|
||||
try {
|
||||
console;
|
||||
} catch (a) {
|
||||
var a = 2 + x();
|
||||
}
|
||||
}
|
||||
f();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
function f() {
|
||||
a++;
|
||||
try {
|
||||
console;
|
||||
} catch (a) {
|
||||
var a = x();
|
||||
}
|
||||
}
|
||||
f();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_1715_4: {
|
||||
options = {
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
!function a() {
|
||||
a++;
|
||||
try {
|
||||
x();
|
||||
} catch (a) {
|
||||
var a;
|
||||
}
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
!function() {
|
||||
a++;
|
||||
try {
|
||||
x();
|
||||
} catch (a) {
|
||||
var a;
|
||||
}
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -196,10 +196,11 @@ negative_zero: {
|
||||
console.log(
|
||||
-0,
|
||||
0,
|
||||
1 / (-0),
|
||||
1 / (-0)
|
||||
-1/0,
|
||||
-1/0
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
positive_zero: {
|
||||
@@ -216,10 +217,11 @@ positive_zero: {
|
||||
console.log(
|
||||
0,
|
||||
-0,
|
||||
1 / (0),
|
||||
1 / (0)
|
||||
1/0,
|
||||
1/0
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_constant: {
|
||||
@@ -243,6 +245,7 @@ unsafe_constant: {
|
||||
(void 0).a
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_object: {
|
||||
@@ -266,6 +269,7 @@ unsafe_object: {
|
||||
1..b + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_object_nested: {
|
||||
@@ -289,6 +293,7 @@ unsafe_object_nested: {
|
||||
2
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_object_complex: {
|
||||
@@ -312,6 +317,7 @@ unsafe_object_complex: {
|
||||
2
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_object_repeated: {
|
||||
@@ -335,6 +341,7 @@ unsafe_object_repeated: {
|
||||
1..b + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_object_accessor: {
|
||||
@@ -384,6 +391,7 @@ unsafe_function: {
|
||||
({a:{b:1},b:function(){}}).a.b + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_integer_key: {
|
||||
@@ -411,6 +419,7 @@ unsafe_integer_key: {
|
||||
1["1"] + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_integer_key_complex: {
|
||||
@@ -438,6 +447,7 @@ unsafe_integer_key_complex: {
|
||||
2
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_float_key: {
|
||||
@@ -465,6 +475,7 @@ unsafe_float_key: {
|
||||
1["3.14"] + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_float_key_complex: {
|
||||
@@ -492,6 +503,7 @@ unsafe_float_key_complex: {
|
||||
2
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_array: {
|
||||
@@ -527,6 +539,7 @@ unsafe_array: {
|
||||
(void 0)[1] + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_string: {
|
||||
@@ -554,6 +567,7 @@ unsafe_string: {
|
||||
"11"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_array_bad_index: {
|
||||
@@ -575,6 +589,7 @@ unsafe_array_bad_index: {
|
||||
[1, 2, 3, 4][3.14] + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_string_bad_index: {
|
||||
@@ -596,6 +611,7 @@ unsafe_string_bad_index: {
|
||||
"1234"[3.14] + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_prototype_function: {
|
||||
@@ -642,6 +658,7 @@ call_args: {
|
||||
console.log(1);
|
||||
+(1, 1);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
call_args_drop_param: {
|
||||
@@ -663,6 +680,7 @@ call_args_drop_param: {
|
||||
console.log(1);
|
||||
+(b, 1);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
in_boolean_context: {
|
||||
@@ -700,4 +718,142 @@ in_boolean_context: {
|
||||
(foo(), !1)
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_charAt: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
unsafe : true
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
"1234" + 1,
|
||||
"1234".charAt(0) + 1,
|
||||
"1234".charAt(6 - 5) + 1,
|
||||
("12" + "34").charAt(0) + 1,
|
||||
("12" + "34").charAt(6 - 5) + 1,
|
||||
[1, 2, 3, 4].join("").charAt(0) + 1
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
console.log(
|
||||
"12341",
|
||||
"11",
|
||||
"21",
|
||||
"11",
|
||||
"21",
|
||||
"11"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_charAt_bad_index: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
unsafe : true
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
"1234".charAt() + 1,
|
||||
"1234".charAt("a") + 1,
|
||||
"1234".charAt(3.14) + 1
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
console.log(
|
||||
"11",
|
||||
"11",
|
||||
"41"
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unsafe_charAt_noop: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
unsafe : true
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
s.charAt(0),
|
||||
"string".charAt(x)
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
console.log(
|
||||
s.charAt(0),
|
||||
"string".charAt(x)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
issue_1649: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
console.log(-1 + -1);
|
||||
}
|
||||
expect: {
|
||||
console.log(-2);
|
||||
}
|
||||
expect_stdout: "-2";
|
||||
}
|
||||
|
||||
issue_1760_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
!function(a) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (NaN) {
|
||||
a = +"foo";
|
||||
}
|
||||
console.log(a);
|
||||
}();
|
||||
}
|
||||
expect: {
|
||||
!function(a) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (NaN) {
|
||||
a = 0 / 0;
|
||||
}
|
||||
console.log(a);
|
||||
}();
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_1760_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_infinity: true,
|
||||
}
|
||||
input: {
|
||||
!function(a) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (Infinity) {
|
||||
a = 123456789 / 0;
|
||||
}
|
||||
console.log(a);
|
||||
}();
|
||||
}
|
||||
expect: {
|
||||
!function(a) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (Infinity) {
|
||||
a = 1 / 0;
|
||||
}
|
||||
console.log(a);
|
||||
}();
|
||||
}
|
||||
expect_stdout: "Infinity"
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ iifes_returning_constants_keep_fargs_true: {
|
||||
console.log(6);
|
||||
console.log((a(), b(), 6));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iifes_returning_constants_keep_fargs_false: {
|
||||
@@ -73,6 +74,7 @@ iifes_returning_constants_keep_fargs_false: {
|
||||
console.log(6);
|
||||
console.log((a(), b(), 6));
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_485_crashing_1530: {
|
||||
|
||||
@@ -47,22 +47,6 @@ html_comment_in_greater_than_or_equal: {
|
||||
expect_exact: "function f(a,b){return a-- >=b}";
|
||||
}
|
||||
|
||||
html_comment_in_right_shift_assign: {
|
||||
input: {
|
||||
// Note: illegal javascript
|
||||
function f(a, b) { return a-- >>= b; }
|
||||
}
|
||||
expect_exact: "function f(a,b){return a-- >>=b}";
|
||||
}
|
||||
|
||||
html_comment_in_zero_fill_right_shift_assign: {
|
||||
input: {
|
||||
// Note: illegal javascript
|
||||
function f(a, b) { return a-- >>>= b; }
|
||||
}
|
||||
expect_exact: "function f(a,b){return a-- >>>=b}";
|
||||
}
|
||||
|
||||
html_comment_in_string_literal: {
|
||||
input: {
|
||||
function f() { return "<!--HTML-->comment in<!--string literal-->"; }
|
||||
|
||||
@@ -39,7 +39,7 @@ non_hoisted_function_after_return_2a: {
|
||||
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
|
||||
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
|
||||
if_return: true, join_vars: true, cascade: true, side_effects: true,
|
||||
collapse_vars: false, passes: 2
|
||||
collapse_vars: false, passes: 2, warnings: "verbose"
|
||||
}
|
||||
input: {
|
||||
function foo(x) {
|
||||
@@ -75,7 +75,7 @@ non_hoisted_function_after_return_2a: {
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]",
|
||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]",
|
||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]"
|
||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -114,8 +114,5 @@ non_hoisted_function_after_return_2b: {
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]",
|
||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:95,20]",
|
||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:97,16]"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -193,13 +193,15 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
|
||||
cascade: true,
|
||||
side_effects: true,
|
||||
sequences: false,
|
||||
keep_infinity: false,
|
||||
}
|
||||
input: {
|
||||
var f = console.log;
|
||||
var o = {
|
||||
undefined : 3,
|
||||
NaN : 4,
|
||||
Infinity : 5,
|
||||
}
|
||||
};
|
||||
if (o) {
|
||||
f(undefined, void 0);
|
||||
f(NaN, 0/0);
|
||||
@@ -216,25 +218,88 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var o = {
|
||||
var f = console.log, o = {
|
||||
undefined : 3,
|
||||
NaN : 4,
|
||||
Infinity : 5
|
||||
}
|
||||
};
|
||||
if (o) {
|
||||
f(void 0, void 0);
|
||||
f(NaN, NaN);
|
||||
f(1/0, 1/0);
|
||||
f(-(1/0), -(1/0));
|
||||
f(-1/0, -1/0);
|
||||
f(NaN, NaN);
|
||||
}
|
||||
with (o) {
|
||||
f(undefined, void 0);
|
||||
f(NaN, 0/0);
|
||||
f(Infinity, 1/0);
|
||||
f(-Infinity, -(1/0));
|
||||
f(-Infinity, -1/0);
|
||||
f(9 + undefined, 9 + void 0);
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
assorted_Infinity_NaN_undefined_in_with_scope_keep_infinity: {
|
||||
options = {
|
||||
unused: true,
|
||||
evaluate: true,
|
||||
dead_code: true,
|
||||
conditionals: true,
|
||||
comparisons: true,
|
||||
booleans: true,
|
||||
hoist_funs: true,
|
||||
keep_fargs: true,
|
||||
if_return: true,
|
||||
join_vars: true,
|
||||
cascade: true,
|
||||
side_effects: true,
|
||||
sequences: false,
|
||||
keep_infinity: true,
|
||||
}
|
||||
input: {
|
||||
var f = console.log;
|
||||
var o = {
|
||||
undefined : 3,
|
||||
NaN : 4,
|
||||
Infinity : 5,
|
||||
};
|
||||
if (o) {
|
||||
f(undefined, void 0);
|
||||
f(NaN, 0/0);
|
||||
f(Infinity, 1/0);
|
||||
f(-Infinity, -(1/0));
|
||||
f(2 + 7 + undefined, 2 + 7 + void 0);
|
||||
}
|
||||
with (o) {
|
||||
f(undefined, void 0);
|
||||
f(NaN, 0/0);
|
||||
f(Infinity, 1/0);
|
||||
f(-Infinity, -(1/0));
|
||||
f(2 + 7 + undefined, 2 + 7 + void 0);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var f = console.log, o = {
|
||||
undefined : 3,
|
||||
NaN : 4,
|
||||
Infinity : 5
|
||||
};
|
||||
if (o) {
|
||||
f(void 0, void 0);
|
||||
f(NaN, NaN);
|
||||
f(Infinity, 1/0);
|
||||
f(-Infinity, -1/0);
|
||||
f(NaN, NaN);
|
||||
}
|
||||
with (o) {
|
||||
f(undefined, void 0);
|
||||
f(NaN, 0/0);
|
||||
f(Infinity, 1/0);
|
||||
f(-Infinity, -1/0);
|
||||
f(9 + undefined, 9 + void 0);
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -49,4 +49,3 @@ mangle_keep_fnames_true: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -154,12 +154,12 @@ should_warn: {
|
||||
"WARN: Boolean || always true [test/compress/issue-1261.js:129,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:129,23]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:129,23]",
|
||||
"WARN: Boolean || always true [test/compress/issue-1261.js:130,8]",
|
||||
"WARN: Condition left of || always true [test/compress/issue-1261.js:130,8]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:130,8]",
|
||||
"WARN: Boolean && always false [test/compress/issue-1261.js:131,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:131,23]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:131,23]",
|
||||
"WARN: Boolean && always false [test/compress/issue-1261.js:132,8]",
|
||||
"WARN: Condition left of && always false [test/compress/issue-1261.js:132,8]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:132,8]",
|
||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:133,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:133,23]",
|
||||
|
||||
@@ -46,4 +46,5 @@ string_plus_optimization: {
|
||||
}
|
||||
foo();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ issue_1321_no_debug: {
|
||||
x["a"] = 2 * x.b;
|
||||
console.log(x.b, x["a"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1321_debug: {
|
||||
@@ -33,6 +34,7 @@ issue_1321_debug: {
|
||||
x["_$foo$_"] = 2 * x.a;
|
||||
console.log(x.a, x["_$foo$_"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1321_with_quoted: {
|
||||
@@ -51,4 +53,5 @@ issue_1321_with_quoted: {
|
||||
x["b"] = 2 * x.a;
|
||||
console.log(x.a, x["b"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -42,4 +42,5 @@ conditional_false_stray_else_in_loop: {
|
||||
}
|
||||
}
|
||||
expect_exact: "for(var i=1;i<=4;++i)if(!(i<=2))console.log(i);"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -85,3 +85,15 @@ unsafe_undefined: {
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
runtime_error: {
|
||||
input: {
|
||||
const a = 1;
|
||||
console.log(a++);
|
||||
}
|
||||
expect: {
|
||||
const a = 1;
|
||||
console.log(a++);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
88
test/compress/issue-1639.js
Normal file
88
test/compress/issue-1639.js
Normal file
@@ -0,0 +1,88 @@
|
||||
|
||||
issue_1639_1: {
|
||||
options = {
|
||||
booleans: true,
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
loops: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
|
||||
var L1 = 5;
|
||||
while (--L1 > 0) {
|
||||
if ((--b), false) {
|
||||
if (b) {
|
||||
var ignore = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
for (var a = 100, b = 10, L1 = 5; --L1 > 0;)
|
||||
if (--b, !1) var ignore = 0;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1639_2: {
|
||||
options = {
|
||||
booleans: true,
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
|
||||
function f19() {
|
||||
if (++a, false)
|
||||
if (a)
|
||||
if (++a);
|
||||
}
|
||||
f19();
|
||||
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 100, b = 10;
|
||||
function f19() {
|
||||
++a, 1;
|
||||
}
|
||||
f19(),
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1639_3: {
|
||||
options = {
|
||||
booleans: true,
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
a++ && false && a ? 0 : 0;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 100, b = 10;
|
||||
a++,
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
45
test/compress/issue-1656.js
Normal file
45
test/compress/issue-1656.js
Normal file
@@ -0,0 +1,45 @@
|
||||
f7: {
|
||||
options = {
|
||||
booleans: true,
|
||||
cascade: true,
|
||||
collapse_vars: true,
|
||||
comparisons: true,
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
drop_debugger: true,
|
||||
evaluate: true,
|
||||
hoist_funs: true,
|
||||
if_return: true,
|
||||
join_vars: true,
|
||||
loops: true,
|
||||
negate_iife: true,
|
||||
passes: 3,
|
||||
properties: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
function f22464() {
|
||||
var brake146670 = 5;
|
||||
while (((b = a) ? !a : ~a ? null : b += a) && --brake146670 > 0) {
|
||||
}
|
||||
}
|
||||
f22464();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_exact: [
|
||||
"var a = 100, b = 10;",
|
||||
"",
|
||||
"!function() {",
|
||||
" for (;b = a, !1; ) ;",
|
||||
"}(), console.log(a, b);",
|
||||
]
|
||||
expect_stdout: true
|
||||
}
|
||||
161
test/compress/issue-1673.js
Normal file
161
test/compress/issue-1673.js
Normal file
@@ -0,0 +1,161 @@
|
||||
side_effects_catch: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
function g() {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
g();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
(function() {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (e) {
|
||||
console.log("PASS");
|
||||
}
|
||||
})();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
side_effects_else: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(x) {
|
||||
function g() {
|
||||
if (x);
|
||||
else console.log("PASS");
|
||||
}
|
||||
g();
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect: {
|
||||
function f(x) {
|
||||
(function() {
|
||||
if (x);
|
||||
else console.log("PASS");
|
||||
})();
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
side_effects_finally: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
function g() {
|
||||
try {
|
||||
x();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
g();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
(function() {
|
||||
try {
|
||||
x();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
console.log("PASS");
|
||||
}
|
||||
})();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
side_effects_label: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(x) {
|
||||
function g() {
|
||||
L: {
|
||||
console.log("PASS");
|
||||
break L;
|
||||
}
|
||||
}
|
||||
g();
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect: {
|
||||
function f(x) {
|
||||
(function() {
|
||||
L: {
|
||||
console.log("PASS");
|
||||
break L;
|
||||
}
|
||||
})();
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
side_effects_switch: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
function g() {
|
||||
switch (0) {
|
||||
default:
|
||||
case console.log("PASS"):
|
||||
}
|
||||
}
|
||||
g();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
(function() {
|
||||
switch (0) {
|
||||
default:
|
||||
case console.log("PASS"):
|
||||
}
|
||||
})();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
347
test/compress/issue-1704.js
Normal file
347
test/compress/issue-1704.js
Normal file
@@ -0,0 +1,347 @@
|
||||
mangle_catch: {
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
toplevel: false,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
toplevel: false,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (args) {
|
||||
a = "PASS";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var a="FAIL";try{throw 1}catch(o){a="PASS"}console.log(a);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_ie8: {
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
toplevel: false,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
toplevel: false,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (args) {
|
||||
a = "PASS";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var a="FAIL";try{throw 1}catch(args){a="PASS"}console.log(a);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_var: {
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
toplevel: false,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
toplevel: false,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (args) {
|
||||
var a = "PASS";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var a="FAIL";try{throw 1}catch(o){var a="PASS"}console.log(a);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_var_ie8: {
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
toplevel: false,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
toplevel: false,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (args) {
|
||||
var a = "PASS";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var a="FAIL";try{throw 1}catch(args){var a="PASS"}console.log(a);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_toplevel: {
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (args) {
|
||||
a = "PASS";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_ie8_toplevel: {
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
toplevel: true,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (args) {
|
||||
a = "PASS";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_var_toplevel: {
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (args) {
|
||||
var a = "PASS";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_var_ie8_toplevel: {
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
toplevel: true,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (args) {
|
||||
var a = "PASS";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_redef_1: {
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
toplevel: false,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
toplevel: false,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
try {
|
||||
throw "FAIL1";
|
||||
} catch (a) {
|
||||
var a = "FAIL2";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var a="PASS";try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_redef_1_ie8: {
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
toplevel: false,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
toplevel: false,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
try {
|
||||
throw "FAIL1";
|
||||
} catch (a) {
|
||||
var a = "FAIL2";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var a="PASS";try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_redef_1_toplevel: {
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
try {
|
||||
throw "FAIL1";
|
||||
} catch (a) {
|
||||
var a = "FAIL2";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var o="PASS";try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_redef_1_ie8_toplevel: {
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
toplevel: true,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = "PASS";
|
||||
try {
|
||||
throw "FAIL1";
|
||||
} catch (a) {
|
||||
var a = "FAIL2";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'var o="PASS";try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
mangle_catch_redef_2: {
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
toplevel: false,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
toplevel: false,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw "FAIL1";
|
||||
} catch (a) {
|
||||
var a = "FAIL2";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
mangle_catch_redef_2_ie8: {
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
toplevel: false,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
toplevel: false,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw "FAIL1";
|
||||
} catch (a) {
|
||||
var a = "FAIL2";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'try{throw"FAIL1"}catch(a){var a="FAIL2"}console.log(a);'
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
mangle_catch_redef_2_toplevel: {
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw "FAIL1";
|
||||
} catch (a) {
|
||||
var a = "FAIL2";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
mangle_catch_redef_2_ie8_toplevel: {
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
toplevel: true,
|
||||
}
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
throw "FAIL1";
|
||||
} catch (a) {
|
||||
var a = "FAIL2";
|
||||
}
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
97
test/compress/issue-1733.js
Normal file
97
test/compress/issue-1733.js
Normal file
@@ -0,0 +1,97 @@
|
||||
function_iife_catch: {
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
}
|
||||
input: {
|
||||
function f(n) {
|
||||
!function() {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (n) {
|
||||
var a = 1;
|
||||
console.log(n, a);
|
||||
}
|
||||
}();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_exact: "function f(o){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
|
||||
expect_stdout: "0 1"
|
||||
}
|
||||
|
||||
function_iife_catch_ie8: {
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
}
|
||||
input: {
|
||||
function f(n) {
|
||||
!function() {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (n) {
|
||||
var a = 1;
|
||||
console.log(n, a);
|
||||
}
|
||||
}();
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
|
||||
expect_stdout: "0 1"
|
||||
}
|
||||
|
||||
function_catch_catch: {
|
||||
mangle = {
|
||||
screw_ie8: true,
|
||||
}
|
||||
input: {
|
||||
var o = 0;
|
||||
function f() {
|
||||
try {
|
||||
throw 1;
|
||||
} catch (c) {
|
||||
try {
|
||||
throw 2;
|
||||
} catch (o) {
|
||||
var o = 3;
|
||||
console.log(o);
|
||||
}
|
||||
}
|
||||
console.log(o);
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
|
||||
expect_stdout: [
|
||||
"3",
|
||||
"undefined",
|
||||
]
|
||||
}
|
||||
|
||||
function_catch_catch_ie8: {
|
||||
mangle = {
|
||||
screw_ie8: false,
|
||||
}
|
||||
input: {
|
||||
var o = 0;
|
||||
function f() {
|
||||
try {
|
||||
throw 1;
|
||||
} catch (c) {
|
||||
try {
|
||||
throw 2;
|
||||
} catch (o) {
|
||||
var o = 3;
|
||||
console.log(o);
|
||||
}
|
||||
}
|
||||
console.log(o);
|
||||
}
|
||||
f();
|
||||
}
|
||||
expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
|
||||
expect_stdout: [
|
||||
"3",
|
||||
"undefined",
|
||||
]
|
||||
}
|
||||
54
test/compress/issue-1750.js
Normal file
54
test/compress/issue-1750.js
Normal file
@@ -0,0 +1,54 @@
|
||||
case_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = 1;
|
||||
switch (true) {
|
||||
case a, true:
|
||||
default:
|
||||
b = 2;
|
||||
case true:
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 0, b = 1;
|
||||
switch (true) {
|
||||
case a, true:
|
||||
b = 2;
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "0 2"
|
||||
}
|
||||
|
||||
case_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0, b = 1;
|
||||
switch (0) {
|
||||
default:
|
||||
b = 2;
|
||||
case a:
|
||||
a = 3;
|
||||
case 0:
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 0, b = 1;
|
||||
switch (0) {
|
||||
case a:
|
||||
a = 3;
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "3 1"
|
||||
}
|
||||
@@ -6,7 +6,7 @@ NaN_and_Infinity_must_have_parens: {
|
||||
}
|
||||
expect: {
|
||||
(1/0).toString();
|
||||
NaN.toString(); // transformation to 0/0 dropped
|
||||
NaN.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,3 +23,135 @@ NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: {
|
||||
NaN.toString();
|
||||
}
|
||||
}
|
||||
|
||||
NaN_and_Infinity_must_have_parens_evaluate: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
(123456789 / 0).toString();
|
||||
(+"foo").toString();
|
||||
}
|
||||
expect: {
|
||||
(1/0).toString();
|
||||
NaN.toString();
|
||||
}
|
||||
}
|
||||
|
||||
NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined_evaluate: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
var Infinity, NaN;
|
||||
(123456789 / 0).toString();
|
||||
(+"foo").toString();
|
||||
}
|
||||
expect: {
|
||||
var Infinity, NaN;
|
||||
(1/0).toString();
|
||||
(0/0).toString();
|
||||
}
|
||||
}
|
||||
|
||||
beautify_off_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
beautify = {
|
||||
beautify: false,
|
||||
}
|
||||
input: {
|
||||
var NaN;
|
||||
console.log(
|
||||
null,
|
||||
undefined,
|
||||
Infinity,
|
||||
NaN,
|
||||
Infinity * undefined,
|
||||
Infinity.toString(),
|
||||
NaN.toString(),
|
||||
(Infinity * undefined).toString()
|
||||
);
|
||||
}
|
||||
expect_exact: "var NaN;console.log(null,void 0,1/0,NaN,0/0,(1/0).toString(),NaN.toString(),(0/0).toString());"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
beautify_off_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
beautify = {
|
||||
beautify: false,
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
null.toString(),
|
||||
undefined.toString()
|
||||
);
|
||||
}
|
||||
expect_exact: "console.log(null.toString(),(void 0).toString());"
|
||||
}
|
||||
|
||||
beautify_on_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
input: {
|
||||
var NaN;
|
||||
console.log(
|
||||
null,
|
||||
undefined,
|
||||
Infinity,
|
||||
NaN,
|
||||
Infinity * undefined,
|
||||
Infinity.toString(),
|
||||
NaN.toString(),
|
||||
(Infinity * undefined).toString()
|
||||
);
|
||||
}
|
||||
expect_exact: [
|
||||
"var NaN;",
|
||||
"",
|
||||
"console.log(null, void 0, 1 / 0, NaN, 0 / 0, (1 / 0).toString(), NaN.toString(), (0 / 0).toString());",
|
||||
]
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
beautify_on_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
input: {
|
||||
console.log(
|
||||
null.toString(),
|
||||
undefined.toString()
|
||||
);
|
||||
}
|
||||
expect_exact: "console.log(null.toString(), (void 0).toString());"
|
||||
}
|
||||
|
||||
issue_1724: {
|
||||
input: {
|
||||
var a = 0;
|
||||
++a % Infinity | Infinity ? a++ : 0;
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: "var a=0;++a%(1/0)|1/0?a++:0;console.log(a);"
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
issue_1725: {
|
||||
input: {
|
||||
([].length === 0) % Infinity ? console.log("PASS") : console.log("FAIL");
|
||||
}
|
||||
expect_exact: '(0===[].length)%(1/0)?console.log("PASS"):console.log("FAIL");'
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ dead_code_const_annotation_regex: {
|
||||
var CONST_FOO_ANN = !1;
|
||||
if (CONST_FOO_ANN) console.log('reachable');
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
drop_console_2: {
|
||||
@@ -225,6 +226,7 @@ issue_1254_negate_iife_true: {
|
||||
})()();
|
||||
}
|
||||
expect_exact: '(function(){return function(){console.log("test")}})()();'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1254_negate_iife_nested: {
|
||||
@@ -240,6 +242,7 @@ issue_1254_negate_iife_nested: {
|
||||
})()()()()();
|
||||
}
|
||||
expect_exact: '(function(){return function(){console.log("test")}})()()()()();'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
conditional: {
|
||||
|
||||
@@ -29,4 +29,5 @@ dont_mangle_arguments: {
|
||||
})(5,6,7);
|
||||
}
|
||||
expect_exact: "(function(){var arguments=arguments,o=9;console.log(o,arguments)})(5,6,7);"
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ eval_collapse_vars: {
|
||||
eval("console.log(a);");
|
||||
})(eval);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
eval_unused: {
|
||||
|
||||
@@ -9,6 +9,7 @@ labels_1: {
|
||||
expect: {
|
||||
foo || console.log("bar");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
labels_2: {
|
||||
@@ -40,6 +41,7 @@ labels_3: {
|
||||
for (var i = 0; i < 5; ++i)
|
||||
i < 3 || console.log(i);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
labels_4: {
|
||||
@@ -54,6 +56,7 @@ labels_4: {
|
||||
for (var i = 0; i < 5; ++i)
|
||||
i < 3 || console.log(i);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
labels_5: {
|
||||
|
||||
@@ -166,6 +166,7 @@ keep_collapse_const_in_own_block_scope: {
|
||||
console.log(i);
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
keep_collapse_const_in_own_block_scope_2: {
|
||||
@@ -186,6 +187,7 @@ keep_collapse_const_in_own_block_scope_2: {
|
||||
console.log(i);
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
evaluate: {
|
||||
@@ -438,3 +440,21 @@ issue_186_beautify_bracketize_ie8: {
|
||||
'}',
|
||||
]
|
||||
}
|
||||
|
||||
issue_1648: {
|
||||
options = {
|
||||
join_vars: true,
|
||||
loops: true,
|
||||
passes: 2,
|
||||
sequences: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
x();
|
||||
var b = 1;
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
expect_exact: "function f(){for(x();1;);}"
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ negate_iife_3_evaluate: {
|
||||
expect: {
|
||||
console.log(true);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
negate_iife_3_side_effects: {
|
||||
@@ -111,6 +112,7 @@ negate_iife_3_off_evaluate: {
|
||||
expect: {
|
||||
console.log(true);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
negate_iife_4: {
|
||||
@@ -243,6 +245,7 @@ negate_iife_nested: {
|
||||
}(7);
|
||||
}).f();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
negate_iife_nested_off: {
|
||||
@@ -275,6 +278,7 @@ negate_iife_nested_off: {
|
||||
})(7);
|
||||
}).f();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
negate_iife_issue_1073: {
|
||||
@@ -299,6 +303,7 @@ negate_iife_issue_1073: {
|
||||
};
|
||||
}(7))();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1254_negate_iife_false: {
|
||||
@@ -313,6 +318,7 @@ issue_1254_negate_iife_false: {
|
||||
})()();
|
||||
}
|
||||
expect_exact: '(function(){return function(){console.log("test")}})()();'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1254_negate_iife_true: {
|
||||
@@ -327,6 +333,7 @@ issue_1254_negate_iife_true: {
|
||||
})()();
|
||||
}
|
||||
expect_exact: '!function(){return function(){console.log("test")}}()();'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1254_negate_iife_nested: {
|
||||
@@ -341,12 +348,14 @@ issue_1254_negate_iife_nested: {
|
||||
})()()()()();
|
||||
}
|
||||
expect_exact: '!function(){return function(){console.log("test")}}()()()()();'
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1288: {
|
||||
options = {
|
||||
negate_iife: true,
|
||||
conditionals: true,
|
||||
negate_iife: true,
|
||||
side_effects: false,
|
||||
};
|
||||
input: {
|
||||
if (w) ;
|
||||
@@ -366,11 +375,11 @@ issue_1288: {
|
||||
})(0);
|
||||
}
|
||||
expect: {
|
||||
w || function f() {}();
|
||||
x || function() {
|
||||
w || !function f() {}();
|
||||
x || !function() {
|
||||
x = {};
|
||||
}();
|
||||
y ? function() {}() : function(z) {
|
||||
y ? !function() {}() : !function(z) {
|
||||
return z;
|
||||
}(0);
|
||||
}
|
||||
|
||||
@@ -153,3 +153,52 @@ evaluate_4: {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
issue_1710: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
var x = {};
|
||||
console.log((x += 1) + -x);
|
||||
}
|
||||
expect: {
|
||||
var x = {};
|
||||
console.log((x += 1) + -x);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
unary_binary_parenthesis: {
|
||||
input: {
|
||||
var v = [ 0, 1, NaN, Infinity, null, undefined, true, false, "", "foo", /foo/ ];
|
||||
v.forEach(function(x) {
|
||||
v.forEach(function(y) {
|
||||
console.log(
|
||||
+(x*y),
|
||||
+(x/y),
|
||||
+(x%y),
|
||||
-(x*y),
|
||||
-(x/y),
|
||||
-(x%y)
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
var v = [ 0, 1, NaN, 1/0, null, void 0, true, false, "", "foo", /foo/ ];
|
||||
v.forEach(function(x) {
|
||||
v.forEach(function(y) {
|
||||
console.log(
|
||||
+x*y,
|
||||
+x/y,
|
||||
+x%y,
|
||||
-x*y,
|
||||
-x/y,
|
||||
-x%y
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ reduce_vars: {
|
||||
})();
|
||||
console.log(2);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
modified: {
|
||||
@@ -401,6 +402,7 @@ iife: {
|
||||
console.log(0, 1 * b, 5);
|
||||
}(1, 2, 3);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_new: {
|
||||
@@ -420,9 +422,10 @@ iife_new: {
|
||||
console.log(0, 1 * b, 5);
|
||||
}(1, 2, 3);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
multi_def: {
|
||||
multi_def_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
@@ -432,7 +435,7 @@ multi_def: {
|
||||
if (a)
|
||||
var b = 1;
|
||||
else
|
||||
var b = 2
|
||||
var b = 2;
|
||||
console.log(b + 1);
|
||||
}
|
||||
}
|
||||
@@ -441,7 +444,7 @@ multi_def: {
|
||||
if (a)
|
||||
var b = 1;
|
||||
else
|
||||
var b = 2
|
||||
var b = 2;
|
||||
console.log(b + 1);
|
||||
}
|
||||
}
|
||||
@@ -476,6 +479,33 @@ multi_def_2: {
|
||||
}
|
||||
}
|
||||
|
||||
multi_def_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
var b = 2;
|
||||
if (a)
|
||||
var b;
|
||||
else
|
||||
var b;
|
||||
console.log(b + 1);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
var b = 2;
|
||||
if (a)
|
||||
var b;
|
||||
else
|
||||
var b;
|
||||
console.log(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use_before_var: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
@@ -707,6 +737,7 @@ toplevel_on: {
|
||||
expect: {
|
||||
console.log(3);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
toplevel_off: {
|
||||
@@ -724,6 +755,7 @@ toplevel_off: {
|
||||
var x = 3;
|
||||
console.log(x);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
toplevel_on_loops_1: {
|
||||
@@ -751,6 +783,7 @@ toplevel_on_loops_1: {
|
||||
})();
|
||||
while (x);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
toplevel_off_loops_1: {
|
||||
@@ -779,6 +812,7 @@ toplevel_off_loops_1: {
|
||||
bar();
|
||||
while (x);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
toplevel_on_loops_2: {
|
||||
@@ -1121,6 +1155,7 @@ defun_label: {
|
||||
}(2));
|
||||
}();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
double_reference: {
|
||||
@@ -1164,6 +1199,7 @@ iife_arguments_1: {
|
||||
return f;
|
||||
});
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_arguments_2: {
|
||||
@@ -1186,6 +1222,7 @@ iife_arguments_2: {
|
||||
}() === arguments[0]);
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_eval_1: {
|
||||
@@ -1207,6 +1244,7 @@ iife_eval_1: {
|
||||
return f;
|
||||
});
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_eval_2: {
|
||||
@@ -1230,6 +1268,7 @@ iife_eval_2: {
|
||||
console.log(x() === eval("x"));
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife_func_side_effects: {
|
||||
@@ -1326,6 +1365,7 @@ issue_1595_4: {
|
||||
if (a) iife(a - 1, b, c);
|
||||
})(3, 4, 5);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1606: {
|
||||
@@ -1351,3 +1391,478 @@ issue_1606: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_1670_1: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
dead_code: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function f() {
|
||||
switch (1) {
|
||||
case 0:
|
||||
var a = true;
|
||||
break;
|
||||
default:
|
||||
if (typeof a === "undefined") console.log("PASS");
|
||||
else console.log("FAIL");
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var a;
|
||||
void 0 === a ? console.log("PASS") : console.log("FAIL");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_1670_2: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
dead_code: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function f() {
|
||||
switch (1) {
|
||||
case 0:
|
||||
var a = true;
|
||||
break;
|
||||
default:
|
||||
if (typeof a === "undefined") console.log("PASS");
|
||||
else console.log("FAIL");
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_1670_3: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
dead_code: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function f() {
|
||||
switch (1) {
|
||||
case 0:
|
||||
var a = true;
|
||||
break;
|
||||
case 1:
|
||||
if (typeof a === "undefined") console.log("PASS");
|
||||
else console.log("FAIL");
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var a;
|
||||
void 0 === a ? console.log("PASS") : console.log("FAIL");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_1670_4: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
dead_code: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function f() {
|
||||
switch (1) {
|
||||
case 0:
|
||||
var a = true;
|
||||
break;
|
||||
case 1:
|
||||
if (typeof a === "undefined") console.log("PASS");
|
||||
else console.log("FAIL");
|
||||
}
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_1670_5: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
switch (1) {
|
||||
case a:
|
||||
console.log(a);
|
||||
break;
|
||||
default:
|
||||
console.log(2);
|
||||
break;
|
||||
}
|
||||
})(1);
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
console.log(1);
|
||||
})();
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_1670_6: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(a) {
|
||||
switch (1) {
|
||||
case a = 1:
|
||||
console.log(a);
|
||||
break;
|
||||
default:
|
||||
console.log(2);
|
||||
break;
|
||||
}
|
||||
})(1);
|
||||
}
|
||||
expect: {
|
||||
(function(a) {
|
||||
switch (1) {
|
||||
case a = 1:
|
||||
console.log(a);
|
||||
break;
|
||||
default:
|
||||
console.log(2);
|
||||
}
|
||||
})(1);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
unary_delete: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var b = 10;
|
||||
function f() {
|
||||
var a;
|
||||
if (delete a) b--;
|
||||
}
|
||||
f();
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
var b = 10;
|
||||
function f() {
|
||||
var a;
|
||||
if (delete a) b--;
|
||||
}
|
||||
f();
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
redefine_arguments_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
var arguments;
|
||||
return typeof arguments;
|
||||
}
|
||||
function g() {
|
||||
var arguments = 42;
|
||||
return typeof arguments;
|
||||
}
|
||||
function h(x) {
|
||||
var arguments = x;
|
||||
return typeof arguments;
|
||||
}
|
||||
console.log(f(), g(), h());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
var arguments;
|
||||
return typeof arguments;
|
||||
}
|
||||
function g() {
|
||||
return"number";
|
||||
}
|
||||
function h(x) {
|
||||
var arguments = x;
|
||||
return typeof arguments;
|
||||
}
|
||||
console.log(f(), g(), h());
|
||||
}
|
||||
expect_stdout: "object number undefined"
|
||||
}
|
||||
|
||||
redefine_arguments_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
var arguments;
|
||||
return typeof arguments;
|
||||
}
|
||||
function g() {
|
||||
var arguments = 42;
|
||||
return typeof arguments;
|
||||
}
|
||||
function h(x) {
|
||||
var arguments = x;
|
||||
return typeof arguments;
|
||||
}
|
||||
console.log(f(), g(), h());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var arguments;
|
||||
return typeof arguments;
|
||||
}(), function() {
|
||||
return"number";
|
||||
}(), function(x) {
|
||||
var arguments = x;
|
||||
return typeof arguments;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "object number undefined"
|
||||
}
|
||||
|
||||
redefine_arguments_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: false,
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
var arguments;
|
||||
return typeof arguments;
|
||||
}
|
||||
function g() {
|
||||
var arguments = 42;
|
||||
return typeof arguments;
|
||||
}
|
||||
function h(x) {
|
||||
var arguments = x;
|
||||
return typeof arguments;
|
||||
}
|
||||
console.log(f(), g(), h());
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
var arguments;
|
||||
return typeof arguments;
|
||||
}(), "number", "undefined");
|
||||
}
|
||||
expect_stdout: "object number undefined"
|
||||
}
|
||||
|
||||
redefine_farg_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
var a;
|
||||
return typeof a;
|
||||
}
|
||||
function g(a) {
|
||||
var a = 42;
|
||||
return typeof a;
|
||||
}
|
||||
function h(a, b) {
|
||||
var a = b;
|
||||
return typeof a;
|
||||
}
|
||||
console.log(f([]), g([]), h([]));
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
var a;
|
||||
return typeof a;
|
||||
}
|
||||
function g() {
|
||||
return"number";
|
||||
}
|
||||
function h(a, b) {
|
||||
var a = b;
|
||||
return typeof a;
|
||||
}
|
||||
console.log(f([]), g([]), h([]));
|
||||
}
|
||||
expect_stdout: "object number undefined"
|
||||
}
|
||||
|
||||
redefine_farg_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: false,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
var a;
|
||||
return typeof a;
|
||||
}
|
||||
function g(a) {
|
||||
var a = 42;
|
||||
return typeof a;
|
||||
}
|
||||
function h(a, b) {
|
||||
var a = b;
|
||||
return typeof a;
|
||||
}
|
||||
console.log(f([]), g([]), h([]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
var a;
|
||||
return typeof a;
|
||||
}([]), function() {
|
||||
return "number";
|
||||
}(),function(a, b) {
|
||||
var a = b;
|
||||
return typeof a;
|
||||
}([]));
|
||||
}
|
||||
expect_stdout: "object number undefined"
|
||||
}
|
||||
|
||||
redefine_farg_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
keep_fargs: false,
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
var a;
|
||||
return typeof a;
|
||||
}
|
||||
function g(a) {
|
||||
var a = 42;
|
||||
return typeof a;
|
||||
}
|
||||
function h(a, b) {
|
||||
var a = b;
|
||||
return typeof a;
|
||||
}
|
||||
console.log(f([]), g([]), h([]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
var a;
|
||||
return typeof a;
|
||||
}([]), "number", function(a) {
|
||||
var a = void 0;
|
||||
return typeof a;
|
||||
}([]));
|
||||
}
|
||||
expect_stdout: "object number undefined"
|
||||
}
|
||||
|
||||
delay_def: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return a;
|
||||
var a;
|
||||
}
|
||||
function g() {
|
||||
return a;
|
||||
var a = 1;
|
||||
}
|
||||
console.log(f(), g());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return a;
|
||||
var a;
|
||||
}
|
||||
function g() {
|
||||
return a;
|
||||
var a = 1;
|
||||
}
|
||||
console.log(f(), g());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
do_screw: {
|
||||
options = { screw_ie8: true };
|
||||
options = {
|
||||
screw_ie8: true,
|
||||
}
|
||||
beautify = {
|
||||
screw_ie8: true,
|
||||
ascii_only: true
|
||||
};
|
||||
|
||||
input: f("\v");
|
||||
expect_exact: 'f("\\v");';
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
f("\v");
|
||||
}
|
||||
expect_exact: 'f("\\v");'
|
||||
}
|
||||
|
||||
dont_screw: {
|
||||
options = { screw_ie8: false };
|
||||
beautify = { screw_ie8: false, ascii_only: true };
|
||||
|
||||
input: f("\v");
|
||||
expect_exact: 'f("\\x0B");';
|
||||
options = {
|
||||
screw_ie8: false,
|
||||
}
|
||||
beautify = {
|
||||
screw_ie8: false,
|
||||
ascii_only: true,
|
||||
}
|
||||
input: {
|
||||
f("\v");
|
||||
}
|
||||
expect_exact: 'f("\\x0B");'
|
||||
}
|
||||
|
||||
do_screw_constants: {
|
||||
@@ -119,6 +128,7 @@ do_screw_try_catch_undefined: {
|
||||
return void 0===o
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
dont_screw_try_catch_undefined: {
|
||||
@@ -147,6 +157,7 @@ dont_screw_try_catch_undefined: {
|
||||
return n === undefined
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
reduce_vars: {
|
||||
@@ -193,12 +204,13 @@ issue_1586_1: {
|
||||
input: {
|
||||
function f() {
|
||||
try {
|
||||
x();
|
||||
} catch (err) {
|
||||
console.log(err.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
expect_exact: "function f(){try{}catch(c){console.log(c.message)}}"
|
||||
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
|
||||
}
|
||||
|
||||
issue_1586_2: {
|
||||
@@ -211,10 +223,11 @@ issue_1586_2: {
|
||||
input: {
|
||||
function f() {
|
||||
try {
|
||||
x();
|
||||
} catch (err) {
|
||||
console.log(err.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
expect_exact: "function f(){try{}catch(c){console.log(c.message)}}"
|
||||
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ make_sequences_4: {
|
||||
switch (x = 5, y) {}
|
||||
with (x = 5, obj);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
lift_sequences_1: {
|
||||
@@ -103,15 +104,18 @@ lift_sequences_1: {
|
||||
lift_sequences_2: {
|
||||
options = { sequences: true, evaluate: true };
|
||||
input: {
|
||||
var foo, bar;
|
||||
var foo = 1, bar;
|
||||
foo.x = (foo = {}, 10);
|
||||
bar = (bar = {}, 10);
|
||||
console.log(foo, bar);
|
||||
}
|
||||
expect: {
|
||||
var foo, bar;
|
||||
var foo = 1, bar;
|
||||
foo.x = (foo = {}, 10),
|
||||
bar = {}, bar = 10;
|
||||
bar = {}, bar = 10,
|
||||
console.log(foo, bar);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
lift_sequences_3: {
|
||||
@@ -138,6 +142,23 @@ lift_sequences_4: {
|
||||
}
|
||||
}
|
||||
|
||||
lift_sequences_5: {
|
||||
options = {
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
var a = 2, b;
|
||||
a *= (b, a = 4, 3);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 2, b;
|
||||
b, a *= (a = 4, 3),
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "6"
|
||||
}
|
||||
|
||||
for_sequences: {
|
||||
options = { sequences: true };
|
||||
input: {
|
||||
@@ -230,6 +251,7 @@ negate_iife_for: {
|
||||
for (!function() {}(), i = 0; i < 5; i++) console.log(i);
|
||||
for (function() {}(); i < 5; i++) console.log(i);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
iife: {
|
||||
@@ -284,3 +306,163 @@ unsafe_undefined: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_1685: {
|
||||
options = {
|
||||
cascade: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
function f() {
|
||||
var a = (a--, delete a && --b);
|
||||
}
|
||||
f();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 100, b = 10;
|
||||
function f() {
|
||||
var a = (a--, delete a && --b);
|
||||
}
|
||||
f();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
func_def_1: {
|
||||
options = {
|
||||
cascade: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return f = 0, !!f;
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return !!(f = 0);
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect_stdout: "false"
|
||||
}
|
||||
|
||||
func_def_2: {
|
||||
options = {
|
||||
cascade: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
return f = 0, !!f;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function f() {
|
||||
return f = 0, !!f;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
func_def_3: {
|
||||
options = {
|
||||
cascade: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
function g() {}
|
||||
return g = 0, !!g;
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
function g() {}
|
||||
return !!(g = 0);
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect_stdout: "false"
|
||||
}
|
||||
|
||||
func_def_4: {
|
||||
options = {
|
||||
cascade: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
function g() {
|
||||
return g = 0, !!g;
|
||||
}
|
||||
return g();
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
function g() {
|
||||
return !!(g = 0);
|
||||
}
|
||||
return g();
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect_stdout: "false"
|
||||
}
|
||||
|
||||
func_def_5: {
|
||||
options = {
|
||||
cascade: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
return function g(){
|
||||
return g = 0, !!g;
|
||||
}();
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return function g(){
|
||||
return g = 0, !!g;
|
||||
}();
|
||||
}
|
||||
console.log(f());
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
issue_1758: {
|
||||
options = {
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(c) {
|
||||
var undefined = 42;
|
||||
return function() {
|
||||
c--;
|
||||
c--, c.toString();
|
||||
return;
|
||||
}();
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(function(c) {
|
||||
var undefined = 42;
|
||||
return function() {
|
||||
return c--, c--, c.toString(), void 0;
|
||||
}();
|
||||
}());
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
constant_switch_1: {
|
||||
options = { dead_code: true, evaluate: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (1+1) {
|
||||
case 1: foo(); break;
|
||||
@@ -13,7 +18,12 @@ constant_switch_1: {
|
||||
}
|
||||
|
||||
constant_switch_2: {
|
||||
options = { dead_code: true, evaluate: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (1) {
|
||||
case 1: foo();
|
||||
@@ -28,7 +38,12 @@ constant_switch_2: {
|
||||
}
|
||||
|
||||
constant_switch_3: {
|
||||
options = { dead_code: true, evaluate: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (10) {
|
||||
case 1: foo();
|
||||
@@ -44,7 +59,12 @@ constant_switch_3: {
|
||||
}
|
||||
|
||||
constant_switch_4: {
|
||||
options = { dead_code: true, evaluate: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (2) {
|
||||
case 1:
|
||||
@@ -65,7 +85,12 @@ constant_switch_4: {
|
||||
}
|
||||
|
||||
constant_switch_5: {
|
||||
options = { dead_code: true, evaluate: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (1) {
|
||||
case 1:
|
||||
@@ -94,7 +119,12 @@ constant_switch_5: {
|
||||
}
|
||||
|
||||
constant_switch_6: {
|
||||
options = { dead_code: true, evaluate: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
OUT: {
|
||||
foo();
|
||||
@@ -123,7 +153,12 @@ constant_switch_6: {
|
||||
}
|
||||
|
||||
constant_switch_7: {
|
||||
options = { dead_code: true, evaluate: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
OUT: {
|
||||
foo();
|
||||
@@ -161,7 +196,12 @@ constant_switch_7: {
|
||||
}
|
||||
|
||||
constant_switch_8: {
|
||||
options = { dead_code: true, evaluate: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
OUT: switch (1) {
|
||||
case 1:
|
||||
@@ -185,7 +225,12 @@ constant_switch_8: {
|
||||
}
|
||||
|
||||
constant_switch_9: {
|
||||
options = { dead_code: true, evaluate: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
OUT: switch (1) {
|
||||
case 1:
|
||||
@@ -210,7 +255,10 @@ constant_switch_9: {
|
||||
}
|
||||
|
||||
drop_default_1: {
|
||||
options = { dead_code: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case 'bar': baz();
|
||||
@@ -225,7 +273,10 @@ drop_default_1: {
|
||||
}
|
||||
|
||||
drop_default_2: {
|
||||
options = { dead_code: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case 'bar': baz(); break;
|
||||
@@ -241,7 +292,10 @@ drop_default_2: {
|
||||
}
|
||||
|
||||
keep_default: {
|
||||
options = { dead_code: true };
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case 'bar': baz();
|
||||
@@ -258,3 +312,507 @@ keep_default: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_1663: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
function f() {
|
||||
switch (1) {
|
||||
case 1:
|
||||
b = a++;
|
||||
return ++b;
|
||||
default:
|
||||
var b;
|
||||
}
|
||||
}
|
||||
f();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 100, b = 10;
|
||||
function f() {
|
||||
var b;
|
||||
b = a++;
|
||||
return ++b;
|
||||
}
|
||||
f();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
drop_case: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case 'bar': baz(); break;
|
||||
case 'moo':
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
switch (foo) {
|
||||
case 'bar': baz();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
keep_case: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case 'bar': baz(); break;
|
||||
case moo:
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
switch (foo) {
|
||||
case 'bar': baz(); break;
|
||||
case moo:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_376: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (true) {
|
||||
case boolCondition:
|
||||
console.log(1);
|
||||
break;
|
||||
case false:
|
||||
console.log(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
switch (true) {
|
||||
case boolCondition:
|
||||
console.log(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_441_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case bar:
|
||||
qux();
|
||||
break;
|
||||
case baz:
|
||||
qux();
|
||||
break;
|
||||
default:
|
||||
qux();
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
switch (foo) {
|
||||
case bar:
|
||||
case baz:
|
||||
default:
|
||||
qux();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_441_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (foo) {
|
||||
case bar:
|
||||
// TODO: Fold into the case below
|
||||
qux();
|
||||
break;
|
||||
case fall:
|
||||
case baz:
|
||||
qux();
|
||||
break;
|
||||
default:
|
||||
qux();
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
switch (foo) {
|
||||
case bar:
|
||||
qux();
|
||||
break;
|
||||
case fall:
|
||||
case baz:
|
||||
default:
|
||||
qux();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_1674: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (0) {
|
||||
default:
|
||||
console.log("FAIL");
|
||||
break;
|
||||
case 0:
|
||||
console.log("PASS");
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_1679: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
function f() {
|
||||
switch (--b) {
|
||||
default:
|
||||
case !function x() {}:
|
||||
break;
|
||||
case b--:
|
||||
switch (0) {
|
||||
default:
|
||||
case a--:
|
||||
}
|
||||
break;
|
||||
case (a++):
|
||||
break;
|
||||
}
|
||||
}
|
||||
f();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 100, b = 10;
|
||||
function f() {
|
||||
switch (--b) {
|
||||
default:
|
||||
case !function x() {}:
|
||||
break;
|
||||
case b--:
|
||||
switch (0) {
|
||||
default:
|
||||
case a--:
|
||||
}
|
||||
break;
|
||||
case (a++):
|
||||
}
|
||||
}
|
||||
f();
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1680_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
function f(x) {
|
||||
console.log(x);
|
||||
return x + 1;
|
||||
}
|
||||
switch (2) {
|
||||
case f(0):
|
||||
case f(1):
|
||||
f(2);
|
||||
case 2:
|
||||
case f(3):
|
||||
case f(4):
|
||||
f(5);
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f(x) {
|
||||
console.log(x);
|
||||
return x + 1;
|
||||
}
|
||||
switch (2) {
|
||||
case f(0):
|
||||
case f(1):
|
||||
f(2);
|
||||
case 2:
|
||||
f(5);
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"5",
|
||||
]
|
||||
}
|
||||
|
||||
issue_1680_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100, b = 10;
|
||||
switch (b) {
|
||||
case a--:
|
||||
break;
|
||||
case b:
|
||||
var c;
|
||||
break;
|
||||
case a:
|
||||
break;
|
||||
case a--:
|
||||
break;
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 100, b = 10;
|
||||
switch (b) {
|
||||
case a--:
|
||||
break;
|
||||
case b:
|
||||
var c;
|
||||
break;
|
||||
case a:
|
||||
case a--:
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1690_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (console.log("PASS")) {}
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_1690_2: {
|
||||
options = {
|
||||
dead_code: false,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (console.log("PASS")) {}
|
||||
}
|
||||
expect: {
|
||||
switch (console.log("PASS")) {}
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
if_switch_typeof: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
if (a) switch(typeof b) {}
|
||||
}
|
||||
expect: {
|
||||
a;
|
||||
}
|
||||
}
|
||||
|
||||
issue_1698: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
!function() {
|
||||
switch (a++) {}
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
!function() {
|
||||
switch (a++) {}
|
||||
}();
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
issue_1705_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
switch (a) {
|
||||
default:
|
||||
console.log("FAIL");
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
switch (a) {
|
||||
default:
|
||||
console.log("FAIL");
|
||||
case 0:
|
||||
}
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1705_2: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
switch (a) {
|
||||
default:
|
||||
console.log("FAIL");
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_1705_3: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
switch (a) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
a;
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
beautify: {
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
input: {
|
||||
switch (a) {
|
||||
case 0:
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
}
|
||||
switch (b) {
|
||||
case 3:
|
||||
foo();
|
||||
bar();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
expect_exact: [
|
||||
"switch (a) {",
|
||||
" case 0:",
|
||||
" case 1:",
|
||||
" break;",
|
||||
"",
|
||||
" case 2:",
|
||||
" default:",
|
||||
"}",
|
||||
"",
|
||||
"switch (b) {",
|
||||
" case 3:",
|
||||
" foo();",
|
||||
" bar();",
|
||||
"",
|
||||
" default:",
|
||||
" break;",
|
||||
"}",
|
||||
]
|
||||
}
|
||||
|
||||
issue_1758: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
switches: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1, b = 2;
|
||||
switch (a--) {
|
||||
default:
|
||||
b++;
|
||||
}
|
||||
console.log(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a = 1, b = 2;
|
||||
a--;
|
||||
b++;
|
||||
console.log(a, b);
|
||||
}
|
||||
expect_stdout: "0 3"
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ booleans_evaluate: {
|
||||
console.log(!0, !0);
|
||||
console.log(!1, !1);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
booleans_global_defs: {
|
||||
|
||||
@@ -48,3 +48,15 @@ typeof_in_boolean_context: {
|
||||
foo();
|
||||
}
|
||||
}
|
||||
|
||||
issue_1668: {
|
||||
options = {
|
||||
booleans: true,
|
||||
}
|
||||
input: {
|
||||
if (typeof bar);
|
||||
}
|
||||
expect: {
|
||||
if (!0);
|
||||
}
|
||||
}
|
||||
|
||||
1
test/input/invalid/assign_1.js
Normal file
1
test/input/invalid/assign_1.js
Normal file
@@ -0,0 +1 @@
|
||||
console.log(1 || 5--);
|
||||
1
test/input/invalid/assign_2.js
Normal file
1
test/input/invalid/assign_2.js
Normal file
@@ -0,0 +1 @@
|
||||
console.log(2 || (Math.random() /= 2));
|
||||
1
test/input/invalid/assign_3.js
Normal file
1
test/input/invalid/assign_3.js
Normal file
@@ -0,0 +1 @@
|
||||
console.log(3 || ++this);
|
||||
1
test/input/issue-1632/^{foo}[bar](baz)+$.js
Normal file
1
test/input/issue-1632/^{foo}[bar](baz)+$.js
Normal file
@@ -0,0 +1 @@
|
||||
console.log(x);
|
||||
@@ -251,4 +251,59 @@ describe("bin/uglifyjs", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should support hyphen as shorthand", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep-fnames=true';
|
||||
|
||||
exec(command, function (err, stdout) {
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (5--)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
|
||||
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||
"Parse error at test/input/invalid/assign_1.js:1,18",
|
||||
"console.log(1 || 5--);",
|
||||
" ^",
|
||||
"SyntaxError: Invalid use of -- operator"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (Math.random() /= 2)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
|
||||
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||
"Parse error at test/input/invalid/assign_2.js:1,32",
|
||||
"console.log(2 || (Math.random() /= 2));",
|
||||
" ^",
|
||||
"SyntaxError: Invalid assignment"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (++this)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
|
||||
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||
"Parse error at test/input/invalid/assign_3.js:1,18",
|
||||
"console.log(3 || ++this);",
|
||||
" ^",
|
||||
"SyntaxError: Invalid use of ++ operator"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -79,5 +79,13 @@ describe("comment filters", function() {
|
||||
output: { preamble: "/* Build */" }
|
||||
}).code;
|
||||
assert.strictEqual(code, "#!/usr/bin/node\n/* Build */\nvar x=10;");
|
||||
})
|
||||
});
|
||||
|
||||
it("Should handle preamble without shebang correctly", function() {
|
||||
var code = UglifyJS.minify("var x = 10;", {
|
||||
fromString: true,
|
||||
output: { preamble: "/* Build */" }
|
||||
}).code;
|
||||
assert.strictEqual(code, "/* Build */\nvar x=10;");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -176,7 +176,7 @@ describe("Directives", function() {
|
||||
});
|
||||
|
||||
it("Should test EXPECT_DIRECTIVE RegExp", function() {
|
||||
var tests = [
|
||||
[
|
||||
["", true],
|
||||
["'test';", true],
|
||||
["'test';;", true],
|
||||
@@ -185,11 +185,12 @@ describe("Directives", function() {
|
||||
["'tests'; \n\t", true],
|
||||
["'tests';\n\n", true],
|
||||
["\n\n\"use strict\";\n\n", true]
|
||||
];
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.strictEqual(uglify.EXPECT_DIRECTIVE.test(tests[i][0]), tests[i][1], tests[i][0]);
|
||||
}
|
||||
].forEach(function(test) {
|
||||
var out = uglify.OutputStream();
|
||||
out.print(test[0]);
|
||||
out.print_string("", null, true);
|
||||
assert.strictEqual(out.get() === test[0] + ';""', test[1], test[0]);
|
||||
});
|
||||
});
|
||||
|
||||
it("Should only print 2 semicolons spread over 2 lines in beautify mode", function() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var Uglify = require('../../');
|
||||
var assert = require("assert");
|
||||
var path = require("path");
|
||||
|
||||
describe("minify() with input file globs", function() {
|
||||
it("minify() with one input file glob string.", function() {
|
||||
@@ -19,6 +20,39 @@ describe("minify() with input file globs", function() {
|
||||
], {
|
||||
compress: { toplevel: true }
|
||||
});
|
||||
assert.strictEqual(result.code, 'var print=console.log.bind(console);print("qux",function(n){return 3*n}(3),function(n){return n/2}(12)),function(n){print("Foo:",2*n)}(11);');
|
||||
assert.strictEqual(result.code, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){print("Foo:",2*n)}(11);');
|
||||
});
|
||||
it("should throw with non-matching glob string", function() {
|
||||
var glob = "test/input/issue-1242/blah.*";
|
||||
assert.strictEqual(Uglify.simple_glob(glob).length, 1);
|
||||
assert.strictEqual(Uglify.simple_glob(glob)[0], glob);
|
||||
assert.throws(function() {
|
||||
Uglify.minify(glob);
|
||||
}, "should throw file not found");
|
||||
});
|
||||
it('"?" in glob string should not match "/"', function() {
|
||||
var glob = "test/input?issue-1242/foo.*";
|
||||
assert.strictEqual(Uglify.simple_glob(glob).length, 1);
|
||||
assert.strictEqual(Uglify.simple_glob(glob)[0], glob);
|
||||
assert.throws(function() {
|
||||
Uglify.minify(glob);
|
||||
}, "should throw file not found");
|
||||
});
|
||||
it("should handle special characters in glob string", function() {
|
||||
var result = Uglify.minify("test/input/issue-1632/^{*}[???](*)+$.??");
|
||||
assert.strictEqual(result.code, "console.log(x);");
|
||||
});
|
||||
it("should handle array of glob strings - matching and otherwise", function() {
|
||||
var dir = "test/input/issue-1242";
|
||||
var matches = Uglify.simple_glob([
|
||||
path.join(dir, "b*.es5"),
|
||||
path.join(dir, "z*.es5"),
|
||||
path.join(dir, "*.js"),
|
||||
]);
|
||||
assert.strictEqual(matches.length, 4);
|
||||
assert.strictEqual(matches[0], path.join(dir, "bar.es5"));
|
||||
assert.strictEqual(matches[1], path.join(dir, "baz.es5"));
|
||||
assert.strictEqual(matches[2], path.join(dir, "z*.es5"));
|
||||
assert.strictEqual(matches[3], path.join(dir, "qux.js"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ var UglifyJS = require(".."),
|
||||
escodegen = require("escodegen"),
|
||||
esfuzz = require("esfuzz"),
|
||||
estraverse = require("estraverse"),
|
||||
prefix = Array(20).join("\b") + " ";
|
||||
prefix = "\r ";
|
||||
|
||||
// Normalizes input AST for UglifyJS in order to get correct comparison.
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
global.UGLIFY_DEBUG = true;
|
||||
|
||||
var U = require("../tools/node");
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var assert = require("assert");
|
||||
var vm = require("vm");
|
||||
var sandbox = require("./sandbox");
|
||||
|
||||
var tests_dir = path.dirname(module.filename);
|
||||
var failures = 0;
|
||||
@@ -72,10 +70,15 @@ function test_directory(dir) {
|
||||
}
|
||||
|
||||
function as_toplevel(input, mangle_options) {
|
||||
if (input instanceof U.AST_BlockStatement) input = input.body;
|
||||
else if (input instanceof U.AST_Statement) input = [ input ];
|
||||
else throw new Error("Unsupported input syntax");
|
||||
var toplevel = new U.AST_Toplevel({ body: input });
|
||||
if (!(input instanceof U.AST_BlockStatement))
|
||||
throw new Error("Unsupported input syntax");
|
||||
for (var i = 0; i < input.body.length; i++) {
|
||||
var stat = input.body[i];
|
||||
if (stat instanceof U.AST_SimpleStatement && stat.body instanceof U.AST_String)
|
||||
input.body[i] = new U.AST_Directive(stat.body);
|
||||
else break;
|
||||
}
|
||||
var toplevel = new U.AST_Toplevel(input);
|
||||
toplevel.figure_out_scope(mangle_options);
|
||||
return toplevel;
|
||||
}
|
||||
@@ -89,6 +92,23 @@ function run_compress_tests() {
|
||||
function test_case(test) {
|
||||
log_test(test.name);
|
||||
U.base54.reset();
|
||||
var output_options = test.beautify || {};
|
||||
var expect;
|
||||
if (test.expect) {
|
||||
expect = make_code(as_toplevel(test.expect, test.mangle), output_options);
|
||||
} else {
|
||||
expect = test.expect_exact;
|
||||
}
|
||||
var input = as_toplevel(test.input, test.mangle);
|
||||
var input_code = make_code(input, output_options);
|
||||
var input_formatted = make_code(test.input, {
|
||||
beautify: true,
|
||||
quote_style: 3,
|
||||
keep_quoted_props: true
|
||||
});
|
||||
if (test.mangle_props) {
|
||||
input = U.mangle_properties(input, test.mangle_props);
|
||||
}
|
||||
var options = U.defaults(test.options, {
|
||||
warnings: false
|
||||
});
|
||||
@@ -98,25 +118,9 @@ function run_compress_tests() {
|
||||
U.AST_Node.warn_function = function(text) {
|
||||
warnings_emitted.push("WARN: " + text);
|
||||
};
|
||||
options.warnings = true;
|
||||
if (!options.warnings) options.warnings = true;
|
||||
}
|
||||
var cmp = new U.Compressor(options, true);
|
||||
var output_options = test.beautify || {};
|
||||
var expect;
|
||||
if (test.expect) {
|
||||
expect = make_code(as_toplevel(test.expect, test.mangle), output_options);
|
||||
} else {
|
||||
expect = test.expect_exact;
|
||||
}
|
||||
var input = as_toplevel(test.input, test.mangle);
|
||||
var input_code = make_code(test.input, {
|
||||
beautify: true,
|
||||
quote_style: 3,
|
||||
keep_quoted_props: true
|
||||
});
|
||||
if (test.mangle_props) {
|
||||
input = U.mangle_properties(input, test.mangle_props);
|
||||
}
|
||||
var output = cmp.compress(input);
|
||||
output.figure_out_scope(test.mangle);
|
||||
if (test.mangle) {
|
||||
@@ -126,7 +130,7 @@ function run_compress_tests() {
|
||||
output = make_code(output, output_options);
|
||||
if (expect != output) {
|
||||
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
|
||||
input: input_code,
|
||||
input: input_formatted,
|
||||
output: output,
|
||||
expected: expect
|
||||
});
|
||||
@@ -139,7 +143,7 @@ function run_compress_tests() {
|
||||
var reparsed_ast = U.parse(output);
|
||||
} catch (ex) {
|
||||
log("!!! Test matched expected result but cannot parse output\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n--REPARSE ERROR--\n{error}\n\n", {
|
||||
input: input_code,
|
||||
input: input_formatted,
|
||||
output: output,
|
||||
error: ex.toString(),
|
||||
});
|
||||
@@ -158,7 +162,7 @@ function run_compress_tests() {
|
||||
var actual_warnings = JSON.stringify(warnings_emitted);
|
||||
if (expected_warnings != actual_warnings) {
|
||||
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED WARNINGS---\n{expected_warnings}\n---ACTUAL WARNINGS---\n{actual_warnings}\n\n", {
|
||||
input: input_code,
|
||||
input: input_formatted,
|
||||
expected_warnings: expected_warnings,
|
||||
actual_warnings: actual_warnings,
|
||||
});
|
||||
@@ -167,48 +171,33 @@ function run_compress_tests() {
|
||||
}
|
||||
}
|
||||
if (test.expect_stdout) {
|
||||
try {
|
||||
var stdout = run_code(input_code);
|
||||
var stdout = sandbox.run_code(input_code);
|
||||
if (test.expect_stdout === true) {
|
||||
test.expect_stdout = stdout;
|
||||
}
|
||||
if (test.expect_stdout != stdout) {
|
||||
log("!!! Invalid input or expected stdout\n---INPUT---\n{input}\n---EXPECTED STDOUT---\n{expected}\n---ACTUAL STDOUT---\n{actual}\n\n", {
|
||||
input: input_code,
|
||||
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
|
||||
log("!!! Invalid input or expected stdout\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||
input: input_formatted,
|
||||
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
|
||||
expected: test.expect_stdout,
|
||||
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
||||
actual: stdout,
|
||||
});
|
||||
failures++;
|
||||
failed_files[file] = 1;
|
||||
} else {
|
||||
try {
|
||||
stdout = run_code(output);
|
||||
if (test.expect_stdout != stdout) {
|
||||
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED STDOUT---\n{expected}\n---ACTUAL STDOUT---\n{actual}\n\n", {
|
||||
input: input_code,
|
||||
stdout = sandbox.run_code(output);
|
||||
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
|
||||
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||
input: input_formatted,
|
||||
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
|
||||
expected: test.expect_stdout,
|
||||
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
||||
actual: stdout,
|
||||
});
|
||||
failures++;
|
||||
failed_files[file] = 1;
|
||||
}
|
||||
} catch (ex) {
|
||||
log("!!! Execution of output failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n--ERROR--\n{error}\n\n", {
|
||||
input: input_code,
|
||||
output: output,
|
||||
error: ex.toString(),
|
||||
});
|
||||
failures++;
|
||||
failed_files[file] = 1;
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
log("!!! Execution of input failed\n---INPUT---\n{input}\n--ERROR--\n{error}\n\n", {
|
||||
input: input_code,
|
||||
error: ex.toString(),
|
||||
});
|
||||
failures++;
|
||||
failed_files[file] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,10 +288,6 @@ function parse_test(file) {
|
||||
})
|
||||
);
|
||||
var stat = node.body;
|
||||
if (stat instanceof U.AST_BlockStatement) {
|
||||
if (stat.body.length == 1) stat = stat.body[0];
|
||||
else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
|
||||
}
|
||||
if (label.name == "expect_exact") {
|
||||
test[label.name] = read_string(stat);
|
||||
} else if (label.name == "expect_stdout") {
|
||||
@@ -334,17 +319,3 @@ function evaluate(code) {
|
||||
code = make_code(code, { beautify: true });
|
||||
return new Function("return(" + code + ")")();
|
||||
}
|
||||
|
||||
function run_code(code) {
|
||||
var stdout = "";
|
||||
var original_write = process.stdout.write;
|
||||
process.stdout.write = function(chunk) {
|
||||
stdout += chunk;
|
||||
};
|
||||
try {
|
||||
new vm.Script(code).runInNewContext({ console: console }, { timeout: 5000 });
|
||||
return stdout;
|
||||
} finally {
|
||||
process.stdout.write = original_write;
|
||||
}
|
||||
}
|
||||
|
||||
50
test/sandbox.js
Normal file
50
test/sandbox.js
Normal file
@@ -0,0 +1,50 @@
|
||||
var vm = require("vm");
|
||||
|
||||
var FUNC_TOSTRING = [
|
||||
"Function.prototype.toString = Function.prototype.valueOf = function() {",
|
||||
" var ids = [];",
|
||||
" return function() {",
|
||||
" var i = ids.indexOf(this);",
|
||||
" if (i < 0) {",
|
||||
" i = ids.length;",
|
||||
" ids.push(this);",
|
||||
" }",
|
||||
' return "[Function: __func_" + i + "__]";',
|
||||
" }",
|
||||
"}();",
|
||||
""
|
||||
].join("\n");
|
||||
exports.run_code = function(code) {
|
||||
var stdout = "";
|
||||
var original_write = process.stdout.write;
|
||||
process.stdout.write = function(chunk) {
|
||||
stdout += chunk;
|
||||
};
|
||||
try {
|
||||
new vm.Script(FUNC_TOSTRING + code).runInNewContext({
|
||||
console: {
|
||||
log: function() {
|
||||
return console.log.apply(console, [].map.call(arguments, function(arg) {
|
||||
return typeof arg == "function" ? arg.toString() : arg;
|
||||
}));
|
||||
}
|
||||
}
|
||||
}, { timeout: 30000 });
|
||||
return stdout;
|
||||
} catch (ex) {
|
||||
return ex;
|
||||
} finally {
|
||||
process.stdout.write = original_write;
|
||||
}
|
||||
};
|
||||
exports.same_stdout = ~process.version.lastIndexOf("v0.12.", 0) ? function(expected, actual) {
|
||||
if (typeof expected != typeof actual) return false;
|
||||
if (typeof expected != "string") {
|
||||
if (expected.name != actual.name) return false;
|
||||
expected = expected.message.slice(expected.message.lastIndexOf("\n") + 1);
|
||||
actual = actual.message.slice(actual.message.lastIndexOf("\n") + 1);
|
||||
}
|
||||
return expected == actual;
|
||||
} : function(expected, actual) {
|
||||
return typeof expected == typeof actual && expected.toString() == actual.toString();
|
||||
};
|
||||
760
test/ufuzz.js
Normal file
760
test/ufuzz.js
Normal file
@@ -0,0 +1,760 @@
|
||||
// ufuzz.js
|
||||
// derived from https://github.com/qfox/uglyfuzzer by Peter van der Zee
|
||||
"use strict";
|
||||
|
||||
// check both cli and file modes of nodejs (!). See #1695 for details. and the various settings of uglify.
|
||||
// bin/uglifyjs s.js -c && bin/uglifyjs s.js -c passes=3 && bin/uglifyjs s.js -c passes=3 -m
|
||||
// cat s.js | node && node s.js && bin/uglifyjs s.js -c | node && bin/uglifyjs s.js -c passes=3 | node && bin/uglifyjs s.js -c passes=3 -m | node
|
||||
|
||||
// workaround for tty output truncation upon process.exit()
|
||||
[process.stdout, process.stderr].forEach(function(stream){
|
||||
if (stream._handle && stream._handle.setBlocking)
|
||||
stream._handle.setBlocking(true);
|
||||
});
|
||||
|
||||
var UglifyJS = require("..");
|
||||
var randomBytes = require("crypto").randomBytes;
|
||||
var sandbox = require("./sandbox");
|
||||
|
||||
var MAX_GENERATED_TOPLEVELS_PER_RUN = 1;
|
||||
var MAX_GENERATION_RECURSION_DEPTH = 12;
|
||||
var INTERVAL_COUNT = 100;
|
||||
|
||||
var STMT_BLOCK = 0;
|
||||
var STMT_IF_ELSE = 1;
|
||||
var STMT_DO_WHILE = 2;
|
||||
var STMT_WHILE = 3;
|
||||
var STMT_FOR_LOOP = 4;
|
||||
var STMT_SEMI = 5;
|
||||
var STMT_EXPR = 6;
|
||||
var STMT_SWITCH = 7;
|
||||
var STMT_VAR = 8;
|
||||
var STMT_RETURN_ETC = 9;
|
||||
var STMT_FUNC_EXPR = 10;
|
||||
var STMT_TRY = 11;
|
||||
var STMT_C = 12;
|
||||
var STMTS_TO_USE = [
|
||||
STMT_BLOCK,
|
||||
STMT_IF_ELSE,
|
||||
STMT_DO_WHILE,
|
||||
STMT_WHILE,
|
||||
STMT_FOR_LOOP,
|
||||
STMT_SEMI,
|
||||
STMT_EXPR,
|
||||
STMT_SWITCH,
|
||||
STMT_VAR,
|
||||
STMT_RETURN_ETC,
|
||||
STMT_FUNC_EXPR,
|
||||
STMT_TRY,
|
||||
STMT_C,
|
||||
];
|
||||
var STMT_ARG_TO_ID = {
|
||||
block: STMT_BLOCK,
|
||||
ifelse: STMT_IF_ELSE,
|
||||
dowhile: STMT_DO_WHILE,
|
||||
while: STMT_WHILE,
|
||||
forloop: STMT_FOR_LOOP,
|
||||
semi: STMT_SEMI,
|
||||
expr: STMT_EXPR,
|
||||
switch: STMT_SWITCH,
|
||||
var: STMT_VAR,
|
||||
stop: STMT_RETURN_ETC,
|
||||
funcexpr: STMT_FUNC_EXPR,
|
||||
try: STMT_TRY,
|
||||
c: STMT_C,
|
||||
};
|
||||
|
||||
var STMT_FIRST_LEVEL_OVERRIDE = -1;
|
||||
var STMT_SECOND_LEVEL_OVERRIDE = -1;
|
||||
var STMT_COUNT_FROM_GLOBAL = true; // count statement depth from nearest function scope or just global scope?
|
||||
|
||||
var num_iterations = +process.argv[2] || 1/0;
|
||||
var verbose = false; // log every generated test
|
||||
var verbose_interval = false; // log every 100 generated tests
|
||||
for (var i = 2; i < process.argv.length; ++i) {
|
||||
switch (process.argv[i]) {
|
||||
case '-v':
|
||||
verbose = true;
|
||||
break;
|
||||
case '-V':
|
||||
verbose_interval = true;
|
||||
break;
|
||||
case '-t':
|
||||
MAX_GENERATED_TOPLEVELS_PER_RUN = +process.argv[++i];
|
||||
if (!MAX_GENERATED_TOPLEVELS_PER_RUN) throw new Error('Must generate at least one toplevel per run');
|
||||
break;
|
||||
case '-r':
|
||||
MAX_GENERATION_RECURSION_DEPTH = +process.argv[++i];
|
||||
if (!MAX_GENERATION_RECURSION_DEPTH) throw new Error('Recursion depth must be at least 1');
|
||||
break;
|
||||
case '-s1':
|
||||
var name = process.argv[++i];
|
||||
STMT_FIRST_LEVEL_OVERRIDE = STMT_ARG_TO_ID[name];
|
||||
if (!(STMT_FIRST_LEVEL_OVERRIDE >= 0)) throw new Error('Unknown statement name; use -? to get a list');
|
||||
break;
|
||||
case '-s2':
|
||||
var name = process.argv[++i];
|
||||
STMT_SECOND_LEVEL_OVERRIDE = STMT_ARG_TO_ID[name];
|
||||
if (!(STMT_SECOND_LEVEL_OVERRIDE >= 0)) throw new Error('Unknown statement name; use -? to get a list');
|
||||
break;
|
||||
case '--stmt-depth-from-func':
|
||||
STMT_COUNT_FROM_GLOBAL = false;
|
||||
break;
|
||||
case '--only-stmt':
|
||||
STMTS_TO_USE = process.argv[++i].split(',').map(function(name){ return STMT_ARG_TO_ID[name]; });
|
||||
break;
|
||||
case '--without-stmt':
|
||||
// meh. it runs once it's fine.
|
||||
process.argv[++i].split(',').forEach(function(name){
|
||||
var omit = STMT_ARG_TO_ID[name];
|
||||
STMTS_TO_USE = STMTS_TO_USE.filter(function(id){ return id !== omit; })
|
||||
});
|
||||
break;
|
||||
case '--help':
|
||||
case '-h':
|
||||
case '-?':
|
||||
console.log('** UglifyJS fuzzer help **');
|
||||
console.log('Valid options (optional):');
|
||||
console.log('<number>: generate this many cases (if used must be first arg)');
|
||||
console.log('-v: print every generated test case');
|
||||
console.log('-V: print every 100th generated test case');
|
||||
console.log('-t <int>: generate this many toplevels per run (more take longer)');
|
||||
console.log('-r <int>: maximum recursion depth for generator (higher takes longer)');
|
||||
console.log('-s1 <statement name>: force the first level statement to be this one (see list below)');
|
||||
console.log('-s2 <statement name>: force the second level statement to be this one (see list below)');
|
||||
console.log('--stmt-depth-from-func: reset statement depth counter at each function, counts from global otherwise');
|
||||
console.log('--only-stmt <statement names>: a comma delimited white list of statements that may be generated');
|
||||
console.log('--without-stmt <statement names>: a comma delimited black list of statements never to generate');
|
||||
console.log('List of accepted statement names: ' + Object.keys(STMT_ARG_TO_ID));
|
||||
console.log('** UglifyJS fuzzer exiting **');
|
||||
return 0;
|
||||
default:
|
||||
// first arg may be a number.
|
||||
if (i > 2 || !parseInt(process.argv[i], 10)) throw new Error('Unknown argument[' + process.argv[i] + ']; see -h for help');
|
||||
}
|
||||
}
|
||||
|
||||
var VALUES = [
|
||||
'true',
|
||||
'false',
|
||||
' /[a2][^e]+$/ ',
|
||||
'(-1)',
|
||||
'(-2)',
|
||||
'(-3)',
|
||||
'(-4)',
|
||||
'(-5)',
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'22',
|
||||
'-0', // 0/-0 !== 0
|
||||
'23..toString()',
|
||||
'24 .toString()',
|
||||
'25. ',
|
||||
'0x26.toString()',
|
||||
'NaN',
|
||||
'undefined',
|
||||
'Infinity',
|
||||
'null',
|
||||
'[]',
|
||||
'[,0][1]', // an array with elisions... but this is always false
|
||||
'([,0].length === 2)', // an array with elisions... this is always true
|
||||
'({})', // wrapped the object causes too many syntax errors in statements
|
||||
'"foo"',
|
||||
'"bar"',
|
||||
'"undefined"',
|
||||
'"object"',
|
||||
'"number"',
|
||||
'"function"',
|
||||
];
|
||||
|
||||
var BINARY_OPS_NO_COMMA = [
|
||||
' + ', // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors)
|
||||
' - ',
|
||||
'/',
|
||||
'*',
|
||||
'&',
|
||||
'|',
|
||||
'^',
|
||||
'<',
|
||||
'<=',
|
||||
'>',
|
||||
'>=',
|
||||
'==',
|
||||
'===',
|
||||
'!=',
|
||||
'!==',
|
||||
'<<',
|
||||
'>>',
|
||||
'>>>',
|
||||
'%',
|
||||
'&&',
|
||||
'||',
|
||||
'^' ];
|
||||
|
||||
var BINARY_OPS = [','].concat(BINARY_OPS_NO_COMMA);
|
||||
|
||||
var ASSIGNMENTS = [
|
||||
'=',
|
||||
'=',
|
||||
'=',
|
||||
'=',
|
||||
'=',
|
||||
'=',
|
||||
|
||||
'==',
|
||||
'!=',
|
||||
'===',
|
||||
'!==',
|
||||
'+=',
|
||||
'-=',
|
||||
'*=',
|
||||
'/=',
|
||||
'&=',
|
||||
'|=',
|
||||
'^=',
|
||||
'<<=',
|
||||
'>>=',
|
||||
'>>>=',
|
||||
'%=' ];
|
||||
|
||||
var UNARY_OPS = [
|
||||
'--',
|
||||
'++',
|
||||
'~',
|
||||
'!',
|
||||
'void ',
|
||||
'delete ', // should be safe, even `delete foo` and `delete f()` shouldn't crash
|
||||
' - ',
|
||||
' + ' ];
|
||||
|
||||
var NO_COMMA = true;
|
||||
var COMMA_OK = false;
|
||||
var MAYBE = true;
|
||||
var MANDATORY = false;
|
||||
var CAN_THROW = true;
|
||||
var CANNOT_THROW = false;
|
||||
var CAN_BREAK = true;
|
||||
var CANNOT_BREAK = false;
|
||||
var CAN_CONTINUE = true;
|
||||
var CANNOT_CONTINUE = false;
|
||||
var CAN_RETURN = false;
|
||||
var CANNOT_RETURN = true;
|
||||
var NOT_GLOBAL = true;
|
||||
var IN_GLOBAL = true;
|
||||
var ANY_TYPE = false;
|
||||
var NO_DECL = true;
|
||||
var DONT_STORE = true;
|
||||
|
||||
var VAR_NAMES = [
|
||||
'foo',
|
||||
'bar',
|
||||
'a',
|
||||
'b',
|
||||
'c', // prevent redeclaring this, avoid assigning to this
|
||||
'undefined', // fun!
|
||||
'eval', // mmmm, ok, also fun!
|
||||
'NaN', // mmmm, ok, also fun!
|
||||
'Infinity', // the fun never ends!
|
||||
'arguments', // this one is just creepy
|
||||
'Math', // since Math is assumed to be a non-constructor/function it may trip certain cases
|
||||
'parseInt',
|
||||
'parseFloat',
|
||||
'isNaN',
|
||||
'isFinite',
|
||||
'decodeURI',
|
||||
'decodeURIComponent',
|
||||
'encodeURI',
|
||||
'encodeURIComponent',
|
||||
'Object'];
|
||||
var INITIAL_NAMES_LEN = VAR_NAMES.length;
|
||||
|
||||
var TYPEOF_OUTCOMES = [
|
||||
'function',
|
||||
'undefined',
|
||||
'string',
|
||||
'number',
|
||||
'object',
|
||||
'boolean',
|
||||
'special',
|
||||
'unknown',
|
||||
'symbol',
|
||||
'crap' ];
|
||||
|
||||
var loops = 0;
|
||||
var funcs = 0;
|
||||
|
||||
function rng(max) {
|
||||
var r = randomBytes(2).readUInt16LE(0) / 65536;
|
||||
return Math.floor(max * r);
|
||||
}
|
||||
|
||||
function createTopLevelCode() {
|
||||
if (rng(2) === 0) return createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0);
|
||||
return createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, IN_GLOBAL, ANY_TYPE, CANNOT_THROW, 0);
|
||||
}
|
||||
|
||||
function createFunctions(n, recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
|
||||
if (--recurmax < 0) { return ';'; }
|
||||
var s = '';
|
||||
while (n-- > 0) {
|
||||
s += createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) + '\n';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
|
||||
if (--recurmax < 0) { return ';'; }
|
||||
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
||||
var func = funcs++;
|
||||
var namesLenBefore = VAR_NAMES.length;
|
||||
var name = (inGlobal || rng(5) > 0) ? 'f' + func : createVarName(MANDATORY, noDecl);
|
||||
if (name === 'a' || name === 'b' || name === 'c') name = 'f' + func; // quick hack to prevent assignment to func names of being called
|
||||
var s = '';
|
||||
if (rng(5) === 0) {
|
||||
// functions with functions. lower the recursion to prevent a mess.
|
||||
s = 'function ' + name + '(' + createVarName(MANDATORY) + '){' + createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), NOT_GLOBAL, ANY_TYPE, canThrow, stmtDepth) + '}\n';
|
||||
} else {
|
||||
// functions with statements
|
||||
s = 'function ' + name + '(' + createVarName(MANDATORY) + '){' + createStatements(3, recurmax, canThrow, CANNOT_THROW, CANNOT_CONTINUE, CAN_RETURN, stmtDepth) + '}\n';
|
||||
}
|
||||
|
||||
VAR_NAMES.length = namesLenBefore;
|
||||
|
||||
if (noDecl) s = '!' + s + '(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ')';
|
||||
// avoid "function statements" (decl inside statements)
|
||||
else if (inGlobal || rng(10) > 0) s += name + '();'
|
||||
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
||||
if (--recurmax < 0) { return ';'; }
|
||||
var s = '';
|
||||
while (--n > 0) {
|
||||
s += createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + '\n';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
||||
++stmtDepth;
|
||||
var loop = ++loops;
|
||||
if (--recurmax < 0) {
|
||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ';';
|
||||
}
|
||||
|
||||
// allow to forcefully generate certain structures at first or second recursion level
|
||||
var target = 0;
|
||||
if (stmtDepth === 1 && STMT_FIRST_LEVEL_OVERRIDE >= 0) target = STMT_FIRST_LEVEL_OVERRIDE;
|
||||
else if (stmtDepth === 2 && STMT_SECOND_LEVEL_OVERRIDE >= 0) target = STMT_SECOND_LEVEL_OVERRIDE;
|
||||
else target = STMTS_TO_USE[rng(STMTS_TO_USE.length)];
|
||||
|
||||
switch (target) {
|
||||
case STMT_BLOCK:
|
||||
return '{' + createStatements(rng(5) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + '}';
|
||||
case STMT_IF_ELSE:
|
||||
return 'if (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ')' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + (rng(2) === 1 ? ' else ' + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) : '');
|
||||
case STMT_DO_WHILE:
|
||||
return '{var brake' + loop + ' = 5; do {' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE, cannotReturn, stmtDepth) + '} while ((' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && --brake' + loop + ' > 0);}';
|
||||
case STMT_WHILE:
|
||||
return '{var brake' + loop + ' = 5; while ((' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && --brake' + loop + ' > 0)' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE, cannotReturn, stmtDepth) + '}';
|
||||
case STMT_FOR_LOOP:
|
||||
return 'for (var brake' + loop + ' = 5; (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ') && brake' + loop + ' > 0; --brake' + loop + ')' + createStatement(recurmax, canThrow, CAN_BREAK, CAN_CONTINUE, cannotReturn, stmtDepth);
|
||||
case STMT_SEMI:
|
||||
return ';';
|
||||
case STMT_EXPR:
|
||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ';';
|
||||
case STMT_SWITCH:
|
||||
// note: case args are actual expressions
|
||||
// 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)) {
|
||||
case 0:
|
||||
var name = createVarName(MANDATORY);
|
||||
if (name === 'c') name = 'a';
|
||||
return 'var ' + name + ';';
|
||||
case 1:
|
||||
// initializer can only have one expression
|
||||
var name = createVarName(MANDATORY);
|
||||
if (name === 'c') name = 'b';
|
||||
return 'var ' + name + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
|
||||
default:
|
||||
// initializer can only have one expression
|
||||
var n1 = createVarName(MANDATORY);
|
||||
if (n1 === 'c') n1 = 'b';
|
||||
var n2 = createVarName(MANDATORY);
|
||||
if (n2 === 'c') n2 = 'b';
|
||||
return 'var ' + n1 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ', ' + n2 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
|
||||
}
|
||||
case STMT_RETURN_ETC:
|
||||
switch (rng(3)) {
|
||||
case 1:
|
||||
if (canBreak && rng(5) === 0) return 'break;';
|
||||
if (canContinue && rng(5) === 0) return 'continue;';
|
||||
if (cannotReturn) return createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
|
||||
return '/*3*/return;';
|
||||
case 2:
|
||||
// must wrap in curlies to prevent orphaned `else` statement
|
||||
if (canThrow && rng(5) === 0) return '{ throw ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + '}';
|
||||
if (cannotReturn) return createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
|
||||
return '{ /*1*/ return ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + '}';
|
||||
default:
|
||||
// this is actually more like a parser test, but perhaps it hits some dead code elimination traps
|
||||
// must wrap in curlies to prevent orphaned `else` statement
|
||||
// note: you can't `throw` without an expression so don't put a `throw` option in this case
|
||||
if (cannotReturn) return createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
|
||||
return '{ /*2*/ return\n' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + '}';
|
||||
}
|
||||
case STMT_FUNC_EXPR:
|
||||
// "In non-strict mode code, functions can only be declared at top level, inside a block, or ..."
|
||||
// (dont both with func decls in `if`; it's only a parser thing because you cant call them without a block)
|
||||
return '{' + createFunction(recurmax, NOT_GLOBAL, NO_DECL, canThrow, stmtDepth) + '}';
|
||||
case STMT_TRY:
|
||||
// catch var could cause some problems
|
||||
// note: the "blocks" are syntactically mandatory for try/catch/finally
|
||||
var n = rng(3); // 0=only catch, 1=only finally, 2=catch+finally
|
||||
var s = 'try {' + createStatement(recurmax, n === 1 ? CANNOT_THROW : CAN_THROW, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
|
||||
if (n !== 1) {
|
||||
// the catch var should only be accessible in the catch clause...
|
||||
// we have to do go through some trouble here to prevent leaking it
|
||||
var nameLenBefore = VAR_NAMES.length;
|
||||
var catchName = createVarName(MANDATORY);
|
||||
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
|
||||
s += ' catch (' + catchName + ') { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
|
||||
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1); // remove catch name
|
||||
}
|
||||
if (n !== 0) s += ' finally { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
|
||||
return s;
|
||||
case STMT_C:
|
||||
return 'c = c + 1;';
|
||||
default:
|
||||
throw 'no';
|
||||
}
|
||||
}
|
||||
|
||||
function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
||||
var hadDefault = false;
|
||||
var s = '';
|
||||
while (n-- > 0) {
|
||||
//hadDefault = n > 0; // disables weird `default` clause positioning (use when handling destabilizes)
|
||||
if (hadDefault || rng(5) > 0) {
|
||||
s += '' +
|
||||
'case ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ':\n' +
|
||||
createStatements(rng(3) + 1, recurmax, canThrow, CAN_BREAK, canContinue, cannotReturn, stmtDepth) +
|
||||
'\n' +
|
||||
(rng(10) > 0 ? ' break;' : '/* fall-through */') +
|
||||
'\n';
|
||||
} else {
|
||||
hadDefault = true;
|
||||
s += '' +
|
||||
'default:\n' +
|
||||
createStatements(rng(3) + 1, recurmax, canThrow, CAN_BREAK, canContinue, cannotReturn, stmtDepth) +
|
||||
'\n';
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
if (--recurmax < 0) {
|
||||
return '(c = 1 + c, ' + createNestedBinaryExpr(recurmax, noComma) + ')'; // note: should return a simple non-recursing expression value!
|
||||
}
|
||||
// since `a` and `b` are our canaries we want them more frequently than other expressions (1/3rd chance of a canary)
|
||||
var r = rng(6);
|
||||
if (r < 1) return 'a++ + ' + _createExpression(recurmax, noComma, stmtDepth, canThrow);
|
||||
if (r < 2) return '(--b) + ' + _createExpression(recurmax, noComma, stmtDepth, canThrow);
|
||||
if (r < 3) return '(c = c + 1) + ' + _createExpression(recurmax, noComma, stmtDepth, canThrow); // c only gets incremented
|
||||
|
||||
return _createExpression(recurmax, noComma, stmtDepth, canThrow);
|
||||
}
|
||||
function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
switch (rng(15)) {
|
||||
case 0:
|
||||
return createUnaryOp() + (rng(2) === 1 ? 'a' : 'b');
|
||||
case 1:
|
||||
return 'a' + (rng(2) == 1 ? '++' : '--');
|
||||
case 2:
|
||||
// parens needed because assignments aren't valid unless they're the left-most op(s) in an expression
|
||||
return '(b ' + createAssignment() + ' a)';
|
||||
case 3:
|
||||
return rng(2) + ' === 1 ? a : b';
|
||||
case 4:
|
||||
return createNestedBinaryExpr(recurmax, noComma) + createBinaryOp(noComma) + createExpression(recurmax, noComma, stmtDepth, canThrow);
|
||||
case 5:
|
||||
return createValue();
|
||||
case 6:
|
||||
return '(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ')';
|
||||
case 7:
|
||||
return createExpression(recurmax, noComma, stmtDepth, canThrow) + '?' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ':' + createExpression(recurmax, noComma, stmtDepth, canThrow);
|
||||
case 8:
|
||||
var nameLenBefore = VAR_NAMES.length;
|
||||
var name = createVarName(MAYBE); // note: this name is only accessible from _within_ the function. and immutable at that.
|
||||
if (name === 'c') name = 'a';
|
||||
var s = '';
|
||||
switch(rng(4)) {
|
||||
case 0:
|
||||
s = '(function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth) + '})()';
|
||||
break;
|
||||
case 1:
|
||||
s = '+function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth) + '}()';
|
||||
break;
|
||||
case 2:
|
||||
s = '!function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth) + '}()';
|
||||
break;
|
||||
default:
|
||||
s = 'void function ' + name + '(){' + createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth) + '}()';
|
||||
break;
|
||||
}
|
||||
VAR_NAMES.length = nameLenBefore;
|
||||
return s;
|
||||
case 9:
|
||||
return createTypeofExpr(recurmax, stmtDepth, canThrow);
|
||||
case 10:
|
||||
// you could statically infer that this is just `Math`, regardless of the other expression
|
||||
// I don't think Uglify does this at this time...
|
||||
return ''+
|
||||
'new function(){ \n' +
|
||||
(rng(2) === 1 ? createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + '\n' : '') +
|
||||
'return Math;\n' +
|
||||
'}';
|
||||
case 11:
|
||||
// more like a parser test but perhaps comment nodes mess up the analysis?
|
||||
// note: parens not needed for post-fix (since that's the default when ambiguous)
|
||||
// for prefix ops we need parens to prevent accidental syntax errors.
|
||||
switch (rng(6)) {
|
||||
case 0:
|
||||
return 'a/* ignore */++';
|
||||
case 1:
|
||||
return 'b/* ignore */--';
|
||||
case 2:
|
||||
return '(++/* ignore */a)';
|
||||
case 3:
|
||||
return '(--/* ignore */b)';
|
||||
case 4:
|
||||
// only groups that wrap a single variable return a "Reference", so this is still valid.
|
||||
// may just be a parser edge case that is invisible to uglify...
|
||||
return '(--(b))';
|
||||
case 5:
|
||||
// classic 0.3-0.1 case; 1-0.1-0.1-0.1 is not 0.7 :)
|
||||
return 'b + 1-0.1-0.1-0.1';
|
||||
default:
|
||||
return '(--/* ignore */b)';
|
||||
}
|
||||
case 12:
|
||||
return createNestedBinaryExpr(recurmax, noComma);
|
||||
case 13:
|
||||
return " ((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || a || 3).toString() ";
|
||||
case 14:
|
||||
return " /[abc4]/.test(((" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ") || b || 5).toString()) ";
|
||||
}
|
||||
}
|
||||
|
||||
function createNestedBinaryExpr(recurmax, noComma) {
|
||||
recurmax = 3; // note that this generates 2^recurmax expression parts... make sure to cap it
|
||||
return _createSimpleBinaryExpr(recurmax, noComma);
|
||||
}
|
||||
function _createSimpleBinaryExpr(recurmax, noComma) {
|
||||
// intentionally generate more hardcore ops
|
||||
if (--recurmax < 0) return createValue();
|
||||
var r = rng(30);
|
||||
if (r === 0) return '(c = c + 1, ' + _createSimpleBinaryExpr(recurmax, noComma) + ')';
|
||||
var s = _createSimpleBinaryExpr(recurmax, noComma) + createBinaryOp(noComma) + _createSimpleBinaryExpr(recurmax, noComma);
|
||||
if (r === 1) {
|
||||
// try to get a generated name reachable from current scope. default to just `a`
|
||||
var assignee = VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)] || 'a';
|
||||
return '( ' + assignee + createAssignment() + s + ')';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function createTypeofExpr(recurmax, stmtDepth, canThrow) {
|
||||
switch (rng(8)) {
|
||||
case 0:
|
||||
return 'typeof ' + createVarName(MANDATORY, DONT_STORE) + ' === "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
|
||||
case 1:
|
||||
return 'typeof ' + createVarName(MANDATORY, DONT_STORE) + ' !== "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
|
||||
case 2:
|
||||
return 'typeof ' + createVarName(MANDATORY, DONT_STORE) + ' == "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
|
||||
case 3:
|
||||
return 'typeof ' + createVarName(MANDATORY, DONT_STORE) + ' != "' + TYPEOF_OUTCOMES[rng(TYPEOF_OUTCOMES.length)] + '"';
|
||||
case 4:
|
||||
return 'typeof ' + createVarName(MANDATORY, DONT_STORE);
|
||||
default:
|
||||
return '(typeof ' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ')';
|
||||
}
|
||||
}
|
||||
|
||||
function createValue() {
|
||||
return VALUES[rng(VALUES.length)];
|
||||
}
|
||||
|
||||
function createBinaryOp(noComma) {
|
||||
if (noComma) return BINARY_OPS_NO_COMMA[rng(BINARY_OPS_NO_COMMA.length)];
|
||||
return BINARY_OPS[rng(BINARY_OPS.length)];
|
||||
}
|
||||
|
||||
function createAssignment() {
|
||||
return ASSIGNMENTS[rng(ASSIGNMENTS.length)];
|
||||
}
|
||||
|
||||
function createUnaryOp() {
|
||||
return UNARY_OPS[rng(UNARY_OPS.length)];
|
||||
}
|
||||
|
||||
function createVarName(maybe, dontStore) {
|
||||
if (!maybe || rng(2) === 1) {
|
||||
var r = rng(VAR_NAMES.length);
|
||||
var suffixed = rng(5) > 0;
|
||||
var name = VAR_NAMES[r] + (suffixed ? '_' + (++loops) : '');
|
||||
if (!dontStore && suffixed) VAR_NAMES.push(name);
|
||||
return name;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function try_beautify(code, result) {
|
||||
try {
|
||||
var beautified = UglifyJS.minify(code, {
|
||||
fromString: true,
|
||||
compress: false,
|
||||
mangle: false,
|
||||
output: {
|
||||
beautify: true,
|
||||
bracketize: true,
|
||||
},
|
||||
}).code;
|
||||
if (sandbox.same_stdout(sandbox.run_code(beautified), result)) {
|
||||
console.log("// (beautified)");
|
||||
console.log(beautified);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("// !!! beautify failed !!!");
|
||||
console.log(e.stack);
|
||||
}
|
||||
console.log("//");
|
||||
console.log(code);
|
||||
}
|
||||
|
||||
function infer_options(ctor) {
|
||||
try {
|
||||
ctor({ 0: 0 });
|
||||
} catch (e) {
|
||||
return e.defs;
|
||||
}
|
||||
}
|
||||
|
||||
var default_options = {
|
||||
compress: infer_options(UglifyJS.Compressor),
|
||||
mangle: {
|
||||
"cache": null,
|
||||
"eval": false,
|
||||
"keep_fnames": false,
|
||||
"screw_ie8": true,
|
||||
"toplevel": false,
|
||||
},
|
||||
output: infer_options(UglifyJS.OutputStream),
|
||||
};
|
||||
|
||||
function log_suspects(minify_options, component) {
|
||||
var options = component in minify_options ? minify_options[component] : true;
|
||||
if (!options) return;
|
||||
options = UglifyJS.defaults(options, default_options[component]);
|
||||
var suspects = Object.keys(default_options[component]).filter(function(name) {
|
||||
if (options[name]) {
|
||||
var m = JSON.parse(JSON.stringify(minify_options));
|
||||
var o = JSON.parse(JSON.stringify(options));
|
||||
o[name] = false;
|
||||
m[component] = o;
|
||||
try {
|
||||
var r = sandbox.run_code(UglifyJS.minify(original_code, m).code);
|
||||
return sandbox.same_stdout(original_result, r);
|
||||
} catch (e) {
|
||||
console.log("Error testing options." + component + "." + name);
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (suspects.length > 0) {
|
||||
console.log("Suspicious", component, "options:");
|
||||
suspects.forEach(function(name) {
|
||||
console.log(" " + name);
|
||||
});
|
||||
console.log();
|
||||
}
|
||||
}
|
||||
|
||||
function log(options) {
|
||||
if (!ok) console.log('\n\n\n\n\n\n!!!!!!!!!!\n\n\n');
|
||||
console.log("//=============================================================");
|
||||
if (!ok) console.log("// !!!!!! Failed... round", round);
|
||||
console.log("// original code");
|
||||
try_beautify(original_code, original_result);
|
||||
console.log();
|
||||
console.log();
|
||||
console.log("//-------------------------------------------------------------");
|
||||
if (typeof uglify_code == "string") {
|
||||
console.log("// uglified code");
|
||||
try_beautify(uglify_code, uglify_result);
|
||||
console.log();
|
||||
console.log();
|
||||
console.log("original result:");
|
||||
console.log(original_result);
|
||||
console.log("uglified result:");
|
||||
console.log(uglify_result);
|
||||
} else {
|
||||
console.log("// !!! uglify failed !!!");
|
||||
console.log(uglify_code.stack);
|
||||
}
|
||||
console.log("minify(options):");
|
||||
options = JSON.parse(options);
|
||||
console.log(options);
|
||||
console.log();
|
||||
if (!ok) {
|
||||
Object.keys(default_options).forEach(log_suspects.bind(null, options));
|
||||
console.log("!!!!!! Failed... round", round);
|
||||
}
|
||||
}
|
||||
|
||||
var minify_options = require("./ufuzz.json").map(function(options) {
|
||||
options.fromString = true;
|
||||
return JSON.stringify(options);
|
||||
});
|
||||
var original_code, original_result;
|
||||
var uglify_code, uglify_result, ok;
|
||||
for (var round = 1; round <= num_iterations; round++) {
|
||||
process.stdout.write(round + " of " + num_iterations + "\r");
|
||||
|
||||
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
|
||||
loops = 0;
|
||||
funcs = 0;
|
||||
|
||||
original_code = [
|
||||
"var a = 100, b = 10, c = 0;",
|
||||
createTopLevelCode(),
|
||||
"console.log(null, a, b, c);" // preceding `null` makes for a cleaner output (empty string still shows up etc)
|
||||
].join("\n");
|
||||
|
||||
minify_options.forEach(function(options) {
|
||||
try {
|
||||
uglify_code = UglifyJS.minify(original_code, JSON.parse(options)).code;
|
||||
} catch (e) {
|
||||
uglify_code = e;
|
||||
}
|
||||
|
||||
ok = typeof uglify_code == "string";
|
||||
if (ok) {
|
||||
original_result = sandbox.run_code(original_code);
|
||||
uglify_result = sandbox.run_code(uglify_code);
|
||||
ok = sandbox.same_stdout(original_result, uglify_result);
|
||||
}
|
||||
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
||||
if (!ok && isFinite(num_iterations)) process.exit(1);
|
||||
});
|
||||
}
|
||||
33
test/ufuzz.json
Normal file
33
test/ufuzz.json
Normal file
@@ -0,0 +1,33 @@
|
||||
[
|
||||
{
|
||||
"compress": {
|
||||
"warnings": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"compress": {
|
||||
"warnings": false
|
||||
},
|
||||
"mangle": false
|
||||
},
|
||||
{
|
||||
"compress": false,
|
||||
"mangle": true
|
||||
},
|
||||
{
|
||||
"compress": false,
|
||||
"mangle": false,
|
||||
"output": {
|
||||
"beautify": true,
|
||||
"bracketize": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"compress": {
|
||||
"keep_fargs": false,
|
||||
"passes": 3,
|
||||
"pure_getters": true,
|
||||
"warnings": false
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -17,7 +17,3 @@ exports["string_template"] = string_template;
|
||||
exports["tokenizer"] = tokenizer;
|
||||
exports["is_identifier"] = is_identifier;
|
||||
exports["SymbolDef"] = SymbolDef;
|
||||
|
||||
if (typeof DEBUG !== "undefined" && DEBUG) {
|
||||
exports["EXPECT_DIRECTIVE"] = EXPECT_DIRECTIVE;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
|
||||
var FILES = exports.FILES = [
|
||||
var UglifyJS = exports;
|
||||
var FILES = UglifyJS.FILES = [
|
||||
"../lib/utils.js",
|
||||
"../lib/ast.js",
|
||||
"../lib/parse.js",
|
||||
@@ -20,17 +21,14 @@ var FILES = exports.FILES = [
|
||||
"../lib/propmangle.js",
|
||||
"./exports.js",
|
||||
].map(function(file){
|
||||
return fs.realpathSync(path.join(path.dirname(__filename), file));
|
||||
return require.resolve(file);
|
||||
});
|
||||
|
||||
var UglifyJS = exports;
|
||||
|
||||
new Function("MOZ_SourceMap", "exports", "DEBUG", FILES.map(function(file){
|
||||
new Function("MOZ_SourceMap", "exports", FILES.map(function(file){
|
||||
return fs.readFileSync(file, "utf8");
|
||||
}).join("\n\n"))(
|
||||
require("source-map"),
|
||||
UglifyJS,
|
||||
!!global.UGLIFY_DEBUG
|
||||
UglifyJS
|
||||
);
|
||||
|
||||
UglifyJS.AST_Node.warn_function = function(txt) {
|
||||
@@ -46,23 +44,23 @@ function read_source_map(code) {
|
||||
return JSON.parse(new Buffer(match[2], "base64"));
|
||||
}
|
||||
|
||||
exports.minify = function(files, options) {
|
||||
UglifyJS.minify = function(files, options) {
|
||||
options = UglifyJS.defaults(options, {
|
||||
spidermonkey : false,
|
||||
outSourceMap : null,
|
||||
outFileName : null,
|
||||
sourceRoot : null,
|
||||
inSourceMap : null,
|
||||
sourceMapUrl : null,
|
||||
sourceMapInline : false,
|
||||
compress : {},
|
||||
fromString : false,
|
||||
warnings : false,
|
||||
inSourceMap : null,
|
||||
mangle : {},
|
||||
mangleProperties : false,
|
||||
nameCache : null,
|
||||
outFileName : null,
|
||||
output : null,
|
||||
compress : {},
|
||||
parse : {}
|
||||
outSourceMap : null,
|
||||
parse : {},
|
||||
sourceMapInline : false,
|
||||
sourceMapUrl : null,
|
||||
sourceRoot : null,
|
||||
spidermonkey : false,
|
||||
warnings : false,
|
||||
});
|
||||
UglifyJS.base54.reset();
|
||||
|
||||
@@ -181,7 +179,7 @@ exports.minify = function(files, options) {
|
||||
};
|
||||
};
|
||||
|
||||
// exports.describe_ast = function() {
|
||||
// UglifyJS.describe_ast = function() {
|
||||
// function doitem(ctor) {
|
||||
// var sub = {};
|
||||
// ctor.SUBCLASSES.forEach(function(ctor){
|
||||
@@ -195,7 +193,7 @@ exports.minify = function(files, options) {
|
||||
// return doitem(UglifyJS.AST_Node).sub;
|
||||
// }
|
||||
|
||||
exports.describe_ast = function() {
|
||||
UglifyJS.describe_ast = function() {
|
||||
var out = UglifyJS.OutputStream({ beautify: true });
|
||||
function doitem(ctor) {
|
||||
out.print("AST_" + ctor.TYPE);
|
||||
@@ -249,13 +247,13 @@ function readReservedFile(filename, reserved) {
|
||||
return reserved;
|
||||
}
|
||||
|
||||
exports.readReservedFile = readReservedFile;
|
||||
UglifyJS.readReservedFile = readReservedFile;
|
||||
|
||||
exports.readDefaultReservedFile = function(reserved) {
|
||||
return readReservedFile(path.join(__dirname, "domprops.json"), reserved);
|
||||
UglifyJS.readDefaultReservedFile = function(reserved) {
|
||||
return readReservedFile(require.resolve("./domprops.json"), reserved);
|
||||
};
|
||||
|
||||
exports.readNameCache = function(filename, key) {
|
||||
UglifyJS.readNameCache = function(filename, key) {
|
||||
var cache = null;
|
||||
if (filename) {
|
||||
try {
|
||||
@@ -273,7 +271,7 @@ exports.readNameCache = function(filename, key) {
|
||||
return cache;
|
||||
};
|
||||
|
||||
exports.writeNameCache = function(filename, key, cache) {
|
||||
UglifyJS.writeNameCache = function(filename, key, cache) {
|
||||
if (filename) {
|
||||
var data;
|
||||
try {
|
||||
@@ -294,13 +292,9 @@ exports.writeNameCache = function(filename, key, cache) {
|
||||
// Example: "foo/bar/*baz??.*.js"
|
||||
// Argument `glob` may be a string or an array of strings.
|
||||
// Returns an array of strings. Garbage in, garbage out.
|
||||
exports.simple_glob = function simple_glob(glob) {
|
||||
var results = [];
|
||||
UglifyJS.simple_glob = function simple_glob(glob) {
|
||||
if (Array.isArray(glob)) {
|
||||
glob.forEach(function(elem) {
|
||||
results = results.concat(simple_glob(elem));
|
||||
});
|
||||
return results;
|
||||
return [].concat.apply([], glob.map(simple_glob));
|
||||
}
|
||||
if (glob.match(/\*|\?/)) {
|
||||
var dir = path.dirname(glob);
|
||||
@@ -308,28 +302,19 @@ exports.simple_glob = function simple_glob(glob) {
|
||||
var entries = fs.readdirSync(dir);
|
||||
} catch (ex) {}
|
||||
if (entries) {
|
||||
var pattern = "^" + (path.basename(glob)
|
||||
.replace(/\(/g, "\\(")
|
||||
.replace(/\)/g, "\\)")
|
||||
.replace(/\{/g, "\\{")
|
||||
.replace(/\}/g, "\\}")
|
||||
.replace(/\[/g, "\\[")
|
||||
.replace(/\]/g, "\\]")
|
||||
.replace(/\+/g, "\\+")
|
||||
.replace(/\^/g, "\\^")
|
||||
.replace(/\$/g, "\\$")
|
||||
var pattern = "^" + path.basename(glob)
|
||||
.replace(/[.+^$[\]\\(){}]/g, "\\$&")
|
||||
.replace(/\*/g, "[^/\\\\]*")
|
||||
.replace(/\./g, "\\.")
|
||||
.replace(/\?/g, ".")) + "$";
|
||||
.replace(/\?/g, "[^/\\\\]") + "$";
|
||||
var mod = process.platform === "win32" ? "i" : "";
|
||||
var rx = new RegExp(pattern, mod);
|
||||
for (var i in entries) {
|
||||
if (rx.test(entries[i]))
|
||||
results.push(dir + "/" + entries[i]);
|
||||
var results = entries.filter(function(name) {
|
||||
return rx.test(name);
|
||||
}).map(function(name) {
|
||||
return path.join(dir, name);
|
||||
});
|
||||
if (results.length) return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (results.length === 0)
|
||||
results = [ glob ];
|
||||
return results;
|
||||
return [ glob ];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user