Compare commits

..

59 Commits

Author SHA1 Message Date
Alex Lam S.L
9d758a216b v3.10.1 2020-08-02 21:08:48 +08:00
Alex Lam S.L
af13f8dd2c improve diagnostics upon AST validation failure (#4033) 2020-07-31 22:50:16 +08:00
Alex Lam S.L
88423f2574 validate against multiple parents on AST_Node (#4032)
- fix related issues in `global_defs`, `ie8` & `reduce_vars`
2020-07-31 08:09:19 +08:00
Alex Lam S.L
ee632a5519 fix corner case in reduce_vars (#4031)
fixes #4030
2020-07-31 08:05:09 +08:00
Alex Lam S.L
dfe47bcc42 fix corner case in ie8 & reduce_vars (#4029)
fixes #4028
2020-07-29 03:11:02 +08:00
Alex Lam S.L
6d3dcaa59e fix corner case in unused (#4026)
fixes #4025
2020-07-26 09:27:54 +08:00
Alex Lam S.L
1bc0df1569 fix corner case in hoist_props (#4024)
fixes #4023
2020-07-26 09:27:34 +08:00
Alex Lam S.L
a98ba994bd reduce ufuzz test cases that fail to minify() (#4021) 2020-07-21 17:22:18 +08:00
Alex Lam S.L
cd671221c5 fix corner case in ie8 & reduce_vars (#4020)
fixes #4019
2020-07-21 17:22:18 +08:00
Alex Lam S.L
bce3919748 fix corner case in unused (#4018)
fixes #4017
2020-07-21 17:21:58 +08:00
Alex Lam S.L
61b66e83f1 fix corner case in ie8 (#4016)
fixes #4015
2020-07-21 02:32:20 +08:00
Alex Lam S.L
a5db8cd14c fix corner case in collapse_vars (#4013)
fixes #4012
2020-07-20 23:28:13 +08:00
Alex Lam S.L
2021c2fa3e fix corner case in false positive detection (#4011) 2020-07-20 21:57:22 +08:00
Alex Lam S.L
484d3fd8c7 fix corner case in side_effects (#4009)
fixes #4008
2020-07-01 11:33:48 +08:00
Alex Lam S.L
3bf8699f95 fix corner case in inline (#4007)
fixes #4006
2020-06-29 09:06:23 +08:00
Alex Lam S.L
58c24f8007 v3.10.0 2020-06-21 11:30:24 +01:00
Alex Lam S.L
e61bc34eb1 fix corner case in collapse_vars (#4002)
fixes #4001
2020-06-20 02:19:37 +08:00
Alex Lam S.L
8b2cfd45fa fix corner case in rename (#4000)
fixes #3999
2020-06-15 01:29:01 +08:00
Alex Lam S.L
ae9f56be10 fix corner case in evaluate (#3998)
fixes #3997
2020-06-15 01:28:44 +08:00
Alex Lam S.L
9aed0e3a73 speed up false positive detection in ufuzz (#3996) 2020-06-14 03:42:42 +08:00
Alex Lam S.L
88850a6e05 enhance evaluate (#3995) 2020-06-14 02:50:26 +08:00
Alex Lam S.L
9e881407bd fix corner cases related to AST_Hole (#3994) 2020-06-13 15:24:57 +01:00
Alex Lam S.L
3188db7b90 remove AppVeyor (#3992) 2020-06-12 08:43:42 +08:00
Alex Lam S.L
a82ca62b66 fix corner case in dead_code (#3991) 2020-06-12 08:00:19 +08:00
Alex Lam S.L
e9465717ab enhance dead_code (#3990) 2020-06-12 02:16:13 +08:00
Alex Lam S.L
e89031f1af fix corner case in unsafe evaluate (#3989)
fixes #3988
2020-06-11 07:37:39 +08:00
Alex Lam S.L
596fad182e fix corner case in unused (#3987)
fixes #3986
2020-06-11 02:01:23 +08:00
Alex Lam S.L
ed69adedcd fix corner case in --reduce-test (#3985) 2020-06-10 15:51:00 +01:00
Alex Lam S.L
1dbf7d4a3a fix corner case in side_effects (#3984)
fixes #3983
2020-06-10 19:30:37 +08:00
Alex Lam S.L
2a9d0fc6fb improve false positive detection in ufuzz (#3982) 2020-06-10 07:28:56 +08:00
Alex Lam S.L
45db96679e perform ufuzz on more stable Node.js version (#3981) 2020-06-10 00:02:05 +08:00
Alex Lam S.L
1d15f51238 improve fix for #3976 (#3980) 2020-06-10 00:00:57 +08:00
Alex Lam S.L
ed7c82fa5e fix corner case in collapse_vars (#3978)
fixes #3976
2020-06-09 19:07:20 +08:00
Alex Lam S.L
3b273cecac improve false positive detection in ufuzz (#3977) 2020-06-09 19:07:02 +08:00
Alex Lam S.L
d764b6cc3b fix corner case in reduce_vars (#3975)
fixes #3974
2020-06-09 10:33:47 +08:00
Alex Lam S.L
08c4729eb4 improve false positive detection in ufuzz (#3973) 2020-06-09 01:47:50 +08:00
Alex Lam S.L
5561d3e7f3 fix corner case in collapse_vars (#3972)
fixes #3971
2020-06-09 00:09:21 +08:00
Alex Lam S.L
491d6ce1d5 improve false positive detection in ufuzz (#3968) 2020-06-08 14:21:45 +08:00
Alex Lam S.L
cd55eeb77c fix corner case in dead_code (#3969)
fixes #3967
2020-06-08 13:42:09 +08:00
Alex Lam S.L
3230952d57 improve handling of invalid CLI options (#3966) 2020-06-08 11:16:03 +08:00
Alex Lam S.L
df3bb8028a fix corner cases related to in (#3964) 2020-06-08 05:23:23 +08:00
Alex Lam S.L
28b7b15da1 parse command line internally (#3961) 2020-06-07 13:48:51 +08:00
Alex Lam S.L
aa37b19698 fix corner case in unused (#3963)
fixes #3962
2020-06-07 13:48:29 +08:00
Alex Lam S.L
02e889e449 improve fix for #3958 (#3960) 2020-06-06 15:07:32 +01:00
Alex Lam S.L
486ce00b8e fix corner case in reduce_vars (#3959)
fixes #3958
2020-06-06 10:04:37 +08:00
Alex Lam S.L
eb481cee8c fix corner cases in reduce_vars & unused (#3955)
fixes #3953
fixes #3956
fixes #3957
2020-06-05 18:51:21 +08:00
Alex Lam S.L
fbc9d8009b fix corner case in collapse_vars (#3954) 2020-06-05 14:28:08 +08:00
Alex Lam S.L
04fd3d90f8 fix corner cases in assignments, reduce_vars & unused (#3950)
fixes #3949
fixes #3951
2020-06-05 04:06:43 +08:00
Alex Lam S.L
a489f8cb5e add test case for #3945 (#3948) 2020-06-03 03:34:38 +08:00
Alex Lam S.L
e2e4b7fb37 fix corner case in hoist_props (#3947)
fixes #3945
2020-06-02 23:51:06 +08:00
Alex Lam S.L
c97ad98f92 fix corner case in evaluate (#3946)
fixes #3944
2020-06-02 23:50:40 +08:00
Alex Lam S.L
b24eb22c6b enhance reduce_vars (#3942) 2020-06-01 20:55:23 +08:00
Alex Lam S.L
06ba4e2ce8 fix corner case in arguments (#3939) 2020-05-31 12:18:27 +08:00
Alex Lam S.L
0eb4577a82 fix corner case in evaluate (#3938)
fixes #3937
2020-05-30 18:22:40 +08:00
Alex Lam S.L
43498769f0 fix corner case in evaluate (#3936)
fixes #3935
2020-05-29 22:10:36 +08:00
Alex Lam S.L
60c0bc1e6b fix corner case in evaluate (#3934)
fixes #3933
2020-05-29 17:48:26 +08:00
Alex Lam S.L
6a5c63e1e3 enhance evaluate, functions & inline (#3931) 2020-05-29 07:05:47 +08:00
Alex Lam S.L
d47ea77811 fix corner case in functions (#3930)
fixes #3929
2020-05-28 20:07:36 +08:00
Alex Lam S.L
7840746bd9 fix corner case in collapse_vars (#3928)
fixes #3927
2020-05-27 21:02:48 +08:00
33 changed files with 2921 additions and 812 deletions

View File

@@ -17,13 +17,13 @@ jobs:
shell: bash shell: bash
run: | run: |
git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs git clone --branch v1.5.4 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add 10 && nvs use 10'; do while ! timeout 60 bash -c '. ~/.nvs/nvs.sh add 8 && nvs use 8'; do
cd ~/.nvs cd ~/.nvs
while !(git clean -xdf); do echo "'git clean' failed - retrying..."; done while !(git clean -xdf); do echo "'git clean' failed - retrying..."; done
cd - cd -
done done
. ~/.nvs/nvs.sh --version . ~/.nvs/nvs.sh --version
nvs use 10 nvs use 8
node --version node --version
npm config set audit false npm config set audit false
npm config set optional false npm config set optional false

View File

@@ -1,5 +0,0 @@
build: off
matrix:
fast_finish: true
test_script:
- echo No longer in use

View File

@@ -8,185 +8,252 @@ require("../tools/exit");
var fs = require("fs"); var fs = require("fs");
var info = require("../package.json"); var info = require("../package.json");
var path = require("path"); var path = require("path");
var program = require("commander");
var UglifyJS = require("../tools/node"); var UglifyJS = require("../tools/node");
var skip_keys = [ "cname", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ]; var skip_keys = [ "cname", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ];
var files = {}; var files = {};
var options = { var options = {};
compress: false, var short_forms = {
mangle: false b: "beautify",
c: "compress",
d: "define",
e: "enclose",
h: "help",
m: "mangle",
o: "output",
O: "output-opts",
p: "parse",
v: "version",
V: "version",
}; };
program.version(info.name + " " + info.version); var args = process.argv.slice(2);
program.parseArgv = program.parse; var paths = [];
program.parse = undefined; var output, nameCache;
if (process.argv.indexOf("ast") >= 0) program.helpInformation = UglifyJS.describe_ast; var specified = {};
else if (process.argv.indexOf("options") >= 0) program.helpInformation = function() { while (args.length) {
var text = []; var arg = args.shift();
var toplevels = []; if (arg[0] != "-") {
var padding = ""; paths.push(arg);
var options = UglifyJS.default_options(); } else if (arg == "--") {
for (var name in options) { paths = paths.concat(args);
var option = options[name]; break;
if (option && typeof option == "object") { } else if (arg[1] == "-") {
text.push("--" + ({ process_option(arg.slice(2));
output: "beautify", } else [].forEach.call(arg.slice(1), function(letter, index, arg) {
sourceMap: "source-map", if (!(letter in short_forms)) fatal("invalid option -" + letter);
}[name] || name) + " options:"); process_option(short_forms[letter], index + 1 < arg.length);
text.push(format_object(option));
text.push("");
} else {
if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
toplevels.push([ {
keep_fnames: "keep-fnames",
nameCache: "name-cache",
}[name] || name, option ]);
}
}
toplevels.forEach(function(tokens) {
text.push("--" + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
}); });
return text.join("\n"); }
};
program.option("-p, --parse <options>", "Specify parser options.", parse_js()); function process_option(name, no_value) {
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js()); specified[name] = true;
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js()); switch (name) {
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js()); case "help":
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js()); switch (read_value()) {
program.option("-O, --output-opts [options]", "Output options (beautify disabled).", parse_js()); case "ast":
program.option("-o, --output <file>", "Output file (default STDOUT)."); print(UglifyJS.describe_ast());
program.option("--comments [filter]", "Preserve copyright comments in the output."); break;
program.option("--config-file <file>", "Read minify() options from JSON file."); case "options":
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define")); var text = [];
program.option("-e, --enclose [arg[,...][:value[,...]]]", "Embed everything in a big function, with configurable argument(s) & value(s)."); var toplevels = [];
program.option("--ie8", "Support non-standard Internet Explorer 8."); var padding = "";
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name."); var defaults = UglifyJS.default_options();
program.option("--name-cache <file>", "File to hold mangled name mappings."); for (var name in defaults) {
program.option("--rename", "Force symbol expansion."); var option = defaults[name];
program.option("--no-rename", "Disable symbol expansion."); if (option && typeof option == "object") {
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)"); text.push("--" + ({
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js()); output: "beautify",
program.option("--timings", "Display operations run time on STDERR."); sourceMap: "source-map",
program.option("--toplevel", "Compress and/or mangle variables in toplevel scope."); }[name] || name) + " options:");
program.option("--validate", "Perform validation during AST manipulations."); text.push(format_object(option));
program.option("--verbose", "Print diagnostic messages."); text.push("");
program.option("--warn", "Print warning messages."); } else {
program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally."); if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
program.option("--reduce-test", "Reduce a standalone `console.log` based test case."); toplevels.push([ {
program.arguments("[files...]").parseArgv(process.argv); keep_fnames: "keep-fnames",
if (program.configFile) { nameCache: "name-cache",
options = JSON.parse(read_file(program.configFile)); }[name] || name, option ]);
if (options.mangle && options.mangle.properties && options.mangle.properties.regex) { }
options.mangle.properties.regex = UglifyJS.parse(options.mangle.properties.regex, { }
expression: true toplevels.forEach(function(tokens) {
}).value; text.push("--" + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
});
print(text.join("\n"));
break;
default:
print([
"Usage: uglifyjs [files...] [options]",
"",
"Options:",
" -h, --help Print usage information.",
" `--help options` for details on available options.",
" -v, -V, --version Print version number.",
" -p, --parse <options> Specify parser options.",
" -c, --compress [options] Enable compressor/specify compressor options.",
" -m, --mangle [options] Mangle names/specify mangler options.",
" --mangle-props [options] Mangle properties/specify mangler options.",
" -b, --beautify [options] Beautify output/specify output options.",
" -O, --output-opts <options> Output options (beautify disabled).",
" -o, --output <file> Output file (default STDOUT).",
" --comments [filter] Preserve copyright comments in the output.",
" --config-file <file> Read minify() options from JSON file.",
" -d, --define <expr>[=value] Global definitions.",
" -e, --enclose [arg[,...][:value[,...]]] Embed everything in a big function, with configurable argument(s) & value(s).",
" --ie8 Support non-standard Internet Explorer 8.",
" --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.",
" --name-cache <file> File to hold mangled name mappings.",
" --rename Force symbol expansion.",
" --no-rename Disable symbol expansion.",
" --self Build UglifyJS as a library (implies --wrap UglifyJS)",
" --source-map [options] Enable source map/specify source map options.",
" --timings Display operations run time on STDERR.",
" --toplevel Compress and/or mangle variables in toplevel scope.",
" --validate Perform validation during AST manipulations.",
" --verbose Print diagnostic messages.",
" --warn Print warning messages.",
" --wrap <name> Embed everything as a function with “exports” corresponding to “name” globally.",
" --reduce-test Reduce a standalone test case (assumes cloned repository).",
].join("\n"));
}
process.exit();
case "version":
print(info.name + " " + info.version);
process.exit();
case "config-file":
var config = JSON.parse(read_file(read_value(true)));
if (config.mangle && config.mangle.properties && config.mangle.properties.regex) {
config.mangle.properties.regex = UglifyJS.parse(config.mangle.properties.regex, {
expression: true,
}).value;
}
for (var key in config) if (!(key in options)) options[key] = config[key];
break;
case "compress":
case "mangle":
options[name] = parse_js(read_value(), options[name]);
break;
case "source-map":
options.sourceMap = parse_js(read_value(), options.sourceMap);
break;
case "enclose":
options[name] = read_value();
break;
case "ie8":
case "timings":
case "toplevel":
case "validate":
options[name] = true;
break;
case "keep-fnames":
options.keep_fnames = true;
break;
case "wrap":
options[name] = read_value(true);
break;
case "verbose":
options.warnings = "verbose";
break;
case "warn":
if (!options.warnings) options.warnings = true;
break;
case "beautify":
options.output = parse_js(read_value(), options.output);
if (!("beautify" in options.output)) options.output.beautify = true;
break;
case "output-opts":
options.output = parse_js(read_value(true), options.output);
break;
case "comments":
if (typeof options.output != "object") options.output = {};
options.output.comments = read_value();
if (options.output.comments === true) options.output.comments = "some";
break;
case "define":
if (typeof options.compress != "object") options.compress = {};
options.compress.global_defs = parse_js(read_value(true), options.compress.global_defs, "define");
break;
case "mangle-props":
if (typeof options.mangle != "object") options.mangle = {};
options.mangle.properties = parse_js(read_value(), options.mangle.properties);
break;
case "name-cache":
nameCache = read_value(true);
options.nameCache = JSON.parse(read_file(nameCache, "{}"));
break;
case "output":
output = read_value(true);
break;
case "parse":
options.parse = parse_js(read_value(true), options.parse);
break;
case "rename":
options.rename = true;
break;
case "no-rename":
options.rename = false;
break;
case "reduce-test":
case "self":
break;
default:
fatal("invalid option --" + name);
}
function read_value(required) {
if (no_value || !args.length || args[0][0] == "-") {
if (required) fatal("missing option argument for --" + name);
return true;
}
return args.shift();
} }
} }
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") { if (!output && options.sourceMap && options.sourceMap.url != "inline") fatal("cannot write source map to STDOUT");
fatal("cannot write source map to STDOUT"); if (specified["beautify"] && specified["output-opts"]) fatal("--beautify cannot be used with --output-opts");
} [ "compress", "mangle" ].forEach(function(name) {
[ if (!(name in options)) options[name] = false;
"compress",
"enclose",
"ie8",
"mangle",
"sourceMap",
"toplevel",
"validate",
"wrap"
].forEach(function(name) {
if (name in program) {
options[name] = program[name];
}
}); });
if (program.verbose) { if (options.mangle && options.mangle.properties) {
options.warnings = "verbose"; if (options.mangle.properties.domprops) {
} else if (program.warn) { delete options.mangle.properties.domprops;
options.warnings = true; } else {
if (typeof options.mangle.properties != "object") options.mangle.properties = {};
if (!Array.isArray(options.mangle.properties.reserved)) options.mangle.properties.reserved = [];
require("../tools/domprops").forEach(function(name) {
UglifyJS.push_uniq(options.mangle.properties.reserved, name);
});
}
}
if (output == "ast") options.output = {
ast: true,
code: false,
};
if (options.parse && (options.parse.acorn || options.parse.spidermonkey)
&& options.sourceMap && options.sourceMap.content == "inline") {
fatal("inline source map only works with built-in parser");
} }
if (options.warnings) { if (options.warnings) {
UglifyJS.AST_Node.log_function(print_error, options.warnings == "verbose"); UglifyJS.AST_Node.log_function(print_error, options.warnings == "verbose");
delete options.warnings; delete options.warnings;
} }
if (program.beautify) {
options.output = typeof program.beautify == "object" ? program.beautify : {};
if (!("beautify" in options.output)) {
options.output.beautify = true;
}
}
if (program.outputOpts) {
if (program.beautify) fatal("--beautify cannot be used with --output-opts");
options.output = typeof program.outputOpts == "object" ? program.outputOpts : {};
}
if (program.comments) {
if (typeof options.output != "object") options.output = {};
options.output.comments = typeof program.comments == "string" ? program.comments : "some";
}
if (program.define) {
if (typeof options.compress != "object") options.compress = {};
if (typeof options.compress.global_defs != "object") options.compress.global_defs = {};
for (var expr in program.define) {
options.compress.global_defs[expr] = program.define[expr];
}
}
if (program.keepFnames) {
options.keep_fnames = true;
}
if (program.mangleProps) {
if (program.mangleProps.domprops) {
delete program.mangleProps.domprops;
} else {
if (typeof program.mangleProps != "object") program.mangleProps = {};
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
require("../tools/domprops").forEach(function(name) {
UglifyJS.push_uniq(program.mangleProps.reserved, name);
});
}
if (typeof options.mangle != "object") options.mangle = {};
options.mangle.properties = program.mangleProps;
}
if (program.nameCache) {
options.nameCache = JSON.parse(read_file(program.nameCache, "{}"));
}
if (program.output == "ast") {
options.output = {
ast: true,
code: false
};
}
if (program.parse) {
if (!program.parse.acorn && !program.parse.spidermonkey) {
options.parse = program.parse;
} else if (program.sourceMap && program.sourceMap.content == "inline") {
fatal("inline source map only works with built-in parser");
}
}
if (~program.rawArgs.indexOf("--rename")) {
options.rename = true;
} else if (!program.rename) {
options.rename = false;
}
var convert_path = function(name) { var convert_path = function(name) {
return name; return name;
}; };
if (typeof program.sourceMap == "object" && "base" in program.sourceMap) { if (typeof options.sourceMap == "object" && "base" in options.sourceMap) {
convert_path = function() { convert_path = function() {
var base = program.sourceMap.base; var base = options.sourceMap.base;
delete options.sourceMap.base; delete options.sourceMap.base;
return function(name) { return function(name) {
return path.relative(base, name); return path.relative(base, name);
}; };
}(); }();
} }
if (program.self) { if (specified["self"]) {
if (program.args.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed"); if (paths.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed");
if (!options.wrap) options.wrap = "UglifyJS"; if (!options.wrap) options.wrap = "UglifyJS";
simple_glob(UglifyJS.FILES).forEach(function(name) { paths = UglifyJS.FILES;
files[convert_path(name)] = read_file(name); }
}); if (paths.length) {
run(); simple_glob(paths).forEach(function(name) {
} else if (program.args.length) {
simple_glob(program.args).forEach(function(name) {
files[convert_path(name)] = read_file(name); files[convert_path(name)] = read_file(name);
}); });
run(); run();
@@ -207,15 +274,14 @@ function convert_ast(fn) {
} }
function run() { function run() {
var content = program.sourceMap && program.sourceMap.content; var content = options.sourceMap && options.sourceMap.content;
if (content && content != "inline") { if (content && content != "inline") {
UglifyJS.AST_Node.info("Using input source map: " + content); UglifyJS.AST_Node.info("Using input source map: " + content);
options.sourceMap.content = read_file(content, content); options.sourceMap.content = read_file(content, content);
} }
if (program.timings) options.timings = true;
try { try {
if (program.parse) { if (options.parse) {
if (program.parse.acorn) { if (options.parse.acorn) {
files = convert_ast(function(toplevel, name) { files = convert_ast(function(toplevel, name) {
return require("acorn").parse(files[name], { return require("acorn").parse(files[name], {
locations: true, locations: true,
@@ -223,7 +289,7 @@ function run() {
sourceFile: name sourceFile: name
}); });
}); });
} else if (program.parse.spidermonkey) { } else if (options.parse.spidermonkey) {
files = convert_ast(function(toplevel, name) { files = convert_ast(function(toplevel, name) {
var obj = JSON.parse(files[name]); var obj = JSON.parse(files[name]);
if (!toplevel) return obj; if (!toplevel) return obj;
@@ -235,17 +301,17 @@ function run() {
} catch (ex) { } catch (ex) {
fatal(ex); fatal(ex);
} }
if (program.reduceTest) { var result;
// load on demand - assumes dev tree checked out if (specified["reduce-test"]) {
// load on demand - assumes cloned repository
var reduce_test = require("../test/reduce"); var reduce_test = require("../test/reduce");
var testcase = files[0] || files[Object.keys(files)[0]]; if (Object.keys(files).length != 1) fatal("can only test on a single file");
var result = reduce_test(testcase, options, { result = reduce_test(files[Object.keys(files)[0]], options, {
log: print_error, log: print_error,
verbose: true, verbose: true,
}); });
} } else {
else { result = UglifyJS.minify(files, options);
var result = UglifyJS.minify(files, options);
} }
if (result.error) { if (result.error) {
var ex = result.error; var ex = result.error;
@@ -275,10 +341,8 @@ function run() {
print_error(format_object(ex.defs)); print_error(format_object(ex.defs));
} }
fatal(ex); fatal(ex);
} else if (program.output == "ast") { } else if (output == "ast") {
if (!options.compress && !options.mangle) { if (!options.compress && !options.mangle) result.ast.figure_out_scope({});
result.ast.figure_out_scope({});
}
print(JSON.stringify(result.ast, function(key, value) { print(JSON.stringify(result.ast, function(key, value) {
if (value) switch (key) { if (value) switch (key) {
case "thedef": case "thedef":
@@ -304,26 +368,22 @@ function run() {
} }
return value; return value;
}, 2)); }, 2));
} else if (program.output == "spidermonkey") { } else if (output == "spidermonkey") {
print(JSON.stringify(UglifyJS.minify(result.code, { print(JSON.stringify(UglifyJS.minify(result.code, {
compress: false, compress: false,
mangle: false, mangle: false,
output: { output: {
ast: true, ast: true,
code: false code: false
} },
}).ast.to_mozilla_ast(), null, 2)); }).ast.to_mozilla_ast(), null, 2));
} else if (program.output) { } else if (output) {
fs.writeFileSync(program.output, result.code); fs.writeFileSync(output, result.code);
if (result.map) { if (result.map) fs.writeFileSync(output + ".map", result.map);
fs.writeFileSync(program.output + ".map", result.map);
}
} else { } else {
print(result.code); print(result.code);
} }
if (program.nameCache) { if (nameCache) fs.writeFileSync(nameCache, JSON.stringify(options.nameCache));
fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache));
}
if (result.timings) for (var phase in result.timings) { if (result.timings) for (var phase in result.timings) {
print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s"); print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
} }
@@ -379,47 +439,45 @@ function read_file(path, default_value) {
} }
} }
function parse_js(flag) { function parse_js(value, options, flag) {
return function(value, options) { if (!options || typeof options != "object") options = {};
options = options || {}; if (typeof value == "string") try {
try { UglifyJS.parse(value, {
UglifyJS.parse(value, { expression: true
expression: true }).walk(new UglifyJS.TreeWalker(function(node) {
}).walk(new UglifyJS.TreeWalker(function(node) { if (node instanceof UglifyJS.AST_Assign) {
if (node instanceof UglifyJS.AST_Assign) { var name = node.left.print_to_string();
var name = node.left.print_to_string(); var value = node.right;
var value = node.right; if (flag) {
if (flag) { options[name] = value;
options[name] = value; } else if (value instanceof UglifyJS.AST_Array) {
} else if (value instanceof UglifyJS.AST_Array) { options[name] = value.elements.map(to_string);
options[name] = value.elements.map(to_string); } else {
} else { options[name] = to_string(value);
options[name] = to_string(value);
}
return true;
} }
if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_PropAccess) { return true;
var name = node.print_to_string();
options[name] = true;
return true;
}
if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
function to_string(value) {
return value instanceof UglifyJS.AST_Constant ? value.value : value.print_to_string({
quote_keys: true
});
}
}));
} catch (ex) {
if (flag) {
fatal("cannot parse arguments for '" + flag + "': " + value);
} else {
options[value] = null;
} }
if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_PropAccess) {
var name = node.print_to_string();
options[name] = true;
return true;
}
if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
function to_string(value) {
return value instanceof UglifyJS.AST_Constant ? value.value : value.print_to_string({
quote_keys: true
});
}
}));
} catch (ex) {
if (flag) {
fatal("cannot parse arguments for '" + flag + "': " + value);
} else {
options[value] = null;
} }
return options;
} }
return options;
} }
function skip_key(key) { function skip_key(key) {

View File

@@ -120,6 +120,20 @@ var AST_Node = DEFNODE("Node", "start end", {
ctor.prototype._validate.call(this); ctor.prototype._validate.call(this);
} while (ctor = ctor.BASE); } while (ctor = ctor.BASE);
}, },
validate_ast: function() {
var marker = {};
this.walk(new TreeWalker(function(node) {
if (node.validate_visited === marker) {
throw new Error(string_template("cannot reuse {type} from [{file}:{line},{col}]", {
type: "AST_" + node.TYPE,
file: node.start.file,
line: node.start.line,
col: node.start.col,
}));
}
node.validate_visited = marker;
}));
},
}, null); }, null);
(AST_Node.log_function = function(fn, verbose) { (AST_Node.log_function = function(fn, verbose) {

File diff suppressed because it is too large Load Diff

View File

@@ -178,13 +178,17 @@ function minify(files, options) {
toplevel = toplevel[action](option); toplevel = toplevel[action](option);
files[toplevel.start.file] = toplevel.print_to_string().replace(orig, ""); files[toplevel.start.file] = toplevel.print_to_string().replace(orig, "");
}); });
if (options.validate) toplevel.validate_ast();
if (timings) timings.rename = Date.now(); if (timings) timings.rename = Date.now();
if (options.rename) { if (options.rename) {
toplevel.figure_out_scope(options.mangle); toplevel.figure_out_scope(options.mangle);
toplevel.expand_names(options.mangle); toplevel.expand_names(options.mangle);
} }
if (timings) timings.compress = Date.now(); if (timings) timings.compress = Date.now();
if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel); if (options.compress) {
toplevel = new Compressor(options.compress).compress(toplevel);
if (options.validate) toplevel.validate_ast();
}
if (timings) timings.scope = Date.now(); if (timings) timings.scope = Date.now();
if (options.mangle) toplevel.figure_out_scope(options.mangle); if (options.mangle) toplevel.figure_out_scope(options.mangle);
if (timings) timings.mangle = Date.now(); if (timings) timings.mangle = Date.now();

View File

@@ -305,6 +305,7 @@ function OutputStream(options) {
|| (ch == "/" && ch == prev) || (ch == "/" && ch == prev)
|| ((ch == "+" || ch == "-") && ch == last) || ((ch == "+" || ch == "-") && ch == last)
|| str == "--" && last == "!" || str == "--" && last == "!"
|| str == "in" && prev == "/"
|| last == "--" && ch == ">") { || last == "--" && ch == ">") {
OUTPUT += " "; OUTPUT += " ";
current_col++; current_col++;

View File

@@ -230,6 +230,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
} else { } else {
new_def = scope.def_variable(node); new_def = scope.def_variable(node);
} }
old_def.defun = new_def.scope;
old_def.orig.concat(old_def.references).forEach(function(node) { old_def.orig.concat(old_def.references).forEach(function(node) {
node.thedef = new_def; node.thedef = new_def;
node.reference(options); node.reference(options);
@@ -543,11 +544,8 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
var redef = def.redefined(); var redef = def.redefined();
var name = redef ? redef.rename || redef.name : next_name(); var name = redef ? redef.rename || redef.name : next_name();
def.rename = name; def.rename = name;
def.orig.forEach(function(sym) { def.orig.concat(def.references).forEach(function(sym) {
sym.name = name; if (sym.definition() === def) sym.name = name;
});
def.references.forEach(function(sym) {
sym.name = name;
}); });
} }
}); });

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit", "description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)", "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"version": "3.9.4", "version": "3.10.1",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
@@ -22,9 +22,6 @@
"tools", "tools",
"LICENSE" "LICENSE"
], ],
"dependencies": {
"commander": "~2.20.3"
},
"devDependencies": { "devDependencies": {
"acorn": "~7.1.0", "acorn": "~7.1.0",
"semver": "~6.3.0" "semver": "~6.3.0"

View File

@@ -269,6 +269,7 @@ function test_case(test) {
quote_style: 3, quote_style: 3,
}); });
try { try {
input.validate_ast();
U.parse(input_code); U.parse(input_code);
} catch (ex) { } catch (ex) {
log([ log([
@@ -315,8 +316,8 @@ function test_case(test) {
output = U.mangle_properties(output, test.mangle.properties); output = U.mangle_properties(output, test.mangle.properties);
} }
} }
output = make_code(output, output_options); var output_code = make_code(output, output_options);
if (expect != output) { if (expect != output_code) {
log([ log([
"!!! failed", "!!! failed",
"---INPUT---", "---INPUT---",
@@ -329,14 +330,15 @@ function test_case(test) {
"", "",
].join("\n"), { ].join("\n"), {
input: input_formatted, input: input_formatted,
output: output, output: output_code,
expected: expect expected: expect
}); });
return false; return false;
} }
// expect == output // expect == output
try { try {
U.parse(output); output.validate_ast();
U.parse(output_code);
} catch (ex) { } catch (ex) {
log([ log([
"!!! Test matched expected result but cannot parse output", "!!! Test matched expected result but cannot parse output",
@@ -350,7 +352,7 @@ function test_case(test) {
"", "",
].join("\n"), { ].join("\n"), {
input: input_formatted, input: input_formatted,
output: output, output: output_code,
error: ex, error: ex,
}); });
return false; return false;
@@ -409,7 +411,7 @@ function test_case(test) {
}); });
return false; return false;
} }
actual = run_code(output, toplevel); actual = run_code(output_code, toplevel);
if (!sandbox.same_stdout(test.expect_stdout, actual)) { if (!sandbox.same_stdout(test.expect_stdout, actual)) {
log([ log([
"!!! failed", "!!! failed",

View File

@@ -243,20 +243,18 @@ issue_3273: {
arguments: true, arguments: true,
} }
input: { input: {
function f(a) { (function(a) {
console.log(arguments[0], a); console.log(arguments[0], a);
arguments[0]++; arguments[0]++;
console.log(arguments[0], a); console.log(arguments[0], a);
} })(0);
f(0);
} }
expect: { expect: {
function f(a) { (function(a) {
console.log(a, a); console.log(a, a);
a++; a++;
console.log(a, a); console.log(a, a);
} })(0);
f(0);
} }
expect_stdout: [ expect_stdout: [
"0 0", "0 0",
@@ -264,26 +262,43 @@ issue_3273: {
] ]
} }
issue_3273_no_call_arg: {
options = {
arguments: true,
}
input: {
(function(a) {
arguments[0] = "FAIL";
console.log(a);
})();
}
expect: {
(function(a) {
arguments[0] = "FAIL";
console.log(a);
})();
}
expect_stdout: "undefined"
}
issue_3273_reduce_vars: { issue_3273_reduce_vars: {
options = { options = {
arguments: true, arguments: true,
reduce_vars: true, reduce_vars: true,
} }
input: { input: {
function f(a) { (function(a) {
console.log(arguments[0], a); console.log(arguments[0], a);
arguments[0]++; arguments[0]++;
console.log(arguments[0], a); console.log(arguments[0], a);
} })(0);
f(0);
} }
expect: { expect: {
function f(a) { (function(a) {
console.log(a, a); console.log(a, a);
a++; a++;
console.log(a, a); console.log(a, a);
} })(0);
f(0);
} }
expect_stdout: [ expect_stdout: [
"0 0", "0 0",
@@ -296,22 +311,20 @@ issue_3273_local_strict: {
arguments: true, arguments: true,
} }
input: { input: {
function f(a) { (function(a) {
"use strict"; "use strict";
console.log(arguments[0], a); console.log(arguments[0], a);
arguments[0]++; arguments[0]++;
console.log(arguments[0], a); console.log(arguments[0], a);
} })(0);
f(0);
} }
expect: { expect: {
function f(a) { (function(a) {
"use strict"; "use strict";
console.log(arguments[0], a); console.log(arguments[0], a);
arguments[0]++; arguments[0]++;
console.log(arguments[0], a); console.log(arguments[0], a);
} })(0);
f(0);
} }
expect_stdout: [ expect_stdout: [
"0 0", "0 0",
@@ -325,22 +338,20 @@ issue_3273_local_strict_reduce_vars: {
reduce_vars: true, reduce_vars: true,
} }
input: { input: {
function f(a) { (function(a) {
"use strict"; "use strict";
console.log(arguments[0], a); console.log(arguments[0], a);
arguments[0]++; arguments[0]++;
console.log(arguments[0], a); console.log(arguments[0], a);
} })(0);
f(0);
} }
expect: { expect: {
function f(a) { (function(a) {
"use strict"; "use strict";
console.log(arguments[0], a); console.log(arguments[0], a);
arguments[0]++; arguments[0]++;
console.log(arguments[0], a); console.log(arguments[0], a);
} })(0);
f(0);
} }
expect_stdout: [ expect_stdout: [
"0 0", "0 0",
@@ -354,21 +365,19 @@ issue_3273_global_strict: {
} }
input: { input: {
"use strict"; "use strict";
function f(a) { (function(a) {
console.log(arguments[0], a); console.log(arguments[0], a);
arguments[0]++; arguments[0]++;
console.log(arguments[0], a); console.log(arguments[0], a);
} })(0);
f(0);
} }
expect: { expect: {
"use strict"; "use strict";
function f(a) { (function(a) {
console.log(arguments[0], a); console.log(arguments[0], a);
arguments[0]++; arguments[0]++;
console.log(arguments[0], a); console.log(arguments[0], a);
} })(0);
f(0);
} }
expect_stdout: [ expect_stdout: [
"0 0", "0 0",
@@ -383,21 +392,19 @@ issue_3273_global_strict_reduce_vars: {
} }
input: { input: {
"use strict"; "use strict";
function f(a) { (function(a) {
console.log(arguments[0], a); console.log(arguments[0], a);
arguments[0]++; arguments[0]++;
console.log(arguments[0], a); console.log(arguments[0], a);
} })(0);
f(0);
} }
expect: { expect: {
"use strict"; "use strict";
function f(a) { (function(a) {
console.log(arguments[0], a); console.log(arguments[0], a);
arguments[0]++; arguments[0]++;
console.log(arguments[0], a); console.log(arguments[0], a);
} })(0);
f(0);
} }
expect_stdout: [ expect_stdout: [
"0 0", "0 0",

View File

@@ -407,3 +407,57 @@ issue_3429_2: {
} }
expect_stdout: "undefined" expect_stdout: "undefined"
} }
issue_3949_1: {
options = {
assignments: true,
evaluate: true,
reduce_vars: true,
}
input: {
var a = 42;
function f() {
var b = a;
b = b >> 2;
return 100 + b;
}
console.log(f());
}
expect: {
var a = 42;
function f() {
var b = a;
b >>= 2;
return 100 + b;
}
console.log(f());
}
expect_stdout: "110"
}
issue_3949_2: {
options = {
assignments: true,
evaluate: true,
reduce_vars: true,
}
input: {
var a = 42;
function f() {
var b = a;
b = 5 & b;
return 100 + b;
}
console.log(f());
}
expect: {
var a = 42;
function f() {
var b = a;
b &= 5;
return 100 + b;
}
console.log(f());
}
expect_stdout: "100"
}

View File

@@ -62,7 +62,7 @@ collapse_vars_side_effects_1: {
expect: { expect: {
function f1() { function f1() {
var s = "abcdef", i = 2; var s = "abcdef", i = 2;
console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(i++), 7); console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(4), 7);
} }
function f2() { function f2() {
var s = "abcdef", i = 2; var s = "abcdef", i = 2;
@@ -74,13 +74,14 @@ collapse_vars_side_effects_1: {
log = console.log.bind(console), log = console.log.bind(console),
x = s.charAt(i++), x = s.charAt(i++),
y = s.charAt(i++); y = s.charAt(i++);
log(x, s.charAt(i++), y, 7); log(x, s.charAt(4), y, 7);
} }
function f4() { function f4() {
var i = 10, var i = 10;
x = i += 2, i += 2,
y = i += 3; i += 3,
console.log.bind(console)(x, i += 4, y, 19); i += 4;
console.log.bind(console)(12, 19, 15, 19);
} }
f1(), f2(), f3(), f4(); f1(), f2(), f3(), f4();
} }
@@ -916,7 +917,7 @@ collapse_vars_lvalues_drop_assign: {
} }
} }
collapse_vars_misc1: { collapse_vars_misc: {
options = { options = {
booleans: true, booleans: true,
collapse_vars: true, collapse_vars: true,
@@ -970,8 +971,8 @@ collapse_vars_misc1: {
function f7() { var b = window.a * window.z; return b + b } function f7() { var b = window.a * window.z; return b + b }
function f8() { var b = window.a * window.z; return b + (5 + b) } function f8() { var b = window.a * window.z; return b + (5 + b) }
function f9() { var b = window.a * window.z; return bar() || b } function f9() { var b = window.a * window.z; return bar() || b }
function f10(x) { var a = 5; return a += 3; } function f10(x) { return 8; }
function f11(x) { var a = 5; return a += 2; } function f11(x) { return 7; }
} }
} }
@@ -3000,8 +3001,7 @@ issue_2298: {
expect: { expect: {
!function() { !function() {
(function() { (function() {
var a = undefined; 0;
var undefined = a++;
try { try {
!function(b) { !function(b) {
(void 0)[1] = "foo"; (void 0)[1] = "foo";
@@ -3835,20 +3835,19 @@ issue_2436_3: {
}(o)); }(o));
} }
expect: { expect: {
var o = {
a: 1,
b: 2,
};
console.log(function(c) { console.log(function(c) {
o = { ({
a: 3, a: 3,
b: 4, b: 4,
}; });
return { return {
x: c.a, x: c.a,
y: c.b, y: c.b,
}; };
}(o)); }({
a: 1,
b: 2,
}));
} }
expect_stdout: true expect_stdout: true
} }
@@ -4070,16 +4069,15 @@ issue_2436_10: {
}(o).join(" ")); }(o).join(" "));
} }
expect: { expect: {
var o = {
a: 1,
b: 2,
};
function f(n) { function f(n) {
o = { b: 3 }; ({ b: 3 });
return n; return n;
} }
console.log([ console.log([
(c = o).a, (c = {
a: 1,
b: 2,
}).a,
f(c.b), f(c.b),
c.b, c.b,
].join(" ")); ].join(" "));
@@ -6890,6 +6888,30 @@ sequence_in_iife_2: {
} }
expect: { expect: {
var a = "foo", b = 42; var a = "foo", b = 42;
b = a;
console.log(a, b);
}
expect_stdout: "foo foo"
}
sequence_in_iife_3: {
options = {
collapse_vars: true,
inline: true,
passes: 2,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "foo", b = 42;
(function() {
var c = (b = a, b);
})();
console.log(a, b);
}
expect: {
var a = "foo";
console.log(a, a); console.log(a, a);
} }
expect_stdout: "foo foo" expect_stdout: "foo foo"
@@ -7955,7 +7977,7 @@ mangleable_var: {
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3884: { issue_3884_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
@@ -7973,9 +7995,33 @@ issue_3884: {
console.log(a, b); console.log(a, b);
} }
expect: { expect: {
var a = 100; var a = 100, b = 1;
++a; b <<= ++a;
console.log(a, 32); console.log(a, b);
}
expect_stdout: "101 32"
}
issue_3884_2: {
options = {
collapse_vars: true,
evaluate: true,
passes: 3,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = 100, b = 1;
{
a++ + a || a;
b <<= a;
}
console.log(a, b);
}
expect: {
console.log(101, 32);
} }
expect_stdout: "101 32" expect_stdout: "101 32"
} }
@@ -8108,3 +8154,166 @@ issue_3908: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3927: {
options = {
collapse_vars: true,
}
input: {
var a = 0;
console.log(function(b) {
try {
try {
if (a + (b = "PASS", true)) return;
b.p;
} finally {
return b;
}
} catch (e) {
}
}());
}
expect: {
var a = 0;
console.log(function(b) {
try {
try {
if (a + (b = "PASS", true)) return;
b.p;
} finally {
return b;
}
} catch (e) {}
}());
}
expect_stdout: "PASS"
}
operator_in: {
options = {
collapse_vars: true,
}
input: {
function log(msg) {
console.log(msg);
}
var a = "FAIL";
try {
a = "PASS";
0 in null;
log("FAIL", a);
} catch (e) {}
log(a);
}
expect: {
function log(msg) {
console.log(msg);
}
var a = "FAIL";
try {
a = "PASS";
0 in null;
log("FAIL", a);
} catch (e) {}
log(a);
}
expect_stdout: "PASS"
}
issue_3971: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = 0 == typeof f, b = 0;
{
var a = void (a++ + (b |= a));
}
console.log(b);
}
expect: {
var a = 0 == typeof f, b = 0;
var a = void (b |= ++a);
console.log(b);
}
expect_stdout: "1"
}
issue_3976: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
console.log("FAIL");
}
(function(a) {
function g() {
if ((a = 0) || f(0)) {
f();
} else {
f();
}
if (h(a = 0));
}
function h() {
g();
}
})();
console.log("PASS");
}
expect: {
function f() {
console.log("FAIL");
}
void 0;
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_4012: {
options = {
collapse_vars: true,
dead_code: true,
evaluate: true,
}
input: {
(function(a) {
try {
throw 2;
} catch (b) {
a = "PASS";
if (--b)
return;
if (3);
} finally {
console.log(a);
}
})();
}
expect: {
(function(a) {
try {
throw 2;
} catch (b) {
a = "PASS";
if (--b)
return;
if (3);
} finally {
console.log(a);
}
})();
}
expect_stdout: "PASS"
}

View File

@@ -236,7 +236,7 @@ collapse_vars_lvalues_drop_assign: {
} }
} }
collapse_vars_misc1: { collapse_vars_misc: {
options = { options = {
collapse_vars: true, collapse_vars: true,
dead_code: true, dead_code: true,
@@ -1169,27 +1169,175 @@ redundant_assignments: {
expect_stdout: "PASS PASS" expect_stdout: "PASS PASS"
} }
self_assignments: { self_assignments_1: {
options = { options = {
dead_code: true, dead_code: true,
} }
input: { input: {
var a = "PASS", b = 0, l = [ "FAIL", "PASS" ], o = { p: "PASS" }; var a = "PASS";
a = a; a = a;
l[0] = l[0]; console.log(a);
l[b] = l[b];
l[b++] = l[b++];
o.p = o.p;
console.log(a, b, l[0], o.p);
} }
expect: { expect: {
var a = "PASS", b = 0, l = [ "FAIL", "PASS" ], o = { p: "PASS" }; var a = "PASS";
a; a;
l[0]; console.log(a);
l[b];
l[b++] = l[b++];
o.p;
console.log(a, b, l[0], o.p);
} }
expect_stdout: "PASS 2 PASS PASS" expect_stdout: "PASS"
}
self_assignments_2: {
options = {
dead_code: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = "q", o = {
p: "PASS",
};
o.p = o.p;
o[a] = o[a];
console.log(o.p, o[a]);
}
expect: {
var a = "q", o = {
p: "PASS",
};
console.log(o.p, o[a]);
}
expect_stdout: "PASS undefined"
}
self_assignments_3: {
options = {
dead_code: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = "q", o = {
p: "FAIL",
get q() {
return "PASS";
},
set q(v) {
this.p = v;
},
};
o.p = o.p;
o[a] = o[a];
console.log(o.p, o[a]);
}
expect: {
var a = "q", o = {
p: "FAIL",
get q() {
return "PASS";
},
set q(v) {
this.p = v;
},
};
o.p = o.p;
o[a] = o[a];
console.log(o.p, o[a]);
}
expect_stdout: "PASS PASS"
}
self_assignments_4: {
options = {
dead_code: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var i = 0, l = [ "PASS" ];
l[0] = l[0];
l[i] = l[i];
console.log(l[0], i);
}
expect: {
var i = 0, l = [ "PASS" ];
console.log(l[0], i);
}
expect_stdout: "PASS 0"
}
self_assignments_5: {
options = {
dead_code: true,
evaluate: true,
passes: 3,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var i = 0, l = [ "FAIL", "PASS" ];
l[0] = l[0];
l[i] = l[i];
l[i++] = l[i++];
console.log(l[0], i);
}
expect: {
var i = 0, l = [ "FAIL", "PASS" ];
l[0];
l[0];
l[0] = l[1];
console.log(l[0], 2);
}
expect_stdout: "PASS 2"
}
self_assignments_6: {
options = {
dead_code: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var o = {
p: "PASS",
};
console.log(o.p = o.p);
}
expect: {
var o = {
p: "PASS",
};
console.log(o.p);
}
expect_stdout: "PASS"
}
issue_3967: {
options = {
dead_code: true,
}
input: {
var a = "FAIL";
try {
a = 0 in (a = "PASS");
} catch (e) {}
console.log(a);
}
expect: {
var a = "FAIL";
try {
a = 0 in (a = "PASS");
} catch (e) {}
console.log(a);
}
expect_stdout: "PASS"
} }

View File

@@ -2285,7 +2285,7 @@ issue_3598: {
try { try {
(function() { (function() {
a = "PASS"; a = "PASS";
var c = (void (c.p = 0))[!1]; (void ((void 0).p = 0))[!1];
})(); })();
} catch (e) {} } catch (e) {}
console.log(a); console.log(a);
@@ -2557,11 +2557,294 @@ issue_3899: {
console.log(typeof a); console.log(typeof a);
} }
expect: { expect: {
++a; function a() {
var a = function() {
return 2; return 2;
}; }
console.log(typeof a); console.log(typeof a);
} }
expect_stdout: "function" expect_stdout: "function"
} }
cross_scope_assign_chain: {
options = {
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a, b = 0;
(function() {
a = b;
a++;
while (b++);
})();
console.log(a ? "PASS" : "FAIL");
}
expect: {
var a, b = 0;
(function() {
a = b;
a++;
while (b++);
})();
console.log(a ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
assign_if_assign_read: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(a) {
var b;
do {
b = "FAIL";
if (Array.isArray(a)) {
b = a[0];
console.log(b);
}
} while (!console);
})([ "PASS" ]);
}
expect: {
(function(a) {
var b;
do {
"FAIL";
if (Array.isArray(a)) {
b = a[0];
console.log(b);
}
} while (!console);
})([ "PASS" ]);
}
expect_stdout: "PASS"
}
issue_3951: {
options = {
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = console.log("PASS");
console.log(a);
a = "0";
console.log(a.p = 0);
a && a;
}
expect: {
var a = console.log("PASS");
console.log(a);
a = "0";
console.log(a.p = 0);
}
expect_stdout: [
"PASS",
"undefined",
"0",
]
}
issue_3956: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
(function(a) {
function f(b) {
console.log(b);
a = 1;
}
var c = f(c += 0);
(function(d) {
console.log(d);
})(console.log(a) ^ 1, c);
})();
}
expect: {
var c, d;
c += 0,
console.log(NaN),
d = 1 ^ console.log(1),
console.log(d);
}
expect_stdout: [
"NaN",
"1",
"1",
]
}
issue_3962_1: {
options = {
evaluate: true,
keep_fargs: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 0;
function f(b, c) {
do {
var d = console + e, e = 0..toString() === b;
} while (0);
if (c) console.log("PASS");
}
var a = f(a--, 1);
a;
}
expect: {
var a = 0;
a = (function(c) {
do {
console;
0..toString();
} while (0);
if (c) console.log("PASS");
}((a--, 1)), 0);
void 0;
}
expect_stdout: "PASS"
}
issue_3962_2: {
options = {
keep_fargs: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = 0;
function f(b, c) {
do {
var d = console + e, e = 0..toString() === b;
} while (0);
if (c) console.log("PASS");
}
var a = f(a--, 1);
a;
}
expect: {
var a = 0;
a = (function(c) {
do {
console;
0..toString();
} while (0);
if (c) console.log("PASS");
}((a--, 1)), 0);
}
expect_stdout: "PASS"
}
issue_3986: {
options = {
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = 0, b = 0;
(function() {
try {
throw 42;
} catch (e) {
a++;
}
b = b && 0;
})(b *= a);
console.log(b);
}
expect: {
var a = 0, b = 0;
(function() {
try {
throw 42;
} catch (e) {
a++;
}
b = b && 0;
})(b *= a);
console.log(b);
}
expect_stdout: "0"
}
issue_4017: {
options = {
pure_getters: "strict",
reduce_vars: true,
unused: true,
}
input: {
var a = 0;
console.log(function f() {
var b = c &= 0;
var c = a++ + (A = a);
var d = c && c[f];
}());
}
expect: {
var a = 0;
console.log(function() {
c &= 0;
var c = (a++, A = a, 0);
}());
}
expect_stdout: "undefined"
}
issue_4025: {
options = {
collapse_vars: true,
evaluate: true,
passes: 2,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 0, b = 0, c = 0, d = a++;
try {
var e = console.log(c), f = b;
} finally {
var d = b = 1, d = c + 1;
c = 0;
}
console.log(a, b, d);
}
expect: {
var d, c = 0;
try {
console.log(c);
} finally {
d = c + 1;
c = 0;
}
console.log(1, 1, d);
}
expect_stdout: [
"0",
"1 1 1",
]
}

View File

@@ -558,34 +558,51 @@ unsafe_array: {
unsafe: true, unsafe: true,
} }
input: { input: {
console.log( var a = "PASS";
[1, , 3][1], Array.prototype[1] = a;
[1, 2, 3, a] + 1, console.log([, ].length);
[1, 2, 3, 4] + 1, console.log("" + [, , ]);
[1, 2, 3, a][0] + 1, console.log([1, , 3][1]);
[1, 2, 3, 4][0] + 1, console.log([1, 2, 3, a] + 1);
[1, 2, 3, 4][6 - 5] + 1, console.log([1, 2, 3, 4] + 1);
[1, , 3, 4][6 - 5] + 1, console.log([1, 2, 3, a][0] + 1);
[[1, 2], [3, 4]][0] + 1, console.log([1, 2, 3, 4][0] + 1);
[[1, 2], [3, 4]][6 - 5][1] + 1, console.log([1, 2, 3, 4][6 - 5] + 1);
[[1, 2], , [3, 4]][6 - 5][1] + 1 console.log([1, , 3, 4][6 - 5] + 1);
); console.log([[1, 2], [3, 4]][0] + 1);
console.log([[1, 2], [3, 4]][6 - 5][1] + 1);
console.log([[1, 2], , [3, 4]][6 - 5][1] + 1);
} }
expect: { expect: {
console.log( var a = "PASS";
void 0, Array.prototype[1] = a;
[1, 2, 3, a] + 1, console.log([, ].length);
"1,2,3,41", console.log("" + [, , ]);
[1, 2, 3, a][0] + 1, console.log([1, , 3][1]);
2, console.log([1, 2, 3, a] + 1);
3, console.log("1,2,3,41");
NaN, console.log([1, 2, 3, a][0] + 1);
"1,21", console.log(2);
5, console.log(3);
(void 0)[1] + 1 console.log([1, , 3, 4][1] + 1);
); console.log("1,21");
console.log(5);
console.log([[1, 2], , [3, 4]][1][1] + 1);
} }
expect_stdout: true expect_stdout: [
"1",
",PASS",
"PASS",
"1,2,3,PASS1",
"1,2,3,41",
"2",
"2",
"3",
"PASS1",
"1,21",
"5",
"A1",
]
} }
unsafe_string: { unsafe_string: {
@@ -1579,9 +1596,9 @@ issue_2968_1: {
expect: { expect: {
var c = "FAIL"; var c = "FAIL";
(function() { (function() {
b = -(a = 42), a = 42,
void ((a <<= 0) && (a[(c = "PASS", 0 >>> (b += 1))] = 0)); void ((a <<= 0) && (a[(c = "PASS", 0)] = 0));
var a, b; var a;
})(); })();
console.log(c); console.log(c);
} }
@@ -2341,10 +2358,7 @@ issue_3878_1: {
console.log(b ? "PASS" : "FAIL"); console.log(b ? "PASS" : "FAIL");
} }
expect: { expect: {
var b = function(a) { console.log(true ? "PASS" : "FAIL");
return (a = 0) == (a && this > (a += 0));
}();
console.log(b ? "PASS" : "FAIL");
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
@@ -2412,9 +2426,9 @@ issue_3887: {
expect: { expect: {
(function(b) { (function(b) {
try { try {
b-- && console.log("PASS"); 1, console.log("PASS");
} catch (a_2) {} } catch (a_2) {}
})(1); })();
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
@@ -2435,12 +2449,11 @@ issue_3903: {
console.log(d); console.log(d);
} }
expect: { expect: {
var a = "PASS";
function f(b, c) { function f(b, c) {
return console, c; return console, c;
} }
var d = f(f(), a = a); f(f(), "PASS");
console.log(d); console.log("PASS");
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
@@ -2478,10 +2491,345 @@ issue_3920: {
console.log(a); console.log(a);
} }
expect: { expect: {
var a = function(b) { (function(b) {
return (b[b = 0] = 0) >= (b ? 0 : 1); "foo"[0] = 0;
}("foo"); })();
console.log(a); console.log(false);
} }
expect_stdout: "false" expect_stdout: "false"
} }
inlined_increment_prefix: {
options = {
evaluate: true,
inline: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 0;
(function() {
++a;
})();
console.log(a += 0);
}
expect: {
var a = 0;
void ++a;
console.log(1);
}
expect_stdout: "1"
}
inlined_increment_postfix: {
options = {
evaluate: true,
inline: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 0;
(function() {
a++;
})();
console.log(a += 0);
}
expect: {
var a = 0;
void a++;
console.log(1);
}
expect_stdout: "1"
}
compound_assignment_to_property: {
options = {
evaluate: true,
unsafe: true,
}
input: {
1 + (0..p >>= 0) && console.log("PASS");
}
expect: {
1 + (0..p >>= 0),
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_2208_assign: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
a = 42;
console.log({
p: function() {
return function() {
return this.a;
}();
}
}.p());
}
expect: {
a = 42;
console.log({
p: function() {
return function() {
return this.a;
}();
}
}.p());
}
expect_stdout: "42"
}
issue_2208_postfix: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
a = 41;
a++;
console.log({
p: function() {
return function() {
return this.a;
}();
}
}.p());
}
expect: {
a = 41;
a++;
console.log({
p: function() {
return function() {
return this.a;
}();
}
}.p());
}
expect_stdout: "42"
}
issue_2208_prefix: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
a = 43;
--a;
console.log({
p: function() {
return function() {
return this.a;
}();
}
}.p());
}
expect: {
a = 43;
--a;
console.log({
p: function() {
return function() {
return this.a;
}();
}
}.p());
}
expect_stdout: "42"
}
issue_3933: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
(function(a, b) {
a && (b ^= 1) && console.log("PASS");
})(1);
}
expect: {
(function(a, b) {
1, 1, console.log("PASS");
})();
}
expect_stdout: "PASS"
}
issue_3935: {
options = {
evaluate: true,
}
input: {
console.log(function f(a) {
return a++;
}());
}
expect: {
console.log(NaN);
}
expect_stdout: "NaN"
}
issue_3937: {
options = {
conditionals: true,
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var a = 123;
(a++ + (b = a))[b] ? 0 ? a : b : 0 ? a : b;
console.log(a, b);
}
expect: {
var a = 123;
(a++ + (b = a))[b], 0, b;
console.log(a, b);
}
expect_stdout: "124 124"
}
issue_3944: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
function f() {
while (function() {
var a = 0 == (b && b.p), b = console.log(a);
}());
f;
}
f();
})();
}
expect: {
void function f() {
while (a = 0 == (a = void 0), console.log(a), void 0);
var a;
f;
}();
}
expect_stdout: "false"
}
issue_3953: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
function f(a) {
(a += 0 * (a = 0)) && console.log("PASS");
}
f(1);
}
expect: {
function f(a) {
(a += 0 * (a = 0)) && console.log("PASS");
}
f(1);
}
expect_stdout: "PASS"
}
issue_3988: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
function f(b) {
return ("" + (b &= 0))[b && this];
}
var a = f();
console.log(a);
}
expect: {
var a = function(b) {
return ("" + (b &= 0))[b && this];
}();
console.log(a);
}
expect_stdout: "0"
}
operator_in: {
options = {
evaluate: true,
unsafe: true,
}
input: {
Object.prototype.PASS = 0;
console.log(0 in [ 1 ]);
console.log(0 in [ , ]);
console.log(0 / 0 in { NaN: 2 });
console.log("PASS" in { });
console.log("FAIL" in { });
console.log("toString" in { });
console.log("toString" in { toString: 3 });
}
expect: {
Object.prototype.PASS = 0;
console.log(true);
console.log(0 in [ , ]);
console.log(true);
console.log("PASS" in { });
console.log("FAIL" in { });
console.log("toString" in { });
console.log(true);
}
expect_stdout: [
"true",
"false",
"true",
"true",
"false",
"true",
"true",
]
}
issue_3997: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = function f(b) {
return b[b += this] = b;
}(0);
console.log(typeof a);
}
expect: {
var a = function f(b) {
return b[b += this] = b;
}(0);
console.log(typeof a);
}
expect_stdout: "string"
}

View File

@@ -2336,6 +2336,7 @@ issue_3274: {
inline: true, inline: true,
join_vars: true, join_vars: true,
loops: true, loops: true,
passes: 2,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -4705,3 +4706,75 @@ issue_3911: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3929: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var abc = function f() {
(function() {
switch (f) {
default:
var abc = 0;
case 0:
abc.p;
}
console.log(typeof f);
})();
};
typeof abc && abc();
})();
}
expect: {
(function() {
var abc = function f() {
(function() {
switch (f) {
default:
var abc = 0;
case 0:
abc.p;
}
console.log(typeof f);
})();
};
typeof abc && abc();
})();
}
expect_stdout: "function"
}
issue_4006: {
options = {
dead_code: true,
evaluate: true,
inline: true,
keep_fargs: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
var a = 0;
(function() {
(function(b, c) {
for (var k in console.log(c), 0)
return b += 0;
})(0, --a);
return a ? 0 : --a;
})();
}
expect: {
var a = 0;
(function(c) {
for (var k in console.log(c), 0)
return;
})(--a), a || --a;
}
expect_stdout: "-1"
}

View File

@@ -12,6 +12,20 @@ must_replace: {
} }
} }
repeated_nodes: {
options = {
global_defs: {
"@N": "rand()",
},
}
input: {
console.log(N, N);
}
expect: {
console.log(rand(), rand());
}
}
keyword: { keyword: {
options = { options = {
global_defs: { global_defs: {

View File

@@ -972,3 +972,72 @@ issue_3871: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3945_1: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
function f() {
o.p;
var o = {
q: 0,
};
}
}
expect: {
function f() {
o.p;
var o = {
q: 0,
};
}
}
}
issue_3945_2: {
options = {
hoist_props: true,
reduce_vars: true,
toplevel: true,
}
input: {
console.log(typeof o);
var o = {
p: 0,
};
}
expect: {
console.log(typeof o);
var o = {
p: 0,
};
}
expect_stdout: "undefined"
}
issue_4023: {
options = {
comparisons: true,
hoist_props: true,
inline: true,
reduce_vars: true,
toplevel: true,
typeofs: true,
unused: true,
}
input: {
function f() {
var a = function() {
return { p: 0 };
}();
return console.log("undefined" != typeof a);
}
f();
}
expect: {
console.log(void 0 !== {});
}
expect_stdout: "true"
}

View File

@@ -2223,13 +2223,13 @@ issue_3523_rename_ie8: {
expect: { expect: {
var a = 0, b, c = "FAIL"; var a = 0, b, c = "FAIL";
(function() { (function() {
var c, n, t, o, a, r, f, i, u, e, h, l, v, y; var c, n, t, o, a, r, e, f, i, u, h, l, v, y;
})(); })();
try { try {
throw 0; throw 0;
} catch (e) { } catch (e) {
(function() { (function() {
(function n() { (function e() {
c = "PASS"; c = "PASS";
})(); })();
})(); })();
@@ -2522,3 +2522,195 @@ issue_3918: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3999: {
rename = true
mangle = {
ie8: true,
}
input: {
(function() {
(function f() {
for (var i = 0; i < 2; i++)
try {
f[0];
} catch (f) {
var f = 0;
console.log(i);
}
})();
})(typeof f);
}
expect: {
(function() {
(function f() {
for (var o = 0; o < 2; o++)
try {
f[0];
} catch (f) {
var f = 0;
console.log(o);
}
})();
})(typeof f);
}
expect_stdout: [
"0",
"1",
]
}
issue_4001: {
options = {
collapse_vars: true,
ie8: true,
inline: true,
reduce_vars: true,
sequences: true,
toplevel: true,
unused: true,
}
input: {
console.log(function(a) {
function f() {
return a;
var b;
}
var c = f();
(function g() {
c[42];
f;
})();
(function a() {});
}(42));
}
expect: {
function f() {
return a;
}
var a;
console.log((a = 42, void f()[42], void function a() {}));
}
expect_stdout: "undefined"
}
issue_4015: {
rename = true
mangle = {
ie8: true,
toplevel: true,
}
input: {
var n, a = 0, b;
function f() {
try {
throw 0;
} catch (b) {
(function g() {
(function b() {
a++;
})();
})();
}
}
f();
console.log(a);
}
expect: {
var n, o = 0, c;
function t() {
try {
throw 0;
} catch (c) {
(function n() {
(function c() {
o++;
})();
})();
}
}
t();
console.log(o);
}
expect_stdout: "1"
}
issue_4019: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
ie8: true,
toplevel: true,
}
input: {
var a = function() {
try {
console.log("FAIL");
} catch (b) {}
}, a = (console.log(a.length), ++a);
}
expect: {
var o = function() {
try {
console.log("FAIL");
} catch (o) {}
}, o = (console.log(o.length), ++o);
}
expect_stdout: "0"
}
issue_4028: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {
ie8: true,
}
input: {
function a() {
try {
A;
} catch (e) {}
}
var b = a += a;
console.log(typeof b);
}
expect: {
function a() {
try {
A;
} catch (a) {}
}
var b = a += a;
console.log(typeof b);
}
expect_stdout: "string"
}
issue_2737: {
options = {
ie8: true,
reduce_vars: true,
unused: true,
}
input: {
(function(a) {
a();
})(function f() {
console.log(typeof f);
});
}
expect: {
(function(a) {
a();
})(function f() {
console.log(typeof f);
});
}
expect_stdout: "function"
}

View File

@@ -808,9 +808,9 @@ issue_3795: {
} }
expect: { expect: {
var a = "FAIL", d = function() { var a = "FAIL", d = function() {
if (a = 42, d) return -1; if (void 0) return -1;
a = "PASS"; a = "PASS";
}(); }(a = 42);
console.log(a, d); console.log(a, d);
} }
expect_stdout: "PASS undefined" expect_stdout: "PASS undefined"

View File

@@ -306,8 +306,7 @@ issue_2298: {
expect: { expect: {
!function() { !function() {
(function() { (function() {
var a = undefined; 0;
var undefined = a++;
try { try {
!function() { !function() {
(void 0)[1] = "foo"; (void 0)[1] = "foo";

View File

@@ -1046,16 +1046,22 @@ array_hole: {
side_effects: true, side_effects: true,
} }
input: { input: {
console.log( Array.prototype[2] = "PASS";
[ 1, 2, , 3][1], console.log([ 1, 2, , 3 ][1]);
[ 1, 2, , 3][2], console.log([ 1, 2, , 3 ][2]);
[ 1, 2, , 3][3] console.log([ 1, 2, , 3 ][3]);
);
} }
expect: { expect: {
console.log(2, void 0, 3); Array.prototype[2] = "PASS";
console.log(2);
console.log([ , , , ][2]);
console.log(3);
} }
expect_stdout: "2 undefined 3" expect_stdout: [
"2",
"PASS",
"3",
]
} }
new_this: { new_this: {

View File

@@ -136,7 +136,7 @@ relational: {
side_effects :true, side_effects :true,
} }
input: { input: {
foo() in foo(); foo() in new foo();
foo() instanceof bar(); foo() instanceof bar();
foo() < "bar"; foo() < "bar";
bar() > foo(); bar() > foo();

View File

@@ -905,7 +905,7 @@ use_before_var: {
} }
expect: { expect: {
function f(){ function f(){
console.log(t); console.log(void 0);
var t = 1; var t = 1;
} }
} }
@@ -981,12 +981,12 @@ inner_var_for_1: {
expect: { expect: {
function f() { function f() {
var a = 1; var a = 1;
x(1, b, d); x(1, void 0, d);
for (var b = 2, c = 3; x(1, b, 3, d); x(1, b, 3, d)) { for (var b = 2, c = 3; x(1, 2, 3, d); x(1, 2, 3, d)) {
var d = 4, e = 5; var d = 4, e = 5;
x(1, b, 3, d, e); x(1, 2, 3, d, e);
} }
x(1, b, 3, d, e); x(1, 2, 3, d, e);
} }
} }
} }
@@ -1520,10 +1520,7 @@ func_inline: {
} }
expect: { expect: {
function f() { function f() {
console.log(1 + h()); console.log(1 + (void 0)());
var h = function() {
return 2;
};
} }
} }
} }
@@ -2372,8 +2369,7 @@ delay_def: {
return; return;
} }
function g() { function g() {
return a; return;
var a = 1;
} }
console.log(f(), g()); console.log(f(), g());
} }
@@ -2395,7 +2391,7 @@ delay_def_lhs: {
expect: { expect: {
console.log(function() { console.log(function() {
long_name++; long_name++;
return long_name; return NaN;
var long_name; var long_name;
}()); }());
} }
@@ -2651,11 +2647,9 @@ var_assign_5: {
} }
expect: { expect: {
!function() { !function() {
var a;
!function(b) { !function(b) {
a = 2, console.log(2, void 0);
console.log(a, b); }();
}(a);
}(); }();
} }
expect_stdout: "2 undefined" expect_stdout: "2 undefined"
@@ -2676,8 +2670,8 @@ var_assign_6: {
} }
expect: { expect: {
!function() { !function() {
var a = function(){}(a = 1); (function(){}());
console.log(a); console.log(void 0);
}(); }();
} }
expect_stdout: "undefined" expect_stdout: "undefined"
@@ -2724,8 +2718,8 @@ issue_1814_1: {
expect: { expect: {
!function() { !function() {
!function(a) { !function(a) {
console.log(a++, 42); console.log(0, 42);
}(0); }();
}(); }();
} }
expect_stdout: "0 42" expect_stdout: "0 42"
@@ -2751,8 +2745,8 @@ issue_1814_2: {
expect: { expect: {
!function() { !function() {
!function(a) { !function(a) {
console.log("321", a++); console.log("321", 0);
}(0); }();
}(); }();
} }
expect_stdout: "321 0" expect_stdout: "321 0"
@@ -4725,7 +4719,7 @@ escape_conditional: {
function bar() {} function bar() {}
(function() { (function() {
var thing = baz(); var thing = baz();
if (thing !== (thing = baz())) if (thing !== baz())
console.log("FAIL"); console.log("FAIL");
else else
console.log("PASS"); console.log("PASS");
@@ -4763,7 +4757,7 @@ escape_sequence: {
function bar() {} function bar() {}
(function() { (function() {
var thing = baz(); var thing = baz();
if (thing !== (thing = baz())) if (thing !== baz())
console.log("FAIL"); console.log("FAIL");
else else
console.log("PASS"); console.log("PASS");
@@ -4808,7 +4802,7 @@ escape_throw: {
function foo() {} function foo() {}
(function() { (function() {
var thing = baz(); var thing = baz();
if (thing !== (thing = baz())) if (thing !== baz())
console.log("FAIL"); console.log("FAIL");
else else
console.log("PASS"); console.log("PASS");
@@ -4845,7 +4839,7 @@ escape_local_conditional: {
} }
(function() { (function() {
var thing = baz(); var thing = baz();
if (thing !== (thing = baz())) if (thing !== baz())
console.log("PASS"); console.log("PASS");
else else
console.log("FAIL"); console.log("FAIL");
@@ -4882,7 +4876,7 @@ escape_local_sequence: {
} }
(function() { (function() {
var thing = baz(); var thing = baz();
if (thing !== (thing = baz())) if (thing !== baz())
console.log("PASS"); console.log("PASS");
else else
console.log("FAIL"); console.log("FAIL");
@@ -4926,7 +4920,7 @@ escape_local_throw: {
} }
(function() { (function() {
var thing = baz(); var thing = baz();
if (thing !== (thing = baz())) if (thing !== baz())
console.log("PASS"); console.log("PASS");
else else
console.log("FAIL"); console.log("FAIL");
@@ -4980,11 +4974,7 @@ inverted_var: {
console.log(1, 2, 3, 4, 5, function c() { console.log(1, 2, 3, 4, 5, function c() {
c = 6; c = 6;
return c; return c;
}(), 7, function() { }(), 7, 8);
c = 8;
return c;
var c = "foo";
}());
} }
expect_stdout: true expect_stdout: true
} }
@@ -5180,9 +5170,7 @@ defun_var_3: {
var a = 42, b; var a = 42, b;
} }
expect: { expect: {
function a() {} console.log("function", "function");
console.log(typeof a, "function");
var a = 42;
} }
expect_stdout: "function function" expect_stdout: "function function"
} }
@@ -7122,3 +7110,299 @@ issue_3922: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3949_1: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
(function f(a) {
var a = void (a = 0, g);
function g() {
console.log(typeof a);
}
g();
})();
}
expect: {
(function f(a) {
var a = void (a = 0, g);
function g() {
console.log(typeof a);
}
g();
})();
}
expect_stdout: "undefined"
}
issue_3949_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function f(a) {
var a = void (a = 0, g);
function g() {
console.log(typeof a);
}
g();
})();
}
expect: {
(function(a) {
a = void (a = 0, g);
function g() {
console.log(typeof a);
}
g();
})();
}
expect_stdout: "undefined"
}
issue_3949_3: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
function f() {}
for (var a, i = 3; 0 <= --i; ) {
a = f;
console.log(a === b);
var b = a;
}
}
expect: {
function f() {}
for (var a, i = 3; 0 <= --i; ) {
a = f;
console.log(a === b);
var b = a;
}
}
expect_stdout: [
"false",
"true",
"true",
]
}
issue_3949_4: {
options = {
reduce_vars: true,
unused: true,
toplevel: true,
}
input: {
function f() {}
for (var a, i = 3; 0 <= --i; ) {
a = f;
console.log(a === b);
var b = a;
}
}
expect: {
function f() {}
for (var a, i = 3; 0 <= --i; ) {
a = f;
console.log(a === b);
var b = a;
}
}
expect_stdout: [
"false",
"true",
"true",
]
}
local_assignment_lambda: {
options = {
evaluate: true,
reduce_vars: true,
sequences: true,
toplevel: true,
unused: true,
}
input: {
var a = "FAIL";
function f() {
a = "PASS";
console.log(a);
}
f();
f();
}
expect: {
function f() {
console.log("PASS");
}
f(),
f();
}
expect_stdout: [
"PASS",
"PASS",
]
}
local_assignment_loop: {
options = {
evaluate: true,
reduce_vars: true,
sequences: true,
toplevel: true,
unused: true,
}
input: {
var a = "FAIL";
do {
a = "PASS";
console.log(a);
} while (!console);
}
expect: {
do {
console.log("PASS");
} while (!console);
}
expect_stdout: "PASS"
}
issue_3957_1: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
function f(a) {
while (a += console.log(a = 0))
a = 0;
}
f("FAIL");
}
expect: {
function f(a) {
while (a += console.log(a = 0))
a = 0;
}
f("FAIL");
}
expect_stdout: [
"0",
"0",
]
}
issue_3957_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
function f(a) {
while (a += console.log(a = 0))
a = 0;
}
f("FAIL");
}
expect: {
function f(a) {
while (a += console.log(a = 0))
a = 0;
}
f("FAIL");
}
expect_stdout: [
"0",
"0",
]
}
issue_3958: {
options = {
evaluate: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var a;
(function(b) {
(function(c) {
console.log(c[0] = 1);
})(a = b);
--a;
})([]);
console.log(a);
}
expect: {
var a;
(function(b) {
(function(c) {
console.log(c[0] = 1);
})(a = []);
--a;
})();
console.log(a);
}
expect_stdout: [
"1",
"0",
]
}
issue_3974: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
try {
var a = 0 in 0;
0 && a;
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
var a = 0 in 0;
0 && a;
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_4030: {
options = {
collapse_vars: true,
evaluate: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a;
{
delete (a = "PASS");
A = "PASS";
}
console.log(A);
}
expect: {
A = "PASS";
console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -97,9 +97,8 @@ issue_2233_2: {
var RegExp; var RegExp;
UndeclaredGlobal; UndeclaredGlobal;
function foo() { function foo() {
var Number;
AnotherUndeclaredGlobal; AnotherUndeclaredGlobal;
Number.isNaN; (void 0).isNaN;
} }
} }
} }
@@ -275,3 +274,120 @@ drop_value: {
foo(), bar(); foo(), bar();
} }
} }
operator_in: {
options = {
side_effects: true,
}
input: {
try {
"foo" in true;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect: {
try {
0 in true;
console.log("FAIL");
} catch (e) {
console.log("PASS");
}
}
expect_stdout: "PASS"
}
issue_3983_1: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
inline: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS";
function f() {
g && g();
}
f();
function g() {
0 ? a : 0;
}
var b = a;
console.log(a);
}
expect: {
var a = "PASS";
g();
function g() {}
console.log(a);
}
expect_stdout: "PASS"
}
issue_3983_2: {
options = {
collapse_vars: true,
conditionals: true,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var a = "PASS";
function f() {
g && g();
}
f();
function g() {
0 ? a : 0;
}
var b = a;
console.log(a);
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_4008: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
toplevel: true,
}
input: {
var a = "PASS";
function f(b, b) {
console.log(b);
}
f && f(a && a[a]);
console.log(a);
}
expect: {
var a = "PASS";
function f(b, b) {
console.log(b);
}
f(a[a]);
console.log(a);
}
expect_stdout: [
"undefined",
"PASS",
]
}

View File

@@ -0,0 +1,5 @@
(function f(a) {
do {
console.log(f.length);
} while (console.log(f += 0));
})();

View File

@@ -0,0 +1,19 @@
// (beautified)
(function f(a) {
do {
console.log(f.length);
} while (console.log(f += 0));
})();
// output: 1
// function(){}0
//
// minify: 0
// function(){}0
//
// options: {
// "compress": {
// "keep_fargs": false,
// "unsafe": true
// },
// "mangle": false
// }

View File

@@ -249,7 +249,7 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should work with `--output-opts`", function(done) { it("Should work with `--output-opts`", function(done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -O'; var command = uglifyjscmd + ' test/input/issue-1482/input.js -O ascii_only';
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, read("test/input/issue-1482/default.js")); assert.strictEqual(stdout, read("test/input/issue-1482/default.js"));
@@ -257,7 +257,7 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should fail when both --beautify & --output-opts are specified", function(done) { it("Should fail when both --beautify & --output-opts are specified", function(done) {
var command = uglifyjscmd + " test/input/issue-520/input.js -bO"; var command = uglifyjscmd + " test/input/issue-520/input.js -bO ascii_only";
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.strictEqual(stderr, "ERROR: --beautify cannot be used with --output-opts\n"); assert.strictEqual(stderr, "ERROR: --beautify cannot be used with --output-opts\n");
@@ -717,7 +717,7 @@ describe("bin/uglifyjs", function() {
var command = uglifyjscmd + " test/input/issue-3315/input.js --config-file test/input/issue-3315/config.json"; var command = uglifyjscmd + " test/input/issue-3315/input.js --config-file test/input/issue-3315/config.json";
exec(command, function(err, stdout) { exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, 'function f(){"aaaaaaaaaa";var a={prop:1,a:2};return a.prop+a.a}\n'); assert.strictEqual(stdout, 'function f(){"aaaaaaaaaa";var a={prop:1,t:2};return a.prop+a.t}\n');
done(); done();
}); });
}); });

View File

@@ -486,4 +486,19 @@ describe("operator", function() {
assert.strictEqual(UglifyJS.parse(exp[0]).print_to_string(), exp[1] + ";"); assert.strictEqual(UglifyJS.parse(exp[0]).print_to_string(), exp[1] + ";");
}); });
}); });
it("Should preserve space between /regex/ and `in`", function() {
[
"/regex/ in {}",
"/regex/g in {}",
"0 + /regex/ in {}",
"0 + /regex/g in {}",
].forEach(function(exp) {
var code = UglifyJS.parse(exp).print_to_string();
try {
assert.strictEqual(UglifyJS.parse(code).print_to_string(), code);
} catch (ex) {
assert.fail("Failed to reparse: " + exp + "\n" + ex);
}
});
});
}); });

View File

@@ -296,4 +296,18 @@ describe("test/reduce.js", function() {
"// }", "// }",
]).join("\n")); ]).join("\n"));
}); });
it("Should handle corner cases when intermediate case differs only in Error.message", function() {
if (semver.satisfies(process.version, "<=0.10")) return;
var result = reduce_test(read("test/input/reduce/diff_error.js"), {
compress: {
keep_fargs: false,
unsafe: true,
},
mangle: false,
}, {
verbose: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, read("test/input/reduce/diff_error.reduced.js"));
});
}); });

View File

@@ -438,7 +438,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
} }
})); }));
var code = testcase_ast.print_to_string(); var code = testcase_ast.print_to_string();
if (diff = test_for_diff(code, minify_options, result_cache, max_timeout)) { var diff = test_for_diff(code, minify_options, result_cache, max_timeout);
if (diff && !diff.timed_out && !diff.error) {
testcase = code; testcase = code;
differs = diff; differs = diff;
} else { } else {

View File

@@ -168,7 +168,7 @@ var VALUES = [
"this", "this",
]; ];
var BINARY_OPS_NO_COMMA = [ var BINARY_OPS = [
" + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors) " + ", // spaces needed to disambiguate with ++ cases (could otherwise cause syntax errors)
" - ", " - ",
"/", "/",
@@ -190,9 +190,15 @@ var BINARY_OPS_NO_COMMA = [
"%", "%",
"&&", "&&",
"||", "||",
"^" ]; "^",
",",
var BINARY_OPS = [","].concat(BINARY_OPS_NO_COMMA); ];
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
BINARY_OPS = BINARY_OPS.concat(BINARY_OPS);
BINARY_OPS.push(" in ");
var ASSIGNMENTS = [ var ASSIGNMENTS = [
"=", "=",
@@ -762,6 +768,10 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
return createArrayLiteral(recurmax, stmtDepth, canThrow) + "." + getDotKey(); return createArrayLiteral(recurmax, stmtDepth, canThrow) + "." + getDotKey();
case p++: case p++:
return createObjectLiteral(recurmax, stmtDepth, canThrow) + "." + getDotKey(); return createObjectLiteral(recurmax, stmtDepth, canThrow) + "." + getDotKey();
case p++:
return createValue() + " in " + createArrayLiteral(recurmax, stmtDepth, canThrow);
case p++:
return createValue() + " in " + createObjectLiteral(recurmax, stmtDepth, canThrow);
case p++: case p++:
var name = getVarName(); var name = getVarName();
var s = name + "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]"; var s = name + "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]";
@@ -879,7 +889,7 @@ function createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
} }
function _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) { function _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
return "(" + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) return "(" + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow)
+ createBinaryOp(noComma) + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")"; + createBinaryOp(noComma, canThrow) + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
} }
function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) { function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
// intentionally generate more hardcore ops // intentionally generate more hardcore ops
@@ -929,9 +939,12 @@ function createValue() {
return VALUES[rng(VALUES.length)]; return VALUES[rng(VALUES.length)];
} }
function createBinaryOp(noComma) { function createBinaryOp(noComma, canThrow) {
if (noComma) return BINARY_OPS_NO_COMMA[rng(BINARY_OPS_NO_COMMA.length)]; var op;
return BINARY_OPS[rng(BINARY_OPS.length)]; do {
op = BINARY_OPS[rng(BINARY_OPS.length)];
} while (noComma && op == "," || !canThrow && op == " in ");
return op;
} }
function createAssignment() { function createAssignment() {
@@ -1124,18 +1137,6 @@ function log(options) {
errorln(original_result); errorln(original_result);
errorln("uglified result:"); errorln("uglified result:");
errorln(uglify_result); errorln(uglify_result);
errorln("//-------------------------------------------------------------");
var reduced = reduce_test(original_code, JSON.parse(options), {
verbose: false,
}).code;
if (reduced) {
errorln();
errorln("// reduced test case (output will differ)");
errorln();
errorln(reduced);
errorln();
errorln("//-------------------------------------------------------------");
}
} else { } else {
errorln("// !!! uglify failed !!!"); errorln("// !!! uglify failed !!!");
errorln(uglify_code); errorln(uglify_code);
@@ -1146,6 +1147,20 @@ function log(options) {
errorln(original_result); errorln(original_result);
} }
} }
errorln("//-------------------------------------------------------------");
var reduce_options = JSON.parse(options);
reduce_options.validate = true;
var reduced = reduce_test(original_code, reduce_options, {
verbose: false,
}).code;
if (reduced) {
errorln();
errorln("// reduced test case (output will differ)");
errorln();
errorln(reduced);
errorln();
errorln("//-------------------------------------------------------------");
}
errorln("minify(options):"); errorln("minify(options):");
errorln(JSON.stringify(JSON.parse(options), null, 2)); errorln(JSON.stringify(JSON.parse(options), null, 2));
errorln(); errorln();
@@ -1159,6 +1174,10 @@ function log(options) {
} }
} }
function sort_globals(code) {
return "var " + sandbox.run_code("throw Object.keys(this).sort();" + code).join(",") + ";" + code;
}
function fuzzy_match(original, uglified) { function fuzzy_match(original, uglified) {
uglified = uglified.split(" "); uglified = uglified.split(" ");
var i = uglified.length; var i = uglified.length;
@@ -1173,34 +1192,63 @@ function fuzzy_match(original, uglified) {
return true; return true;
} }
function skip_infinite_recursion(orig, toplevel) { function patch_try_catch(orig, toplevel) {
var code = orig; var stack = [ {
var tries = []; code: orig,
var offset = 0; index: 0,
offset: 0,
tries: [],
} ];
var re = /(?:(?:^|[\s{}):;])try|}\s*catch\s*\(([^)]+)\)|}\s*finally)\s*(?={)/g; var re = /(?:(?:^|[\s{}):;])try|}\s*catch\s*\(([^)]+)\)|}\s*finally)\s*(?={)/g;
var match; while (stack.length) {
while (match = re.exec(code)) { var code = stack[0].code;
if (/}\s*finally\s*$/.test(match[0])) { var offset = stack[0].offset;
tries.shift(); var tries = stack[0].tries;
continue; var match;
} re.lastIndex = stack.shift().index;
var index = match.index + match[0].length + 1; while (match = re.exec(code)) {
if (/(?:^|[\s{}):;])try\s*$/.test(match[0])) { var index = match.index + match[0].length + 1;
tries.unshift({ try: index - offset }); if (/(?:^|[\s{}):;])try\s*$/.test(match[0])) {
continue; tries.unshift({ try: index - offset });
} continue;
while (tries.length && tries[0].catch) tries.shift(); }
tries[0].catch = index; var insert;
var insert = "throw " + match[1] + ".ufuzz_skip || (" + match[1] + ".ufuzz_skip = " + tries[0].try + "), " + match[1] + ";"; if (/}\s*finally\s*$/.test(match[0])) {
var new_code = code.slice(0, index) + insert + code.slice(index); tries.shift();
var result = sandbox.run_code(new_code, toplevel); insert = 'if (typeof UFUZZ_ERROR == "object") throw UFUZZ_ERROR;';
if (typeof result != "object" || typeof result.name != "string" || typeof result.message != "string") { } else {
offset += insert.length; while (tries.length && tries[0].catch) tries.shift();
code = new_code; tries[0].catch = index - offset;
} else if (result.name == "RangeError" && result.message == "Maximum call stack size exceeded") { insert = [
index = result.ufuzz_skip; "if (!" + match[1] + ".ufuzz_var) {",
return orig.slice(0, index) + 'throw new Error("skipping infinite recursion");' + orig.slice(index); match[1] + '.ufuzz_var = "' + match[1] + '";',
match[1] + ".ufuzz_try = " + tries[0].try + ";",
match[1] + ".ufuzz_catch = " + tries[0].catch + ";",
"UFUZZ_ERROR = " + match[1] + ";",
"}",
"throw " + match[1] + ";",
].join("\n");
}
var new_code = code.slice(0, index) + insert + code.slice(index);
var result = sandbox.run_code(new_code, toplevel);
if (typeof result != "object" || typeof result.name != "string" || typeof result.message != "string") {
if (!stack.filled && match[1]) stack.push({
code: code,
index: index && index - 1,
offset: offset,
tries: JSON.parse(JSON.stringify(tries)),
});
offset += insert.length;
code = new_code;
} else if (result.name == "TypeError" && /'in'/.test(result.message)) {
index = result.ufuzz_catch;
return orig.slice(0, index) + result.ufuzz_var + ' = new Error("invalid `in`");' + orig.slice(index);
} else if (result.name == "RangeError" && result.message == "Maximum call stack size exceeded") {
index = result.ufuzz_try;
return orig.slice(0, index) + 'throw new Error("skipping infinite recursion");' + orig.slice(index);
}
} }
stack.filled = true;
} }
} }
@@ -1209,14 +1257,6 @@ var fallback_options = [ JSON.stringify({
mangle: false mangle: false
}) ]; }) ];
var minify_options = require("./options.json").map(JSON.stringify); var minify_options = require("./options.json").map(JSON.stringify);
var sort_globals = [
"Object.keys(this).sort().forEach(function(name) {",
" var value = this[name];",
" delete this[name];",
" this[name] = value;",
"});",
"",
].join("\n");
var original_code, original_result, errored; var original_code, original_result, errored;
var uglify_code, uglify_result, ok; var uglify_code, uglify_result, ok;
for (var round = 1; round <= num_iterations; round++) { for (var round = 1; round <= num_iterations; round++) {
@@ -1238,7 +1278,7 @@ for (var round = 1; round <= num_iterations; round++) {
ok = sandbox.same_stdout(original_result, uglify_result); ok = sandbox.same_stdout(original_result, uglify_result);
// ignore declaration order of global variables // ignore declaration order of global variables
if (!ok && !toplevel) { if (!ok && !toplevel) {
ok = sandbox.same_stdout(sandbox.run_code(sort_globals + original_code), sandbox.run_code(sort_globals + uglify_code)); ok = sandbox.same_stdout(sandbox.run_code(sort_globals(original_code)), sandbox.run_code(sort_globals(uglify_code)));
} }
// ignore numerical imprecision caused by `unsafe_math` // ignore numerical imprecision caused by `unsafe_math`
if (!ok && typeof uglify_result == "string" && o.compress && o.compress.unsafe_math) { if (!ok && typeof uglify_result == "string" && o.compress && o.compress.unsafe_math) {
@@ -1248,10 +1288,11 @@ for (var round = 1; round <= num_iterations; round++) {
ok = sandbox.same_stdout(fuzzy_result, uglify_result); ok = sandbox.same_stdout(fuzzy_result, uglify_result);
} }
} }
// ignore difference in error message caused by `in`
// ignore difference in depth of termination caused by infinite recursion // ignore difference in depth of termination caused by infinite recursion
if (!ok) { if (!ok) {
var orig_skipped = skip_infinite_recursion(original_code, toplevel); var orig_skipped = patch_try_catch(original_code, toplevel);
var uglify_skipped = skip_infinite_recursion(uglify_code, toplevel); var uglify_skipped = patch_try_catch(uglify_code, toplevel);
if (orig_skipped && uglify_skipped) { if (orig_skipped && uglify_skipped) {
ok = sandbox.same_stdout(sandbox.run_code(orig_skipped, toplevel), sandbox.run_code(uglify_skipped, toplevel)); ok = sandbox.same_stdout(sandbox.run_code(orig_skipped, toplevel), sandbox.run_code(uglify_skipped, toplevel));
} }