Compare commits

..

17 Commits

Author SHA1 Message Date
Alex Lam S.L
87f8a484e6 v2.8.24 2017-05-12 15:47:02 +08:00
Alex Lam S.L
c736834aa4 Merge pull request #1921 from alexlamsl/v2.8.24 2017-05-12 14:58:35 +08:00
olsonpm
9a98513981 add documentation for side_effects & [#@]__PURE__ (#1925) 2017-05-12 12:55:07 +08:00
Alex Lam S.L
f631d6437a avoid arguments and eval in reduce_vars (#1924)
fixes #1922
2017-05-12 12:45:38 +08:00
Alex Lam S.L
aa7e8783f8 fix invalid transform on const (#1919)
- preserve (re)assignment to `const` for runtime error
- suppress `cascade` on `const`, as runtime behaviour is ill-defined
2017-05-12 05:04:28 +08:00
Alex Lam S.L
13e5e33448 document known issues with const (#1916) 2017-05-12 03:36:54 +08:00
kzc
487ae8e3be change harmony references to uglify-es in README (#1902) 2017-05-10 16:38:10 +08:00
Alex Lam S.L
5dfda6e212 v2.8.23 2017-05-07 04:31:54 +08:00
Alex Lam S.L
d08c772eb3 Merge pull request #1871 from alexlamsl/v2.8.23 2017-05-07 04:06:51 +08:00
Alex Lam S.L
90ed54401b fix test for #1865 (#1873) 2017-05-07 03:04:17 +08:00
Alex Lam S.L
d8106b6c63 fix label-related bugs (#1835)
- deep cloning of `AST_LabeledStatement`
- `L:do{...}while(false)`
- empty statement with label within block

extend `test/ufuzz.js`
- generate labels for blocks & loops
- generate for-in statements
- skip suspicious option search if `minify()` errs

fixes #1833
2017-05-07 00:16:30 +08:00
alexlamsl
dda4eb96e1 backport test scripts 2017-05-06 23:48:28 +08:00
Alex Lam S.L
7305ba0296 fix unsafe on evaluate of reduce_vars (#1870)
Determine if variables with non-constant values can escape and be modified.

fixes #1865
2017-05-06 23:40:19 +08:00
Alex Lam S.L
2c21dc5e8e fix unused on for-in statements (#1843)
Only need to avoid `var` within the initialisation block.

fixes #1841
2017-05-06 23:34:21 +08:00
Alex Lam S.L
d0faa471db fix unused on labeled for-loop (#1831)
fixes #1830
2017-05-06 23:31:22 +08:00
Alex Lam S.L
6ad823d1e8 fix reduce_vars within try-block (#1818)
Possible partial execution due to exceptions.
2017-05-06 23:28:07 +08:00
Alex Lam S.L
43ad4e9775 fix variable substitution (#1816)
- let `collapse_vars` take care of value containing any symbols
- improve overhead accounting
2017-05-06 23:26:54 +08:00
140 changed files with 11688 additions and 25173 deletions

View File

@@ -1,29 +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`)
<!-- Note: sub-optimal but correct code is not a bug --> - JavaScript input - ideally as small as possible.
- The `uglifyjs` CLI command executed or `minify()` options used.
**ES5 or ES6+ input?** - An example of JavaScript output produced and/or the error or warning.
<!-- Note: for ES6 see: https://github.com/mishoo/UglifyJS2/tree/harmony#harmony -->
**Uglify version (`uglifyjs -V`)**
**JavaScript input**
<!-- <!--
A complete parsable JS program exhibiting the issue with Note: the release version of uglify-js only supports ES5. Those wishing
UglifyJS alone - without third party tools or libraries. to minify ES6 should use the experimental harmony branch.
Ideally the input should be as small as possible.
Post a link to a gist if necessary.
Issues without a reproducible test case will be closed.
-->
**The `uglifyjs` CLI command executed or `minify()` options used.**
**JavaScript output or error produced.**
<!--
Note: `uglify-js` only supports ES5.
Those wishing to minify ES6 should use `uglify-es`.
--> -->

View File

@@ -1,14 +1,12 @@
language: node_js language: node_js
before_install: "npm install -g npm"
node_js: node_js:
- "0.10" - "0.10"
- "0.12" - "0.12"
- "4" - "4"
- "6" - "6"
- "8"
env: env:
- UGLIFYJS_TEST_ALL=1 - UGLIFYJS_TEST_ALL=1
matrix: matrix:
fast_finish: true fast_finish: true
sudo: false sudo: false
cache:
directories: tmp

1518
README.md

File diff suppressed because it is too large Load Diff

77
bin/extract-props.js Executable file
View File

@@ -0,0 +1,77 @@
#! /usr/bin/env node
"use strict";
var U2 = require("../tools/node");
var fs = require("fs");
var yargs = require("yargs");
var ARGS = yargs
.describe("o", "Output file")
.argv;
var files = ARGS._.slice();
var output = {
vars: {},
props: {}
};
if (ARGS.o) try {
output = JSON.parse(fs.readFileSync(ARGS.o, "utf8"));
} catch(ex) {}
files.forEach(getProps);
if (ARGS.o) {
fs.writeFileSync(ARGS.o, JSON.stringify(output, null, 2), "utf8");
} else {
console.log("%s", JSON.stringify(output, null, 2));
}
function getProps(filename) {
var code = fs.readFileSync(filename, "utf8");
var ast = U2.parse(code);
ast.walk(new U2.TreeWalker(function(node){
if (node instanceof U2.AST_ObjectKeyVal) {
add(node.key);
}
else if (node instanceof U2.AST_ObjectProperty) {
add(node.key.name);
}
else if (node instanceof U2.AST_Dot) {
add(node.property);
}
else if (node instanceof U2.AST_Sub) {
addStrings(node.property);
}
}));
function addStrings(node) {
var out = {};
try {
(function walk(node){
node.walk(new U2.TreeWalker(function(node){
if (node instanceof U2.AST_Seq) {
walk(node.cdr);
return true;
}
if (node instanceof U2.AST_String) {
add(node.value);
return true;
}
if (node instanceof U2.AST_Conditional) {
walk(node.consequent);
walk(node.alternative);
return true;
}
throw out;
}));
})(node);
} catch(ex) {
if (ex !== out) throw ex;
}
}
function add(name) {
output.props[name] = true;
}
}

View File

@@ -3,402 +3,633 @@
"use strict"; "use strict";
// 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 fs = require("fs");
var info = require("../package.json");
var path = require("path");
var program = require("commander");
var UglifyJS = require("../tools/node"); var UglifyJS = require("../tools/node");
var sys = require("util");
var yargs = require("yargs");
var fs = require("fs");
var path = require("path");
var acorn;
var screw_ie8 = true;
var ARGS = yargs
.usage("$0 input1.js [input2.js ...] [options]\n\
Use a single dash to read input from the standard input.\
\n\n\
NOTE: by default there is no mangling/compression.\n\
Without [options] it will simply parse input files and dump the AST\n\
with whitespace and comments discarded. To achieve compression and\n\
mangling you need to use `-c` and `-m`.\
")
.describe("source-map", "Specify an output file where to generate source map.")
.describe("source-map-root", "The path to the original source to be included in the source map.")
.describe("source-map-url", "The path to the source map to be added in //# sourceMappingURL. Defaults to the value passed with --source-map.")
.describe("source-map-inline", "Write base64-encoded source map to the end of js output. Disabled by default")
.describe("source-map-include-sources", "Pass this flag if you want to include the content of source files in the source map as sourcesContent property.")
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
.describe("screw-ie8", "Do not support Internet Explorer 6/7/8. This flag is enabled by default.")
.describe("support-ie8", "Support non-standard Internet Explorer 6/7/8 javascript.")
.describe("expr", "Parse a single expression, rather than a program (for parsing JSON)")
.describe("p", "Skip prefix for original filenames that appear in source maps. \
For example -p 3 will drop 3 directories from file names and ensure they are relative paths. \
You can also specify -p relative, which will make UglifyJS figure out itself the relative paths between original sources, \
the source map and the output file.")
.describe("o", "Output file (default STDOUT).")
.describe("b", "Beautify output/specify output options.")
.describe("m", "Mangle names/pass mangler options.")
.describe("r", "Reserved names to exclude from mangling.")
.describe("c", "Enable compressor/pass compressor options. \
Pass options like -c hoist_vars=false,if_return=false. \
Use -c with no argument to use the default compression options.")
.describe("d", "Global definitions")
.describe("e", "Embed everything in a big function, with a configurable parameter/argument list.")
var skip_keys = [ "cname", "enclosed", "inlined", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ]; .describe("comments", "Preserve copyright comments in the output. \
var files = {}; By default this works like Google Closure, keeping JSDoc-style comments that contain \"@license\" or \"@preserve\". \
var options = { You can optionally pass one of the following arguments to this flag:\n\
compress: false, - \"all\" to keep all comments\n\
mangle: false - a valid JS RegExp like `/foo/`or `/^!/` to keep only matching comments.\n\
}; \
program.version(info.name + " " + info.version); Note that currently not *all* comments can be kept when compression is on, \
program.parseArgv = program.parse; because of dead code removal or cascading statements into sequences.")
program.parse = undefined;
if (process.argv.indexOf("ast") >= 0) program.helpInformation = UglifyJS.describe_ast;
else if (process.argv.indexOf("options") >= 0) program.helpInformation = function() {
var text = [];
var options = UglifyJS.default_options();
for (var option in options) {
text.push("--" + (option == "output" ? "beautify" : option == "sourceMap" ? "source-map" : option) + " options:");
text.push(format_object(options[option]));
text.push("");
}
return text.join("\n");
};
program.option("-p, --parse <options>", "Specify parser options.", parse_js());
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js());
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
program.option("-b, --beautify [options]", "Beautify output/specify output options.", parse_js());
program.option("-o, --output <file>", "Output file (default STDOUT).");
program.option("--comments [filter]", "Preserve copyright comments in the output.");
program.option("--config-file <file>", "Read minify() options from JSON file.");
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
program.option("--ie8", "Support non-standard Internet Explorer 8.");
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
program.option("--name-cache <file>", "File to hold mangled name mappings.");
program.option("--no-rename", "Disable symbol expansion.");
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_source_map());
program.option("--timings", "Display operations run time on STDERR.")
program.option("--toplevel", "Compress and/or mangle variables in toplevel scope.");
program.option("--verbose", "Print diagnostic messages.");
program.option("--warn", "Print warning messages.");
program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally.");
program.arguments("[files...]").parseArgv(process.argv);
if (program.configFile) {
options = JSON.parse(read_file(program.configFile));
}
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
fatal("ERROR: cannot write source map to STDOUT");
}
[
"compress",
"ie8",
"mangle",
"rename",
"sourceMap",
"toplevel",
"wrap"
].forEach(function(name) {
if (name in program) {
if (name == "rename" && program[name]) return;
options[name] = program[name];
}
});
if (program.beautify) {
options.output = typeof program.beautify == "object" ? program.beautify : {};
if (!("beautify" in options.output)) {
options.output.beautify = true;
}
}
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("ERROR: inline source map only works with built-in parser");
}
}
var convert_path = function(name) {
return name;
};
if (typeof program.sourceMap == "object" && "base" in program.sourceMap) {
convert_path = function() {
var base = program.sourceMap.base;
delete options.sourceMap.base;
return function(name) {
return path.relative(base, name);
};
}();
}
if (program.verbose) {
options.warnings = "verbose";
} else if (program.warn) {
options.warnings = true;
}
if (program.self) {
if (program.args.length) {
print_error("WARN: Ignoring input files since --self was passed");
}
if (!options.wrap) options.wrap = "UglifyJS";
simple_glob(UglifyJS.FILES).forEach(function(name) {
files[convert_path(name)] = read_file(name);
});
run();
} else if (program.args.length) {
simple_glob(program.args).forEach(function(name) {
files[convert_path(name)] = read_file(name);
});
run();
} else {
var chunks = [];
process.stdin.setEncoding("utf8");
process.stdin.on("data", function(chunk) {
chunks.push(chunk);
}).on("end", function() {
files = [ chunks.join("") ];
run();
});
process.stdin.resume();
}
function convert_ast(fn) { .describe("preamble", "Preamble to prepend to the output. You can use this to insert a \
return UglifyJS.AST_Node.from_mozilla_ast(Object.keys(files).reduce(fn, null)); comment, for example for licensing information. This will not be \
} parsed, but the source map will adjust for its presence.")
function run() { .describe("stats", "Display operations run time on STDERR.")
UglifyJS.AST_Node.warn_function = function(msg) { .describe("acorn", "Use Acorn for parsing.")
.describe("spidermonkey", "Assume input files are SpiderMonkey AST format (as JSON).")
.describe("self", "Build itself (UglifyJS2) as a library (implies --wrap=UglifyJS --export-all)")
.describe("wrap", "Embed everything in a big function, making the “exports” and “global” variables available. \
You need to pass an argument to this option to specify the name that your module will take when included in, say, a browser.")
.describe("export-all", "Only used when --wrap, this tells UglifyJS to add code to automatically export all globals.")
.describe("lint", "Display some scope warnings")
.describe("v", "Verbose")
.describe("V", "Print version number and exit.")
.describe("noerr", "Don't throw an error for unknown options in -c, -b or -m.")
.describe("bare-returns", "Allow return outside of functions. Useful when minifying CommonJS modules.")
.describe("keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.")
.describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)")
.describe("reserved-file", "File containing reserved names")
.describe("reserve-domprops", "Make (most?) DOM properties reserved for --mangle-props")
.describe("mangle-props", "Mangle property names (0 - disabled, 1 - mangle all properties, 2 - mangle unquoted properies)")
.describe("mangle-regex", "Only mangle property names matching the regex")
.describe("name-cache", "File to hold mangled names mappings")
.describe("pure-funcs", "List of functions that can be safely removed if their return value is not used")
.describe("dump-spidermonkey-ast", "Dump SpiderMonkey AST to stdout.")
.describe("wrap-iife", "Wrap IIFEs in parenthesis. Note: this disables the negate_iife compression option")
.alias("p", "prefix")
.alias("o", "output")
.alias("v", "verbose")
.alias("b", "beautify")
.alias("m", "mangle")
.alias("c", "compress")
.alias("d", "define")
.alias("r", "reserved")
.alias("V", "version")
.alias("e", "enclose")
.alias("q", "quotes")
.string("source-map")
.string("source-map-root")
.string("source-map-url")
.string("b")
.string("beautify")
.string("m")
.string("mangle")
.string("mangle-props-debug")
.string("c")
.string("compress")
.string("d")
.string("define")
.string("e")
.string("enclose")
.string("comments")
.string("wrap")
.string("p")
.string("prefix")
.string("name-cache")
.array("reserved-file")
.array("pure-funcs")
.boolean("expr")
.boolean("source-map-inline")
.boolean("source-map-include-sources")
.boolean("screw-ie8")
.boolean("support-ie8")
.boolean("export-all")
.boolean("self")
.boolean("v")
.boolean("verbose")
.boolean("stats")
.boolean("acorn")
.boolean("spidermonkey")
.boolean("dump-spidermonkey-ast")
.boolean("lint")
.boolean("V")
.boolean("version")
.boolean("noerr")
.boolean("bare-returns")
.boolean("keep-fnames")
.boolean("reserve-domprops")
.boolean("wrap-iife")
.wrap(80)
.argv
;
normalize(ARGS);
if (ARGS.noerr) {
UglifyJS.DefaultsError.croak = function(msg, defs) {
print_error("WARN: " + msg); print_error("WARN: " + msg);
}; };
if (program.timings) options.timings = true; }
try {
if (program.parse) { if (ARGS.version || ARGS.V) {
if (program.parse.acorn) { var json = require("../package.json");
files = convert_ast(function(toplevel, name) { print(json.name + ' ' + json.version);
return require("acorn").parse(files[name], { process.exit(0);
locations: true, }
program: toplevel,
sourceFile: name if (ARGS.ast_help) {
}); var desc = UglifyJS.describe_ast();
}); print(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2));
} else if (program.parse.spidermonkey) { process.exit(0);
files = convert_ast(function(toplevel, name) { }
var obj = JSON.parse(files[name]);
if (!toplevel) return obj; if (ARGS.h || ARGS.help) {
toplevel.body = toplevel.body.concat(obj.body); print(yargs.help());
return toplevel; process.exit(0);
}); }
}
} if (ARGS.acorn) {
} catch (ex) { acorn = require("acorn");
fatal(ex); }
}
var result = UglifyJS.minify(files, options); var COMPRESS = getOptions("c", true);
if (result.error) { var MANGLE = getOptions("m", true);
var ex = result.error; var BEAUTIFY = getOptions("b", true);
if (ex.name == "SyntaxError") { var RESERVED = null;
print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
var col = ex.col; if (ARGS.reserved_file) ARGS.reserved_file.forEach(function(filename){
var lines = files[ex.filename].split(/\r?\n/); RESERVED = UglifyJS.readReservedFile(filename, RESERVED);
var line = lines[ex.line - 1]; });
if (!line && !col) {
line = lines[ex.line - 2]; if (ARGS.reserve_domprops) {
col = line.length; RESERVED = UglifyJS.readDefaultReservedFile(RESERVED);
} }
if (line) {
var limit = 70; if (ARGS.d) {
if (col > limit) { if (COMPRESS) COMPRESS.global_defs = getOptions("d");
line = line.slice(col - limit); }
col = limit;
} if (ARGS.pure_funcs) {
print_error(line.slice(0, 80)); if (COMPRESS) COMPRESS.pure_funcs = ARGS.pure_funcs;
print_error(line.slice(0, col).replace(/\S/g, " ") + "^"); }
}
} if (ARGS.r) {
if (ex.defs) { if (MANGLE) MANGLE.except = ARGS.r.replace(/^\s+|\s+$/g).split(/\s*,+\s*/);
print_error("Supported options:"); }
print_error(format_object(ex.defs));
} if (RESERVED && MANGLE) {
fatal(ex); if (!MANGLE.except) MANGLE.except = RESERVED.vars;
} else if (program.output == "ast") { else MANGLE.except = MANGLE.except.concat(RESERVED.vars);
print(JSON.stringify(result.ast, function(key, value) { }
if (skip_key(key)) return;
if (value instanceof UglifyJS.AST_Token) return; function readNameCache(key) {
if (value instanceof UglifyJS.Dictionary) return; return UglifyJS.readNameCache(ARGS.name_cache, key);
if (value instanceof UglifyJS.AST_Node) { }
var result = {
_class: "AST_" + value.TYPE function writeNameCache(key, cache) {
}; return UglifyJS.writeNameCache(ARGS.name_cache, key, cache);
value.CTOR.PROPS.forEach(function(prop) { }
result[prop] = value[prop];
}); function extractRegex(str) {
return result; if (/^\/.*\/[a-zA-Z]*$/.test(str)) {
} var regex_pos = str.lastIndexOf("/");
return value; return new RegExp(str.substr(1, regex_pos - 1), str.substr(regex_pos + 1));
}, 2));
} else if (program.output == "spidermonkey") {
print(JSON.stringify(UglifyJS.minify(result.code, {
compress: false,
mangle: false,
output: {
ast: true,
code: false
}
}).ast.to_mozilla_ast(), null, 2));
} else if (program.output) {
fs.writeFileSync(program.output, result.code);
if (result.map) {
fs.writeFileSync(program.output + ".map", result.map);
}
} else { } else {
print(result.code); throw new Error("Invalid regular expression: " + str);
}
if (program.nameCache) {
fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache));
}
if (result.timings) for (var phase in result.timings) {
print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
} }
} }
function fatal(message) { if (ARGS.quotes === true) {
if (message instanceof Error) message = message.stack.replace(/^\S*?Error:/, "ERROR:") ARGS.quotes = 3;
print_error(message); }
if (ARGS.mangle_props === true) {
ARGS.mangle_props = 1;
} else if (ARGS.mangle_props === "unquoted") {
ARGS.mangle_props = 2;
}
var OUTPUT_OPTIONS = {
beautify : BEAUTIFY ? true : false,
max_line_len : 32000,
preamble : ARGS.preamble || null,
quote_style : ARGS.quotes != null ? ARGS.quotes : 0,
};
if (ARGS.mangle_props == 2) {
OUTPUT_OPTIONS.keep_quoted_props = true;
if (COMPRESS && !("properties" in COMPRESS))
COMPRESS.properties = false;
}
if (ARGS.support_ie8 === true && ARGS.screw_ie8 !== true) {
screw_ie8 = false;
}
if (COMPRESS) COMPRESS.screw_ie8 = screw_ie8;
if (MANGLE) MANGLE.screw_ie8 = screw_ie8;
OUTPUT_OPTIONS.screw_ie8 = screw_ie8;
if (ARGS.keep_fnames) {
if (COMPRESS) COMPRESS.keep_fnames = true;
if (MANGLE) MANGLE.keep_fnames = true;
}
if (ARGS.wrap_iife) {
if (COMPRESS) COMPRESS.negate_iife = false;
OUTPUT_OPTIONS.wrap_iife = true;
}
if (BEAUTIFY)
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
if (ARGS.comments === "") {
OUTPUT_OPTIONS.comments = "some";
} else {
OUTPUT_OPTIONS.comments = ARGS.comments;
}
var files = ARGS._.slice();
if (process.platform === "win32")
files = UglifyJS.simple_glob(files);
if (ARGS.self) {
if (files.length > 0) {
print_error("WARN: Ignoring input files since --self was passed");
}
files = UglifyJS.FILES;
if (!ARGS.wrap) ARGS.wrap = "UglifyJS";
}
var ORIG_MAP = ARGS.in_source_map;
if (ORIG_MAP && ORIG_MAP != "inline") {
ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP));
if (files.length == 0) {
print_error("INFO: Using file from the input source map: " + ORIG_MAP.file);
files = [ ORIG_MAP.file ];
}
}
if (files.length == 0) {
files = [ "-" ];
}
if (ORIG_MAP == "inline") {
if (files.length > 1) {
print_error("ERROR: Inline source map only works with singular input");
process.exit(1);
}
if (ARGS.acorn || ARGS.spidermonkey) {
print_error("ERROR: Inline source map only works with built-in parser");
process.exit(1);
}
}
if (files.indexOf("-") >= 0 && ARGS.source_map) {
print_error("ERROR: Source map doesn't work with input from STDIN");
process.exit(1); process.exit(1);
} }
// A file glob function that only supports "*" and "?" wildcards in the basename. if (files.filter(function(el){ return el == "-" }).length > 1) {
// Example: "foo/bar/*baz??.*.js" print_error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
// Argument `glob` may be a string or an array of strings. process.exit(1);
// Returns an array of strings. Garbage in, garbage out.
function simple_glob(glob) {
if (Array.isArray(glob)) {
return [].concat.apply([], glob.map(simple_glob));
}
if (glob.match(/\*|\?/)) {
var dir = path.dirname(glob);
try {
var entries = fs.readdirSync(dir);
} catch (ex) {}
if (entries) {
var pattern = "^" + path.basename(glob)
.replace(/[.+^$[\]\\(){}]/g, "\\$&")
.replace(/\*/g, "[^/\\\\]*")
.replace(/\?/g, "[^/\\\\]") + "$";
var mod = process.platform === "win32" ? "i" : "";
var rx = new RegExp(pattern, mod);
var results = entries.filter(function(name) {
return rx.test(name);
}).map(function(name) {
return path.join(dir, name);
});
if (results.length) return results;
}
}
return [ glob ];
} }
function read_file(path, default_value) { var STATS = {};
try { var TOPLEVEL = null;
return fs.readFileSync(path, "utf8"); var P_RELATIVE = ARGS.p && ARGS.p == "relative";
} catch (ex) { var SOURCES_CONTENT = {};
if (ex.code == "ENOENT" && default_value != null) return default_value; var index = 0;
fatal(ex);
}
}
function parse_js(flag) { !function cb() {
return function(value, options) { if (index == files.length) return done();
options = options || {}; var file = files[index++];
try { read_whole_file(file, function (err, code) {
UglifyJS.minify(value, { if (err) {
parse: { print_error("ERROR: can't read file: " + file);
expression: true process.exit(1);
},
compress: false,
mangle: false,
output: {
ast: true,
code: false
} }
}).ast.walk(new UglifyJS.TreeWalker(function(node) { if (ORIG_MAP == "inline") {
if (node instanceof UglifyJS.AST_Assign) { ORIG_MAP = read_source_map(code);
var name = node.left.print_to_string(); }
var value = node.right; if (ARGS.p != null) {
if (flag) { if (P_RELATIVE) {
options[name] = value; file = path.relative(path.dirname(ARGS.source_map), file).replace(/\\/g, '/');
} else if (value instanceof UglifyJS.AST_Array) {
options[name] = value.elements.map(to_string);
} else { } else {
options[name] = to_string(value); var p = parseInt(ARGS.p, 10);
if (!isNaN(p)) {
file = file.replace(/^\/+/, "").split(/\/+/).slice(ARGS.p).join("/");
} }
return true;
} }
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; SOURCES_CONTENT[file] = code;
time_it("parse", function(){
function to_string(value) { if (ARGS.spidermonkey) {
return value instanceof UglifyJS.AST_Constant ? value.getValue() : value.print_to_string({ var program = JSON.parse(code);
quote_keys: true if (!TOPLEVEL) TOPLEVEL = program;
else TOPLEVEL.body = TOPLEVEL.body.concat(program.body);
}
else if (ARGS.acorn) {
TOPLEVEL = acorn.parse(code, {
locations : true,
sourceFile : file,
program : TOPLEVEL
}); });
} }
})); else {
try {
TOPLEVEL = UglifyJS.parse(code, {
filename : file,
toplevel : TOPLEVEL,
expression : ARGS.expr,
bare_returns : ARGS.bare_returns,
});
} catch(ex) { } catch(ex) {
if (flag) { if (ex instanceof UglifyJS.JS_Parse_Error) {
fatal("Error parsing arguments for '" + flag + "': " + value); print_error("Parse error at " + file + ":" + ex.line + "," + ex.col);
var col = ex.col;
var line = code.split(/\r?\n/)[ex.line - (col ? 1 : 2)];
if (line) {
if (col > 40) {
line = line.slice(col - 40);
col = 40;
}
if (col) {
print_error(line.slice(0, 80));
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
} else { } else {
options[value] = null; print_error(line.slice(-40));
print_error(line.slice(-40).replace(/\S/g, " ") + "^");
} }
} }
return options; print_error(ex.stack);
process.exit(1);
} }
} throw ex;
function parse_source_map() {
var parse = parse_js();
return function(value, options) {
var hasContent = options && "content" in options;
var settings = parse(value, options);
if (!hasContent && settings.content && settings.content != "inline") {
print_error("INFO: Using input source map: " + settings.content);
settings.content = read_file(settings.content, settings.content);
} }
return settings; };
}
}
function skip_key(key) {
return skip_keys.indexOf(key) >= 0;
}
function format_object(obj) {
var lines = [];
var padding = "";
Object.keys(obj).map(function(name) {
if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
return [ name, JSON.stringify(obj[name]) ];
}).forEach(function(tokens) {
lines.push(" " + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
}); });
return lines.join("\n"); cb();
});
}();
function done() {
var OUTPUT_FILE = ARGS.o;
var SOURCE_MAP = (ARGS.source_map || ARGS.source_map_inline) ? UglifyJS.SourceMap({
file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE,
root: ARGS.source_map_root || ORIG_MAP && ORIG_MAP.sourceRoot,
orig: ORIG_MAP,
}) : null;
OUTPUT_OPTIONS.source_map = SOURCE_MAP;
try {
var output = UglifyJS.OutputStream(OUTPUT_OPTIONS);
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
} catch(ex) {
if (ex instanceof UglifyJS.DefaultsError) {
print_error(ex.message);
print_error("Supported options:");
print_error(sys.inspect(ex.defs));
process.exit(1);
}
}
if (ARGS.acorn || ARGS.spidermonkey) time_it("convert_ast", function(){
TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL);
});
if (ARGS.wrap != null) {
TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all);
}
if (ARGS.enclose != null) {
var arg_parameter_list = ARGS.enclose;
if (arg_parameter_list === true) {
arg_parameter_list = [];
}
else if (!(arg_parameter_list instanceof Array)) {
arg_parameter_list = [arg_parameter_list];
}
TOPLEVEL = TOPLEVEL.wrap_enclose(arg_parameter_list);
}
if (ARGS.mangle_props || ARGS.name_cache) (function(){
var reserved = RESERVED ? RESERVED.props : null;
var cache = readNameCache("props");
var regex;
try {
regex = ARGS.mangle_regex ? extractRegex(ARGS.mangle_regex) : null;
} catch (e) {
print_error("ERROR: Invalid --mangle-regex: " + e.message);
process.exit(1);
}
TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, {
reserved : reserved,
cache : cache,
only_cache : !ARGS.mangle_props,
regex : regex,
ignore_quoted : ARGS.mangle_props == 2,
debug : typeof ARGS.mangle_props_debug === "undefined" ? false : ARGS.mangle_props_debug
});
writeNameCache("props", cache);
})();
var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint
var TL_CACHE = readNameCache("vars");
if (MANGLE) MANGLE.cache = TL_CACHE;
if (SCOPE_IS_NEEDED) {
time_it("scope", function(){
TOPLEVEL.figure_out_scope(MANGLE || { screw_ie8: screw_ie8, cache: TL_CACHE });
if (ARGS.lint) {
TOPLEVEL.scope_warnings();
}
});
}
if (COMPRESS) {
time_it("squeeze", function(){
TOPLEVEL = compressor.compress(TOPLEVEL);
});
}
if (SCOPE_IS_NEEDED) {
time_it("scope", function(){
TOPLEVEL.figure_out_scope(MANGLE || { screw_ie8: screw_ie8, cache: TL_CACHE });
if (MANGLE && !TL_CACHE) {
TOPLEVEL.compute_char_frequency(MANGLE);
}
});
}
if (MANGLE) time_it("mangle", function(){
TOPLEVEL.mangle_names(MANGLE);
});
writeNameCache("vars", TL_CACHE);
if (ARGS.source_map_include_sources) {
for (var file in SOURCES_CONTENT) {
if (SOURCES_CONTENT.hasOwnProperty(file)) {
SOURCE_MAP.get().setSourceContent(file, SOURCES_CONTENT[file]);
}
}
}
if (ARGS.dump_spidermonkey_ast) {
print(JSON.stringify(TOPLEVEL.to_mozilla_ast(), null, 2));
} else {
time_it("generate", function(){
TOPLEVEL.print(output);
});
output = output.get();
if (SOURCE_MAP) {
if (ARGS.source_map_inline) {
var base64_string = new Buffer(SOURCE_MAP.toString()).toString('base64');
output += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + base64_string;
} else {
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
var source_map_url = ARGS.source_map_url || (
P_RELATIVE
? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map)
: ARGS.source_map
);
output += "\n//# sourceMappingURL=" + source_map_url;
}
}
if (OUTPUT_FILE) {
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
} else {
print(output);
}
}
if (ARGS.stats) {
print_error(UglifyJS.string_template("Timing information (compressed {count} files):", {
count: files.length
}));
for (var i in STATS) if (STATS.hasOwnProperty(i)) {
print_error(UglifyJS.string_template("- {name}: {time}s", {
name: i,
time: (STATS[i] / 1000).toFixed(3)
}));
}
}
}
/* -----[ functions ]----- */
function normalize(o) {
for (var i in o) if (o.hasOwnProperty(i) && /-/.test(i)) {
o[i.replace(/-/g, "_")] = o[i];
delete o[i];
}
}
function getOptions(flag, constants) {
var x = ARGS[flag];
if (x == null || x === false) return null;
var ret = {};
if (x !== "") {
if (Array.isArray(x)) x = x.map(function (v) { return "(" + v + ")"; }).join(", ");
var ast;
try {
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);
process.exit(1);
}
}
ast.walk(new UglifyJS.TreeWalker(function(node){
if (node instanceof UglifyJS.AST_Seq) return; // descend
if (node instanceof UglifyJS.AST_Assign) {
var name = node.left.print_to_string().replace(/-/g, "_");
var value = node.right;
if (constants)
value = new Function("return (" + value.print_to_string() + ")")();
ret[name] = value;
return true; // no descend
}
if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_Binary) {
var name = node.print_to_string().replace(/-/g, "_");
ret[name] = true;
return true; // no descend
}
print_error(node.TYPE)
print_error("Error parsing arguments for flag `" + flag + "': " + x);
process.exit(1);
}));
}
return ret;
}
function read_whole_file(filename, cb) {
if (filename == "-") {
var chunks = [];
process.stdin.setEncoding('utf-8');
process.stdin.on('data', function (chunk) {
chunks.push(chunk);
}).on('end', function () {
cb(null, chunks.join(""));
});
process.openStdin();
} else {
fs.readFile(filename, "utf-8", cb);
}
}
function read_source_map(code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) {
print_error("WARN: inline source map not found");
return null;
}
return JSON.parse(new Buffer(match[2], "base64"));
}
function time_it(name, cont) {
var t1 = new Date().getTime();
var ret = cont();
if (ARGS.stats) {
var spent = new Date().getTime() - t1;
if (STATS[name]) STATS[name] += spent;
else STATS[name] = spent;
}
return ret;
} }
function print_error(msg) { function print_error(msg) {
process.stderr.write(msg); console.error("%s", msg);
process.stderr.write("\n");
} }
function print(txt) { function print(txt) {
process.stdout.write(txt); console.log("%s", txt);
process.stdout.write("\n");
} }

View File

@@ -87,7 +87,7 @@ function DEFNODE(type, props, methods, base) {
return ctor; return ctor;
}; };
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before comments_after file raw", { var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file raw", {
}, null); }, null);
var AST_Node = DEFNODE("Node", "start end", { var AST_Node = DEFNODE("Node", "start end", {
@@ -134,10 +134,11 @@ var AST_Debugger = DEFNODE("Debugger", null, {
$documentation: "Represents a debugger statement", $documentation: "Represents a debugger statement",
}, AST_Statement); }, AST_Statement);
var AST_Directive = DEFNODE("Directive", "value quote", { var AST_Directive = DEFNODE("Directive", "value scope quote", {
$documentation: "Represents a directive, like \"use strict\";", $documentation: "Represents a directive, like \"use strict\";",
$propdoc: { $propdoc: {
value: "[string] The value of this directive as a plain string (it's not an AST_String!)", value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
scope: "[AST_Scope/S] The scope that this directive affects",
quote: "[string] the original quote character" quote: "[string] the original quote character"
}, },
}, AST_Statement); }, AST_Statement);
@@ -181,13 +182,21 @@ var AST_BlockStatement = DEFNODE("BlockStatement", null, {
}, AST_Block); }, AST_Block);
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, { var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
$documentation: "The empty statement (empty block or simply a semicolon)" $documentation: "The empty statement (empty block or simply a semicolon)",
_walk: function(visitor) {
return visitor._visit(this);
}
}, AST_Statement); }, AST_Statement);
var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", { var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
$documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`", $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
$propdoc: { $propdoc: {
body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement" body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
this.body._walk(visitor);
});
} }
}, AST_Statement); }, AST_Statement);
@@ -298,9 +307,10 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */ /* -----[ scope and functions ]----- */
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", { var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
$documentation: "Base class for all statements introducing a lexical scope", $documentation: "Base class for all statements introducing a lexical scope",
$propdoc: { $propdoc: {
directives: "[string*/S] an array of directives declared in this scope",
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
functions: "[Object/S] like `variables`, but only lists function declarations", functions: "[Object/S] like `variables`, but only lists function declarations",
uses_with: "[boolean/S] tells whether this scope uses the `with` statement", uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
@@ -316,14 +326,63 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
$propdoc: { $propdoc: {
globals: "[Object/S] a map of name -> SymbolDef for all undeclared names", globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
}, },
wrap_commonjs: function(name) { wrap_enclose: function(arg_parameter_pairs) {
var body = this.body; var self = this;
var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");"; var args = [];
var parameters = [];
arg_parameter_pairs.forEach(function(pair) {
var splitAt = pair.lastIndexOf(":");
args.push(pair.substr(0, splitAt));
parameters.push(pair.substr(splitAt + 1));
});
var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
wrapped_tl = parse(wrapped_tl); wrapped_tl = parse(wrapped_tl);
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){ wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
if (node instanceof AST_Directive && node.value == "$ORIG") { if (node instanceof AST_Directive && node.value == "$ORIG") {
return MAP.splice(self.body);
}
}));
return wrapped_tl;
},
wrap_commonjs: function(name, export_all) {
var self = this;
var to_export = [];
if (export_all) {
self.figure_out_scope();
self.walk(new TreeWalker(function(node){
if (node instanceof AST_SymbolDeclaration && node.definition().global) {
if (!find_if(function(n){ return n.name == node.name }, to_export))
to_export.push(node);
}
}));
}
var wrapped_tl = "(function(exports, global){ '$ORIG'; '$EXPORTS'; global['" + name + "'] = exports; }({}, (function(){return this}())))";
wrapped_tl = parse(wrapped_tl);
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
if (node instanceof AST_Directive) {
switch (node.value) {
case "$ORIG":
return MAP.splice(self.body);
case "$EXPORTS":
var body = [];
to_export.forEach(function(sym){
body.push(new AST_SimpleStatement({
body: new AST_Assign({
left: new AST_Sub({
expression: new AST_SymbolRef({ name: "exports" }),
property: new AST_String({ value: sym.name }),
}),
operator: "=",
right: new AST_SymbolRef(sym),
}),
}));
});
return MAP.splice(body); return MAP.splice(body);
} }
}
})); }));
return wrapped_tl; return wrapped_tl;
} }
@@ -352,11 +411,11 @@ var AST_Accessor = DEFNODE("Accessor", null, {
$documentation: "A setter/getter function. The `name` property is always null." $documentation: "A setter/getter function. The `name` property is always null."
}, AST_Lambda); }, AST_Lambda);
var AST_Function = DEFNODE("Function", "inlined", { var AST_Function = DEFNODE("Function", null, {
$documentation: "A function expression" $documentation: "A function expression"
}, AST_Lambda); }, AST_Lambda);
var AST_Defun = DEFNODE("Defun", "inlined", { var AST_Defun = DEFNODE("Defun", null, {
$documentation: "A function definition" $documentation: "A function definition"
}, AST_Lambda); }, AST_Lambda);
@@ -493,10 +552,10 @@ var AST_Finally = DEFNODE("Finally", null, {
$documentation: "A `finally` node; only makes sense as part of a `try` statement" $documentation: "A `finally` node; only makes sense as part of a `try` statement"
}, AST_Block); }, AST_Block);
/* -----[ VAR ]----- */ /* -----[ VAR/CONST ]----- */
var AST_Definitions = DEFNODE("Definitions", "definitions", { var AST_Definitions = DEFNODE("Definitions", "definitions", {
$documentation: "Base class for `var` nodes (variable declarations/initializations)", $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
$propdoc: { $propdoc: {
definitions: "[AST_VarDef*] array of variable definitions" definitions: "[AST_VarDef*] array of variable definitions"
}, },
@@ -514,10 +573,14 @@ var AST_Var = DEFNODE("Var", null, {
$documentation: "A `var` statement" $documentation: "A `var` statement"
}, AST_Definitions); }, AST_Definitions);
var AST_Const = DEFNODE("Const", null, {
$documentation: "A `const` statement"
}, AST_Definitions);
var AST_VarDef = DEFNODE("VarDef", "name value", { var AST_VarDef = DEFNODE("VarDef", "name value", {
$documentation: "A variable declaration; only appears in a AST_Definitions node", $documentation: "A variable declaration; only appears in a AST_Definitions node",
$propdoc: { $propdoc: {
name: "[AST_SymbolVar] name of the variable", name: "[AST_SymbolVar|AST_SymbolConst] name of the variable",
value: "[AST_Node?] initializer, or null of there's no initializer" value: "[AST_Node?] initializer, or null of there's no initializer"
}, },
_walk: function(visitor) { _walk: function(visitor) {
@@ -538,11 +601,11 @@ var AST_Call = DEFNODE("Call", "expression args", {
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function(){
this.expression._walk(visitor);
var args = this.args; var args = this.args;
for (var i = 0, len = args.length; i < len; i++) { for (var i = 0, len = args.length; i < len; i++) {
args[i]._walk(visitor); args[i]._walk(visitor);
} }
this.expression._walk(visitor);
}); });
} }
}); });
@@ -551,16 +614,68 @@ var AST_New = DEFNODE("New", null, {
$documentation: "An object instantiation. Derives from a function call since it has exactly the same properties" $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
}, AST_Call); }, AST_Call);
var AST_Sequence = DEFNODE("Sequence", "expressions", { var AST_Seq = DEFNODE("Seq", "car cdr", {
$documentation: "A sequence expression (comma-separated expressions)", $documentation: "A sequence expression (two comma-separated expressions)",
$propdoc: { $propdoc: {
expressions: "[AST_Node*] array of expressions (at least two)" car: "[AST_Node] first element in sequence",
cdr: "[AST_Node] second element in sequence"
},
$cons: function(x, y) {
var seq = new AST_Seq(x);
seq.car = x;
seq.cdr = y;
return seq;
},
$from_array: function(array) {
if (array.length == 0) return null;
if (array.length == 1) return array[0].clone();
var list = null;
for (var i = array.length; --i >= 0;) {
list = AST_Seq.cons(array[i], list);
}
var p = list;
while (p) {
if (p.cdr && !p.cdr.cdr) {
p.cdr = p.cdr.car;
break;
}
p = p.cdr;
}
return list;
},
to_array: function() {
var p = this, a = [];
while (p) {
a.push(p.car);
if (p.cdr && !(p.cdr instanceof AST_Seq)) {
a.push(p.cdr);
break;
}
p = p.cdr;
}
return a;
},
add: function(node) {
var p = this;
while (p) {
if (!(p.cdr instanceof AST_Seq)) {
var cell = AST_Seq.cons(p.cdr, node);
return p.cdr = cell;
}
p = p.cdr;
}
},
len: function() {
if (this.cdr instanceof AST_Seq) {
return this.cdr.len() + 1;
} else {
return 2;
}
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function(){
this.expressions.forEach(function(node) { this.car._walk(visitor);
node._walk(visitor); if (this.cdr) this.cdr._walk(visitor);
});
}); });
} }
}); });
@@ -613,7 +728,7 @@ var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
$documentation: "Unary postfix expression, i.e. `i++`" $documentation: "Unary postfix expression, i.e. `i++`"
}, AST_Unary); }, AST_Unary);
var AST_Binary = DEFNODE("Binary", "operator left right", { var AST_Binary = DEFNODE("Binary", "left operator right", {
$documentation: "Binary expression, i.e. `a + b`", $documentation: "Binary expression, i.e. `a + b`",
$propdoc: { $propdoc: {
left: "[AST_Node] left-hand side expression", left: "[AST_Node] left-hand side expression",
@@ -683,8 +798,8 @@ var AST_Object = DEFNODE("Object", "properties", {
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", { var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
$documentation: "Base class for literal object properties", $documentation: "Base class for literal object properties",
$propdoc: { $propdoc: {
key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an AST_SymbolAccessor.", key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.",
value: "[AST_Node] property value. For setters and getters this is an AST_Accessor." value: "[AST_Node] property value. For setters and getters this is an AST_Function."
}, },
_walk: function(visitor) { _walk: function(visitor) {
return visitor._visit(this, function(){ return visitor._visit(this, function(){
@@ -722,13 +837,17 @@ var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
}, AST_Symbol); }, AST_Symbol);
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", { var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)", $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
}, AST_Symbol); }, AST_Symbol);
var AST_SymbolVar = DEFNODE("SymbolVar", null, { var AST_SymbolVar = DEFNODE("SymbolVar", null, {
$documentation: "Symbol defining a variable", $documentation: "Symbol defining a variable",
}, AST_SymbolDeclaration); }, AST_SymbolDeclaration);
var AST_SymbolConst = DEFNODE("SymbolConst", null, {
$documentation: "A constant declaration"
}, AST_SymbolDeclaration);
var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, { var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
$documentation: "Symbol naming a function argument", $documentation: "Symbol naming a function argument",
}, AST_SymbolVar); }, AST_SymbolVar);
@@ -857,13 +976,13 @@ TreeWalker.prototype = {
if (!ret && descend) { if (!ret && descend) {
descend.call(node); descend.call(node);
} }
this.pop(); this.pop(node);
return ret; return ret;
}, },
parent: function(n) { parent: function(n) {
return this.stack[this.stack.length - 2 - (n || 0)]; return this.stack[this.stack.length - 2 - (n || 0)];
}, },
push: function(node) { push: function (node) {
if (node instanceof AST_Lambda) { if (node instanceof AST_Lambda) {
this.directives = Object.create(this.directives); this.directives = Object.create(this.directives);
} else if (node instanceof AST_Directive && !this.directives[node.value]) { } else if (node instanceof AST_Directive && !this.directives[node.value]) {
@@ -871,8 +990,9 @@ TreeWalker.prototype = {
} }
this.stack.push(node); this.stack.push(node);
}, },
pop: function() { pop: function(node) {
if (this.stack.pop() instanceof AST_Lambda) { this.stack.pop();
if (node instanceof AST_Lambda) {
this.directives = Object.getPrototypeOf(this.directives); this.directives = Object.getPrototypeOf(this.directives);
} }
}, },
@@ -898,6 +1018,24 @@ TreeWalker.prototype = {
} }
} }
}, },
in_boolean_context: function() {
var stack = this.stack;
var i = stack.length, self = stack[--i];
while (i > 0) {
var p = stack[--i];
if ((p instanceof AST_If && p.condition === self) ||
(p instanceof AST_Conditional && p.condition === self) ||
(p instanceof AST_DWLoop && p.condition === self) ||
(p instanceof AST_For && p.condition === self) ||
(p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self))
{
return true;
}
if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||")))
return false;
self = p;
}
},
loopcontrol_target: function(node) { loopcontrol_target: function(node) {
var stack = this.stack; var stack = this.stack;
if (node.label) for (var i = stack.length; --i >= 0;) { if (node.label) for (var i = stack.length; --i >= 0;) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,228 +0,0 @@
"use strict";
var to_ascii = typeof atob == "undefined" ? function(b64) {
return new Buffer(b64, "base64").toString();
} : atob;
var to_base64 = typeof btoa == "undefined" ? function(str) {
return new Buffer(str).toString("base64");
} : btoa;
function read_source_map(code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) {
AST_Node.warn("inline source map not found");
return null;
}
return to_ascii(match[2]);
}
function set_shorthand(name, options, keys) {
if (options[name]) {
keys.forEach(function(key) {
if (options[key]) {
if (typeof options[key] != "object") options[key] = {};
if (!(name in options[key])) options[key][name] = options[name];
}
});
}
}
function init_cache(cache) {
if (!cache) return;
if (!("cname" in cache)) cache.cname = -1;
if (!("props" in cache)) {
cache.props = new Dictionary();
} else if (!(cache.props instanceof Dictionary)) {
cache.props = Dictionary.fromObject(cache.props);
}
}
function to_json(cache) {
return {
cname: cache.cname,
props: cache.props.toObject()
};
}
function minify(files, options) {
var warn_function = AST_Node.warn_function;
try {
options = defaults(options, {
compress: {},
ie8: false,
keep_fnames: false,
mangle: {},
nameCache: null,
output: {},
parse: {},
rename: undefined,
sourceMap: false,
timings: false,
toplevel: false,
warnings: false,
wrap: false,
}, true);
var timings = options.timings && {
start: Date.now()
};
if (options.rename === undefined) {
options.rename = options.compress && options.mangle;
}
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]);
var quoted_props;
if (options.mangle) {
options.mangle = defaults(options.mangle, {
cache: options.nameCache && (options.nameCache.vars || {}),
eval: false,
ie8: false,
keep_fnames: false,
properties: false,
reserved: [],
toplevel: false,
}, true);
if (options.mangle.properties) {
if (typeof options.mangle.properties != "object") {
options.mangle.properties = {};
}
if (options.mangle.properties.keep_quoted) {
quoted_props = options.mangle.properties.reserved;
if (!Array.isArray(quoted_props)) quoted_props = [];
options.mangle.properties.reserved = quoted_props;
}
if (options.nameCache && !("cache" in options.mangle.properties)) {
options.mangle.properties.cache = options.nameCache.props || {};
}
}
init_cache(options.mangle.cache);
init_cache(options.mangle.properties.cache);
}
if (options.sourceMap) {
options.sourceMap = defaults(options.sourceMap, {
content: null,
filename: null,
includeSources: false,
root: null,
url: null,
}, true);
}
var warnings = [];
if (options.warnings && !AST_Node.warn_function) {
AST_Node.warn_function = function(warning) {
warnings.push(warning);
};
}
if (timings) timings.parse = Date.now();
var toplevel;
if (files instanceof AST_Toplevel) {
toplevel = files;
} else {
if (typeof files == "string") {
files = [ files ];
}
options.parse = options.parse || {};
options.parse.toplevel = null;
for (var name in files) if (HOP(files, name)) {
options.parse.filename = name;
options.parse.toplevel = parse(files[name], options.parse);
if (options.sourceMap && options.sourceMap.content == "inline") {
if (Object.keys(files).length > 1)
throw new Error("inline source map only works with singular input");
options.sourceMap.content = read_source_map(files[name]);
}
}
toplevel = options.parse.toplevel;
}
if (quoted_props) {
reserve_quoted_keys(toplevel, quoted_props);
}
if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap);
}
if (timings) timings.rename = Date.now();
if (options.rename) {
toplevel.figure_out_scope(options.mangle);
toplevel.expand_names(options.mangle);
}
if (timings) timings.compress = Date.now();
if (options.compress) toplevel = new Compressor(options.compress).compress(toplevel);
if (timings) timings.scope = Date.now();
if (options.mangle) toplevel.figure_out_scope(options.mangle);
if (timings) timings.mangle = Date.now();
if (options.mangle) {
base54.reset();
toplevel.compute_char_frequency(options.mangle);
toplevel.mangle_names(options.mangle);
}
if (timings) timings.properties = Date.now();
if (options.mangle && options.mangle.properties) {
toplevel = mangle_properties(toplevel, options.mangle.properties);
}
if (timings) timings.output = Date.now();
var result = {};
if (options.output.ast) {
result.ast = toplevel;
}
if (!HOP(options.output, "code") || options.output.code) {
if (options.sourceMap) {
if (typeof options.sourceMap.content == "string") {
options.sourceMap.content = JSON.parse(options.sourceMap.content);
}
options.output.source_map = SourceMap({
file: options.sourceMap.filename,
orig: options.sourceMap.content,
root: options.sourceMap.root
});
if (options.sourceMap.includeSources) {
if (files instanceof AST_Toplevel) {
throw new Error("original source content unavailable");
} else for (var name in files) if (HOP(files, name)) {
options.output.source_map.get().setSourceContent(name, files[name]);
}
}
}
delete options.output.ast;
delete options.output.code;
var stream = OutputStream(options.output);
toplevel.print(stream);
result.code = stream.get();
if (options.sourceMap) {
result.map = options.output.source_map.toString();
if (options.sourceMap.url == "inline") {
result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(result.map);
} else if (options.sourceMap.url) {
result.code += "\n//# sourceMappingURL=" + options.sourceMap.url;
}
}
}
if (options.nameCache && options.mangle) {
if (options.mangle.cache) options.nameCache.vars = to_json(options.mangle.cache);
if (options.mangle.properties && options.mangle.properties.cache) {
options.nameCache.props = to_json(options.mangle.properties.cache);
}
}
if (timings) {
timings.end = Date.now();
result.timings = {
parse: 1e-3 * (timings.rename - timings.parse),
rename: 1e-3 * (timings.compress - timings.rename),
compress: 1e-3 * (timings.scope - timings.compress),
scope: 1e-3 * (timings.mangle - timings.scope),
mangle: 1e-3 * (timings.properties - timings.mangle),
properties: 1e-3 * (timings.output - timings.properties),
output: 1e-3 * (timings.end - timings.output),
total: 1e-3 * (timings.end - timings.start)
}
}
if (warnings.length) {
result.warnings = warnings;
}
return result;
} catch (ex) {
return { error: ex };
} finally {
AST_Node.warn_function = warn_function;
}
}

View File

@@ -111,19 +111,23 @@
}, },
Property: function(M) { Property: function(M) {
var key = M.key; var key = M.key;
var name = key.type == "Identifier" ? key.name : key.value;
var args = { var args = {
start : my_start_token(key), start : my_start_token(key),
end : my_end_token(M.value), end : my_end_token(M.value),
key : key.type == "Identifier" ? key.name : key.value, key : name,
value : from_moz(M.value) value : from_moz(M.value)
}; };
if (M.kind == "init") return new AST_ObjectKeyVal(args); switch (M.kind) {
args.key = new AST_SymbolAccessor({ case "init":
name: args.key return new AST_ObjectKeyVal(args);
}); case "set":
args.value = new AST_Accessor(args.value); args.value.name = from_moz(key);
if (M.kind == "get") return new AST_ObjectGetter(args); return new AST_ObjectSetter(args);
if (M.kind == "set") return new AST_ObjectSetter(args); case "get":
args.value.name = from_moz(key);
return new AST_ObjectGetter(args);
}
}, },
ArrayExpression: function(M) { ArrayExpression: function(M) {
return new AST_Array({ return new AST_Array({
@@ -145,11 +149,7 @@
}); });
}, },
SequenceExpression: function(M) { SequenceExpression: function(M) {
return new AST_Sequence({ return AST_Seq.from_array(M.expressions.map(from_moz));
start : my_start_token(M),
end : my_end_token(M),
expressions: M.expressions.map(from_moz)
});
}, },
MemberExpression: function(M) { MemberExpression: function(M) {
return new (M.computed ? AST_Sub : AST_Dot)({ return new (M.computed ? AST_Sub : AST_Dot)({
@@ -168,7 +168,7 @@
}); });
}, },
VariableDeclaration: function(M) { VariableDeclaration: function(M) {
return new AST_Var({ return new (M.kind === "const" ? AST_Const : AST_Var)({
start : my_start_token(M), start : my_start_token(M),
end : my_end_token(M), end : my_end_token(M),
definitions : M.declarations.map(from_moz) definitions : M.declarations.map(from_moz)
@@ -204,7 +204,7 @@
Identifier: function(M) { Identifier: function(M) {
var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2]; var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
return new ( p.type == "LabeledStatement" ? AST_Label return new ( p.type == "LabeledStatement" ? AST_Label
: p.type == "VariableDeclarator" && p.id === M ? AST_SymbolVar : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar)
: p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg) : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
: p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg) : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
: p.type == "CatchClause" ? AST_SymbolCatch : p.type == "CatchClause" ? AST_SymbolCatch
@@ -256,7 +256,10 @@
map("CallExpression", AST_Call, "callee>expression, arguments@args"); map("CallExpression", AST_Call, "callee>expression, arguments@args");
def_to_moz(AST_Toplevel, function To_Moz_Program(M) { def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
return to_moz_scope("Program", M); return {
type: "Program",
body: M.body.map(to_moz)
};
}); });
def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) { def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) {
@@ -264,7 +267,7 @@
type: "FunctionDeclaration", type: "FunctionDeclaration",
id: to_moz(M.name), id: to_moz(M.name),
params: M.argnames.map(to_moz), params: M.argnames.map(to_moz),
body: to_moz_scope("BlockStatement", M) body: to_moz_block(M)
} }
}); });
@@ -273,7 +276,7 @@
type: "FunctionExpression", type: "FunctionExpression",
id: to_moz(M.name), id: to_moz(M.name),
params: M.argnames.map(to_moz), params: M.argnames.map(to_moz),
body: to_moz_scope("BlockStatement", M) body: to_moz_block(M)
} }
}); });
@@ -324,15 +327,15 @@
def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) { def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) {
return { return {
type: "VariableDeclaration", type: "VariableDeclaration",
kind: "var", kind: M instanceof AST_Const ? "const" : "var",
declarations: M.definitions.map(to_moz) declarations: M.definitions.map(to_moz)
}; };
}); });
def_to_moz(AST_Sequence, function To_Moz_SequenceExpression(M) { def_to_moz(AST_Seq, function To_Moz_SequenceExpression(M) {
return { return {
type: "SequenceExpression", type: "SequenceExpression",
expressions: M.expressions.map(to_moz) expressions: M.to_array().map(to_moz)
}; };
}); });
@@ -379,10 +382,11 @@
}); });
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) { def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
var key = { var key = (
type: "Literal", is_identifier(M.key)
value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key ? {type: "Identifier", name: M.key}
}; : {type: "Literal", value: M.key}
);
var kind; var kind;
if (M instanceof AST_ObjectKeyVal) { if (M instanceof AST_ObjectKeyVal) {
kind = "init"; kind = "init";
@@ -543,8 +547,8 @@
moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
exports, my_start_token, my_end_token, from_moz exports, my_start_token, my_end_token, from_moz
); );
me_to_moz = new Function("to_moz", "to_moz_block", "to_moz_scope", "return(" + me_to_moz + ")")( me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")(
to_moz, to_moz_block, to_moz_scope to_moz, to_moz_block
); );
MOZ_TO_ME[moztype] = moz_to_me; MOZ_TO_ME[moztype] = moz_to_me;
def_to_moz(mytype, me_to_moz); def_to_moz(mytype, me_to_moz);
@@ -602,14 +606,4 @@
}; };
}; };
function to_moz_scope(type, node) {
var body = node.body.map(to_moz);
if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) {
body.unshift(to_moz(new AST_EmptyStatement(node.body[0])));
}
return {
type: type,
body: body
};
};
})(); })();

View File

@@ -52,13 +52,11 @@ function is_some_comments(comment) {
function OutputStream(options) { function OutputStream(options) {
var readonly = !options;
options = defaults(options, { options = defaults(options, {
ascii_only : false, ascii_only : false,
beautify : false, beautify : false,
bracketize : false, bracketize : false,
comments : false, comments : false,
ie8 : false,
indent_level : 4, indent_level : 4,
indent_start : 0, indent_start : 0,
inline_script : true, inline_script : true,
@@ -68,10 +66,12 @@ function OutputStream(options) {
preserve_line : false, preserve_line : false,
quote_keys : false, quote_keys : false,
quote_style : 0, quote_style : 0,
screw_ie8 : true,
semicolons : true, semicolons : true,
shebang : true, shebang : true,
source_map : null, source_map : null,
webkit : false, space_colon : true,
unescape_regexps : false,
width : 80, width : 80,
wrap_iife : false, wrap_iife : false,
}, true); }, true);
@@ -110,7 +110,7 @@ function OutputStream(options) {
var current_pos = 0; var current_pos = 0;
var OUTPUT = ""; var OUTPUT = "";
var to_utf8 = options.ascii_only ? function(str, identifier) { function to_ascii(str, identifier) {
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) { return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
var code = ch.charCodeAt(0).toString(16); var code = ch.charCodeAt(0).toString(16);
if (code.length <= 2 && !identifier) { if (code.length <= 2 && !identifier) {
@@ -121,17 +121,6 @@ function OutputStream(options) {
return "\\u" + code; return "\\u" + code;
} }
}); });
} : function(str) {
var s = "";
for (var i = 0, len = str.length; i < len; i++) {
if (is_surrogate_pair_head(str[i]) && !is_surrogate_pair_tail(str[i + 1])
|| is_surrogate_pair_tail(str[i]) && !is_surrogate_pair_head(str[i - 1])) {
s += "\\u" + str.charCodeAt(i).toString(16);
} else {
s += str[i];
}
}
return s;
}; };
function make_string(str, quote) { function make_string(str, quote) {
@@ -147,12 +136,12 @@ function OutputStream(options) {
case "\t": return "\\t"; case "\t": return "\\t";
case "\b": return "\\b"; case "\b": return "\\b";
case "\f": return "\\f"; case "\f": return "\\f";
case "\x0B": return options.ie8 ? "\\x0B" : "\\v"; case "\x0B": return options.screw_ie8 ? "\\v" : "\\x0B";
case "\u2028": return "\\u2028"; case "\u2028": return "\\u2028";
case "\u2029": return "\\u2029"; case "\u2029": return "\\u2029";
case "\ufeff": return "\\ufeff"; case "\ufeff": return "\\ufeff";
case "\0": case "\0":
return /[0-9]/.test(str.charAt(i+1)) ? "\\x00" : "\\0"; return /[0-7]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
} }
return s; return s;
}); });
@@ -162,7 +151,7 @@ function OutputStream(options) {
function quote_double() { function quote_double() {
return '"' + str.replace(/\x22/g, '\\"') + '"'; return '"' + str.replace(/\x22/g, '\\"') + '"';
} }
str = to_utf8(str); if (options.ascii_only) str = to_ascii(str);
switch (options.quote_style) { switch (options.quote_style) {
case 1: case 1:
return quote_single(); return quote_single();
@@ -187,7 +176,8 @@ function OutputStream(options) {
function make_name(name) { function make_name(name) {
name = name.toString(); name = name.toString();
name = to_utf8(name, true); if (options.ascii_only)
name = to_ascii(name, true);
return name; return name;
}; };
@@ -200,47 +190,13 @@ function OutputStream(options) {
var might_need_space = false; var might_need_space = false;
var might_need_semicolon = false; var might_need_semicolon = false;
var might_add_newline = 0; var might_add_newline = 0;
var need_newline_indented = false;
var need_space = false;
var newline_insert = -1;
var last = ""; var last = "";
var mapping_token, mapping_name, mappings = options.source_map && [];
var do_add_mapping = mappings ? function() {
mappings.forEach(function(mapping) {
try {
options.source_map.add(
mapping.token.file,
mapping.line, mapping.col,
mapping.token.line, mapping.token.col,
!mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name
);
} catch(ex) {
AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
file: mapping.token.file,
line: mapping.token.line,
col: mapping.token.col,
cline: mapping.line,
ccol: mapping.col,
name: mapping.name || ""
})
}
});
mappings = [];
} : noop;
var ensure_line_len = options.max_line_len ? function() { var ensure_line_len = options.max_line_len ? function() {
if (current_col > options.max_line_len) { if (current_col > options.max_line_len) {
if (might_add_newline) { if (might_add_newline) {
var left = OUTPUT.slice(0, might_add_newline); var left = OUTPUT.slice(0, might_add_newline);
var right = OUTPUT.slice(might_add_newline); var right = OUTPUT.slice(might_add_newline);
if (mappings) {
var delta = right.length - current_col;
mappings.forEach(function(mapping) {
mapping.line++;
mapping.col += delta;
});
}
OUTPUT = left + "\n" + right; OUTPUT = left + "\n" + right;
current_line++; current_line++;
current_pos++; current_pos++;
@@ -250,10 +206,7 @@ function OutputStream(options) {
AST_Node.warn("Output exceeds {max_line_len} characters", options); AST_Node.warn("Output exceeds {max_line_len} characters", options);
} }
} }
if (might_add_newline) {
might_add_newline = 0; might_add_newline = 0;
do_add_mapping();
}
} : noop; } : noop;
var requireSemicolonChars = makePredicate("( [ + * / - , ."); var requireSemicolonChars = makePredicate("( [ + * / - , .");
@@ -261,20 +214,6 @@ function OutputStream(options) {
function print(str) { function print(str) {
str = String(str); str = String(str);
var ch = str.charAt(0); var ch = str.charAt(0);
if (need_newline_indented && ch) {
need_newline_indented = false;
if (ch != "\n") {
print("\n");
indent();
}
}
if (need_space && ch) {
need_space = false;
if (!/[\s;})]/.test(ch)) {
space();
}
}
newline_insert = -1;
var prev = last.charAt(last.length - 1); var prev = last.charAt(last.length - 1);
if (might_need_semicolon) { if (might_need_semicolon) {
might_need_semicolon = false; might_need_semicolon = false;
@@ -327,18 +266,6 @@ function OutputStream(options) {
} }
might_need_space = false; might_need_space = false;
} }
if (mapping_token) {
mappings.push({
token: mapping_token,
name: mapping_name,
line: current_line,
col: current_col
});
mapping_token = false;
if (!might_add_newline) do_add_mapping();
}
OUTPUT += str; OUTPUT += str;
current_pos += str.length; current_pos += str.length;
var a = str.split(/\r?\n/), n = a.length - 1; var a = str.split(/\r?\n/), n = a.length - 1;
@@ -373,13 +300,7 @@ function OutputStream(options) {
} : function(col, cont) { return cont() }; } : function(col, cont) { return cont() };
var newline = options.beautify ? function() { var newline = options.beautify ? function() {
if (newline_insert < 0) return print("\n"); print("\n");
if (OUTPUT[newline_insert] != "\n") {
OUTPUT = OUTPUT.slice(0, newline_insert) + "\n" + OUTPUT.slice(newline_insert);
current_pos++;
current_line++;
}
newline_insert++;
} : options.max_line_len ? function() { } : options.max_line_len ? function() {
ensure_line_len(); ensure_line_len();
might_add_newline = OUTPUT.length; might_add_newline = OUTPUT.length;
@@ -436,12 +357,27 @@ function OutputStream(options) {
function colon() { function colon() {
print(":"); print(":");
space(); if (options.space_colon) space();
}; };
var add_mapping = mappings ? function(token, name) { var add_mapping = options.source_map ? function(token, name) {
mapping_token = token; try {
mapping_name = name; if (token) options.source_map.add(
token.file || "?",
current_line, current_col,
token.line, token.col,
(!name && token.type == "name") ? token.value : name
);
} catch(ex) {
AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
file: token.file,
line: token.line,
col: token.col,
cline: current_line,
ccol: current_col,
name: name || ""
})
}
} : noop; } : noop;
function get() { function get() {
@@ -451,116 +387,6 @@ function OutputStream(options) {
return OUTPUT; return OUTPUT;
}; };
function prepend_comments(node) {
var self = this;
var start = node.start;
if (!(start.comments_before && start.comments_before._dumped === self)) {
var comments = start.comments_before;
if (!comments) {
comments = start.comments_before = [];
}
comments._dumped = self;
if (node instanceof AST_Exit && node.value) {
var tw = new TreeWalker(function(node) {
var parent = tw.parent();
if (parent instanceof AST_Exit
|| parent instanceof AST_Binary && parent.left === node
|| parent.TYPE == "Call" && parent.expression === node
|| parent instanceof AST_Conditional && parent.condition === node
|| parent instanceof AST_Dot && parent.expression === node
|| parent instanceof AST_Sequence && parent.expressions[0] === node
|| parent instanceof AST_Sub && parent.expression === node
|| parent instanceof AST_UnaryPostfix) {
var text = node.start.comments_before;
if (text && text._dumped !== self) {
text._dumped = self;
comments = comments.concat(text);
}
} else {
return true;
}
});
tw.push(node);
node.value.walk(tw);
}
if (current_pos == 0) {
if (comments.length > 0 && options.shebang && comments[0].type == "comment5") {
print("#!" + comments.shift().value + "\n");
indent();
}
var preamble = options.preamble;
if (preamble) {
print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
}
}
comments = comments.filter(comment_filter, node);
if (comments.length == 0) return;
var last_nlb = /(^|\n) *$/.test(OUTPUT);
comments.forEach(function(c, i) {
if (!last_nlb) {
if (c.nlb) {
print("\n");
indent();
last_nlb = true;
} else if (i > 0) {
space();
}
}
if (/comment[134]/.test(c.type)) {
print("//" + c.value.replace(/[@#]__PURE__/g, ' ') + "\n");
indent();
last_nlb = true;
} else if (c.type == "comment2") {
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
last_nlb = false;
}
});
if (!last_nlb) {
if (start.nlb) {
print("\n");
indent();
} else {
space();
}
}
}
}
function append_comments(node, tail) {
var self = this;
var token = node.end;
if (!token) return;
var comments = token[tail ? "comments_before" : "comments_after"];
if (comments && comments._dumped !== self) {
comments._dumped = self;
var insert = OUTPUT.length;
comments.filter(comment_filter, node).forEach(function(c, i) {
need_space = false;
if (need_newline_indented) {
print("\n");
indent();
need_newline_indented = false;
} else if (c.nlb && (i > 0 || !/(^|\n) *$/.test(OUTPUT))) {
print("\n");
indent();
} else if (i > 0 || !tail) {
space();
}
if (/comment[134]/.test(c.type)) {
print("//" + c.value.replace(/[@#]__PURE__/g, ' '));
need_newline_indented = true;
} else if (c.type == "comment2") {
print("/*" + c.value.replace(/[@#]__PURE__/g, ' ') + "*/");
need_space = true;
}
});
if (OUTPUT.length > insert) newline_insert = insert;
}
}
var stack = []; var stack = [];
return { return {
get : get, get : get,
@@ -577,7 +403,7 @@ function OutputStream(options) {
last : function() { return last }, last : function() { return last },
semicolon : semicolon, semicolon : semicolon,
force_semicolon : force_semicolon, force_semicolon : force_semicolon,
to_utf8 : to_utf8, to_ascii : to_ascii,
print_name : function(name) { print(make_name(name)) }, print_name : function(name) { print(make_name(name)) },
print_string : function(str, quote, escape_directive) { print_string : function(str, quote, escape_directive) {
var encoded = encode_string(str, quote); var encoded = encode_string(str, quote);
@@ -598,8 +424,7 @@ function OutputStream(options) {
with_square : with_square, with_square : with_square,
add_mapping : add_mapping, add_mapping : add_mapping,
option : function(opt) { return options[opt] }, option : function(opt) { return options[opt] },
prepend_comments: readonly ? noop : prepend_comments, comment_filter : comment_filter,
append_comments : readonly ? noop : append_comments,
line : function() { return current_line }, line : function() { return current_line },
col : function() { return current_col }, col : function() { return current_col },
pos : function() { return current_pos }, pos : function() { return current_pos },
@@ -622,23 +447,18 @@ function OutputStream(options) {
nodetype.DEFMETHOD("_codegen", generator); nodetype.DEFMETHOD("_codegen", generator);
}; };
var use_asm = false;
var in_directive = false; var in_directive = false;
var active_scope = null;
var use_asm = null;
AST_Node.DEFMETHOD("print", function(stream, force_parens){ AST_Node.DEFMETHOD("print", function(stream, force_parens){
var self = this, generator = self._codegen; var self = this, generator = self._codegen, prev_use_asm = use_asm;
if (self instanceof AST_Scope) { if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
active_scope = self; use_asm = true;
}
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
use_asm = active_scope;
} }
function doit() { function doit() {
stream.prepend_comments(self); self.add_comments(stream);
self.add_source_map(stream); self.add_source_map(stream);
generator(self, stream); generator(self, stream);
stream.append_comments(self);
} }
stream.push_node(self); stream.push_node(self);
if (force_parens || self.needs_parens(stream)) { if (force_parens || self.needs_parens(stream)) {
@@ -647,18 +467,84 @@ function OutputStream(options) {
doit(); doit();
} }
stream.pop_node(); stream.pop_node();
if (self === use_asm) { if (self instanceof AST_Scope) {
use_asm = null; use_asm = prev_use_asm;
} }
}); });
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
AST_Node.DEFMETHOD("print_to_string", function(options){ AST_Node.DEFMETHOD("print_to_string", function(options){
var s = OutputStream(options); var s = OutputStream(options);
if (!options) s._readonly = true;
this.print(s); this.print(s);
return s.get(); return s.get();
}); });
/* -----[ comments ]----- */
AST_Node.DEFMETHOD("add_comments", function(output){
if (output._readonly) return;
var self = this;
var start = self.start;
if (start && !start._comments_dumped) {
start._comments_dumped = true;
var comments = start.comments_before || [];
// XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
// and https://github.com/mishoo/UglifyJS2/issues/372
if (self instanceof AST_Exit && self.value) {
self.value.walk(new TreeWalker(function(node){
if (node.start && node.start.comments_before) {
comments = comments.concat(node.start.comments_before);
node.start.comments_before = [];
}
if (node instanceof AST_Function ||
node instanceof AST_Array ||
node instanceof AST_Object)
{
return true; // don't go inside.
}
}));
}
if (output.pos() == 0) {
if (comments.length > 0 && output.option("shebang") && comments[0].type == "comment5") {
output.print("#!" + comments.shift().value + "\n");
output.indent();
}
var preamble = output.option("preamble");
if (preamble) {
output.print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
}
}
comments = comments.filter(output.comment_filter, self);
// Keep single line comments after nlb, after nlb
if (!output.option("beautify") && comments.length > 0 &&
/comment[134]/.test(comments[0].type) &&
output.col() !== 0 && comments[0].nlb)
{
output.print("\n");
}
comments.forEach(function(c){
if (/comment[134]/.test(c.type)) {
output.print("//" + c.value + "\n");
output.indent();
}
else if (c.type == "comment2") {
output.print("/*" + c.value + "*/");
if (start.nlb) {
output.print("\n");
output.indent();
} else {
output.space();
}
}
});
}
});
/* -----[ PARENTHESES ]----- */ /* -----[ PARENTHESES ]----- */
function PARENS(nodetype, func) { function PARENS(nodetype, func) {
@@ -682,13 +568,6 @@ function OutputStream(options) {
return true; return true;
} }
if (output.option('webkit')) {
var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === this) {
return true;
}
}
if (output.option('wrap_iife')) { if (output.option('wrap_iife')) {
var p = output.parent(); var p = output.parent();
return p instanceof AST_Call && p.expression === this; return p instanceof AST_Call && p.expression === this;
@@ -709,7 +588,7 @@ function OutputStream(options) {
|| p instanceof AST_Call && p.expression === this; || p instanceof AST_Call && p.expression === this;
}); });
PARENS(AST_Sequence, function(output){ PARENS(AST_Seq, function(output){
var p = output.parent(); var p = output.parent();
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4) return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|| p instanceof AST_Unary // !(foo, bar, baz) || p instanceof AST_Unary // !(foo, bar, baz)
@@ -755,15 +634,14 @@ function OutputStream(options) {
// parens around it too, otherwise the call will be // parens around it too, otherwise the call will be
// interpreted as passing the arguments to the upper New // interpreted as passing the arguments to the upper New
// expression. // expression.
var parens = false; try {
this.walk(new TreeWalker(function(node) { this.walk(new TreeWalker(function(node){
if (parens || node instanceof AST_Scope) return true; if (node instanceof AST_Call) throw p;
if (node instanceof AST_Call) { }));
parens = true; } catch(ex) {
if (ex !== p) throw ex;
return true; return true;
} }
}));
return parens;
} }
}); });
@@ -799,7 +677,7 @@ function OutputStream(options) {
} }
}); });
PARENS([ AST_Assign, AST_Conditional ], function(output){ PARENS([ AST_Assign, AST_Conditional ], function (output){
var p = output.parent(); var p = output.parent();
// !(a = false) → true // !(a = false) → true
if (p instanceof AST_Unary) if (p instanceof AST_Unary)
@@ -880,21 +758,14 @@ function OutputStream(options) {
self.body.print(output); self.body.print(output);
output.semicolon(); output.semicolon();
}); });
function print_bracketed(self, output, allow_directives) { function print_bracketed(body, output, allow_directives) {
if (self.body.length > 0) { if (body.length > 0) output.with_block(function(){
output.with_block(function() { display_body(body, false, output, allow_directives);
display_body(self.body, false, output, allow_directives);
}); });
} else { else output.print("{}");
output.print("{");
output.with_indent(output.next_indent(), function() {
output.append_comments(self, true);
});
output.print("}");
}
}; };
DEFPRINT(AST_BlockStatement, function(self, output){ DEFPRINT(AST_BlockStatement, function(self, output){
print_bracketed(self, output); print_bracketed(self.body, output);
}); });
DEFPRINT(AST_EmptyStatement, function(self, output){ DEFPRINT(AST_EmptyStatement, function(self, output){
output.semicolon(); output.semicolon();
@@ -989,7 +860,7 @@ function OutputStream(options) {
}); });
}); });
output.space(); output.space();
print_bracketed(self, output, true); print_bracketed(self.body, output, true);
}); });
DEFPRINT(AST_Lambda, function(self, output){ DEFPRINT(AST_Lambda, function(self, output){
self._do_print(output); self._do_print(output);
@@ -1031,7 +902,7 @@ function OutputStream(options) {
function make_then(self, output) { function make_then(self, output) {
var b = self.body; var b = self.body;
if (output.option("bracketize") if (output.option("bracketize")
|| output.option("ie8") && b instanceof AST_Do) || !output.option("screw_ie8") && b instanceof AST_Do)
return make_block(b, output); return make_block(b, output);
// The squeezer replaces "block"-s that contain only a single // The squeezer replaces "block"-s that contain only a single
// statement with the statement itself; technically, the AST // statement with the statement itself; technically, the AST
@@ -1120,7 +991,7 @@ function OutputStream(options) {
DEFPRINT(AST_Try, function(self, output){ DEFPRINT(AST_Try, function(self, output){
output.print("try"); output.print("try");
output.space(); output.space();
print_bracketed(self, output); print_bracketed(self.body, output);
if (self.bcatch) { if (self.bcatch) {
output.space(); output.space();
self.bcatch.print(output); self.bcatch.print(output);
@@ -1137,12 +1008,12 @@ function OutputStream(options) {
self.argname.print(output); self.argname.print(output);
}); });
output.space(); output.space();
print_bracketed(self, output); print_bracketed(self.body, output);
}); });
DEFPRINT(AST_Finally, function(self, output){ DEFPRINT(AST_Finally, function(self, output){
output.print("finally"); output.print("finally");
output.space(); output.space();
print_bracketed(self, output); print_bracketed(self.body, output);
}); });
/* -----[ var/const ]----- */ /* -----[ var/const ]----- */
@@ -1162,19 +1033,24 @@ function OutputStream(options) {
DEFPRINT(AST_Var, function(self, output){ DEFPRINT(AST_Var, function(self, output){
self._do_print(output, "var"); self._do_print(output, "var");
}); });
DEFPRINT(AST_Const, function(self, output){
self._do_print(output, "const");
});
function parenthesize_for_noin(node, output, noin) { function parenthesize_for_noin(node, output, noin) {
var parens = false; if (!noin) node.print(output);
else try {
// need to take some precautions here: // need to take some precautions here:
// https://github.com/mishoo/UglifyJS2/issues/60 // https://github.com/mishoo/UglifyJS2/issues/60
if (noin) node.walk(new TreeWalker(function(node) { node.walk(new TreeWalker(function(node){
if (parens || node instanceof AST_Scope) return true; if (node instanceof AST_Binary && node.operator == "in")
if (node instanceof AST_Binary && node.operator == "in") { throw output;
parens = true;
return true;
}
})); }));
node.print(output, parens); node.print(output);
} catch(ex) {
if (ex !== output) throw ex;
node.print(output, true);
}
}; };
DEFPRINT(AST_VarDef, function(self, output){ DEFPRINT(AST_VarDef, function(self, output){
@@ -1194,9 +1070,6 @@ function OutputStream(options) {
self.expression.print(output); self.expression.print(output);
if (self instanceof AST_New && !need_constructor_parens(self, output)) if (self instanceof AST_New && !need_constructor_parens(self, output))
return; return;
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
output.add_mapping(self.start);
}
output.with_parens(function(){ output.with_parens(function(){
self.args.forEach(function(expr, i){ self.args.forEach(function(expr, i){
if (i) output.comma(); if (i) output.comma();
@@ -1210,19 +1083,18 @@ function OutputStream(options) {
AST_Call.prototype._codegen(self, output); AST_Call.prototype._codegen(self, output);
}); });
AST_Sequence.DEFMETHOD("_do_print", function(output){ AST_Seq.DEFMETHOD("_do_print", function(output){
this.expressions.forEach(function(node, index) { this.car.print(output);
if (index > 0) { if (this.cdr) {
output.comma(); output.comma();
if (output.should_break()) { if (output.should_break()) {
output.newline(); output.newline();
output.indent(); output.indent();
} }
this.cdr.print(output);
} }
node.print(output);
}); });
}); DEFPRINT(AST_Seq, function(self, output){
DEFPRINT(AST_Sequence, function(self, output){
self._do_print(output); self._do_print(output);
// var p = output.parent(); // var p = output.parent();
// if (p instanceof AST_Statement) { // if (p instanceof AST_Statement) {
@@ -1236,13 +1108,6 @@ function OutputStream(options) {
DEFPRINT(AST_Dot, function(self, output){ DEFPRINT(AST_Dot, function(self, output){
var expr = self.expression; var expr = self.expression;
expr.print(output); expr.print(output);
var prop = self.property;
if (output.option("ie8") && RESERVED_WORDS(prop)) {
output.print("[");
output.add_mapping(self.end);
output.print_string(prop);
output.print("]");
} else {
if (expr instanceof AST_Number && expr.getValue() >= 0) { if (expr instanceof AST_Number && expr.getValue() >= 0) {
if (!/[xa-f.)]/i.test(output.last())) { if (!/[xa-f.)]/i.test(output.last())) {
output.print("."); output.print(".");
@@ -1251,8 +1116,7 @@ function OutputStream(options) {
output.print("."); output.print(".");
// the name after dot would be mapped about here. // the name after dot would be mapped about here.
output.add_mapping(self.end); output.add_mapping(self.end);
output.print_name(prop); output.print_name(self.property);
}
}); });
DEFPRINT(AST_Sub, function(self, output){ DEFPRINT(AST_Sub, function(self, output){
self.expression.print(output); self.expression.print(output);
@@ -1343,8 +1207,9 @@ function OutputStream(options) {
}); });
else output.print("{}"); else output.print("{}");
}); });
DEFPRINT(AST_ObjectKeyVal, function(self, output){
function print_property_name(key, quote, output) { var key = self.key;
var quote = self.quote;
if (output.option("quote_keys")) { if (output.option("quote_keys")) {
output.print_string(key + ""); output.print_string(key + "");
} else if ((typeof key == "number" } else if ((typeof key == "number"
@@ -1352,7 +1217,7 @@ function OutputStream(options) {
&& +key + "" == key) && +key + "" == key)
&& parseFloat(key) >= 0) { && parseFloat(key) >= 0) {
output.print(make_num(key)); output.print(make_num(key));
} else if (RESERVED_WORDS(key) ? !output.option("ie8") : is_identifier_string(key)) { } else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
if (quote && output.option("keep_quoted_props")) { if (quote && output.option("keep_quoted_props")) {
output.print_string(key, quote); output.print_string(key, quote);
} else { } else {
@@ -1361,24 +1226,20 @@ function OutputStream(options) {
} else { } else {
output.print_string(key, quote); output.print_string(key, quote);
} }
}
DEFPRINT(AST_ObjectKeyVal, function(self, output){
print_property_name(self.key, self.quote, output);
output.colon(); output.colon();
self.value.print(output); self.value.print(output);
}); });
AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, output) {
output.print(type);
output.space();
print_property_name(this.key.name, this.quote, output);
this.value._do_print(output, true);
});
DEFPRINT(AST_ObjectSetter, function(self, output){ DEFPRINT(AST_ObjectSetter, function(self, output){
self._print_getter_setter("set", output); output.print("set");
output.space();
self.key.print(output);
self.value._do_print(output, true);
}); });
DEFPRINT(AST_ObjectGetter, function(self, output){ DEFPRINT(AST_ObjectGetter, function(self, output){
self._print_getter_setter("get", output); output.print("get");
output.space();
self.key.print(output);
self.value._do_print(output, true);
}); });
DEFPRINT(AST_Symbol, function(self, output){ DEFPRINT(AST_Symbol, function(self, output){
var def = self.definition(); var def = self.definition();
@@ -1402,13 +1263,46 @@ function OutputStream(options) {
} }
}); });
function regexp_safe_literal(code) {
return [
0x5c , // \
0x2f , // /
0x2e , // .
0x2b , // +
0x2a , // *
0x3f , // ?
0x28 , // (
0x29 , // )
0x5b , // [
0x5d , // ]
0x7b , // {
0x7d , // }
0x24 , // $
0x5e , // ^
0x3a , // :
0x7c , // |
0x21 , // !
0x0a , // \n
0x0d , // \r
0x00 , // \0
0xfeff , // Unicode BOM
0x2028 , // unicode "line separator"
0x2029 , // unicode "paragraph separator"
].indexOf(code) < 0;
};
DEFPRINT(AST_RegExp, function(self, output){ DEFPRINT(AST_RegExp, function(self, output){
var regexp = self.getValue(); var str = self.getValue().toString();
var str = regexp.toString(); if (output.option("ascii_only")) {
if (regexp.raw_source) { str = output.to_ascii(str);
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/")); } else if (output.option("unescape_regexps")) {
str = str.split("\\\\").map(function(str){
return str.replace(/\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2}/g, function(s){
var code = parseInt(s.substr(2), 16);
return regexp_safe_literal(code) ? String.fromCharCode(code) : s;
});
}).join("\\\\");
} }
str = output.to_utf8(str);
output.print(str); output.print(str);
var p = output.parent(); var p = output.parent();
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self) if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)

View File

@@ -111,10 +111,12 @@ var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u20
var NEWLINE_CHARS = makePredicate(characters("\n\r\u2028\u2029")); var NEWLINE_CHARS = makePredicate(characters("\n\r\u2028\u2029"));
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,;:")); var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
var PUNC_CHARS = makePredicate(characters("[]{}(),;:")); var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
var REGEXP_MODIFIERS = makePredicate(characters("gmsiy"));
/* -----[ Tokenizer ]----- */ /* -----[ Tokenizer ]----- */
// regexps adapted from http://xregexp.com/plugins/#unicode // regexps adapted from http://xregexp.com/plugins/#unicode
@@ -132,18 +134,6 @@ function is_letter(code) {
|| (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code))); || (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
}; };
function is_surrogate_pair_head(code) {
if (typeof code == "string")
code = code.charCodeAt(0);
return code >= 0xd800 && code <= 0xdbff;
}
function is_surrogate_pair_tail(code) {
if (typeof code == "string")
code = code.charCodeAt(0);
return code >= 0xdc00 && code <= 0xdfff;
}
function is_digit(code) { function is_digit(code) {
return code >= 48 && code <= 57; return code >= 48 && code <= 57;
}; };
@@ -295,11 +285,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) || S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) || (type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
(type == "punc" && PUNC_BEFORE_EXPRESSION(value))); (type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
if (type == "punc" && value == ".") { prev_was_dot = (type == "punc" && value == ".");
prev_was_dot = true;
} else if (!is_comment) {
prev_was_dot = false;
}
var ret = { var ret = {
type : type, type : type,
value : value, value : value,
@@ -317,7 +303,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} }
if (!is_comment) { if (!is_comment) {
ret.comments_before = S.comments_before; ret.comments_before = S.comments_before;
ret.comments_after = S.comments_before = []; S.comments_before = [];
// make note of any newlines in the comments that came before
for (var i = 0, len = ret.comments_before.length; i < len; i++) {
ret.nlb = ret.nlb || ret.comments_before[i].nlb;
}
} }
S.newline_before = false; S.newline_before = false;
return new AST_Token(ret); return new AST_Token(ret);
@@ -483,31 +473,29 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
return name; return name;
}; };
var read_regexp = with_eof_error("Unterminated regular expression", function(source) { var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
var prev_backslash = false, ch, in_class = false; var prev_backslash = false, ch, in_class = false;
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) { while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
parse_error("Unexpected line terminator"); parse_error("Unexpected line terminator");
} else if (prev_backslash) { } else if (prev_backslash) {
source += "\\" + ch; regexp += "\\" + ch;
prev_backslash = false; prev_backslash = false;
} else if (ch == "[") { } else if (ch == "[") {
in_class = true; in_class = true;
source += ch; regexp += ch;
} else if (ch == "]" && in_class) { } else if (ch == "]" && in_class) {
in_class = false; in_class = false;
source += ch; regexp += ch;
} else if (ch == "/" && !in_class) { } else if (ch == "/" && !in_class) {
break; break;
} else if (ch == "\\") { } else if (ch == "\\") {
prev_backslash = true; prev_backslash = true;
} else { } else {
source += ch; regexp += ch;
} }
var mods = read_name(); var mods = read_name();
try { try {
var regexp = new RegExp(source, mods); return token("regexp", new RegExp(regexp, mods));
regexp.raw_source = source;
return token("regexp", regexp);
} catch(e) { } catch(e) {
parse_error(e.message); parse_error(e.message);
} }
@@ -641,7 +629,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} }
next_token.has_directive = function(directive) { next_token.has_directive = function(directive) {
return S.directives[directive] > 0; return S.directives[directive] !== undefined &&
S.directives[directive] > 0;
} }
return next_token; return next_token;
@@ -690,7 +679,9 @@ var PRECEDENCE = (function(a, ret){
{} {}
); );
var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "string", "regexp", "name" ]); var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
/* -----[ Parser ]----- */ /* -----[ Parser ]----- */
@@ -698,13 +689,14 @@ function parse($TEXT, options) {
options = defaults(options, { options = defaults(options, {
bare_returns : false, bare_returns : false,
cli : false,
expression : false, expression : false,
filename : null, filename : null,
html5_comments : true, html5_comments : true,
shebang : true, shebang : true,
strict : false, strict : false,
toplevel : null, toplevel : null,
}, true); });
var S = { var S = {
input : (typeof $TEXT == "string" input : (typeof $TEXT == "string"
@@ -811,23 +803,28 @@ function parse($TEXT, options) {
}; };
var statement = embed_tokens(function() { var statement = embed_tokens(function() {
var tmp;
handle_regexp(); handle_regexp();
switch (S.token.type) { switch (S.token.type) {
case "string": case "string":
if (S.in_directives) { var dir = false;
var token = peek(); if (S.in_directives === true) {
if (S.token.raw.indexOf("\\") == -1 if ((is_token(peek(), "punc", ";") || peek().nlb) && S.token.raw.indexOf("\\") === -1) {
&& (token.nlb
|| is_token(token, "eof")
|| is_token(token, "punc", ";")
|| is_token(token, "punc", "}"))) {
S.input.add_directive(S.token.value); S.input.add_directive(S.token.value);
} else { } else {
S.in_directives = false; S.in_directives = false;
} }
} }
var dir = S.in_directives, stat = simple_statement(); var dir = S.in_directives, stat = simple_statement();
return dir ? new AST_Directive(stat.body) : stat; if (dir) {
return new AST_Directive({
start : stat.body.start,
end : stat.body.end,
quote : stat.body.quote,
value : stat.body.value,
});
}
return stat;
case "num": case "num":
case "regexp": case "regexp":
case "operator": case "operator":
@@ -859,97 +856,75 @@ function parse($TEXT, options) {
} }
case "keyword": case "keyword":
switch (S.token.value) { switch (tmp = S.token.value, next(), tmp) {
case "break": case "break":
next();
return break_cont(AST_Break); return break_cont(AST_Break);
case "continue": case "continue":
next();
return break_cont(AST_Continue); return break_cont(AST_Continue);
case "debugger": case "debugger":
next();
semicolon(); semicolon();
return new AST_Debugger(); return new AST_Debugger();
case "do": case "do":
next();
var body = in_loop(statement);
expect_token("keyword", "while");
var condition = parenthesised();
semicolon(true);
return new AST_Do({ return new AST_Do({
body : body, body : in_loop(statement),
condition : condition condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(true), tmp)
}); });
case "while": case "while":
next();
return new AST_While({ return new AST_While({
condition : parenthesised(), condition : parenthesised(),
body : in_loop(statement) body : in_loop(statement)
}); });
case "for": case "for":
next();
return for_(); return for_();
case "function": case "function":
next();
return function_(AST_Defun); return function_(AST_Defun);
case "if": case "if":
next();
return if_(); return if_();
case "return": case "return":
if (S.in_function == 0 && !options.bare_returns) if (S.in_function == 0 && !options.bare_returns)
croak("'return' outside of function"); croak("'return' outside of function");
next();
var value = null;
if (is("punc", ";")) {
next();
} else if (!can_insert_semicolon()) {
value = expression(true);
semicolon();
}
return new AST_Return({ return new AST_Return({
value: value value: ( is("punc", ";")
? (next(), null)
: can_insert_semicolon()
? null
: (tmp = expression(true), semicolon(), tmp) )
}); });
case "switch": case "switch":
next();
return new AST_Switch({ return new AST_Switch({
expression : parenthesised(), expression : parenthesised(),
body : in_loop(switch_body_) body : in_loop(switch_body_)
}); });
case "throw": case "throw":
next();
if (S.token.nlb) if (S.token.nlb)
croak("Illegal newline after 'throw'"); croak("Illegal newline after 'throw'");
var value = expression(true);
semicolon();
return new AST_Throw({ return new AST_Throw({
value: value value: (tmp = expression(true), semicolon(), tmp)
}); });
case "try": case "try":
next();
return try_(); return try_();
case "var": case "var":
next(); return tmp = var_(), semicolon(), tmp;
var node = var_();
semicolon(); case "const":
return node; return tmp = const_(), semicolon(), tmp;
case "with": case "with":
if (S.input.has_directive("use strict")) { if (S.input.has_directive("use strict")) {
croak("Strict mode may not include a with statement"); croak("Strict mode may not include a with statement");
} }
next();
return new AST_With({ return new AST_With({
expression : parenthesised(), expression : parenthesised(),
body : statement() body : statement()
@@ -1018,12 +993,8 @@ function parse($TEXT, options) {
? (next(), var_(true)) ? (next(), var_(true))
: expression(true, true); : expression(true, true);
if (is("operator", "in")) { if (is("operator", "in")) {
if (init instanceof AST_Var) { if (init instanceof AST_Var && init.definitions.length > 1)
if (init.definitions.length > 1) croak("Only one variable declaration allowed in for..in loop");
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
} else if (!is_assignable(init)) {
croak("Invalid left-hand side in for..in loop", init.start.line, init.start.col, init.start.pos);
}
next(); next();
return for_in(init); return for_in(init);
} }
@@ -1062,35 +1033,30 @@ function parse($TEXT, options) {
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null; var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
if (in_statement && !name) if (in_statement && !name)
unexpected(); unexpected();
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
unexpected(prev());
expect("("); expect("(");
var argnames = []; return new ctor({
for (var first = true; !is("punc", ")");) { name: name,
argnames: (function(first, a){
while (!is("punc", ")")) {
if (first) first = false; else expect(","); if (first) first = false; else expect(",");
argnames.push(as_symbol(AST_SymbolFunarg)); a.push(as_symbol(AST_SymbolFunarg));
} }
next(); next();
var loop = S.in_loop; return a;
var labels = S.labels; })(true, []),
body: (function(loop, labels){
++S.in_function; ++S.in_function;
S.in_directives = true; S.in_directives = true;
S.input.push_directives_stack(); S.input.push_directives_stack();
S.in_loop = 0; S.in_loop = 0;
S.labels = []; S.labels = [];
var body = block_(); var a = block_();
if (S.input.has_directive("use strict")) {
if (name) strict_verify_symbol(name);
argnames.forEach(strict_verify_symbol);
}
S.input.pop_directives_stack(); S.input.pop_directives_stack();
--S.in_function; --S.in_function;
S.in_loop = loop; S.in_loop = loop;
S.labels = labels; S.labels = labels;
return new ctor({ return a;
name: name, })(S.in_loop, S.labels)
argnames: argnames,
body: body
}); });
}; };
@@ -1186,12 +1152,12 @@ function parse($TEXT, options) {
}); });
}; };
function vardefs(no_in) { function vardefs(no_in, in_const) {
var a = []; var a = [];
for (;;) { for (;;) {
a.push(new AST_VarDef({ a.push(new AST_VarDef({
start : S.token, start : S.token,
name : as_symbol(AST_SymbolVar), name : as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar),
value : is("operator", "=") ? (next(), expression(false, no_in)) : null, value : is("operator", "=") ? (next(), expression(false, no_in)) : null,
end : prev() end : prev()
})); }));
@@ -1205,7 +1171,15 @@ function parse($TEXT, options) {
var var_ = function(no_in) { var var_ = function(no_in) {
return new AST_Var({ return new AST_Var({
start : prev(), start : prev(),
definitions : vardefs(no_in), definitions : vardefs(no_in, false),
end : prev()
});
};
var const_ = function() {
return new AST_Const({
start : prev(),
definitions : vardefs(false, true),
end : prev() end : prev()
}); });
}; };
@@ -1232,6 +1206,7 @@ function parse($TEXT, options) {
var tok = S.token, ret; var tok = S.token, ret;
switch (tok.type) { switch (tok.type) {
case "name": case "name":
case "keyword":
ret = _make_symbol(AST_SymbolRef); ret = _make_symbol(AST_SymbolRef);
break; break;
case "num": case "num":
@@ -1261,6 +1236,13 @@ function parse($TEXT, options) {
break; break;
} }
break; break;
case "operator":
if (!is_identifier_string(tok.value)) {
croak("Invalid getter/setter name: " + tok.value,
tok.line, tok.col, tok.pos);
}
ret = _make_symbol(AST_SymbolRef);
break;
} }
next(); next();
return ret; return ret;
@@ -1276,26 +1258,9 @@ function parse($TEXT, options) {
case "(": case "(":
next(); next();
var ex = expression(true); var ex = expression(true);
var len = start.comments_before.length;
[].unshift.apply(ex.start.comments_before, start.comments_before);
start.comments_before = ex.start.comments_before;
start.comments_before_length = len;
if (len == 0 && start.comments_before.length > 0) {
var comment = start.comments_before[0];
if (!comment.nlb) {
comment.nlb = start.nlb;
start.nlb = false;
}
}
start.comments_after = ex.start.comments_after;
ex.start = start; ex.start = start;
ex.end = S.token;
expect(")"); expect(")");
var end = prev();
end.comments_before = ex.end.comments_before;
[].push.apply(ex.end.comments_after, end.comments_after);
end.comments_after = ex.end.comments_after;
ex.end = end;
if (ex instanceof AST_Call) mark_pure(ex);
return subscripts(ex, allow_calls); return subscripts(ex, allow_calls);
case "[": case "[":
return subscripts(array_(), allow_calls); return subscripts(array_(), allow_calls);
@@ -1311,7 +1276,7 @@ function parse($TEXT, options) {
func.end = prev(); func.end = prev();
return subscripts(func, allow_calls); return subscripts(func, allow_calls);
} }
if (ATOMIC_START_TOKEN(S.token.type)) { if (ATOMIC_START_TOKEN[S.token.type]) {
return subscripts(as_atom_node(), allow_calls); return subscripts(as_atom_node(), allow_calls);
} }
unexpected(); unexpected();
@@ -1355,15 +1320,10 @@ function parse($TEXT, options) {
var type = start.type; var type = start.type;
var name = as_property_name(); var name = as_property_name();
if (type == "name" && !is("punc", ":")) { if (type == "name" && !is("punc", ":")) {
var key = new AST_SymbolAccessor({
start: S.token,
name: as_property_name(),
end: prev()
});
if (name == "get") { if (name == "get") {
a.push(new AST_ObjectGetter({ a.push(new AST_ObjectGetter({
start : start, start : start,
key : key, key : as_atom_node(),
value : create_accessor(), value : create_accessor(),
end : prev() end : prev()
})); }));
@@ -1372,7 +1332,7 @@ function parse($TEXT, options) {
if (name == "set") { if (name == "set") {
a.push(new AST_ObjectSetter({ a.push(new AST_ObjectSetter({
start : start, start : start,
key : key, key : as_atom_node(),
value : create_accessor(), value : create_accessor(),
end : prev() end : prev()
})); }));
@@ -1394,15 +1354,14 @@ function parse($TEXT, options) {
function as_property_name() { function as_property_name() {
var tmp = S.token; var tmp = S.token;
next();
switch (tmp.type) { switch (tmp.type) {
case "operator":
if (!KEYWORDS(tmp.value)) unexpected();
case "num": case "num":
case "string": case "string":
case "name": case "name":
case "operator":
case "keyword": case "keyword":
case "atom": case "atom":
next();
return tmp.value; return tmp.value;
default: default:
unexpected(); unexpected();
@@ -1411,9 +1370,16 @@ function parse($TEXT, options) {
function as_name() { function as_name() {
var tmp = S.token; var tmp = S.token;
if (tmp.type != "name") unexpected();
next(); next();
switch (tmp.type) {
case "name":
case "operator":
case "keyword":
case "atom":
return tmp.value; return tmp.value;
default:
unexpected();
}
}; };
function _make_symbol(type) { function _make_symbol(type) {
@@ -1425,37 +1391,16 @@ function parse($TEXT, options) {
}); });
}; };
function strict_verify_symbol(sym) {
if (sym.name == "arguments" || sym.name == "eval")
croak("Unexpected " + sym.name + " in strict mode", sym.start.line, sym.start.col, sym.start.pos);
}
function as_symbol(type, noerror) { function as_symbol(type, noerror) {
if (!is("name")) { if (!is("name")) {
if (!noerror) croak("Name expected"); if (!noerror) croak("Name expected");
return null; return null;
} }
var sym = _make_symbol(type); var sym = _make_symbol(type);
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
strict_verify_symbol(sym);
}
next(); next();
return sym; return sym;
}; };
function mark_pure(call) {
var start = call.start;
var comments = start.comments_before;
var i = HOP(start, "comments_before_length") ? start.comments_before_length : comments.length;
while (--i >= 0) {
var comment = comments[i];
if (/[@#]__PURE__/.test(comment.value)) {
call.pure = comment;
break;
}
}
}
var subscripts = function(expr, allow_calls) { var subscripts = function(expr, allow_calls) {
var start = expr.start; var start = expr.start;
if (is("punc", ".")) { if (is("punc", ".")) {
@@ -1480,14 +1425,12 @@ function parse($TEXT, options) {
} }
if (allow_calls && is("punc", "(")) { if (allow_calls && is("punc", "(")) {
next(); next();
var call = new AST_Call({ return subscripts(new AST_Call({
start : start, start : start,
expression : expr, expression : expr,
args : expr_list(")"), args : expr_list(")"),
end : prev() end : prev()
}); }), true);
mark_pure(call);
return subscripts(call, true);
} }
return expr; return expr;
}; };
@@ -1497,14 +1440,14 @@ function parse($TEXT, options) {
if (is("operator") && UNARY_PREFIX(start.value)) { if (is("operator") && UNARY_PREFIX(start.value)) {
next(); next();
handle_regexp(); handle_regexp();
var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls)); var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls));
ex.start = start; ex.start = start;
ex.end = prev(); ex.end = prev();
return ex; return ex;
} }
var val = expr_atom(allow_calls); var val = expr_atom(allow_calls);
while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) { while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
val = make_unary(AST_UnaryPostfix, S.token, val); val = make_unary(AST_UnaryPostfix, S.token.value, val);
val.start = start; val.start = start;
val.end = S.token; val.end = S.token;
next(); next();
@@ -1512,19 +1455,9 @@ function parse($TEXT, options) {
return val; return val;
}; };
function make_unary(ctor, token, expr) { function make_unary(ctor, op, expr) {
var op = token.value; if ((op == "++" || op == "--") && !is_assignable(expr))
switch (op) { croak("Invalid use of " + op + " operator", null, ctor === AST_UnaryPrefix ? expr.start.col - 1 : null);
case "++":
case "--":
if (!is_assignable(expr))
croak("Invalid use of " + op + " operator", token.line, token.col, token.pos);
break;
case "delete":
if (expr instanceof AST_SymbolRef && S.input.has_directive("use strict"))
croak("Calling delete on expression not allowed in strict mode", expr.start.line, expr.start.col, expr.start.pos);
break;
}
return new ctor({ operator: op, expression: expr }); return new ctor({ operator: op, expression: expr });
}; };
@@ -1569,6 +1502,7 @@ function parse($TEXT, options) {
}; };
function is_assignable(expr) { function is_assignable(expr) {
if (options.cli) return true;
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef; return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
}; };
@@ -1593,18 +1527,17 @@ function parse($TEXT, options) {
var expression = function(commas, no_in) { var expression = function(commas, no_in) {
var start = S.token; var start = S.token;
var exprs = []; var expr = maybe_assign(no_in);
while (true) { if (commas && is("punc", ",")) {
exprs.push(maybe_assign(no_in));
if (!commas || !is("punc", ",")) break;
next(); next();
commas = true; return new AST_Seq({
}
return exprs.length == 1 ? exprs[0] : new AST_Sequence({
start : start, start : start,
expressions : exprs, car : expr,
cdr : expression(true, no_in),
end : peek() end : peek()
}); });
}
return expr;
}; };
function in_loop(cont) { function in_loop(cont) {

View File

@@ -43,16 +43,16 @@
"use strict"; "use strict";
function find_builtins(reserved) { function find_builtins() {
// NaN will be included due to Number.NaN // NaN will be included due to Number.NaN
[ var a = [
"null", "null",
"true", "true",
"false", "false",
"Infinity", "Infinity",
"-Infinity", "-Infinity",
"undefined", "undefined",
].forEach(add); ];
[ Object, Array, Function, Number, [ Object, Array, Function, Number,
String, Boolean, Error, Math, String, Boolean, Error, Math,
Date, RegExp Date, RegExp
@@ -63,52 +63,24 @@ function find_builtins(reserved) {
} }
}); });
function add(name) { function add(name) {
push_uniq(reserved, name); push_uniq(a, name);
} }
} return a;
function reserve_quoted_keys(ast, reserved) {
function add(name) {
push_uniq(reserved, name);
}
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal && node.quote) {
add(node.key);
} else if (node instanceof AST_Sub) {
addStrings(node.property, add);
}
}));
}
function addStrings(node, add) {
node.walk(new TreeWalker(function(node) {
if (node instanceof AST_Sequence) {
addStrings(node.tail_node(), add);
} else if (node instanceof AST_String) {
add(node.value);
} else if (node instanceof AST_Conditional) {
addStrings(node.consequent, add);
addStrings(node.alternative, add);
}
return true;
}));
} }
function mangle_properties(ast, options) { function mangle_properties(ast, options) {
options = defaults(options, { options = defaults(options, {
builtins: false,
cache: null, cache: null,
debug: false, debug: false,
keep_quoted: false, ignore_quoted: false,
only_cache: false, only_cache: false,
regex: null, regex: null,
reserved: null, reserved: null,
}, true); });
var reserved = options.reserved; var reserved = options.reserved;
if (!Array.isArray(reserved)) reserved = []; if (reserved == null)
if (!options.builtins) find_builtins(reserved); reserved = find_builtins();
var cache = options.cache; var cache = options.cache;
if (cache == null) { if (cache == null) {
@@ -119,11 +91,12 @@ function mangle_properties(ast, options) {
} }
var regex = options.regex; var regex = options.regex;
var ignore_quoted = options.ignore_quoted;
// note debug is either false (disabled), or a string of the debug suffix to use (enabled). // note debug is either false (disabled), or a string of the debug suffix to use (enabled).
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true' // note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
// the same as passing an empty string. // the same as passing an empty string.
var debug = options.debug !== false; var debug = (options.debug !== false);
var debug_name_suffix; var debug_name_suffix;
if (debug) { if (debug) {
debug_name_suffix = (options.debug === true ? "" : options.debug); debug_name_suffix = (options.debug === true ? "" : options.debug);
@@ -131,11 +104,12 @@ function mangle_properties(ast, options) {
var names_to_mangle = []; var names_to_mangle = [];
var unmangleable = []; var unmangleable = [];
var ignored = {};
// step 1: find candidates to mangle // step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node){ ast.walk(new TreeWalker(function(node){
if (node instanceof AST_ObjectKeyVal) { if (node instanceof AST_ObjectKeyVal) {
add(node.key); add(node.key, ignore_quoted && node.quote);
} }
else if (node instanceof AST_ObjectProperty) { else if (node instanceof AST_ObjectProperty) {
// setter or getter, since KeyVal is handled above // setter or getter, since KeyVal is handled above
@@ -145,13 +119,14 @@ function mangle_properties(ast, options) {
add(node.property); add(node.property);
} }
else if (node instanceof AST_Sub) { else if (node instanceof AST_Sub) {
addStrings(node.property, add); addStrings(node.property, ignore_quoted);
} }
})); }));
// step 2: transform the tree, renaming properties // step 2: transform the tree, renaming properties
return ast.transform(new TreeTransformer(function(node){ return ast.transform(new TreeTransformer(function(node){
if (node instanceof AST_ObjectKeyVal) { if (node instanceof AST_ObjectKeyVal) {
if (!(ignore_quoted && node.quote))
node.key = mangle(node.key); node.key = mangle(node.key);
} }
else if (node instanceof AST_ObjectProperty) { else if (node instanceof AST_ObjectProperty) {
@@ -161,9 +136,22 @@ function mangle_properties(ast, options) {
else if (node instanceof AST_Dot) { else if (node instanceof AST_Dot) {
node.property = mangle(node.property); node.property = mangle(node.property);
} }
else if (!options.keep_quoted && node instanceof AST_Sub) { else if (node instanceof AST_Sub) {
if (!ignore_quoted)
node.property = mangleStrings(node.property); node.property = mangleStrings(node.property);
} }
// else if (node instanceof AST_String) {
// if (should_mangle(node.value)) {
// AST_Node.warn(
// "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", {
// file : node.start.file,
// line : node.start.line,
// col : node.start.col,
// prop : node.value
// }
// );
// }
// }
})); }));
// only function declarations after this line // only function declarations after this line
@@ -179,13 +167,19 @@ function mangle_properties(ast, options) {
} }
function should_mangle(name) { function should_mangle(name) {
if (ignore_quoted && name in ignored) return false;
if (regex && !regex.test(name)) return false; if (regex && !regex.test(name)) return false;
if (reserved.indexOf(name) >= 0) return false; if (reserved.indexOf(name) >= 0) return false;
return cache.props.has(name) return cache.props.has(name)
|| names_to_mangle.indexOf(name) >= 0; || names_to_mangle.indexOf(name) >= 0;
} }
function add(name) { function add(name, ignore) {
if (ignore) {
ignored[name] = true;
return;
}
if (can_mangle(name)) if (can_mangle(name))
push_uniq(names_to_mangle, name); push_uniq(names_to_mangle, name);
@@ -205,16 +199,19 @@ function mangle_properties(ast, options) {
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_. // debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_"; var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
if (can_mangle(debug_mangled)) { if (can_mangle(debug_mangled) && !(ignore_quoted && debug_mangled in ignored)) {
mangled = debug_mangled; mangled = debug_mangled;
} }
} }
// either debug mode is off, or it is on and we could not use the mangled name // either debug mode is off, or it is on and we could not use the mangled name
if (!mangled) { if (!mangled) {
// note can_mangle() does not check if the name collides with the 'ignored' set
// (filled with quoted properties when ignore_quoted set). Make sure we add this
// check so we don't collide with a quoted name.
do { do {
mangled = base54(++cache.cname); mangled = base54(++cache.cname);
} while (!can_mangle(mangled)); } while (!can_mangle(mangled) || (ignore_quoted && mangled in ignored));
} }
cache.props.set(name, mangled); cache.props.set(name, mangled);
@@ -222,11 +219,36 @@ function mangle_properties(ast, options) {
return mangled; return mangled;
} }
function addStrings(node, ignore) {
var out = {};
try {
(function walk(node){
node.walk(new TreeWalker(function(node){
if (node instanceof AST_Seq) {
walk(node.cdr);
return true;
}
if (node instanceof AST_String) {
add(node.value, ignore);
return true;
}
if (node instanceof AST_Conditional) {
walk(node.consequent);
walk(node.alternative);
return true;
}
throw out;
}));
})(node);
} catch(ex) {
if (ex !== out) throw ex;
}
}
function mangleStrings(node) { function mangleStrings(node) {
return node.transform(new TreeTransformer(function(node){ return node.transform(new TreeTransformer(function(node){
if (node instanceof AST_Sequence) { if (node instanceof AST_Seq) {
var last = node.expressions.length - 1; node.cdr = mangleStrings(node.cdr);
node.expressions[last] = mangleStrings(node.expressions[last]);
} }
else if (node instanceof AST_String) { else if (node instanceof AST_String) {
node.value = mangle(node.value); node.value = mangle(node.value);
@@ -238,4 +260,5 @@ function mangle_properties(ast, options) {
return node; return node;
})); }));
} }
} }

View File

@@ -43,16 +43,15 @@
"use strict"; "use strict";
function SymbolDef(scope, orig) { function SymbolDef(scope, index, orig) {
this.name = orig.name; this.name = orig.name;
this.orig = [ orig ]; this.orig = [ orig ];
this.eliminated = 0;
this.scope = scope; this.scope = scope;
this.references = []; this.references = [];
this.replaced = 0;
this.global = false; this.global = false;
this.mangled_name = null; this.mangled_name = null;
this.undeclared = false; this.undeclared = false;
this.index = index;
this.id = SymbolDef.next_id++; this.id = SymbolDef.next_id++;
}; };
@@ -77,10 +76,10 @@ SymbolDef.prototype = {
else if (!this.mangled_name && !this.unmangleable(options)) { else if (!this.mangled_name && !this.unmangleable(options)) {
var s = this.scope; var s = this.scope;
var sym = this.orig[0]; var sym = this.orig[0];
if (options.ie8 && sym instanceof AST_SymbolLambda) if (!options.screw_ie8 && sym instanceof AST_SymbolLambda)
s = s.parent_scope; s = s.parent_scope;
var def; var def;
if (def = this.redefined()) { if (this.defun && (def = this.defun.variables.get(this.name))) {
this.mangled_name = def.mangled_name || def.name; this.mangled_name = def.mangled_name || def.name;
} else } else
this.mangled_name = s.next_mangled(options, this); this.mangled_name = s.next_mangled(options, this);
@@ -88,16 +87,13 @@ SymbolDef.prototype = {
cache.set(this.name, this.mangled_name); cache.set(this.name, this.mangled_name);
} }
} }
},
redefined: function() {
return this.defun && this.defun.variables.get(this.name);
} }
}; };
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
options = defaults(options, { options = defaults(options, {
cache: null, cache: null,
ie8: false, screw_ie8: true,
}); });
// pass 1: setup scope chaining and handle definitions // pass 1: setup scope chaining and handle definitions
@@ -160,7 +156,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// later. // later.
(node.scope = defun.parent_scope).def_function(node); (node.scope = defun.parent_scope).def_function(node);
} }
else if (node instanceof AST_SymbolVar) { else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolConst) {
defun.def_variable(node); defun.def_variable(node);
if (defun !== scope) { if (defun !== scope) {
node.mark_enclosed(options); node.mark_enclosed(options);
@@ -187,8 +184,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
self.walk(tw); self.walk(tw);
// pass 2: find back references and eval // pass 2: find back references and eval
self.globals = new Dictionary(); var func = null;
var globals = self.globals = new Dictionary();
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
if (node instanceof AST_Lambda) {
var prev_func = func;
func = node;
descend();
func = prev_func;
return true;
}
if (node instanceof AST_LoopControl && node.label) { if (node instanceof AST_LoopControl && node.label) {
node.label.thedef.references.push(node); node.label.thedef.references.push(node);
return true; return true;
@@ -201,30 +206,21 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
} }
} }
var sym = node.scope.find_variable(name); var sym = node.scope.find_variable(name);
if (node.scope instanceof AST_Lambda && name == "arguments") {
node.scope.uses_arguments = true;
}
if (!sym) { if (!sym) {
sym = self.def_global(node); sym = self.def_global(node);
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
sym.scope.uses_arguments = true;
} }
node.thedef = sym; node.thedef = sym;
node.reference(options); node.reference(options);
return true; return true;
} }
// ensure mangling works if catch reuses a scope variable
var def;
if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) {
var s = node.scope;
while (s) {
push_uniq(s.enclosed, def);
if (s === def.scope) break;
s = s.parent_scope;
}
}
}); });
self.walk(tw); self.walk(tw);
// pass 3: fix up any scoping issue with IE8 // pass 3: fix up any scoping issue with IE8
if (options.ie8) { if (!options.screw_ie8) {
self.walk(new TreeWalker(function(node, descend) { self.walk(new TreeWalker(function(node, descend) {
if (node instanceof AST_SymbolCatch) { if (node instanceof AST_SymbolCatch) {
var name = node.name; var name = node.name;
@@ -236,7 +232,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
ref.reference(options); ref.reference(options);
}); });
node.thedef = def; node.thedef = def;
node.reference(options);
return true; return true;
} }
})); }));
@@ -252,7 +247,7 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
if (globals.has(name)) { if (globals.has(name)) {
return globals.get(name); return globals.get(name);
} else { } else {
var g = new SymbolDef(this, node); var g = new SymbolDef(this, globals.size(), node);
g.undeclared = true; g.undeclared = true;
g.global = true; g.global = true;
globals.set(name, g); globals.set(name, g);
@@ -273,7 +268,7 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
AST_Lambda.DEFMETHOD("init_scope_vars", function(){ AST_Lambda.DEFMETHOD("init_scope_vars", function(){
AST_Scope.prototype.init_scope_vars.apply(this, arguments); AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false; this.uses_arguments = false;
this.def_variable(new AST_SymbolFunarg({ this.def_variable(new AST_SymbolVar({
name: "arguments", name: "arguments",
start: this.start, start: this.start,
end: this.end end: this.end
@@ -313,7 +308,7 @@ AST_Scope.DEFMETHOD("def_function", function(symbol){
AST_Scope.DEFMETHOD("def_variable", function(symbol){ AST_Scope.DEFMETHOD("def_variable", function(symbol){
var def; var def;
if (!this.variables.has(symbol.name)) { if (!this.variables.has(symbol.name)) {
def = new SymbolDef(this, symbol); def = new SymbolDef(this, this.variables.size(), symbol);
this.variables.set(symbol.name, def); this.variables.set(symbol.name, def);
def.global = !this.parent_scope; def.global = !this.parent_scope;
} else { } else {
@@ -330,8 +325,8 @@ AST_Scope.DEFMETHOD("next_mangled", function(options){
if (!is_identifier(m)) continue; // skip over "do" if (!is_identifier(m)) continue; // skip over "do"
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not // https://github.com/mishoo/UglifyJS2/issues/242 -- do not
// shadow a name reserved from mangling. // shadow a name excepted from mangling.
if (member(m, options.reserved)) continue; if (options.except.indexOf(m) >= 0) continue;
// we must ensure that the mangled name does not shadow a name // we must ensure that the mangled name does not shadow a name
// from some parent scope that is referenced in this or in // from some parent scope that is referenced in this or in
@@ -363,18 +358,36 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
}); });
AST_Symbol.DEFMETHOD("unmangleable", function(options){ AST_Symbol.DEFMETHOD("unmangleable", function(options){
var def = this.definition(); return this.definition().unmangleable(options);
return !def || def.unmangleable(options); });
// property accessors are not mangleable
AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){
return true;
}); });
// labels are always mangleable // labels are always mangleable
AST_Label.DEFMETHOD("unmangleable", return_false); AST_Label.DEFMETHOD("unmangleable", function(){
return false;
});
AST_Symbol.DEFMETHOD("unreferenced", function(){ AST_Symbol.DEFMETHOD("unreferenced", function(){
return this.definition().references.length == 0 return this.definition().references.length == 0
&& !(this.scope.uses_eval || this.scope.uses_with); && !(this.scope.uses_eval || this.scope.uses_with);
}); });
AST_Symbol.DEFMETHOD("undeclared", function(){
return this.definition().undeclared;
});
AST_LabelRef.DEFMETHOD("undeclared", function(){
return false;
});
AST_Label.DEFMETHOD("undeclared", function(){
return false;
});
AST_Symbol.DEFMETHOD("definition", function(){ AST_Symbol.DEFMETHOD("definition", function(){
return this.thedef; return this.thedef;
}); });
@@ -383,23 +396,23 @@ AST_Symbol.DEFMETHOD("global", function(){
return this.definition().global; return this.definition().global;
}); });
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) { AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
options = defaults(options, { return defaults(options, {
eval : false, eval : false,
ie8 : false, except : [],
keep_fnames : false, keep_fnames : false,
reserved : [], screw_ie8 : true,
sort : false, // Ignored. Flag retained for backwards compatibility.
toplevel : false, toplevel : false,
}); });
if (!Array.isArray(options.reserved)) options.reserved = [];
// Never mangle arguments
push_uniq(options.reserved, "arguments");
return options;
}); });
AST_Toplevel.DEFMETHOD("mangle_names", function(options){ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
options = this._default_mangler_options(options); options = this._default_mangler_options(options);
// Never mangle arguments
options.except.push('arguments');
// We only need to mangle declaration nodes. Special logic wired // We only need to mangle declaration nodes. Special logic wired
// into the code generator will display the mangled name if it's // into the code generator will display the mangled name if it's
// present (and for AST_SymbolRef-s it'll use the mangled name of // present (and for AST_SymbolRef-s it'll use the mangled name of
@@ -408,7 +421,11 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
var to_mangle = []; var to_mangle = [];
if (options.cache) { if (options.cache) {
this.globals.each(collect); this.globals.each(function(symbol){
if (options.except.indexOf(symbol.name) < 0) {
to_mangle.push(symbol);
}
});
} }
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
@@ -420,7 +437,13 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
return true; // don't descend again in TreeWalker return true; // don't descend again in TreeWalker
} }
if (node instanceof AST_Scope) { if (node instanceof AST_Scope) {
node.variables.each(collect); var p = tw.parent(), a = [];
node.variables.each(function(symbol){
if (options.except.indexOf(symbol.name) < 0) {
a.push(symbol);
}
});
to_mangle.push.apply(to_mangle, a);
return; return;
} }
if (node instanceof AST_Label) { if (node instanceof AST_Label) {
@@ -429,7 +452,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
node.mangled_name = name; node.mangled_name = name;
return true; return true;
} }
if (!options.ie8 && node instanceof AST_SymbolCatch) { if (options.screw_ie8 && node instanceof AST_SymbolCatch) {
to_mangle.push(node.definition()); to_mangle.push(node.definition());
return; return;
} }
@@ -440,146 +463,109 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
if (options.cache) { if (options.cache) {
options.cache.cname = this.cname; options.cache.cname = this.cname;
} }
function collect(symbol) {
if (!member(symbol.name, options.reserved)) {
to_mangle.push(symbol);
}
}
});
AST_Toplevel.DEFMETHOD("find_unique_prefix", function(options) {
var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_";
var cache = options.cache && options.cache.props;
var prefixes = Object.create(null);
options.reserved.forEach(add_prefix);
this.globals.each(add_def);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(add_def);
if (node instanceof AST_SymbolCatch) add_def(node.definition());
}));
var prefix, i = 0;
do {
prefix = create_name(i++);
} while (prefixes[prefix]);
return prefix;
function add_prefix(name) {
if (/[0-9]$/.test(name)) {
prefixes[name.replace(/[0-9]+$/, "")] = true;
}
}
function add_def(def) {
var name = def.name;
if (def.global && cache && cache.has(name)) name = cache.get(name);
else if (!def.unmangleable(options)) return;
add_prefix(name);
}
function create_name(num) {
var name = "";
do {
name += letters[num % letters.length];
num = Math.floor(num / letters.length);
} while (num);
return name;
}
});
AST_Toplevel.DEFMETHOD("expand_names", function(options) {
options = this._default_mangler_options(options);
var prefix = this.find_unique_prefix(options);
this.globals.each(rename);
this.walk(new TreeWalker(function(node) {
if (node instanceof AST_Scope) node.variables.each(rename);
if (node instanceof AST_SymbolCatch) rename(node.definition());
}));
function rename(def) {
if (def.global || def.unmangleable(options)) return;
if (member(def.name, options.reserved)) return;
var d = def.redefined();
def.name = d ? d.name : prefix + def.id;
def.orig.forEach(function(sym) {
sym.name = def.name;
});
def.references.forEach(function(sym) {
sym.name = def.name;
});
}
});
AST_Node.DEFMETHOD("tail_node", return_this);
AST_Sequence.DEFMETHOD("tail_node", function() {
return this.expressions[this.expressions.length - 1];
}); });
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
options = this._default_mangler_options(options); options = this._default_mangler_options(options);
try { var tw = new TreeWalker(function(node){
AST_Node.prototype.print = function(stream, force_parens) { if (node instanceof AST_Constant)
this._print(stream, force_parens); base54.consider(node.print_to_string());
if (this instanceof AST_Symbol && !this.unmangleable(options)) { else if (node instanceof AST_Return)
base54.consider(this.name, -1); base54.consider("return");
} else if (options.properties) { else if (node instanceof AST_Throw)
if (this instanceof AST_Dot) { base54.consider("throw");
base54.consider(this.property, -1); else if (node instanceof AST_Continue)
} else if (this instanceof AST_Sub) { base54.consider("continue");
skip_string(this.property); else if (node instanceof AST_Break)
} base54.consider("break");
} else if (node instanceof AST_Debugger)
}; base54.consider("debugger");
base54.consider(this.print_to_string(), 1); else if (node instanceof AST_Directive)
} finally { base54.consider(node.value);
AST_Node.prototype.print = AST_Node.prototype._print; else if (node instanceof AST_While)
base54.consider("while");
else if (node instanceof AST_Do)
base54.consider("do while");
else if (node instanceof AST_If) {
base54.consider("if");
if (node.alternative) base54.consider("else");
} }
else if (node instanceof AST_Var)
base54.consider("var");
else if (node instanceof AST_Const)
base54.consider("const");
else if (node instanceof AST_Lambda)
base54.consider("function");
else if (node instanceof AST_For)
base54.consider("for");
else if (node instanceof AST_ForIn)
base54.consider("for in");
else if (node instanceof AST_Switch)
base54.consider("switch");
else if (node instanceof AST_Case)
base54.consider("case");
else if (node instanceof AST_Default)
base54.consider("default");
else if (node instanceof AST_With)
base54.consider("with");
else if (node instanceof AST_ObjectSetter)
base54.consider("set" + node.key);
else if (node instanceof AST_ObjectGetter)
base54.consider("get" + node.key);
else if (node instanceof AST_ObjectKeyVal)
base54.consider(node.key);
else if (node instanceof AST_New)
base54.consider("new");
else if (node instanceof AST_This)
base54.consider("this");
else if (node instanceof AST_Try)
base54.consider("try");
else if (node instanceof AST_Catch)
base54.consider("catch");
else if (node instanceof AST_Finally)
base54.consider("finally");
else if (node instanceof AST_Symbol && node.unmangleable(options))
base54.consider(node.name);
else if (node instanceof AST_Unary || node instanceof AST_Binary)
base54.consider(node.operator);
else if (node instanceof AST_Dot)
base54.consider(node.property);
});
this.walk(tw);
base54.sort(); base54.sort();
function skip_string(node) {
if (node instanceof AST_String) {
base54.consider(node.value, -1);
} else if (node instanceof AST_Conditional) {
skip_string(node.consequent);
skip_string(node.alternative);
} else if (node instanceof AST_Sequence) {
skip_string(node.tail_node());
}
}
}); });
var base54 = (function() { var base54 = (function() {
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split(""); var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
var digits = "0123456789".split("");
var chars, frequency; var chars, frequency;
function reset() { function reset() {
frequency = Object.create(null); frequency = Object.create(null);
leading.forEach(function(ch) { chars = string.split("").map(function(ch){ return ch.charCodeAt(0) });
frequency[ch] = 0; chars.forEach(function(ch){ frequency[ch] = 0 });
});
digits.forEach(function(ch) {
frequency[ch] = 0;
});
} }
base54.consider = function(str, delta) { base54.consider = function(str){
for (var i = str.length; --i >= 0;) { for (var i = str.length; --i >= 0;) {
frequency[str[i]] += delta; var code = str.charCodeAt(i);
if (code in frequency) ++frequency[code];
} }
}; };
function compare(a, b) {
return frequency[b] - frequency[a];
}
base54.sort = function() { base54.sort = function() {
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare)); chars = mergeSort(chars, function(a, b){
if (is_digit(a) && !is_digit(b)) return 1;
if (is_digit(b) && !is_digit(a)) return -1;
return frequency[b] - frequency[a];
});
}; };
base54.reset = reset; base54.reset = reset;
reset(); reset();
base54.get = function(){ return chars };
base54.freq = function(){ return frequency };
function base54(num) { function base54(num) {
var ret = "", base = 54; var ret = "", base = 54;
num++; num++;
do { do {
num--; num--;
ret += chars[num % base]; ret += String.fromCharCode(chars[num % base]);
num = Math.floor(num / base); num = Math.floor(num / base);
base = 64; base = 64;
} while (num > 0); } while (num > 0);
@@ -587,3 +573,89 @@ var base54 = (function() {
}; };
return base54; return base54;
})(); })();
AST_Toplevel.DEFMETHOD("scope_warnings", function(options){
options = defaults(options, {
assign_to_global : true,
eval : true,
func_arguments : true,
nested_defuns : true,
undeclared : false, // this makes a lot of noise
unreferenced : true,
});
var tw = new TreeWalker(function(node){
if (options.undeclared
&& node instanceof AST_SymbolRef
&& node.undeclared())
{
// XXX: this also warns about JS standard names,
// i.e. Object, Array, parseInt etc. Should add a list of
// exceptions.
AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", {
name: node.name,
file: node.start.file,
line: node.start.line,
col: node.start.col
});
}
if (options.assign_to_global)
{
var sym = null;
if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef)
sym = node.left;
else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef)
sym = node.init;
if (sym
&& (sym.undeclared()
|| (sym.global() && sym.scope !== sym.definition().scope))) {
AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", {
msg: sym.undeclared() ? "Accidental global?" : "Assignment to global",
name: sym.name,
file: sym.start.file,
line: sym.start.line,
col: sym.start.col
});
}
}
if (options.eval
&& node instanceof AST_SymbolRef
&& node.undeclared()
&& node.name == "eval") {
AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start);
}
if (options.unreferenced
&& (node instanceof AST_SymbolDeclaration || node instanceof AST_Label)
&& !(node instanceof AST_SymbolCatch)
&& node.unreferenced()) {
AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", {
type: node instanceof AST_Label ? "Label" : "Symbol",
name: node.name,
file: node.start.file,
line: node.start.line,
col: node.start.col
});
}
if (options.func_arguments
&& node instanceof AST_Lambda
&& node.uses_arguments) {
AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", {
name: node.name ? node.name.name : "anonymous",
file: node.start.file,
line: node.start.line,
col: node.start.col
});
}
if (options.nested_defuns
&& node instanceof AST_Defun
&& !(tw.parent() instanceof AST_Scope)) {
AST_Node.warn("Function {name} declared in nested statement \"{type}\" [{file}:{line},{col}]", {
name: node.name.name,
type: tw.parent().TYPE,
file: node.start.file,
line: node.start.line,
col: node.start.col
});
}
});
this.walk(tw);
});

View File

@@ -60,14 +60,17 @@ TreeTransformer.prototype = new TreeWalker;
tw.push(this); tw.push(this);
if (tw.before) x = tw.before(this, descend, in_list); if (tw.before) x = tw.before(this, descend, in_list);
if (x === undefined) { if (x === undefined) {
if (!tw.after) {
x = this; x = this;
descend(x, tw); descend(x, tw);
if (tw.after) { } else {
tw.stack[tw.stack.length - 1] = x = this;
descend(x, tw);
y = tw.after(x, in_list); y = tw.after(x, in_list);
if (y !== undefined) x = y; if (y !== undefined) x = y;
} }
} }
tw.pop(); tw.pop(this);
return x; return x;
}); });
}; };
@@ -171,8 +174,9 @@ TreeTransformer.prototype = new TreeWalker;
self.args = do_list(self.args, tw); self.args = do_list(self.args, tw);
}); });
_(AST_Sequence, function(self, tw){ _(AST_Seq, function(self, tw){
self.expressions = do_list(self.expressions, tw); self.car = self.car.transform(tw);
self.cdr = self.cdr.transform(tw);
}); });
_(AST_Dot, function(self, tw){ _(AST_Dot, function(self, tw){

View File

@@ -43,6 +43,17 @@
"use strict"; "use strict";
function array_to_hash(a) {
var ret = Object.create(null);
for (var i = 0; i < a.length; ++i)
ret[a[i]] = true;
return ret;
};
function slice(a, start) {
return Array.prototype.slice.call(a, start || 0);
};
function characters(str) { function characters(str) {
return str.split(""); return str.split("");
}; };
@@ -210,6 +221,18 @@ function mergeSort(array, cmp) {
return _ms(array); return _ms(array);
}; };
function set_difference(a, b) {
return a.filter(function(el){
return b.indexOf(el) < 0;
});
};
function set_intersection(a, b) {
return a.filter(function(el){
return b.indexOf(el) >= 0;
});
};
// this function is taken from Acorn [1], written by Marijn Haverbeke // this function is taken from Acorn [1], written by Marijn Haverbeke
// [1] https://github.com/marijnh/acorn // [1] https://github.com/marijnh/acorn
function makePredicate(words) { function makePredicate(words) {
@@ -323,8 +346,8 @@ function first_in_statement(stack) {
for (var i = 0, p; p = stack.parent(i); i++) { for (var i = 0, p; p = stack.parent(i); i++) {
if (p instanceof AST_Statement && p.body === node) if (p instanceof AST_Statement && p.body === node)
return true; return true;
if ((p instanceof AST_Sequence && p.expressions[0] === node) || if ((p instanceof AST_Seq && p.car === node ) ||
(p.TYPE == "Call" && p.expression === node ) || (p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) ||
(p instanceof AST_Dot && p.expression === node ) || (p instanceof AST_Dot && p.expression === node ) ||
(p instanceof AST_Sub && p.expression === node ) || (p instanceof AST_Sub && p.expression === node ) ||
(p instanceof AST_Conditional && p.condition === node ) || (p instanceof AST_Conditional && p.condition === node ) ||

View File

@@ -4,7 +4,7 @@
"homepage": "http://lisperator.net/uglifyjs", "homepage": "http://lisperator.net/uglifyjs",
"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.3.1", "version": "2.8.24",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
@@ -29,16 +29,26 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"commander": "~2.12.1", "source-map": "~0.5.1",
"source-map": "~0.6.1" "yargs": "~3.10.0"
}, },
"devDependencies": { "devDependencies": {
"acorn": "~5.2.1", "acorn": "~0.6.0",
"mocha": "~3.5.1", "escodegen": "~1.3.3",
"semver": "~5.4.1" "esfuzz": "~0.3.1",
"estraverse": "~1.5.1",
"mocha": "~2.3.4"
},
"optionalDependencies": {
"uglify-to-browserify": "~1.0.0"
},
"browserify": {
"transform": [
"uglify-to-browserify"
]
}, },
"scripts": { "scripts": {
"test": "node test/run-tests.js" "test": "node test/run-tests.js"
}, },
"keywords": ["uglify", "uglify-js", "minify", "minifier", "es5"] "keywords": ["uglify", "uglify-js", "minify", "minifier"]
} }

View File

@@ -4,14 +4,12 @@
"use strict"; "use strict";
var createHash = require("crypto").createHash; var createHash = require("crypto").createHash;
var fetch = require("./fetch");
var fork = require("child_process").fork; var fork = require("child_process").fork;
var zlib = require("zlib");
var args = process.argv.slice(2); var args = process.argv.slice(2);
if (!args.length) { if (!args.length) {
args.push("-mc"); args.push("-mc", "warnings=false");
} }
args.push("--timings"); args.push("--stats");
var urls = [ var urls = [
"https://code.jquery.com/jquery-3.2.1.js", "https://code.jquery.com/jquery-3.2.1.js",
"https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js", "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js",
@@ -21,7 +19,6 @@ var urls = [
"http://builds.emberjs.com/tags/v2.11.0/ember.prod.js", "http://builds.emberjs.com/tags/v2.11.0/ember.prod.js",
"https://cdn.jsdelivr.net/lodash/4.17.4/lodash.js", "https://cdn.jsdelivr.net/lodash/4.17.4/lodash.js",
"https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.js", "https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.js",
"https://raw.githubusercontent.com/kangax/html-minifier/v3.5.7/dist/htmlminifier.js",
]; ];
var results = {}; var results = {};
var remaining = 2 * urls.length; var remaining = 2 * urls.length;
@@ -33,9 +30,13 @@ function done() {
console.log(); console.log();
console.log(url); console.log(url);
console.log(info.log); console.log(info.log);
var elapsed = 0;
info.log.replace(/: ([0-9]+\.[0-9]{3})s/g, function(match, time) {
elapsed += parseFloat(time);
});
console.log("Run-time:", elapsed.toFixed(3), "s");
console.log("Original:", info.input, "bytes"); console.log("Original:", info.input, "bytes");
console.log("Uglified:", info.output, "bytes"); console.log("Uglified:", info.output, "bytes");
console.log("GZipped: ", info.gzip, "bytes");
console.log("SHA1 sum:", info.sha1); console.log("SHA1 sum:", info.sha1);
if (info.code) { if (info.code) {
failures.push(url); failures.push(url);
@@ -54,21 +55,15 @@ urls.forEach(function(url) {
results[url] = { results[url] = {
input: 0, input: 0,
output: 0, output: 0,
gzip: 0,
log: "" log: ""
}; };
fetch(url, function(err, res) { require(url.slice(0, url.indexOf(":"))).get(url, function(res) {
if (err) throw err;
var uglifyjs = fork("bin/uglifyjs", args, { silent: true }); var uglifyjs = fork("bin/uglifyjs", args, { silent: true });
res.on("data", function(data) { res.on("data", function(data) {
results[url].input += data.length; results[url].input += data.length;
}).pipe(uglifyjs.stdin); }).pipe(uglifyjs.stdin);
uglifyjs.stdout.on("data", function(data) { uglifyjs.stdout.on("data", function(data) {
results[url].output += data.length; results[url].output += data.length;
}).pipe(zlib.createGzip({
level: zlib.Z_BEST_COMPRESSION
})).on("data", function(data) {
results[url].gzip += data.length;
}).pipe(createHash("sha1")).on("data", function(data) { }).pipe(createHash("sha1")).on("data", function(data) {
results[url].sha1 = data.toString("hex"); results[url].sha1 = data.toString("hex");
done(); done();

67
test/compress/angular-inject.js vendored Normal file
View File

@@ -0,0 +1,67 @@
ng_inject_defun: {
options = {
angular: true
};
input: {
/*@ngInject*/
function Controller(dependency) {
return dependency;
}
}
expect: {
function Controller(dependency) {
return dependency;
}
Controller.$inject=['dependency']
}
}
ng_inject_assignment: {
options = {
angular: true
};
input: {
/*@ngInject*/
var Controller = function(dependency) {
return dependency;
}
}
expect: {
var Controller = function(dependency) {
return dependency;
}
Controller.$inject=['dependency']
}
}
ng_inject_inline: {
options = {
angular: true
};
input: {
angular.module('a').
factory('b',
/*@ngInject*/
function(dependency) {
return dependency;
}).
directive('c',
/*@ngInject*/
function(anotherDependency) {
return anotherDependency;
})
}
expect: {
angular.module('a').
factory('b',[
'dependency',
function(dependency) {
return dependency;
}]).
directive('c',[
'anotherDependency',
function(anotherDependency) {
return anotherDependency;
}])
}
}

View File

@@ -128,114 +128,50 @@ constant_join_3: {
for_loop: { for_loop: {
options = { options = {
evaluate: true, unsafe : true,
reduce_funcs: true, unused : true,
reduce_vars: true, evaluate : true,
unsafe: true, reduce_vars : true
unused: true,
}; };
input: { input: {
function f0() { function f0() {
var a = [1, 2, 3]; var a = [1, 2, 3];
var b = 0; for (var i = 0; i < a.length; i++) {
for (var i = 0; i < a.length; i++) console.log(a[i]);
b += a[i];
return b;
} }
}
function f1() { function f1() {
var a = [1, 2, 3]; var a = [1, 2, 3];
var b = 0; for (var i = 0, len = a.length; i < len; i++) {
for (var i = 0, len = a.length; i < len; i++) console.log(a[i]);
b += a[i];
return b;
} }
}
function f2() { function f2() {
var a = [1, 2, 3]; var a = [1, 2, 3];
for (var i = 0; i < a.length; i++) for (var i = 0; i < a.length; i++) {
a[i]++; a[i]++;
return a[2];
} }
console.log(f0(), f1(), f2()); }
} }
expect: { expect: {
function f0() { function f0() {
var a = [1, 2, 3]; var a = [1, 2, 3];
var b = 0;
for (var i = 0; i < 3; i++) for (var i = 0; i < 3; i++)
b += a[i]; console.log(a[i]);
return b;
} }
function f1() { function f1() {
var a = [1, 2, 3]; var a = [1, 2, 3];
var b = 0;
for (var i = 0; i < 3; i++) for (var i = 0; i < 3; i++)
b += a[i]; console.log(a[i]);
return b;
} }
function f2() { function f2() {
var a = [1, 2, 3]; var a = [1, 2, 3];
for (var i = 0; i < a.length; i++) for (var i = 0; i < a.length; i++)
a[i]++; a[i]++;
return a[2];
} }
console.log(f0(), f1(), f2());
} }
expect_stdout: "6 6 4"
}
index: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var a = [ 1, 2 ];
console.log(a[0], a[1]);
}
expect: {
console.log(1, 2);
}
expect_stdout: "1 2"
}
length: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var a = [ 1, 2 ];
console.log(a.length);
}
expect: {
console.log(2);
}
expect_stdout: "2"
}
index_length: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var a = [ 1, 2 ];
console.log(a[0], a.length);
}
expect: {
console.log(1, 2);
}
expect_stdout: "1 2"
} }

View File

@@ -2,7 +2,7 @@ ascii_only_true: {
options = {} options = {}
beautify = { beautify = {
ascii_only : true, ascii_only : true,
ie8 : false, screw_ie8 : true,
beautify : false, beautify : false,
} }
input: { input: {
@@ -13,14 +13,14 @@ ascii_only_true: {
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"; "\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
} }
} }
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}' expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
} }
ascii_only_false: { ascii_only_false: {
options = {} options = {}
beautify = { beautify = {
ascii_only : false, ascii_only : false,
ie8 : false, screw_ie8 : true,
beautify : false, beautify : false,
} }
input: { input: {
@@ -31,5 +31,6 @@ ascii_only_false: {
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff"; "\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
} }
} }
expect_exact: 'function f(){return"\\x000\\x001\\x007\\x008\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}' expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
} }

View File

@@ -16,6 +16,7 @@ asm_mixed: {
hoist_vars : true, hoist_vars : true,
if_return : true, if_return : true,
join_vars : true, join_vars : true,
cascade : true,
side_effects : true, side_effects : true,
negate_iife : true negate_iife : true
}; };
@@ -103,65 +104,3 @@ asm_mixed: {
} }
} }
asm_toplevel: {
options = {}
input: {
"use asm";
0.0;
function f() {
0.0;
(function(){
0.0;
});
}
0.0;
}
expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;'
}
asm_function_expression: {
options = {}
input: {
0.0;
var a = function() {
"use asm";
0.0;
}
function f() {
0.0;
return function(){
"use asm";
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;'
}
asm_nested_functions: {
options = {}
input: {
0.0;
function a() {
"use asm";
0.0;
}
0.0;
function b() {
0.0;
function c(){
"use asm";
0.0;
}
0.0;
function d(){
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
}

File diff suppressed because it is too large Load Diff

View File

@@ -74,41 +74,3 @@ dont_change_in_or_instanceof_expressions: {
null instanceof null; null instanceof null;
} }
} }
self_comparison_1: {
options = {
comparisons: true,
}
input: {
a === a;
a !== b;
b.c === a.c;
b.c !== b.c;
}
expect: {
a == a;
a !== b;
b.c === a.c;
b.c != b.c;
}
}
self_comparison_2: {
options = {
comparisons: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
function f() {}
var o = {};
console.log(f != f, o === o);
}
expect: {
function f() {}
var o = {};
console.log(false, true);
}
expect_stdout: "false true"
}

View File

@@ -21,7 +21,7 @@ concat_1: {
var c = 1 + x() + 2 + "boo"; var c = 1 + x() + 2 + "boo";
var d = 1 + x() + 2 + 3 + "boo"; var d = 1 + x() + 2 + 3 + "boo";
var e = 1 + x() + 2 + "X3boo"; var e = 1 + x() + 2 + "X3boo";
var f = "\x00360\x008\0"; var f = "\x00360\08\0";
} }
} }

View File

@@ -166,24 +166,22 @@ cond_1: {
conditionals: true conditionals: true
}; };
input: { input: {
function foo(do_something, some_condition) { var do_something; // if undeclared it's assumed to have side-effects
if (some_condition) { if (some_condition()) {
do_something(x); do_something(x);
} else { } else {
do_something(y); do_something(y);
} }
if (some_condition) { if (some_condition()) {
side_effects(x); side_effects(x);
} else { } else {
side_effects(y); side_effects(y);
} }
} }
}
expect: { expect: {
function foo(do_something, some_condition) { var do_something;
do_something(some_condition ? x : y); do_something(some_condition() ? x : y);
some_condition ? side_effects(x) : side_effects(y); some_condition() ? side_effects(x) : side_effects(y);
}
} }
} }
@@ -192,18 +190,16 @@ cond_2: {
conditionals: true conditionals: true
}; };
input: { input: {
function foo(x, FooBar, some_condition) { var x, FooBar;
if (some_condition) { if (some_condition()) {
x = new FooBar(1); x = new FooBar(1);
} else { } else {
x = new FooBar(2); x = new FooBar(2);
} }
} }
}
expect: { expect: {
function foo(x, FooBar, some_condition) { var x, FooBar;
x = new FooBar(some_condition ? 1 : 2); x = new FooBar(some_condition() ? 1 : 2);
}
} }
} }
@@ -609,47 +605,11 @@ cond_8c: {
} }
} }
cond_9: {
options = {
conditionals: true,
}
input: {
function f(x, y) {
g() ? x(1) : x(2);
x ? (y || x)() : (y || x)();
x ? y(a, b) : y(d, b, c);
x ? y(a, b, c) : y(a, b, c);
x ? y(a, b, c) : y(a, b, f);
x ? y(a, b, c) : y(a, e, c);
x ? y(a, b, c) : y(a, e, f);
x ? y(a, b, c) : y(d, b, c);
x ? y(a, b, c) : y(d, b, f);
x ? y(a, b, c) : y(d, e, c);
x ? y(a, b, c) : y(d, e, f);
}
}
expect: {
function f(x, y) {
g() ? x(1) : x(2);
x, (y || x)();
x ? y(a, b) : y(d, b, c);
x, y(a, b, c);
y(a, b, x ? c : f);
y(a, x ? b : e, c);
x ? y(a, b, c) : y(a, e, f);
y(x ? a : d, b, c);
x ? y(a, b, c) : y(d, b, f);
x ? y(a, b, c) : y(d, e, c);
x ? y(a, b, c) : y(d, e, f);
}
}
}
ternary_boolean_consequent: { ternary_boolean_consequent: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, side_effects:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
} }
input: { input: {
function f1() { return a == b ? true : x; } function f1() { return a == b ? true : x; }
@@ -677,7 +637,7 @@ ternary_boolean_alternative: {
options = { options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, side_effects:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
} }
input: { input: {
function f1() { return a == b ? x : true; } function f1() { return a == b ? x : true; }
@@ -1019,12 +979,12 @@ delete_conditional_1: {
console.log(delete (1 ? 0 / 0 : x)); console.log(delete (1 ? 0 / 0 : x));
} }
expect: { expect: {
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((NaN, !0));
console.log(!0); console.log((NaN, !0));
} }
expect_stdout: true expect_stdout: true
} }
@@ -1046,160 +1006,12 @@ delete_conditional_2: {
console.log(delete (0 ? x : 0 / 0)); console.log(delete (0 ? x : 0 / 0));
} }
expect: { expect: {
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((Infinity, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((NaN, !0));
console.log(!0); console.log((NaN, !0));
} }
expect_stdout: true expect_stdout: true
} }
issue_2535_1: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
passes: 2,
side_effects: true,
}
input: {
if (true || x()) y();
if (true && x()) y();
if (x() || true) y();
if (x() && true) y();
if (false || x()) y();
if (false && x()) y();
if (x() || false) y();
if (x() && false) y();
}
expect: {
y();
x() && y();
(x(), 1) && y();
x() && y();
x() && y();
x() && y();
(x(), 0) && y();
}
}
issue_2535_2: {
options = {
booleans: true,
conditionals: true,
evaluate: true,
side_effects: true,
}
input: {
function x() {}
function y() {
return "foo";
}
console.log((x() || true) || y());
console.log((y() || true) || x());
console.log((x() || true) && y());
console.log((y() || true) && x());
console.log((x() && true) || y());
console.log((y() && true) || x());
console.log((x() && true) && y());
console.log((y() && true) && x());
console.log((x() || false) || y());
console.log((y() || false) || x());
console.log((x() || false) && y());
console.log((y() || false) && x());
console.log((x() && false) || y());
console.log((y() && false) || x());
console.log((x() && false) && y());
console.log((y() && false) && x());
}
expect: {
function x() {}
function y() {
return "foo";
}
console.log(x() || !0);
console.log(y() || !0);
console.log((x(), y()));
console.log((y(), x()));
console.log(!!x() || y());
console.log(!!y() || x());
console.log(x() && y());
console.log(y() && x());
console.log(x() || y());
console.log(y() || x());
console.log(!!x() && y());
console.log(!!y() && x());
console.log((x(), y()));
console.log((y(), x()));
console.log(x() && !1);
console.log(y() && !1);
}
expect_stdout: [
"true",
"foo",
"foo",
"undefined",
"foo",
"true",
"undefined",
"undefined",
"foo",
"foo",
"false",
"undefined",
"foo",
"undefined",
"undefined",
"false",
]
}
issue_2560: {
options = {
conditionals: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function log(x) {
console.log(x);
}
function foo() {
return log;
}
function bar() {
if (x !== (x = foo())) {
x(1);
} else {
x(2);
}
}
var x = function() {
console.log("init");
};
bar();
bar();
}
expect: {
function log(x) {
console.log(x);
}
function bar() {
x !== (x = log) ? x(1) : x(2);
}
var x = function() {
console.log("init");
};
bar();
bar();
}
expect_stdout: [
"1",
"2",
]
}

166
test/compress/const.js Normal file
View File

@@ -0,0 +1,166 @@
issue_1191: {
options = {
evaluate : true,
booleans : true,
comparisons : true,
dead_code : true,
conditionals : true,
side_effects : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
function foo(rot) {
const rotTol = 5;
if (rot < -rotTol || rot > rotTol)
bar();
baz();
}
}
expect: {
function foo(rot) {
(rot < -5 || rot > 5) && bar();
baz();
}
}
}
issue_1194: {
options = {
evaluate : true,
booleans : true,
comparisons : true,
dead_code : true,
conditionals : true,
side_effects : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
function f1() {const a = "X"; return a + a;}
function f2() {const aa = "X"; return aa + aa;}
function f3() {const aaa = "X"; return aaa + aaa;}
}
expect: {
function f1(){return"XX"}
function f2(){return"XX"}
function f3(){return"XX"}
}
}
issue_1396: {
options = {
evaluate : true,
booleans : true,
comparisons : true,
dead_code : true,
conditionals : true,
side_effects : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
function foo(a) {
const VALUE = 1;
console.log(2 | VALUE);
console.log(VALUE + 1);
console.log(VALUE);
console.log(a & VALUE);
}
function bar() {
const s = "01234567890123456789";
console.log(s + s + s + s + s);
const CONSTANT = "abc";
console.log(CONSTANT + CONSTANT + CONSTANT + CONSTANT + CONSTANT);
}
}
expect: {
function foo(a) {
console.log(3);
console.log(2);
console.log(1);
console.log(1 & a);
}
function bar() {
const s = "01234567890123456789";
console.log(s + s + s + s + s);
console.log("abcabcabcabcabc");
}
}
}
unused_regexp_literal: {
options = {
evaluate : true,
booleans : true,
comparisons : true,
dead_code : true,
conditionals : true,
side_effects : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
sequences : false,
collapse_vars : false,
}
input: {
function f(){ var a = /b/; }
}
expect: {
function f(){}
}
}
regexp_literal_not_const: {
options = {
evaluate : true,
booleans : true,
comparisons : true,
dead_code : true,
conditionals : true,
side_effects : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
sequences : false,
collapse_vars : false,
reduce_vars : true,
}
input: {
(function(){
var result;
const s = 'acdabcdeabbb';
const REGEXP_LITERAL = /ab*/g;
while (result = REGEXP_LITERAL.exec(s)) {
console.log(result[0]);
}
})();
}
expect: {
(function() {
var result;
const REGEXP_LITERAL = /ab*/g;
while (result = REGEXP_LITERAL.exec("acdabcdeabbb")) console.log(result[0]);
})();
}
expect_stdout: true
}

View File

@@ -31,7 +31,7 @@ dead_code_2_should_warn: {
function f() { function f() {
g(); g();
x = 10; x = 10;
throw new Error("foo"); throw "foo";
// completely discarding the `if` would introduce some // completely discarding the `if` would introduce some
// bugs. UglifyJS v1 doesn't deal with this issue; in v2 // bugs. UglifyJS v1 doesn't deal with this issue; in v2
// we copy any declarations to the upper scope. // we copy any declarations to the upper scope.
@@ -46,60 +46,16 @@ dead_code_2_should_warn: {
})(); })();
} }
} }
f();
} }
expect: { expect: {
function f() { function f() {
g(); g();
x = 10; x = 10;
throw new Error("foo"); throw "foo";
var x; var x;
function g(){}; function g(){};
} }
f();
} }
expect_stdout: true
node_version: "<=4"
}
dead_code_2_should_warn_strict: {
options = {
dead_code: true
};
input: {
"use strict";
function f() {
g();
x = 10;
throw new Error("foo");
// completely discarding the `if` would introduce some
// bugs. UglifyJS v1 doesn't deal with this issue; in v2
// we copy any declarations to the upper scope.
if (x) {
y();
var x;
function g(){};
// but nested declarations should not be kept.
(function(){
var q;
function y(){};
})();
}
}
f();
}
expect: {
"use strict";
function f() {
g();
x = 10;
throw new Error("foo");
var x;
}
f();
}
expect_stdout: true
node_version: ">=4"
} }
dead_code_constant_boolean_should_warn_more: { dead_code_constant_boolean_should_warn_more: {
@@ -122,55 +78,141 @@ dead_code_constant_boolean_should_warn_more: {
foo(); foo();
var moo; var moo;
} }
bar();
} }
expect: { expect: {
var foo; var foo;
function bar() {} function bar() {}
// nothing for the while // nothing for the while
// as for the for, it should keep: // as for the for, it should keep:
var moo;
var x = 10, y; var x = 10, y;
bar(); var moo;
} }
expect_stdout: true expect_stdout: true
node_version: "<=4"
} }
dead_code_constant_boolean_should_warn_more_strict: { dead_code_const_declaration: {
options = { options = {
dead_code : true, dead_code : true,
loops : true, loops : true,
booleans : true, booleans : true,
conditionals : true, conditionals : true,
evaluate : true, evaluate : true,
side_effects : true, reduce_vars : true,
}; };
input: { input: {
"use strict"; var unused;
while (!((foo && bar) || (x + "0"))) { const CONST_FOO = false;
if (CONST_FOO) {
console.log("unreachable"); console.log("unreachable");
var foo; var moo;
function bar() {} function bar() {}
} }
for (var x = 10, y; x && (y || x) && (!typeof x); ++x) {
asdf();
foo();
var moo;
}
bar();
} }
expect: { expect: {
"use strict"; var unused;
var foo; const CONST_FOO = !1;
// nothing for the while
// as for the for, it should keep:
var moo; var moo;
var x = 10, y; function bar() {}
bar(); }
expect_stdout: true
}
dead_code_const_annotation: {
options = {
dead_code : true,
loops : true,
booleans : true,
conditionals : true,
evaluate : true,
reduce_vars : true,
toplevel : true,
};
input: {
var unused;
/** @const */ var CONST_FOO_ANN = false;
if (CONST_FOO_ANN) {
console.log("unreachable");
var moo;
function bar() {}
}
}
expect: {
var unused;
var CONST_FOO_ANN = !1;
var moo;
function bar() {}
}
expect_stdout: true
}
dead_code_const_annotation_regex: {
options = {
dead_code : true,
loops : true,
booleans : true,
conditionals : true,
evaluate : true
};
input: {
var unused;
// @constraint this shouldn't be a constant
var CONST_FOO_ANN = false;
if (CONST_FOO_ANN) {
console.log("reachable");
}
}
expect: {
var unused;
var CONST_FOO_ANN = !1;
CONST_FOO_ANN && console.log('reachable');
}
expect_stdout: true
}
dead_code_const_annotation_complex_scope: {
options = {
dead_code : true,
loops : true,
booleans : true,
conditionals : true,
evaluate : true,
reduce_vars : true,
toplevel : true,
};
input: {
var unused_var;
/** @const */ var test = 'test';
// @const
var CONST_FOO_ANN = false;
var unused_var_2;
if (CONST_FOO_ANN) {
console.log("unreachable");
var moo;
function bar() {}
}
if (test === 'test') {
var beef = 'good';
/** @const */ var meat = 'beef';
var pork = 'bad';
if (meat === 'pork') {
console.log('also unreachable');
} else if (pork === 'good') {
console.log('reached, not const');
}
}
}
expect: {
var unused_var;
var test = 'test';
var CONST_FOO_ANN = !1;
var unused_var_2;
var moo;
function bar() {}
var beef = 'good';
var meat = 'beef';
var pork = 'bad';
} }
expect_stdout: true expect_stdout: true
node_version: ">=4"
} }
try_catch_finally: { try_catch_finally: {
@@ -178,8 +220,6 @@ try_catch_finally: {
conditionals: true, conditionals: true,
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
passes: 2,
side_effects: true,
} }
input: { input: {
var a = 1; var a = 1;
@@ -216,615 +256,3 @@ try_catch_finally: {
"1", "1",
] ]
} }
accessor: {
options = {
side_effects: true,
}
input: {
({
get a() {},
set a(v){
this.b = 2;
},
b: 1
});
}
expect: {}
}
issue_2233_1: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
Array.isArray;
Boolean;
console.log;
Date;
decodeURI;
decodeURIComponent;
encodeURI;
encodeURIComponent;
Error.name;
escape;
eval;
EvalError;
Function.length;
isFinite;
isNaN;
JSON;
Math.random;
Number.isNaN;
parseFloat;
parseInt;
RegExp;
Object.defineProperty;
String.fromCharCode;
RangeError;
ReferenceError;
SyntaxError;
TypeError;
unescape;
URIError;
}
expect: {}
expect_stdout: true
}
global_timeout_and_interval_symbols: {
options = {
pure_getters: "strict",
side_effects: true,
unsafe: true,
}
input: {
// These global symbols do not exist in the test sandbox
// and must be tested separately.
clearInterval;
clearTimeout;
setInterval;
setTimeout;
}
expect: {}
}
issue_2233_2: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
var RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Number.isNaN;
}
}
}
issue_2233_3: {
options = {
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var RegExp;
Array.isArray;
RegExp;
UndeclaredGlobal;
function foo() {
var Number;
AnotherUndeclaredGlobal;
Math.sin;
Number.isNaN;
}
}
expect: {
UndeclaredGlobal;
}
}
global_fns: {
options = {
side_effects: true,
unsafe: true,
}
input: {
Boolean(1, 2);
decodeURI(1, 2);
decodeURIComponent(1, 2);
Date(1, 2);
encodeURI(1, 2);
encodeURIComponent(1, 2);
Error(1, 2);
escape(1, 2);
EvalError(1, 2);
isFinite(1, 2);
isNaN(1, 2);
Number(1, 2);
Object(1, 2);
parseFloat(1, 2);
parseInt(1, 2);
RangeError(1, 2);
ReferenceError(1, 2);
String(1, 2);
SyntaxError(1, 2);
TypeError(1, 2);
unescape(1, 2);
URIError(1, 2);
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect: {
try {
Function(1, 2);
} catch (e) {
console.log(e.name);
}
try {
RegExp(1, 2);
} catch (e) {
console.log(e.name);
}
try {
Array(NaN);
} catch (e) {
console.log(e.name);
}
}
expect_stdout: [
"SyntaxError",
"SyntaxError",
"RangeError",
]
}
collapse_vars_assignment: {
options = {
collapse_vars: true,
dead_code: true,
passes: 2,
unused: true,
}
input: {
function f0(c) {
var a = 3 / c;
return a = a;
}
}
expect: {
function f0(c) {
return 3 / c;
}
}
}
collapse_vars_lvalues_drop_assign: {
options = {
collapse_vars: true,
dead_code: true,
unused: true,
}
input: {
function f0(x) { var i = ++x; return x += i; }
function f1(x) { var a = (x -= 3); return x += a; }
function f2(x) { var z = x, a = ++z; return z += a; }
}
expect: {
function f0(x) { var i = ++x; return x + i; }
function f1(x) { var a = (x -= 3); return x + a; }
function f2(x) { var z = x, a = ++z; return z + a; }
}
}
collapse_vars_misc1: {
options = {
collapse_vars: true,
dead_code: true,
unused: true,
}
input: {
function f10(x) { var a = 5, b = 3; return a += b; }
function f11(x) { var a = 5, b = 3; return a += --b; }
}
expect: {
function f10(x) { return 5 + 3; }
function f11(x) { var b = 3; return 5 + --b; }
}
}
return_assignment: {
options = {
dead_code: true,
unused: true,
}
input: {
function f1(a, b, c) {
return a = x(), b = y(), b = a && (c >>= 5);
}
function f2() {
return e = x();
}
function f3(e) {
return e = x();
}
function f4() {
var e;
return e = x();
}
function f5(a) {
try {
return a = x();
} catch (b) {
console.log(a);
}
}
function f6(a) {
try {
return a = x();
} finally {
console.log(a);
}
}
function y() {
console.log("y");
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6 ].forEach(function(f, i) {
e = null;
try {
i += 1;
console.log("result " + f(10 * i, 100 * i, 1000 * i));
} catch (x) {
console.log("caught " + x);
}
if (null !== e) console.log("e: " + e);
});
}
var x, e;
test(1);
test(-1);
}
expect: {
function f1(a, b, c) {
return a = x(), y(), a && (c >> 5);
}
function f2() {
return e = x();
}
function f3(e) {
return x();
}
function f4() {
return x();
}
function f5(a) {
try {
return x();
} catch (b) {
console.log(a);
}
}
function f6(a) {
try {
return a = x();
} finally {
console.log(a);
}
}
function y() {
console.log("y");
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6 ].forEach(function(f, i) {
e = null;
try {
i += 1;
console.log("result " + f(10 * i, 100 * i, 1000 * i));
} catch (x) {
console.log("caught " + x);
}
if (null !== e) console.log("e: " + e);
});
}
var x, e;
test(1);
test(-1);
}
expect_stdout: [
"y",
"result 31",
"result 2",
"e: 2",
"result 3",
"result 4",
"result 5",
"6",
"result 6",
"caught -1",
"caught -2",
"caught -3",
"caught -4",
"50",
"result undefined",
"60",
"caught -6",
]
}
throw_assignment: {
options = {
dead_code: true,
unused: true,
}
input: {
function f1() {
throw a = x();
}
function f2(a) {
throw a = x();
}
function f3() {
var a;
throw a = x();
}
function f4() {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f5(a) {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f6() {
var a;
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f7() {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f8(a) {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f9() {
var a;
try {
throw a = x();
} finally {
console.log(a);
}
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6, f7, f8, f9 ].forEach(function(f, i) {
a = null;
try {
f(10 * (1 + i));
} catch (x) {
console.log("caught " + x);
}
if (null !== a) console.log("a: " + a);
});
}
var x, a;
test(1);
test(-1);
}
expect: {
function f1() {
throw a = x();
}
function f2(a) {
throw x();
}
function f3() {
throw x();
}
function f4() {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f5(a) {
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f6() {
var a;
try {
throw a = x();
} catch (b) {
console.log(a);
}
}
function f7() {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f8(a) {
try {
throw a = x();
} finally {
console.log(a);
}
}
function f9() {
var a;
try {
throw a = x();
} finally {
console.log(a);
}
}
function test(inc) {
var counter = 0;
x = function() {
counter += inc;
if (inc < 0) throw counter;
return counter;
};
[ f1, f2, f3, f4, f5, f6, f7, f8, f9 ].forEach(function(f, i) {
a = null;
try {
f(10 * (1 + i));
} catch (x) {
console.log("caught " + x);
}
if (null !== a) console.log("a: " + a);
});
}
var x, a;
test(1);
test(-1);
}
expect_stdout: [
"caught 1",
"a: 1",
"caught 2",
"caught 3",
"4",
"a: 4",
"5",
"6",
"7",
"caught 7",
"a: 7",
"8",
"caught 8",
"9",
"caught 9",
"caught -1",
"caught -2",
"caught -3",
"null",
"50",
"undefined",
"null",
"caught -7",
"80",
"caught -8",
"undefined",
"caught -9",
]
}
issue_2597: {
options = {
dead_code: true,
}
input: {
function f(b) {
try {
try {
throw "foo";
} catch (e) {
return b = true;
}
} finally {
b && (a = "PASS");
}
}
var a = "FAIL";
f();
console.log(a);
}
expect: {
function f(b) {
try {
try {
throw "foo";
} catch (e) {
return b = true;
}
} finally {
b && (a = "PASS");
}
}
var a = "FAIL";
f();
console.log(a);
}
expect_stdout: "PASS"
}

View File

@@ -179,9 +179,7 @@ keep_fnames: {
} }
drop_assign: { drop_assign: {
options = { options = { unused: true };
unused: true,
}
input: { input: {
function f1() { function f1() {
var a; var a;
@@ -202,7 +200,7 @@ drop_assign: {
var a; var a;
return function() { return function() {
a = 1; a = 1;
}; }
} }
} }
expect: { expect: {
@@ -219,17 +217,16 @@ drop_assign: {
return 1; return 1;
} }
function f5() { function f5() {
var a;
return function() { return function() {
1; a = 1;
}; }
} }
} }
} }
keep_assign: { keep_assign: {
options = { options = { unused: "keep_assign" };
unused: "keep_assign",
}
input: { input: {
function f1() { function f1() {
var a; var a;
@@ -250,7 +247,7 @@ keep_assign: {
var a; var a;
return function() { return function() {
a = 1; a = 1;
}; }
} }
} }
expect: { expect: {
@@ -273,22 +270,19 @@ keep_assign: {
var a; var a;
return function() { return function() {
a = 1; a = 1;
}; }
} }
} }
} }
drop_toplevel_funcs: { drop_toplevel_funcs: {
options = { options = { toplevel: "funcs", unused: true };
toplevel: "funcs",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -304,16 +298,13 @@ drop_toplevel_funcs: {
} }
drop_toplevel_vars: { drop_toplevel_vars: {
options = { options = { toplevel: "vars", unused: true };
toplevel: "vars",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -321,10 +312,11 @@ drop_toplevel_vars: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var c = g;
function f(d) { function f(d) {
return function() { return function() {
2; c = 2;
}; }
} }
2; 2;
function g() {} function g() {}
@@ -334,17 +326,13 @@ drop_toplevel_vars: {
} }
drop_toplevel_vars_fargs: { drop_toplevel_vars_fargs: {
options = { options = { keep_fargs: false, toplevel: "vars", unused: true };
keep_fargs: false,
toplevel: "vars",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -352,10 +340,11 @@ drop_toplevel_vars_fargs: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var c = g;
function f() { function f() {
return function() { return function() {
2; c = 2;
}; }
} }
2; 2;
function g() {} function g() {}
@@ -365,16 +354,13 @@ drop_toplevel_vars_fargs: {
} }
drop_toplevel_all: { drop_toplevel_all: {
options = { options = { toplevel: true, unused: true };
toplevel: true,
unused: true
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -388,16 +374,13 @@ drop_toplevel_all: {
} }
drop_toplevel_retain: { drop_toplevel_retain: {
options = { options = { top_retain: "f,a,o", unused: true };
top_retain: "f,a,o",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -405,28 +388,26 @@ drop_toplevel_retain: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var a; var a, c = g;
function f(d) { function f(d) {
return function() { return function() {
2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {}
console.log(3); console.log(3);
} }
} }
drop_toplevel_retain_array: { drop_toplevel_retain_array: {
options = { options = { top_retain: [ "f", "a", "o" ], unused: true };
top_retain: [ "f", "a", "o" ],
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -434,28 +415,26 @@ drop_toplevel_retain_array: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var a; var a, c = g;
function f(d) { function f(d) {
return function() { return function() {
2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {}
console.log(3); console.log(3);
} }
} }
drop_toplevel_retain_regex: { drop_toplevel_retain_regex: {
options = { options = { top_retain: /^[fao]$/, unused: true };
top_retain: /^[fao]$/,
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -463,29 +442,26 @@ drop_toplevel_retain_regex: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var a; var a, c = g;
function f(d) { function f(d) {
return function() { return function() {
2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {}
console.log(3); console.log(3);
} }
} }
drop_toplevel_all_retain: { drop_toplevel_all_retain: {
options = { options = { toplevel: true, top_retain: "f,a,o", unused: true };
toplevel: true,
top_retain: "f,a,o",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -493,29 +469,26 @@ drop_toplevel_all_retain: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var a; var a, c = g;
function f(d) { function f(d) {
return function() { return function() {
2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {}
console.log(3); console.log(3);
} }
} }
drop_toplevel_funcs_retain: { drop_toplevel_funcs_retain: {
options = { options = { toplevel: "funcs", top_retain: "f,a,o", unused: true };
toplevel: "funcs",
top_retain: "f,a,o",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -527,7 +500,7 @@ drop_toplevel_funcs_retain: {
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -536,17 +509,13 @@ drop_toplevel_funcs_retain: {
} }
drop_toplevel_vars_retain: { drop_toplevel_vars_retain: {
options = { options = { toplevel: "vars", top_retain: "f,a,o", unused: true };
toplevel: "vars",
top_retain: "f,a,o",
unused: true,
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -554,11 +523,11 @@ drop_toplevel_vars_retain: {
console.log(b = 3); console.log(b = 3);
} }
expect: { expect: {
var a; var a, c = g;
function f(d) { function f(d) {
return function() { return function() {
2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -568,16 +537,13 @@ drop_toplevel_vars_retain: {
} }
drop_toplevel_keep_assign: { drop_toplevel_keep_assign: {
options = { options = { toplevel: true, unused: "keep_assign" };
toplevel: true,
unused: "keep_assign",
}
input: { input: {
var a, b = 1, c = g; var a, b = 1, c = g;
function f(d) { function f(d) {
return function() { return function() {
c = 2; c = 2;
}; }
} }
a = 2; a = 2;
function g() {} function g() {}
@@ -683,9 +649,40 @@ drop_value: {
} }
} }
const_assign: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
const b = 2;
return 1 + b;
}
function g() {
const b = 2;
b = 3;
return 1 + b;
}
}
expect: {
function f() {
return 3;
}
function g() {
const b = 2;
b = 3;
return 1 + b;
}
}
}
issue_1539: { issue_1539: {
options = { options = {
collapse_vars: true, cascade: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -707,7 +704,6 @@ issue_1539: {
vardef_value: { vardef_value: {
options = { options = {
keep_fnames: false, keep_fnames: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -732,7 +728,7 @@ vardef_value: {
assign_binding: { assign_binding: {
options = { options = {
collapse_vars: true, cascade: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
} }
@@ -769,7 +765,6 @@ assign_chain: {
issue_1583: { issue_1583: {
options = { options = {
keep_fargs: true, keep_fargs: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -787,10 +782,10 @@ issue_1583: {
expect: { expect: {
function m(t) { function m(t) {
(function(e) { (function(e) {
(function() { t = (function() {
return (function(a) { return (function(a) {
return function(a) {}; return a;
})(); })(function(a) {});
})(); })();
})(); })();
} }
@@ -821,6 +816,10 @@ issue_1709: {
var x = 1; var x = 1;
return x; return x;
}(), }(),
function y() {
const y = 2;
return y;
}(),
function z() { function z() {
function z() {} function z() {}
return z; return z;
@@ -833,6 +832,10 @@ issue_1709: {
var x = 1; var x = 1;
return x; return x;
}(), }(),
function() {
const y = 2;
return y;
}(),
function() { function() {
function z() {} function z() {}
return z; return z;
@@ -932,8 +935,7 @@ issue_1715_3: {
try { try {
console; console;
} catch (a) { } catch (a) {
var a; var a = x();
x();
} }
} }
f(); f();
@@ -1028,33 +1030,6 @@ delete_assign_2: {
expect_stdout: true expect_stdout: true
} }
drop_var: {
options = {
toplevel: true,
unused: true,
}
input: {
var a;
console.log(a, b);
var a = 1, b = 2;
console.log(a, b);
var a = 3;
console.log(a, b);
}
expect: {
console.log(a, b);
var a = 1, b = 2;
console.log(a, b);
a = 3;
console.log(a, b);
}
expect_stdout: [
"undefined undefined",
"1 2",
"3 2",
]
}
issue_1830_1: { issue_1830_1: {
options = { options = {
unused: true, unused: true,
@@ -1090,326 +1065,27 @@ issue_1830_2: {
expect_stdout: "1" expect_stdout: "1"
} }
issue_1838: { reassign_const: {
options = { options = {
join_vars: true, cascade: true,
loops: true,
unused: true,
}
beautify = {
beautify: true,
}
input: {
function f() {
var b = a;
while (c);
}
}
expect_exact: [
"function f() {",
" for (a; c; ) ;",
"}",
]
}
var_catch_toplevel: {
options = {
conditionals: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function f() {
a--;
try {
a++;
x();
} catch(a) {
if (a) var a;
var a = 10;
}
}
f();
}
expect: {
!function() {
try {
x();
} catch(a) {
var a;
}
}();
}
}
issue_2105_1: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
!function(factory) {
factory();
}( function() {
return function(fn) {
fn()().prop();
}( function() {
function bar() {
var quux = function() {
console.log("PASS");
}, foo = function() {
console.log;
quux();
};
return { prop: foo };
}
return bar;
} );
});
}
expect: {
({
prop: function() {
console.log;
console.log("PASS");
}
}).prop();
}
expect_stdout: "PASS"
}
issue_2105_2: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
properties: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
!function(factory) {
factory();
}( function() {
return function(fn) {
fn()().prop();
}( function() {
function bar() {
var quux = function() {
console.log("PASS");
}, foo = function() {
console.log;
quux();
};
return { prop: foo };
}
return bar;
} );
});
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
issue_2226_1: {
options = {
side_effects: true,
unused: true,
}
input: {
function f1() {
var a = b;
a += c;
}
function f2(a) {
a <<= b;
}
function f3(a) {
--a;
}
function f4() {
var a = b;
return a *= c;
}
function f5(a) {
x(a /= b);
}
}
expect: {
function f1() {
b;
c;
}
function f2(a) {
b;
}
function f3(a) {
0;
}
function f4() {
var a = b;
return a *= c;
}
function f5(a) {
x(a /= b);
}
}
}
issue_2226_2: {
options = {
collapse_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
} }
input: { input: {
console.log(function(a, b) { function f() {
a += b; const a = 1;
a = 2;
return a; return a;
}(1, 2)); }
console.log(f());
} }
expect: { expect: {
console.log(function(a, b) { function f() {
return a += 2; const a = 1;
}(1)); return a = 2, a;
}
expect_stdout: "3"
}
issue_2226_3: {
options = {
collapse_vars: true,
side_effects: true,
unused: true,
}
input: {
console.log(function(a, b) {
a += b;
return a;
}(1, 2));
}
expect: {
console.log(function(a, b) {
return a += 2;
}(1));
}
expect_stdout: "3"
}
issue_2288: {
options = {
unused: true,
}
beautify = {
beautify: true,
}
input: {
function foo(o) {
for (var j = o.a, i = 0; i < 0; i++);
for (var i = 0; i < 0; i++);
}
}
expect: {
function foo(o) {
o.a;
for (var i = 0; i < 0; i++);
for (i = 0; i < 0; i++);
}
}
}
issue_2516_1: {
options = {
collapse_vars: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function foo() {
function qux(x) {
bar.call(null, x);
}
function bar(x) {
var FOUR = 4;
var trouble = x || never_called();
var value = (FOUR - 1) * trouble;
console.log(value == 6 ? "PASS" : value);
}
Baz = qux;
}
var Baz;
foo();
Baz(2);
}
expect: {
function foo() {
Baz = function(x) {
(function(x) {
var trouble = x || never_called();
var value = (4 - 1) * trouble;
console.log(6 == value ? "PASS" : value);
}).call(null, x);
};
}
var Baz;
foo();
Baz(2);
}
}
issue_2516_2: {
options = {
collapse_vars: true,
reduce_funcs: true,
reduce_vars: true,
passes: 2,
unused: true,
}
input: {
function foo() {
function qux(x) {
bar.call(null, x);
}
function bar(x) {
var FOUR = 4;
var trouble = x || never_called();
var value = (FOUR - 1) * trouble;
console.log(value == 6 ? "PASS" : value);
}
Baz = qux;
}
var Baz;
foo();
Baz(2);
}
expect: {
function foo() {
Baz = function(x) {
(function(x) {
var value = (4 - 1) * (x || never_called());
console.log(6 == value ? "PASS" : value);
}).call(null, x);
};
}
var Baz;
foo();
Baz(2);
} }
console.log(f());
}
expect_stdout: true
} }

View File

@@ -1,7 +1,6 @@
and: { and: {
options = { options = {
evaluate: true, evaluate: true
side_effects: true,
} }
input: { input: {
var a; var a;
@@ -77,8 +76,7 @@ and: {
or: { or: {
options = { options = {
evaluate: true, evaluate: true
side_effects: true,
} }
input: { input: {
var a; var a;
@@ -160,8 +158,7 @@ or: {
unary_prefix: { unary_prefix: {
options = { options = {
evaluate: true, evaluate: true
side_effects: true,
} }
input: { input: {
a = !0 && b; a = !0 && b;
@@ -253,27 +250,22 @@ unsafe_constant: {
unsafe_object: { unsafe_object: {
options = { options = {
evaluate: true, evaluate : true,
reduce_funcs: true, unsafe : true
reduce_vars: true,
toplevel: true,
unsafe: true,
} }
input: { input: {
var o = { a: 1 };
console.log( console.log(
o + 1, ({a:1}) + 1,
o.a + 1, ({a:1}).a + 1,
o.b + 1, ({a:1}).b + 1,
o.a.b + 1 ({a:1}).a.b + 1
); );
} }
expect: { expect: {
var o = { a: 1 };
console.log( console.log(
o + 1, ({a:1}) + 1,
2, 2,
o.b + 1, ({a:1}).b + 1,
1..b + 1 1..b + 1
); );
} }
@@ -282,27 +274,22 @@ unsafe_object: {
unsafe_object_nested: { unsafe_object_nested: {
options = { options = {
evaluate: true, evaluate : true,
reduce_funcs: true, unsafe : true
reduce_vars: true,
toplevel: true,
unsafe: true,
} }
input: { input: {
var o = { a: { b: 1 } };
console.log( console.log(
o + 1, ({a:{b:1}}) + 1,
o.a + 1, ({a:{b:1}}).a + 1,
o.b + 1, ({a:{b:1}}).b + 1,
o.a.b + 1 ({a:{b:1}}).a.b + 1
); );
} }
expect: { expect: {
var o = { a: { b: 1 } };
console.log( console.log(
o + 1, ({a:{b:1}}) + 1,
o.a + 1, ({a:{b:1}}).a + 1,
o.b + 1, ({a:{b:1}}).b + 1,
2 2
); );
} }
@@ -311,26 +298,21 @@ unsafe_object_nested: {
unsafe_object_complex: { unsafe_object_complex: {
options = { options = {
evaluate: true, evaluate : true,
reduce_funcs: true, unsafe : true
reduce_vars: true,
toplevel: true,
unsafe: true,
} }
input: { input: {
var o = { a: { b: 1 }, b: 1 };
console.log( console.log(
o + 1, ({a:{b:1},b:1}) + 1,
o.a + 1, ({a:{b:1},b:1}).a + 1,
o.b + 1, ({a:{b:1},b:1}).b + 1,
o.a.b + 1 ({a:{b:1},b:1}).a.b + 1
); );
} }
expect: { expect: {
var o = { a: { b: 1 }, b: 1 };
console.log( console.log(
o + 1, ({a:{b:1},b:1}) + 1,
o.a + 1, ({a:{b:1},b:1}).a + 1,
2, 2,
2 2
); );
@@ -340,27 +322,22 @@ unsafe_object_complex: {
unsafe_object_repeated: { unsafe_object_repeated: {
options = { options = {
evaluate: true, evaluate : true,
reduce_funcs: true, unsafe : true
reduce_vars: true,
toplevel: true,
unsafe: true,
} }
input: { input: {
var o = { a: { b: 1 }, a: 1 };
console.log( console.log(
o + 1, ({a:{b:1},a:1}) + 1,
o.a + 1, ({a:{b:1},a:1}).a + 1,
o.b + 1, ({a:{b:1},a:1}).b + 1,
o.a.b + 1 ({a:{b:1},a:1}).a.b + 1
); );
} }
expect: { expect: {
var o = { a: { b: 1 }, a: 1 };
console.log( console.log(
o + 1, ({a:{b:1},a:1}) + 1,
2, 2,
o.b + 1, ({a:{b:1},a:1}).b + 1,
1..b + 1 1..b + 1
); );
} }
@@ -370,7 +347,6 @@ unsafe_object_repeated: {
unsafe_object_accessor: { unsafe_object_accessor: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unsafe: true, unsafe: true,
} }
@@ -394,11 +370,10 @@ unsafe_object_accessor: {
} }
} }
prop_function: { unsafe_function: {
options = { options = {
evaluate: true, evaluate : true,
properties: true, unsafe : true
side_effects: true,
} }
input: { input: {
console.log( console.log(
@@ -411,9 +386,9 @@ prop_function: {
expect: { expect: {
console.log( console.log(
({a:{b:1},b:function(){}}) + 1, ({a:{b:1},b:function(){}}) + 1,
({b:1}) + 1, ({a:{b:1},b:function(){}}).a + 1,
function(){} + 1, ({a:{b:1},b:function(){}}).b + 1,
2 ({a:{b:1},b:function(){}}).a.b + 1
); );
} }
expect_stdout: true expect_stdout: true
@@ -639,11 +614,10 @@ unsafe_string_bad_index: {
expect_stdout: true expect_stdout: true
} }
prototype_function: { unsafe_prototype_function: {
options = { options = {
evaluate: true, evaluate : true,
properties: true, unsafe : true
side_effects: true,
} }
input: { input: {
var a = ({valueOf: 0}) < 1; var a = ({valueOf: 0}) < 1;
@@ -662,28 +636,25 @@ prototype_function: {
var d = ({toString: 0}) + ""; var d = ({toString: 0}) + "";
var e = (({valueOf: 0}) + "")[2]; var e = (({valueOf: 0}) + "")[2];
var f = (({toString: 0}) + "")[2]; var f = (({toString: 0}) + "")[2];
var g = 0(); var g = ({valueOf: 0}).valueOf();
var h = 0(); var h = "" + ({toString: 0});
} }
} }
call_args: { call_args: {
options = { options = {
evaluate: true, evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true,
} }
input: { input: {
var a = 1; const a = 1;
console.log(a); console.log(a);
+function(a) { +function(a) {
return a; return a;
}(a); }(a);
} }
expect: { expect: {
var a = 1; const a = 1;
console.log(1); console.log(1);
+(1, 1); +(1, 1);
} }
@@ -693,21 +664,19 @@ call_args: {
call_args_drop_param: { call_args_drop_param: {
options = { options = {
evaluate: true, evaluate: true,
inline: true,
keep_fargs: false, keep_fargs: false,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true,
unused: true, unused: true,
} }
input: { input: {
var a = 1; const a = 1;
console.log(a); console.log(a);
+function(a) { +function(a) {
return a; return a;
}(a, b); }(a, b);
} }
expect: { expect: {
const a = 1;
console.log(1); console.log(1);
+(b, 1); +(b, 1);
} }
@@ -810,15 +779,13 @@ unsafe_charAt_noop: {
input: { input: {
console.log( console.log(
s.charAt(0), s.charAt(0),
"string".charAt(x), "string".charAt(x)
(typeof x).charAt()
); );
} }
expect: { expect: {
console.log( console.log(
s.charAt(0), s.charAt(0),
"string".charAt(x), "string".charAt(x)
(typeof x)[0]
); );
} }
} }
@@ -955,12 +922,12 @@ delete_binary_1: {
console.log(delete (true && (0 / 0))); console.log(delete (true && (0 / 0)));
} }
expect: { expect: {
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((NaN, !0));
console.log(!0); console.log((NaN, !0));
} }
expect_stdout: true expect_stdout: true
} }
@@ -981,12 +948,12 @@ delete_binary_2: {
console.log(delete (false || (0 / 0))); console.log(delete (false || (0 / 0)));
} }
expect: { expect: {
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((Infinity, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((NaN, !0));
console.log(!0); console.log((NaN, !0));
} }
expect_stdout: true expect_stdout: true
} }
@@ -1022,321 +989,3 @@ Infinity_NaN_undefined_LHS: {
"}", "}",
] ]
} }
issue_1964_1: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe_regexp: false,
unused: true,
}
input: {
function f() {
var long_variable_name = /\s/;
console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect: {
function f() {
var long_variable_name = /\s/;
console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect_stdout: [
"\\s",
"b",
]
}
issue_1964_2: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
unsafe_regexp: true,
unused: true,
}
input: {
function f() {
var long_variable_name = /\s/;
console.log(long_variable_name.source);
return "a b c".split(long_variable_name)[1];
}
console.log(f());
}
expect: {
function f() {
console.log(/\s/.source);
return "a b c".split(/\s/)[1];
}
console.log(f());
}
expect_stdout: [
"\\s",
"b",
]
}
array_slice_index: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log([1,2,3].slice(1)[1]);
}
expect: {
console.log(3);
}
expect_stdout: "3"
}
string_charCodeAt: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log("foo".charCodeAt("bar".length));
}
expect: {
console.log(NaN);
}
expect_stdout: "NaN"
}
issue_2207_1: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(String.fromCharCode(65));
console.log(Math.max(3, 6, 2, 7, 3, 4));
console.log(Math.cos(1.2345));
console.log(Math.cos(1.2345) - Math.sin(4.321));
console.log(Math.pow(Math.PI, Math.E - Math.LN10));
}
expect: {
console.log("A");
console.log(7);
console.log(Math.cos(1.2345));
console.log(1.2543732512566947);
console.log(1.6093984514472044);
}
expect_stdout: true
}
issue_2207_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(Math.E);
console.log(Math.LN10);
console.log(Math.LN2);
console.log(Math.LOG2E);
console.log(Math.LOG10E);
console.log(Math.PI);
console.log(Math.SQRT1_2);
console.log(Math.SQRT2);
}
expect: {
console.log(Math.E);
console.log(Math.LN10);
console.log(Math.LN2);
console.log(Math.LOG2E);
console.log(Math.LOG10E);
console.log(Math.PI);
console.log(Math.SQRT1_2);
console.log(Math.SQRT2);
}
expect_stdout: true
}
issue_2207_3: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(Number.MAX_VALUE);
console.log(Number.MIN_VALUE);
console.log(Number.NaN);
console.log(Number.NEGATIVE_INFINITY);
console.log(Number.POSITIVE_INFINITY);
}
expect: {
console.log(Number.MAX_VALUE);
console.log(5e-324);
console.log(NaN);
console.log(-1/0);
console.log(1/0);
}
expect_stdout: true
}
issue_2231_1: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(Object.keys(void 0));
}
expect: {
console.log(Object.keys(void 0));
}
expect_stdout: true
}
issue_2231_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(Object.getOwnPropertyNames(null));
}
expect: {
console.log(Object.getOwnPropertyNames(null));
}
expect_stdout: true
}
self_comparison_1: {
options = {
evaluate: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
unused: true,
}
input: {
var o = { n: NaN };
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
}
expect: {
console.log(false, false, true, true, "number");
}
expect_stdout: "false false true true 'number'"
}
self_comparison_2: {
options = {
evaluate: true,
hoist_props: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = { n: NaN };
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
}
expect: {
console.log(false, false, true, true, "number");
}
expect_stdout: "false false true true 'number'"
}
issue_2535_1: {
options = {
booleans: true,
evaluate: true,
sequences: true,
side_effects: true,
}
input: {
if ((x() || true) || y()) z();
if ((x() || true) && y()) z();
if ((x() && true) || y()) z();
if ((x() && true) && y()) z();
if ((x() || false) || y()) z();
if ((x() || false) && y()) z();
if ((x() && false) || y()) z();
if ((x() && false) && y()) z();
}
expect: {
if (x(), 1) z();
if (x(), y()) z();
if (x() || y()) z();
if (x() && y()) z();
if (x() || y()) z();
if (x() && y()) z();
if (x(), y()) z();
if (x(), 0) z();
}
}
issue_2535_2: {
options = {
booleans: true,
evaluate: true,
sequences: true,
side_effects: true,
}
input: {
(x() || true) || y();
(x() || true) && y();
(x() && true) || y();
(x() && true) && y();
(x() || false) || y();
(x() || false) && y();
(x() && false) || y();
(x() && false) && y();
}
expect: {
x(),
x(), y(),
x() || y(),
x() && y(),
x() || y(),
x() && y(),
x(), y(),
x();
}
}
issue_2535_3: {
options = {
booleans: true,
evaluate: true,
}
input: {
console.log(Object(1) && 1 && 2);
console.log(Object(1) && true && 1 && 2 && Object(2));
console.log(Object(1) && true && 1 && null && 2 && Object(2));
console.log(2 == Object(1) || 0 || void 0 || null);
console.log(2 == Object(1) || 0 || void 0 || null || Object(2));
console.log(2 == Object(1) || 0 || void 0 || "ok" || null || Object(2));
}
expect: {
console.log(Object(1) && 2);
console.log(Object(1) && Object(2));
console.log(Object(1) && null);
console.log(2 == Object(1) || null);
console.log(2 == Object(1) || Object(2));
console.log(2 == Object(1) || "ok");
}
expect_stdout: true
expect_warnings: [
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1316,20]",
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1317,20]",
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1318,20]",
"WARN: Condition left of && always false [test/compress/evaluate.js:1318,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1319,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1320,20]",
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1321,20]",
"WARN: Condition left of || always true [test/compress/evaluate.js:1321,20]",
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,7 +37,6 @@ object: {
VALUE: 42, VALUE: 42,
}, },
}, },
side_effects: true,
unsafe: true, unsafe: true,
} }
input: { input: {
@@ -121,7 +120,7 @@ mixed: {
properties: true, properties: true,
} }
input: { input: {
var FOO = { BAR: 0 }; const FOO = { BAR: 0 };
console.log(FOO.BAR); console.log(FOO.BAR);
console.log(++CONFIG.DEBUG); console.log(++CONFIG.DEBUG);
console.log(++CONFIG.VALUE); console.log(++CONFIG.VALUE);
@@ -131,7 +130,7 @@ mixed: {
console.log(CONFIG); console.log(CONFIG);
} }
expect: { expect: {
var FOO = { BAR: 0 }; const FOO = { BAR: 0 };
console.log("moo"); console.log("moo");
console.log(++CONFIG.DEBUG); console.log(++CONFIG.DEBUG);
console.log(++CONFIG.VALUE); console.log(++CONFIG.VALUE);
@@ -141,9 +140,9 @@ mixed: {
console.log(CONFIG); console.log(CONFIG);
} }
expect_warnings: [ expect_warnings: [
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:126,22]',
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]', 'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]',
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:128,22]', 'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:129,8]',
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:130,8]',
] ]
} }
@@ -161,39 +160,3 @@ issue_1801: {
console.log(!0); console.log(!0);
} }
} }
issue_1986: {
options = {
global_defs: {
"@alert": "console.log",
},
}
input: {
alert(42);
}
expect: {
console.log(42);
}
}
issue_2167: {
options = {
conditionals: true,
dead_code: true,
evaluate: true,
global_defs: {
"@isDevMode": "function(){}",
},
passes: 2,
side_effects: true,
}
input: {
if (isDevMode()) {
greetOverlord();
}
doWork();
}
expect: {
doWork();
}
}

View File

@@ -1,666 +0,0 @@
issue_2377_1: {
options = {
evaluate: true,
inline: true,
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
foo: 1,
bar: 2,
square: function(x) {
return x * x;
},
cube: function(x) {
return x * x * x;
},
};
console.log(obj.foo, obj.cube(3));
}
expect: {
var obj_foo = 1, obj_cube = function(x) {
return x * x * x;
};
console.log(obj_foo, obj_cube(3));
}
expect_stdout: "1 27"
}
issue_2377_2: {
options = {
evaluate: true,
inline: true,
hoist_props: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
foo: 1,
bar: 2,
square: function(x) {
return x * x;
},
cube: function(x) {
return x * x * x;
},
};
console.log(obj.foo, obj.cube(3));
}
expect: {
console.log(1, (x = 3, x * x * x));
var x;
}
expect_stdout: "1 27"
}
issue_2377_3: {
options = {
evaluate: true,
inline: true,
hoist_props: true,
passes: 4,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
foo: 1,
bar: 2,
square: function(x) {
return x * x;
},
cube: function(x) {
return x * x * x;
},
};
console.log(obj.foo, obj.cube(3));
}
expect: {
console.log(1, 27);
}
expect_stdout: "1 27"
}
direct_access_1: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 0;
var obj = {
a: 1,
b: 2,
};
for (var k in obj) a++;
console.log(a, obj.a);
}
expect: {
var a = 0;
var obj = {
a: 1,
b: 2,
};
for (var k in obj) a++;
console.log(a, obj.a);
}
expect_stdout: "2 1"
}
direct_access_2: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = { a: 1 };
var f = function(k) {
if (o[k]) return "PASS";
};
console.log(f("a"));
}
expect: {
var o = { a: 1 };
console.log(function(k) {
if (o[k]) return "PASS";
}("a"));
}
expect_stdout: "PASS"
}
direct_access_3: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = { a: 1 };
o.b;
console.log(o.a);
}
expect: {
var o = { a: 1 };
o.b;
console.log(o.a);
}
expect_stdout: "1"
}
single_use: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var obj = {
bar: function() {
return 42;
},
};
console.log(obj.bar());
}
expect: {
console.log({
bar: function() {
return 42;
},
}.bar());
}
}
name_collision_1: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
var obj_foo = 1;
var obj_bar = 2;
function f() {
var obj = {
foo: 3,
bar: 4,
"b-r": 5,
"b+r": 6,
"b!r": 7,
};
console.log(obj_foo, obj.foo, obj.bar, obj["b-r"], obj["b+r"], obj["b!r"]);
}
f();
}
expect: {
var obj_foo = 1;
var obj_bar = 2;
function f() {
var obj_foo$0 = 3,
obj_bar = 4,
obj_b_r = 5,
obj_b_r$0 = 6,
obj_b_r$1 = 7;
console.log(obj_foo, obj_foo$0, obj_bar, obj_b_r, obj_b_r$0, obj_b_r$1);
}
f();
}
expect_stdout: "1 3 4 5 6 7"
}
name_collision_2: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
var o = {
p: 1,
0: function(x) {
return x;
},
1: function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
console.log(o.p === o.p, o[0](4), o[1](5), o__$0, o__$1);
}
expect: {
var o_p = 1,
o__ = function(x) {
return x;
},
o__$2 = function(x) {
return x + 1;
},
o__$0 = 2,
o__$1 = 3;
console.log(o_p === o_p, o__(4), o__$2(5), o__$0, o__$1);
}
expect_stdout: "true 4 6 2 3"
}
name_collision_3: {
options = {
hoist_props: true,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
}
input: {
var o = {
p: 1,
0: function(x) {
return x;
},
1: function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
console.log(o.p === o.p, o[0](4), o[1](5));
}
expect: {
var o_p = 1,
o__ = function(x) {
return x;
},
o__$2 = function(x) {
return x + 1;
},
o__$0 = 2,
o__$1 = 3;
console.log(o_p === o_p, o__(4), o__$2(5));
}
expect_stdout: "true 4 6"
}
contains_this_1: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p);
}
expect: {
console.log(1, 1);
}
expect_stdout: "1 1"
}
contains_this_2: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p, o.u);
}
expect: {
console.log(1, 1, function() {
return this === this;
});
}
expect_stdout: true
}
contains_this_3: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p, o.u());
}
expect: {
var o = {
u: function() {
return this === this;
},
p: 1
};
console.log(o.p, o.p, o.u());
}
expect_stdout: "1 1 true"
}
new_this: {
options = {
evaluate: true,
hoist_props: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
f: function(a) {
this.b = a;
}
};
console.log(new o.f(o.a).b, o.b);
}
expect: {
console.log(new function(a) {
this.b = a;
}(1).b, 2);
}
expect_stdout: "1 2"
}
issue_2473_1: {
options = {
hoist_props: false,
reduce_vars: true,
top_retain: [ "x", "y" ],
toplevel: true,
unused: true,
}
input: {
var x = {};
var y = [];
var z = {};
}
expect: {
var x = {};
var y = [];
}
}
issue_2473_2: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: [ "x", "y" ],
toplevel: true,
unused: true,
}
input: {
var x = {};
var y = [];
var z = {};
}
expect: {
var x = {};
var y = [];
}
}
issue_2473_3: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: "o",
toplevel: true,
unused: true,
}
input: {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
}
expect: {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
}
expect_stdout: "1 2"
}
issue_2473_4: {
options = {
hoist_props: true,
reduce_vars: true,
top_retain: "o",
toplevel: true,
unused: true,
}
input: {
(function() {
var o = {
a: 1,
b: 2,
};
console.log(o.a, o.b);
})();
}
expect: {
(function() {
var o_a = 1, o_b = 2;
console.log(o_a, o_b);
})();
}
expect_stdout: "1 2"
}
issue_2508_1: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: [ 1 ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
(function(x) {
console.log(x);
})([ 1 ]);
}
expect_stdout: true
}
issue_2508_2: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: { b: 2 },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
(function(x) {
console.log(x);
})({ b: 2 });
}
expect_stdout: true
}
issue_2508_3: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: [ o ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
var o = {
a: [ o ],
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect_stdout: true
}
issue_2508_4: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
a: { b: o },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect: {
var o = {
a: { b: o },
f: function(x) {
console.log(x);
}
};
o.f(o.a);
}
expect_stdout: true
}
issue_2508_5: {
options = {
collapse_vars: true,
hoist_props: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
f: function(x) {
console.log(x);
}
};
o.f(o.f);
}
expect: {
var o_f = function(x) {
console.log(x);
};
o_f(o_f);
}
expect_stdout: true
}
issue_2519: {
options = {
collapse_vars: true,
evaluate: true,
hoist_props: true,
reduce_vars: true,
unused: true,
}
input: {
function testFunc() {
var dimensions = {
minX: 5,
maxX: 6,
};
var scale = 1;
var d = {
x: (dimensions.maxX + dimensions.minX) / 2,
};
return d.x * scale;
}
console.log(testFunc());
}
expect: {
function testFunc() {
return 1 * ((6 + 5) / 2);
}
console.log(testFunc());
}
expect_stdout: "5.5"
}

View File

@@ -88,24 +88,3 @@ sequences_funs: {
} }
} }
} }
issue_2295: {
options = {
collapse_vars: true,
hoist_vars: true,
}
input: {
function foo(o) {
var a = o.a;
if (a) return a;
var a = 1;
}
}
expect: {
function foo(o) {
var a = o.a;
if (a) return a;
a = 1;
}
}
}

View File

@@ -302,27 +302,3 @@ issue_1437_conditionals: {
} }
} }
} }
issue_512: {
options = {
conditionals: true,
if_return: true,
sequences: true,
side_effects: true,
}
input: {
function a() {
if (b()) {
c();
return;
}
throw e;
}
}
expect: {
function a() {
if (!b()) throw e;
c();
}
}
}

View File

@@ -2,7 +2,7 @@ non_hoisted_function_after_return: {
options = { options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, side_effects: true if_return: true, join_vars: true, cascade: true, side_effects: true
} }
input: { input: {
function foo(x) { function foo(x) {
@@ -38,7 +38,7 @@ non_hoisted_function_after_return_2a: {
options = { options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, side_effects: true, if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false, passes: 2, warnings: "verbose" collapse_vars: false, passes: 2, warnings: "verbose"
} }
input: { input: {
@@ -71,13 +71,11 @@ non_hoisted_function_after_return_2a: {
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]", "WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]",
"WARN: pass 0: last_count: Infinity, count: 37",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]", "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 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 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]",
"WARN: pass 1: last_count: 37, count: 18",
] ]
} }
@@ -85,7 +83,7 @@ non_hoisted_function_after_return_2b: {
options = { options = {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, side_effects: true, if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false collapse_vars: false
} }
input: { input: {
@@ -111,146 +109,10 @@ non_hoisted_function_after_return_2b: {
} }
expect_warnings: [ expect_warnings: [
// duplicate warnings no longer emitted // duplicate warnings no longer emitted
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:95,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:95,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:99,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:99,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:103,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]",
]
}
non_hoisted_function_after_return_strict: {
options = {
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, side_effects: true
}
input: {
"use strict";
function foo(x) {
if (x) {
return bar();
not_called1();
} else {
return baz();
not_called2();
}
function bar() { return 7; }
return not_reached;
function UnusedFunction() {}
function baz() { return 8; }
}
console.log(foo(0), foo(1));
}
expect: {
"use strict";
function foo(x) {
return x ? bar() : baz();
function bar() { return 7 }
function baz() { return 8 }
}
console.log(foo(0), foo(1));
}
expect_stdout: "8 7"
expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:133,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:136,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:139,12]",
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:140,21]",
]
}
non_hoisted_function_after_return_2a_strict: {
options = {
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, side_effects: true,
collapse_vars: false, passes: 2, warnings: "verbose"
}
input: {
"use strict";
function foo(x) {
if (x) {
return bar(1);
var a = not_called(1);
} else {
return bar(2);
var b = not_called(2);
}
var c = bar(3);
function bar(x) { return 7 - x; }
function nope() {}
return b || c;
}
console.log(foo(0), foo(1));
}
expect: {
"use strict";
function foo(x) {
return bar(x ? 1 : 2);
function bar(x) {
return 7 - x;
}
}
console.log(foo(0), foo(1));
}
expect_stdout: "5 6"
expect_warnings: [
"WARN: Dropping unreachable code [test/compress/issue-1034.js:175,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:175,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:178,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:178,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:175,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:182,21]",
"WARN: pass 0: last_count: Infinity, count: 48",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:180,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:180,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:183,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:178,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:180,16]",
"WARN: pass 1: last_count: 48, count: 29",
]
}
non_hoisted_function_after_return_2b_strict: {
options = {
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, side_effects: true,
collapse_vars: false
}
input: {
"use strict";
function foo(x) {
if (x) {
return bar(1);
} else {
return bar(2);
var b;
}
var c = bar(3);
function bar(x) {
return 7 - x;
}
return b || c;
}
console.log(foo(0), foo(1));
}
expect: {
"use strict";
function foo(x) {
return bar(x ? 1 : 2);
function bar(x) { return 7 - x; }
}
console.log(foo(0), foo(1));
}
expect_stdout: "5 6"
expect_warnings: [
// duplicate warnings no longer emitted
"WARN: Dropping unreachable code [test/compress/issue-1034.js:229,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:229,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:231,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:231,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:235,12]",
] ]
} }

View File

@@ -1,7 +1,19 @@
const_declaration: {
options = {
evaluate: true
};
input: {
const goog = goog || {};
}
expect: {
const goog = goog || {};
}
}
const_pragma: { const_pragma: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
}; };
@@ -17,7 +29,6 @@ const_pragma: {
not_const: { not_const: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
}; };

View File

@@ -1,91 +1,90 @@
multiple_functions: { multiple_functions: {
options = { options = { if_return: true, hoist_funs: false };
hoist_funs: false,
if_return: true,
}
input: { input: {
( function() { ( function() {
if ( !window ) { if ( !window ) {
return; return;
} }
function f() {} function f() {}
function g() {} function g() {}
} )(); } )();
} }
expect: { expect: {
( function() { ( function() {
function f() {}
function g() {}
// NOTE: other compression steps will reduce this // NOTE: other compression steps will reduce this
// down to just `window`. // down to just `window`.
if ( window ); if ( window );
function f() {}
function g() {}
} )(); } )();
} }
} }
single_function: { single_function: {
options = { options = { if_return: true, hoist_funs: false };
hoist_funs: false,
if_return: true,
}
input: { input: {
( function() { ( function() {
if ( !window ) { if ( !window ) {
return; return;
} }
function f() {} function f() {}
} )(); } )();
} }
expect: { expect: {
( function() { ( function() {
if ( window );
function f() {} function f() {}
if ( window );
} )(); } )();
} }
} }
deeply_nested: { deeply_nested: {
options = { options = { if_return: true, hoist_funs: false };
hoist_funs: false,
if_return: true,
}
input: { input: {
( function() { ( function() {
if ( !window ) { if ( !window ) {
return; return;
} }
function f() {} function f() {}
function g() {} function g() {}
if ( !document ) { if ( !document ) {
return; return;
} }
function h() {} function h() {}
} )(); } )();
} }
expect: { expect: {
( function() { ( function() {
function f() {}
function g() {}
function h() {}
// NOTE: other compression steps will reduce this // NOTE: other compression steps will reduce this
// down to just `window`. // down to just `window`.
if ( window ) if ( window )
if (document); if (document);
function f() {}
function g() {}
function h() {}
} )(); } )();
} }
} }
not_hoisted_when_already_nested: { not_hoisted_when_already_nested: {
options = { options = { if_return: true, hoist_funs: false };
hoist_funs: false,
if_return: true,
}
input: { input: {
( function() { ( function() {
if ( !window ) { if ( !window ) {
return; return;
} }
if ( foo ) function f() {} if ( foo ) function f() {}
} )(); } )();
} }
expect: { expect: {
@@ -95,70 +94,3 @@ not_hoisted_when_already_nested: {
} )(); } )();
} }
} }
defun_if_return: {
options = {
hoist_funs: false,
if_return: true,
}
input: {
function e() {
function f() {}
if (!window) return;
else function g() {}
function h() {}
}
}
expect: {
function e() {
function f() {}
if (window) function g() {}
function h() {}
}
}
}
defun_hoist_funs: {
options = {
hoist_funs: true,
if_return: true,
}
input: {
function e() {
function f() {}
if (!window) return;
else function g() {}
function h() {}
}
}
expect: {
function e() {
function f() {}
function g() {}
function h() {}
if (window);
}
}
}
defun_else_if_return: {
options = {
hoist_funs: false,
if_return: true,
}
input: {
function e() {
function f() {}
if (window) function g() {}
else return;
function h() {}
}
}
expect: {
function e() {
function f() {}
if (window) function g() {}
function h() {}
}
}
}

View File

@@ -190,6 +190,7 @@ assorted_Infinity_NaN_undefined_in_with_scope: {
keep_fargs: true, keep_fargs: true,
if_return: true, if_return: true,
join_vars: true, join_vars: true,
cascade: true,
side_effects: true, side_effects: true,
sequences: false, sequences: false,
keep_infinity: false, keep_infinity: false,
@@ -252,6 +253,7 @@ assorted_Infinity_NaN_undefined_in_with_scope_keep_infinity: {
keep_fargs: true, keep_fargs: true,
if_return: true, if_return: true,
join_vars: true, join_vars: true,
cascade: true,
side_effects: true, side_effects: true,
sequences: false, sequences: false,
keep_infinity: true, keep_infinity: true,

View File

@@ -8,6 +8,7 @@ pure_function_calls: {
unused : true, unused : true,
if_return : true, if_return : true,
join_vars : true, join_vars : true,
cascade : true,
negate_iife : true, negate_iife : true,
} }
input: { input: {
@@ -48,13 +49,13 @@ pure_function_calls: {
a.b(), f.g(); a.b(), f.g();
} }
expect_warnings: [ expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:17,8]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:16,8]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:17,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:29,37]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:30,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:29,16]", "WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:30,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:27,8]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:28,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:37,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:38,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:38,31]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:39,31]",
] ]
} }
@@ -68,6 +69,7 @@ pure_function_calls_toplevel: {
unused : true, unused : true,
if_return : true, if_return : true,
join_vars : true, join_vars : true,
cascade : true,
negate_iife : true, negate_iife : true,
toplevel : true, toplevel : true,
} }
@@ -94,13 +96,6 @@ pure_function_calls_toplevel: {
})(); })();
})(); })();
// pure top-level calls will be dropped regardless of the leading comments position
var MyClass = /*#__PURE__*//*@class*/(function(){
function MyClass() {}
MyClass.prototype.method = function() {};
return MyClass;
})();
// comment #__PURE__ comment // comment #__PURE__ comment
bar(), baz(), quux(); bar(), baz(), quux();
a.b(), /* @__PURE__ */ c.d.e(), f.g(); a.b(), /* @__PURE__ */ c.d.e(), f.g();
@@ -110,17 +105,15 @@ pure_function_calls_toplevel: {
a.b(), f.g(); a.b(), f.g();
} }
expect_warnings: [ expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:77,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:79,8]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:77,8]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:79,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:90,37]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:92,37]",
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:90,16]", "WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:92,16]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:88,8]", "WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:90,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:105,8]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:100,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:106,31]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:101,31]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:82,33]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:84,33]",
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:82,12]", "WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:84,12]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:98,45]",
"WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:98,12]",
] ]
} }
@@ -155,29 +148,29 @@ should_warn: {
baz(); baz();
} }
expect_warnings: [ expect_warnings: [
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,61]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,61]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:128,23]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:128,23]",
"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: 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: 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]",
"WARN: Condition always true [test/compress/issue-1261.js:133,23]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:134,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:134,31]",
"WARN: Condition always true [test/compress/issue-1261.js:134,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]",
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:135,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,24]",
"WARN: Boolean || always true [test/compress/issue-1261.js:136,23]", "WARN: Condition always true [test/compress/issue-1261.js:136,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,23]", "WARN: Dropping __PURE__ call [test/compress/issue-1261.js:137,31]",
"WARN: Condition always true [test/compress/issue-1261.js:136,23]", "WARN: Condition always false [test/compress/issue-1261.js:137,8]",
"WARN: Condition left of || always true [test/compress/issue-1261.js:137,8]",
"WARN: Condition always true [test/compress/issue-1261.js:137,8]",
"WARN: Boolean && always false [test/compress/issue-1261.js:138,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:138,23]",
"WARN: Condition always false [test/compress/issue-1261.js:138,23]",
"WARN: Condition left of && always false [test/compress/issue-1261.js:139,8]",
"WARN: Condition always false [test/compress/issue-1261.js:139,8]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:140,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:140,23]",
"WARN: Condition always true [test/compress/issue-1261.js:140,23]",
"WARN: + in boolean context always true [test/compress/issue-1261.js:141,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:141,31]",
"WARN: Condition always true [test/compress/issue-1261.js:141,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:142,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:143,24]",
"WARN: Condition always true [test/compress/issue-1261.js:143,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:144,31]",
"WARN: Condition always false [test/compress/issue-1261.js:144,8]",
] ]
} }

View File

@@ -9,6 +9,7 @@ string_plus_optimization: {
unused : true, unused : true,
if_return : true, if_return : true,
join_vars : true, join_vars : true,
cascade : true,
hoist_funs : true, hoist_funs : true,
}; };
input: { input: {

View File

@@ -1,8 +1,6 @@
issue_1321_no_debug: { issue_1321_no_debug: {
mangle = { mangle_props = {
properties: { ignore_quoted: true
keep_quoted: true,
},
} }
input: { input: {
var x = {}; var x = {};
@@ -12,19 +10,17 @@ issue_1321_no_debug: {
} }
expect: { expect: {
var x = {}; var x = {};
x.x = 1; x.b = 1;
x["a"] = 2 * x.x; x["a"] = 2 * x.b;
console.log(x.x, x["a"]); console.log(x.b, x["a"]);
} }
expect_stdout: true expect_stdout: true
} }
issue_1321_debug: { issue_1321_debug: {
mangle = { mangle_props = {
properties: { ignore_quoted: true,
debug: "", debug: ""
keep_quoted: true,
},
} }
input: { input: {
var x = {}; var x = {};
@@ -34,18 +30,16 @@ issue_1321_debug: {
} }
expect: { expect: {
var x = {}; var x = {};
x.x = 1; x.a = 1;
x["_$foo$_"] = 2 * x.x; x["_$foo$_"] = 2 * x.a;
console.log(x.x, x["_$foo$_"]); console.log(x.a, x["_$foo$_"]);
} }
expect_stdout: true expect_stdout: true
} }
issue_1321_with_quoted: { issue_1321_with_quoted: {
mangle = { mangle_props = {
properties: { ignore_quoted: false
keep_quoted: false,
},
} }
input: { input: {
var x = {}; var x = {};
@@ -55,9 +49,9 @@ issue_1321_with_quoted: {
} }
expect: { expect: {
var x = {}; var x = {};
x.x = 1; x.a = 1;
x["o"] = 2 * x.x; x["b"] = 2 * x.a;
console.log(x.x, x["o"]); console.log(x.a, x["b"]);
} }
expect_stdout: true expect_stdout: true
} }

View File

@@ -1,7 +1,6 @@
typeof_eq_undefined: { typeof_eq_undefined: {
options = { options = {
comparisons: true, comparisons: true
typeofs: true,
} }
input: { input: {
var a = typeof b != "undefined"; var a = typeof b != "undefined";
@@ -24,8 +23,7 @@ typeof_eq_undefined: {
typeof_eq_undefined_ie8: { typeof_eq_undefined_ie8: {
options = { options = {
comparisons: true, comparisons: true,
ie8: true, screw_ie8: false
typeofs: true,
} }
input: { input: {
var a = typeof b != "undefined"; var a = typeof b != "undefined";
@@ -47,8 +45,7 @@ typeof_eq_undefined_ie8: {
undefined_redefined: { undefined_redefined: {
options = { options = {
comparisons: true, comparisons: true
typeofs: true,
} }
input: { input: {
function f(undefined) { function f(undefined) {
@@ -61,8 +58,7 @@ undefined_redefined: {
undefined_redefined_mangle: { undefined_redefined_mangle: {
options = { options = {
comparisons: true, comparisons: true
typeofs: true,
} }
mangle = {} mangle = {}
input: { input: {

View File

@@ -32,6 +32,7 @@ conditional_false_stray_else_in_loop: {
hoist_vars : true, hoist_vars : true,
join_vars : true, join_vars : true,
if_return : true, if_return : true,
cascade : true,
conditionals : false, conditionals : false,
} }
input: { input: {

View File

@@ -1,9 +1,9 @@
screw_ie8: { screw_ie8: {
options = { options = {
ie8: false, screw_ie8: true,
} }
mangle = { mangle = {
ie8: false, screw_ie8: true,
} }
input: { input: {
try { throw "foo"; } catch (x) { console.log(x); } try { throw "foo"; } catch (x) { console.log(x); }
@@ -16,10 +16,10 @@ screw_ie8: {
support_ie8: { support_ie8: {
options = { options = {
ie8: true, screw_ie8: false,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
} }
input: { input: {
try { throw "foo"; } catch (x) { console.log(x); } try { throw "foo"; } catch (x) { console.log(x); }
@@ -85,3 +85,15 @@ unsafe_undefined: {
} }
expect_stdout: true expect_stdout: true
} }
runtime_error: {
input: {
const a = 1;
console.log(a++);
}
expect: {
const a = 1;
console.log(a++);
}
expect_stdout: true
}

View File

@@ -2,7 +2,6 @@ chained_evaluation_1: {
options = { options = {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -19,7 +18,9 @@ chained_evaluation_1: {
expect: { expect: {
(function() { (function() {
(function() { (function() {
f(1).bar = 1; var c;
c = f(1);
c.bar = 1;
})(); })();
})(); })();
} }
@@ -29,7 +30,6 @@ chained_evaluation_2: {
options = { options = {
collapse_vars: true, collapse_vars: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -46,8 +46,9 @@ chained_evaluation_2: {
expect: { expect: {
(function() { (function() {
(function() { (function() {
var b = "long piece of string"; var c, b = "long piece of string";
f(b).bar = b; c = f(b);
c.bar = b;
})(); })();
})(); })();
} }

View File

@@ -2,7 +2,7 @@
issue_1639_1: { issue_1639_1: {
options = { options = {
booleans: true, booleans: true,
collapse_vars: true, cascade: true,
conditionals: true, conditionals: true,
evaluate: true, evaluate: true,
join_vars: true, join_vars: true,
@@ -26,7 +26,7 @@ issue_1639_1: {
} }
expect: { expect: {
for (var a = 100, b = 10, L1 = 5; --L1 > 0;) for (var a = 100, b = 10, L1 = 5; --L1 > 0;)
if (--b, 0) var ignore = 0; if (--b, !1) var ignore = 0;
console.log(a, b); console.log(a, b);
} }
expect_stdout: true expect_stdout: true
@@ -35,7 +35,7 @@ issue_1639_1: {
issue_1639_2: { issue_1639_2: {
options = { options = {
booleans: true, booleans: true,
collapse_vars: true, cascade: true,
conditionals: true, conditionals: true,
evaluate: true, evaluate: true,
join_vars: true, join_vars: true,
@@ -57,7 +57,7 @@ issue_1639_2: {
expect: { expect: {
var a = 100, b = 10; var a = 100, b = 10;
function f19() { function f19() {
++a, 0; ++a, 1;
} }
f19(), f19(),
console.log(a, b); console.log(a, b);
@@ -68,7 +68,7 @@ issue_1639_2: {
issue_1639_3: { issue_1639_3: {
options = { options = {
booleans: true, booleans: true,
collapse_vars: true, cascade: true,
conditionals: true, conditionals: true,
evaluate: true, evaluate: true,
sequences: true, sequences: true,

View File

@@ -1,6 +1,7 @@
f7: { f7: {
options = { options = {
booleans: true, booleans: true,
cascade: true,
collapse_vars: true, collapse_vars: true,
comparisons: true, comparisons: true,
conditionals: true, conditionals: true,
@@ -14,7 +15,6 @@ f7: {
negate_iife: true, negate_iife: true,
passes: 3, passes: 3,
properties: true, properties: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@@ -38,7 +38,7 @@ f7: {
"var b = 10;", "var b = 10;",
"", "",
"!function() {", "!function() {",
" b = 100;", " for (;b = 100, !1; ) ;",
"}(), console.log(100, b);", "}(), console.log(100, b);",
] ]
expect_stdout: true expect_stdout: true

View File

@@ -1,6 +1,5 @@
side_effects_catch: { side_effects_catch: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -35,7 +34,6 @@ side_effects_catch: {
side_effects_else: { side_effects_else: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -64,7 +62,6 @@ side_effects_else: {
side_effects_finally: { side_effects_finally: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -101,7 +98,6 @@ side_effects_finally: {
side_effects_label: { side_effects_label: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -134,7 +130,6 @@ side_effects_label: {
side_effects_switch: { side_effects_switch: {
options = { options = {
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
unused: true, unused: true,

View File

@@ -1,10 +1,10 @@
mangle_catch: { mangle_catch: {
options = { options = {
ie8: false, screw_ie8: true,
toplevel: false, toplevel: false,
} }
mangle = { mangle = {
ie8: false, screw_ie8: true,
toplevel: false, toplevel: false,
} }
input: { input: {
@@ -22,11 +22,11 @@ mangle_catch: {
mangle_catch_ie8: { mangle_catch_ie8: {
options = { options = {
ie8: true, screw_ie8: false,
toplevel: false, toplevel: false,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
toplevel: false, toplevel: false,
} }
input: { input: {
@@ -44,11 +44,11 @@ mangle_catch_ie8: {
mangle_catch_var: { mangle_catch_var: {
options = { options = {
ie8: false, screw_ie8: true,
toplevel: false, toplevel: false,
} }
mangle = { mangle = {
ie8: false, screw_ie8: true,
toplevel: false, toplevel: false,
} }
input: { input: {
@@ -66,11 +66,11 @@ mangle_catch_var: {
mangle_catch_var_ie8: { mangle_catch_var_ie8: {
options = { options = {
ie8: true, screw_ie8: false,
toplevel: false, toplevel: false,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
toplevel: false, toplevel: false,
} }
input: { input: {
@@ -88,11 +88,11 @@ mangle_catch_var_ie8: {
mangle_catch_toplevel: { mangle_catch_toplevel: {
options = { options = {
ie8: false, screw_ie8: true,
toplevel: true, toplevel: true,
} }
mangle = { mangle = {
ie8: false, screw_ie8: true,
toplevel: true, toplevel: true,
} }
input: { input: {
@@ -110,11 +110,11 @@ mangle_catch_toplevel: {
mangle_catch_ie8_toplevel: { mangle_catch_ie8_toplevel: {
options = { options = {
ie8: true, screw_ie8: false,
toplevel: true, toplevel: true,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
toplevel: true, toplevel: true,
} }
input: { input: {
@@ -132,11 +132,11 @@ mangle_catch_ie8_toplevel: {
mangle_catch_var_toplevel: { mangle_catch_var_toplevel: {
options = { options = {
ie8: false, screw_ie8: true,
toplevel: true, toplevel: true,
} }
mangle = { mangle = {
ie8: false, screw_ie8: true,
toplevel: true, toplevel: true,
} }
input: { input: {
@@ -154,11 +154,11 @@ mangle_catch_var_toplevel: {
mangle_catch_var_ie8_toplevel: { mangle_catch_var_ie8_toplevel: {
options = { options = {
ie8: true, screw_ie8: false,
toplevel: true, toplevel: true,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
toplevel: true, toplevel: true,
} }
input: { input: {
@@ -176,11 +176,11 @@ mangle_catch_var_ie8_toplevel: {
mangle_catch_redef_1: { mangle_catch_redef_1: {
options = { options = {
ie8: false, screw_ie8: true,
toplevel: false, toplevel: false,
} }
mangle = { mangle = {
ie8: false, screw_ie8: true,
toplevel: false, toplevel: false,
} }
input: { input: {
@@ -198,11 +198,11 @@ mangle_catch_redef_1: {
mangle_catch_redef_1_ie8: { mangle_catch_redef_1_ie8: {
options = { options = {
ie8: true, screw_ie8: false,
toplevel: false, toplevel: false,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
toplevel: false, toplevel: false,
} }
input: { input: {
@@ -220,11 +220,11 @@ mangle_catch_redef_1_ie8: {
mangle_catch_redef_1_toplevel: { mangle_catch_redef_1_toplevel: {
options = { options = {
ie8: false, screw_ie8: true,
toplevel: true, toplevel: true,
} }
mangle = { mangle = {
ie8: false, screw_ie8: true,
toplevel: true, toplevel: true,
} }
input: { input: {
@@ -242,11 +242,11 @@ mangle_catch_redef_1_toplevel: {
mangle_catch_redef_1_ie8_toplevel: { mangle_catch_redef_1_ie8_toplevel: {
options = { options = {
ie8: true, screw_ie8: false,
toplevel: true, toplevel: true,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
toplevel: true, toplevel: true,
} }
input: { input: {
@@ -264,11 +264,11 @@ mangle_catch_redef_1_ie8_toplevel: {
mangle_catch_redef_2: { mangle_catch_redef_2: {
options = { options = {
ie8: false, screw_ie8: true,
toplevel: false, toplevel: false,
} }
mangle = { mangle = {
ie8: false, screw_ie8: true,
toplevel: false, toplevel: false,
} }
input: { input: {
@@ -285,11 +285,11 @@ mangle_catch_redef_2: {
mangle_catch_redef_2_ie8: { mangle_catch_redef_2_ie8: {
options = { options = {
ie8: true, screw_ie8: false,
toplevel: false, toplevel: false,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
toplevel: false, toplevel: false,
} }
input: { input: {
@@ -306,11 +306,11 @@ mangle_catch_redef_2_ie8: {
mangle_catch_redef_2_toplevel: { mangle_catch_redef_2_toplevel: {
options = { options = {
ie8: false, screw_ie8: true,
toplevel: true, toplevel: true,
} }
mangle = { mangle = {
ie8: false, screw_ie8: true,
toplevel: true, toplevel: true,
} }
input: { input: {
@@ -327,11 +327,11 @@ mangle_catch_redef_2_toplevel: {
mangle_catch_redef_2_ie8_toplevel: { mangle_catch_redef_2_ie8_toplevel: {
options = { options = {
ie8: true, screw_ie8: false,
toplevel: true, toplevel: true,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
toplevel: true, toplevel: true,
} }
input: { input: {

View File

@@ -1,6 +1,6 @@
function_iife_catch: { function_iife_catch: {
mangle = { mangle = {
ie8: false, screw_ie8: true,
} }
input: { input: {
function f(n) { function f(n) {
@@ -21,7 +21,7 @@ function_iife_catch: {
function_iife_catch_ie8: { function_iife_catch_ie8: {
mangle = { mangle = {
ie8: true, screw_ie8: false,
} }
input: { input: {
function f(n) { function f(n) {
@@ -42,7 +42,7 @@ function_iife_catch_ie8: {
function_catch_catch: { function_catch_catch: {
mangle = { mangle = {
ie8: false, screw_ie8: true,
} }
input: { input: {
var o = 0; var o = 0;
@@ -70,7 +70,7 @@ function_catch_catch: {
function_catch_catch_ie8: { function_catch_catch_ie8: {
mangle = { mangle = {
ie8: true, screw_ie8: false,
} }
input: { input: {
var o = 0; var o = 0;

View File

@@ -7,7 +7,7 @@ case_1: {
input: { input: {
var a = 0, b = 1; var a = 0, b = 1;
switch (true) { switch (true) {
case a || true: case a, true:
default: default:
b = 2; b = 2;
case true: case true:
@@ -17,7 +17,7 @@ case_1: {
expect: { expect: {
var a = 0, b = 1; var a = 0, b = 1;
switch (true) { switch (true) {
case a || true: case a, true:
b = 2; b = 2;
} }
console.log(a, b); console.log(a, b);

View File

@@ -1,7 +1,5 @@
mangle_props: { mangle_props: {
mangle = { mangle_props = {}
properties: true,
}
input: { input: {
var obj = { var obj = {
undefined: 1, undefined: 1,
@@ -56,12 +54,10 @@ mangle_props: {
} }
numeric_literal: { numeric_literal: {
mangle = {
properties: true,
}
beautify = { beautify = {
beautify: true, beautify: true,
} }
mangle_props = {}
input: { input: {
var obj = { var obj = {
0: 0, 0: 0,
@@ -86,7 +82,7 @@ numeric_literal: {
' 42: 2,', ' 42: 2,',
' "42": 3,', ' "42": 3,',
' 37: 4,', ' 37: 4,',
' o: 5,', ' a: 5,',
' 1e42: 6,', ' 1e42: 6,',
' b: 7,', ' b: 7,',
' "1e+42": 8', ' "1e+42": 8',
@@ -96,7 +92,7 @@ numeric_literal: {
'', '',
'console.log(obj[42], obj["42"]);', 'console.log(obj[42], obj["42"]);',
'', '',
'console.log(obj[37], obj["o"], obj[37], obj["37"]);', 'console.log(obj[37], obj["a"], obj[37], obj["37"]);',
'', '',
'console.log(obj[1e42], obj["b"], obj["1e+42"]);', 'console.log(obj[1e42], obj["b"], obj["1e+42"]);',
] ]
@@ -109,9 +105,7 @@ numeric_literal: {
} }
identifier: { identifier: {
mangle = { mangle_props = {}
properties: true,
}
input: { input: {
var obj = { var obj = {
abstract: 1, abstract: 1,
@@ -179,32 +173,32 @@ identifier: {
} }
expect: { expect: {
var obj = { var obj = {
e: 1, a: 1,
t: 2, b: 2,
n: 3, c: 3,
a: 4, d: 4,
i: 5, e: 5,
o: 6, f: 6,
r: 7, g: 7,
l: 8, h: 8,
s: 9, i: 9,
c: 10, j: 10,
f: 11, k: 11,
u: 12, l: 12,
d: 13, m: 13,
h: 14, n: 14,
p: 15, o: 15,
b: 16, p: 16,
v: 17, q: 17,
w: 18, r: 18,
y: 19, s: 19,
g: 20, t: 20,
m: 21, u: 21,
k: 22, v: 22,
x: 23, w: 23,
j: 24, x: 24,
z: 25, y: 25,
q: 26, z: 26,
A: 27, A: 27,
B: 28, B: 28,
C: 29, C: 29,
@@ -235,11 +229,11 @@ identifier: {
Z: 54, Z: 54,
$: 55, $: 55,
_: 56, _: 56,
ee: 57, aa: 57,
te: 58, ba: 58,
ne: 59, ca: 59,
ae: 60, da: 60,
ie: 61, ea: 61,
}; };
} }
} }

View File

@@ -1,8 +1,6 @@
unary_prefix: { unary_prefix: {
options = { options = {
evaluate: true, evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
} }
@@ -12,6 +10,10 @@ unary_prefix: {
return x; return x;
}()); }());
} }
expect_exact: "console.log(-2/3);" expect: {
console.log(function() {
return -2 / 3;
}());
}
expect_stdout: true expect_stdout: true
} }

View File

@@ -1,7 +1,6 @@
iife_for: { iife_for: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -27,7 +26,6 @@ iife_for: {
iife_for_in: { iife_for_in: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -53,7 +51,6 @@ iife_for_in: {
iife_do: { iife_do: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -83,7 +80,6 @@ iife_do: {
iife_while: { iife_while: {
options = { options = {
negate_iife: true, negate_iife: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
@@ -134,5 +130,5 @@ label_while: {
L: while (0) continue L; L: while (0) continue L;
} }
} }
expect_exact: "function f(){L:0}" expect_exact: "function f(){L:;}"
} }

View File

@@ -1,31 +0,0 @@
operator: {
input: {
a. //comment
typeof
}
expect_exact: "a.typeof;"
}
name: {
input: {
a. //comment
b
}
expect_exact: "a.b;"
}
keyword: {
input: {
a. //comment
default
}
expect_exact: "a.default;"
}
atom: {
input: {
a. //comment
true
}
expect_exact: "a.true;"
}

View File

@@ -38,7 +38,7 @@ mixed: {
} }
} }
input: { input: {
var ENV = 3; const ENV = 3;
var FOO = 4; var FOO = 4;
f(ENV * 10); f(ENV * 10);
--FOO; --FOO;
@@ -49,7 +49,7 @@ mixed: {
x = DEBUG; x = DEBUG;
} }
expect: { expect: {
var ENV = 3; const ENV = 3;
var FOO = 4; var FOO = 4;
f(10); f(10);
--FOO; --FOO;
@@ -60,7 +60,7 @@ mixed: {
x = 0; x = 0;
} }
expect_warnings: [ expect_warnings: [
'WARN: global_defs ENV redefined [test/compress/issue-208.js:41,12]', 'WARN: global_defs ENV redefined [test/compress/issue-208.js:41,14]',
'WARN: global_defs FOO redefined [test/compress/issue-208.js:42,12]', 'WARN: global_defs FOO redefined [test/compress/issue-208.js:42,12]',
'WARN: global_defs FOO redefined [test/compress/issue-208.js:44,10]', 'WARN: global_defs FOO redefined [test/compress/issue-208.js:44,10]',
'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:45,8]', 'WARN: global_defs DEBUG redefined [test/compress/issue-208.js:45,8]',

View File

@@ -1,498 +0,0 @@
collapse_vars_constants: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function f1(x) {
var a = 4, b = x.prop, c = 5, d = sideeffect1(), e = sideeffect2();
return b + (function() { return d - a * e - c; })();
}
function f2(x) {
var a = 4, b = x.prop, c = 5, not_used = sideeffect1(), e = sideeffect2();
return b + (function() { return -a * e - c; })();
}
}
expect: {
function f1(x) {
var b = x.prop, d = sideeffect1(), e = sideeffect2();
return b + (d - 4 * e - 5);
}
function f2(x) {
var b = x.prop;
sideeffect1();
return b + (-4 * sideeffect2() - 5);
}
}
}
modified: {
options = {
collapse_vars: true,
inline: true,
unused: true,
}
input: {
function f5(b) {
var a = function() {
return b;
}();
return b++ + a;
}
console.log(f5(1));
}
expect: {
function f5(b) {
var a = b;
return b++ + a;
}
console.log(f5(1));
}
expect_stdout: "2"
}
ref_scope: {
options = {
collapse_vars: true,
inline: true,
unused: true,
}
input: {
console.log(function() {
var a = 1, b = 2, c = 3;
var a = c++, b = b /= a;
return function() {
return a;
}() + b;
}());
}
expect: {
console.log(function() {
var a = 1, b = 2, c = 3;
b = b /= a = c++;
return a + b;
}());
}
expect_stdout: true
}
safe_undefined: {
options = {
conditionals: true,
if_return: true,
inline: true,
unsafe: false,
unused: true,
}
mangle = {}
input: {
var a, c;
console.log(function(undefined) {
return function() {
if (a)
return b;
if (c)
return d;
};
}(1)());
}
expect: {
var a, c;
console.log(a ? b : c ? d : void 0);
}
expect_stdout: true
}
negate_iife_3: {
options = {
conditionals: true,
expression: true,
inline: true,
negate_iife: true,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
t ? console.log(true) : console.log(false);
}
}
negate_iife_3_off: {
options = {
conditionals: true,
expression: true,
inline: true,
negate_iife: false,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
}
expect: {
t ? console.log(true) : console.log(false);
}
}
negate_iife_4: {
options = {
conditionals: true,
expression: true,
inline: true,
negate_iife: true,
sequences: true,
}
input: {
(function(){ return t })() ? console.log(true) : console.log(false);
(function(){
console.log("something");
})();
}
expect: {
t ? console.log(true) : console.log(false), void console.log("something");
}
}
negate_iife_5: {
options = {
conditionals: true,
expression: true,
inline: true,
negate_iife: true,
sequences: true,
}
input: {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
}
(function(){
console.log("something");
})();
}
expect: {
t ? foo(true) : bar(false), void console.log("something");
}
}
negate_iife_5_off: {
options = {
conditionals: true,
expression: true,
inline: true,
negate_iife: false,
sequences: true,
};
input: {
if ((function(){ return t })()) {
foo(true);
} else {
bar(false);
}
(function(){
console.log("something");
})();
}
expect: {
t ? foo(true) : bar(false), void console.log("something");
}
}
issue_1254_negate_iife_true: {
options = {
expression: true,
inline: true,
negate_iife: true,
}
input: {
(function() {
return function() {
console.log('test')
};
})()();
}
expect_exact: 'void console.log("test");'
expect_stdout: true
}
issue_1254_negate_iife_nested: {
options = {
expression: true,
inline: true,
negate_iife: true,
}
input: {
(function() {
return function() {
console.log('test')
};
})()()()()();
}
expect_exact: '(void console.log("test"))()()();'
}
negate_iife_issue_1073: {
options = {
conditionals: true,
evaluate: true,
inline: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
unused: true,
};
input: {
new (function(a) {
return function Foo() {
this.x = a;
console.log(this);
};
}(7))();
}
expect: {
new function() {
this.x = 7,
console.log(this);
}();
}
expect_stdout: true
}
issue_1288_side_effects: {
options = {
conditionals: true,
evaluate: true,
inline: true,
negate_iife: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
};
input: {
if (w) ;
else {
(function f() {})();
}
if (!x) {
(function() {
x = {};
})();
}
if (y)
(function() {})();
else
(function(z) {
return z;
})(0);
}
expect: {
w;
x || (x = {});
y;
}
}
inner_var_for_in_1: {
options = {
evaluate: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
}
input: {
function f() {
var a = 1, b = 2;
for (b in (function() {
return x(a, b, c);
})()) {
var c = 3, d = 4;
x(a, b, c, d);
}
x(a, b, c, d);
}
}
expect: {
function f() {
var a = 1, b = 2;
for (b in x(1, b, c)) {
var c = 3, d = 4;
x(1, b, c, d);
}
x(1, b, c, d);
}
}
}
issue_1595_3: {
options = {
evaluate: true,
inline: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
(function f(a) {
return g(a + 1);
})(2);
}
expect: {
g(3);
}
}
issue_1758: {
options = {
inline: true,
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 c--, c--, void c.toString();
}());
}
expect_stdout: "undefined"
}
wrap_iife: {
options = {
inline: true,
negate_iife: false,
}
beautify = {
wrap_iife: true,
}
input: {
(function() {
return function() {
console.log('test')
};
})()();
}
expect_exact: 'void console.log("test");'
}
wrap_iife_in_expression: {
options = {
inline: true,
negate_iife: false,
}
beautify = {
wrap_iife: true,
}
input: {
foo = (function () {
return bar();
})();
}
expect_exact: 'foo=bar();'
}
wrap_iife_in_return_call: {
options = {
inline: true,
negate_iife: false,
}
beautify = {
wrap_iife: true,
}
input: {
(function() {
return (function() {
console.log('test')
})();
})()();
}
expect_exact: '(void console.log("test"))();'
}
pure_annotation_1: {
options = {
inline: true,
side_effects: true,
}
input: {
/*@__PURE__*/(function() {
console.log("hello");
}());
}
expect_exact: ""
}
pure_annotation_2: {
options = {
collapse_vars: true,
inline: true,
side_effects: true,
}
input: {
/*@__PURE__*/(function(n) {
console.log("hello", n);
}(42));
}
expect_exact: ""
}
drop_fargs: {
options = {
collapse_vars: true,
inline: true,
keep_fargs: false,
side_effects: true,
unused: true,
}
input: {
var a = 1;
!function(a_1) {
a++;
}(a++ + (a && a.var));
console.log(a);
}
expect: {
var a = 1;
++a && a.var, a++;
console.log(a);
}
expect_stdout: "3"
}
keep_fargs: {
options = {
collapse_vars: true,
inline: true,
keep_fargs: true,
side_effects: true,
unused: true,
}
input: {
var a = 1;
!function(a_1) {
a++;
}(a++ + (a && a.var));
console.log(a);
}
expect: {
var a = 1;
++a && a.var, a++;
console.log(a);
}
expect_stdout: "3"
}

View File

@@ -1,6 +1,6 @@
collapse: { collapse: {
options = { options = {
collapse_vars: true, cascade: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
unused: true, unused: true,
@@ -41,7 +41,7 @@ collapse: {
return void 0 !== ('function' === typeof b ? b() : b) && c(); return void 0 !== ('function' === typeof b ? b() : b) && c();
} }
function f2(b) { function f2(b) {
return 'stirng' == typeof ('function' === typeof (b = c()) ? b() : b) && d(); return b = c(), 'stirng' == typeof ('function' === typeof b ? b() : b) && d();
} }
function f3(c) { function f3(c) {
var a; var a;

View File

@@ -17,6 +17,6 @@ wrongly_optimized: {
foo(); foo();
} }
// TODO: optimize to `func(), bar()` // TODO: optimize to `func(), bar()`
(func(), 1) && bar(); (func(), 0) || bar();
} }
} }

View File

@@ -100,7 +100,7 @@ wrongly_optimized: {
foo(); foo();
} }
// TODO: optimize to `func(), bar()` // TODO: optimize to `func(), bar()`
if (func(), 1) bar(); if (func(), !0) bar();
} }
} }
@@ -159,7 +159,7 @@ negate_iife_4: {
})(); })();
} }
expect: { expect: {
!function(){ return t }() ? console.log(false) : console.log(true), function(){ (function(){ return t })() ? console.log(true) : console.log(false), function(){
console.log("something"); console.log("something");
}(); }();
} }
@@ -183,7 +183,7 @@ negate_iife_5: {
})(); })();
} }
expect: { expect: {
!function(){ return t }() ? bar(false) : foo(true), function(){ (function(){ return t })() ? foo(true) : bar(false), function(){
console.log("something"); console.log("something");
}(); }();
} }
@@ -207,7 +207,7 @@ negate_iife_5_off: {
})(); })();
} }
expect: { expect: {
!function(){ return t }() ? bar(false) : foo(true), function(){ (function(){ return t })() ? foo(true) : bar(false), function(){
console.log("something"); console.log("something");
}(); }();
} }

View File

@@ -1,45 +1,37 @@
dont_reuse_prop: { dont_reuse_prop: {
mangle = { mangle_props = {
properties: { regex: /asd/
regex: /asd/, };
},
}
input: { input: {
"aaaaaaaaaabbbbb";
var obj = {}; var obj = {};
obj.a = 123; obj.a = 123;
obj.asd = 256; obj.asd = 256;
console.log(obj.a); console.log(obj.a);
} }
expect: { expect: {
"aaaaaaaaaabbbbb";
var obj = {}; var obj = {};
obj.a = 123; obj.a = 123;
obj.b = 256; obj.b = 256;
console.log(obj.a); console.log(obj.a);
} }
expect_stdout: "123"
} }
unmangleable_props_should_always_be_reserved: { unmangleable_props_should_always_be_reserved: {
mangle = { mangle_props = {
properties: { regex: /asd/
regex: /asd/, };
},
}
input: { input: {
"aaaaaaaaaabbbbb";
var obj = {}; var obj = {};
obj.asd = 256; obj.asd = 256;
obj.a = 123; obj.a = 123;
console.log(obj.a); console.log(obj.a);
} }
expect: { expect: {
"aaaaaaaaaabbbbb";
var obj = {}; var obj = {};
obj.b = 256; obj.b = 256;
obj.a = 123; obj.a = 123;
console.log(obj.a); console.log(obj.a);
} }
expect_stdout: "123"
} }

View File

@@ -18,6 +18,7 @@ dont_mangle_arguments: {
hoist_vars : true, hoist_vars : true,
if_return : true, if_return : true,
join_vars : true, join_vars : true,
cascade : true,
side_effects : true, side_effects : true,
negate_iife : false negate_iife : false
}; };

View File

@@ -1,8 +1,7 @@
this_binding_conditionals: { this_binding_conditionals: {
options = { options = {
conditionals: true, conditionals: true,
evaluate: true, evaluate : true
side_effects: true,
}; };
input: { input: {
(1 && a)(); (1 && a)();
@@ -52,7 +51,6 @@ this_binding_collapse_vars: {
options = { options = {
collapse_vars: true, collapse_vars: true,
toplevel: true, toplevel: true,
unused: true,
}; };
input: { input: {
var c = a; c(); var c = a; c();

View File

@@ -2,7 +2,7 @@ eval_collapse_vars: {
options = { options = {
collapse_vars:true, sequences:false, properties:true, dead_code:true, conditionals:true, collapse_vars:true, sequences:false, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, side_effects:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
}; };
input: { input: {
function f1() { function f1() {

View File

@@ -2,7 +2,7 @@ issue979_reported: {
options = { options = {
sequences:true, properties:true, dead_code:true, conditionals:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, side_effects:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
} }
input: { input: {
function f1() { function f1() {
@@ -32,7 +32,7 @@ issue979_test_negated_is_best: {
options = { options = {
sequences:true, properties:true, dead_code:true, conditionals:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
keep_fargs:true, if_return:true, join_vars:true, side_effects:true keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
} }
input: { input: {
function f3() { function f3() {

View File

@@ -146,13 +146,55 @@ parse_do_while_without_semicolon: {
} }
} }
keep_collapse_const_in_own_block_scope: {
options = {
join_vars: true,
loops: true
}
input: {
var i=2;
const c=5;
while(i--)
console.log(i);
console.log(c);
}
expect: {
var i=2;
const c=5;
for(;i--;)
console.log(i);
console.log(c);
}
expect_stdout: true
}
keep_collapse_const_in_own_block_scope_2: {
options = {
join_vars: true,
loops: true
}
input: {
const c=5;
var i=2; // Moves to loop, while it did not in previous test
while(i--)
console.log(i);
console.log(c);
}
expect: {
const c=5;
for(var i=2;i--;)
console.log(i);
console.log(c);
}
expect_stdout: true
}
evaluate: { evaluate: {
options = { options = {
loops: true,
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
loops: true,
passes: 2,
side_effects: true,
}; };
input: { input: {
while (true) { while (true) {
@@ -203,7 +245,7 @@ issue_1532: {
issue_186: { issue_186: {
beautify = { beautify = {
beautify: false, beautify: false,
ie8: false, screw_ie8: true,
} }
input: { input: {
var x = 3; var x = 3;
@@ -222,7 +264,7 @@ issue_186: {
issue_186_ie8: { issue_186_ie8: {
beautify = { beautify = {
beautify: false, beautify: false,
ie8: true, screw_ie8: false,
} }
input: { input: {
var x = 3; var x = 3;
@@ -241,7 +283,7 @@ issue_186_ie8: {
issue_186_beautify: { issue_186_beautify: {
beautify = { beautify = {
beautify: true, beautify: true,
ie8: false, screw_ie8: true,
} }
input: { input: {
var x = 3; var x = 3;
@@ -268,7 +310,7 @@ issue_186_beautify: {
issue_186_beautify_ie8: { issue_186_beautify_ie8: {
beautify = { beautify = {
beautify: true, beautify: true,
ie8: true, screw_ie8: false,
} }
input: { input: {
var x = 3; var x = 3;
@@ -298,7 +340,7 @@ issue_186_bracketize: {
beautify = { beautify = {
beautify: false, beautify: false,
bracketize: true, bracketize: true,
ie8: false, screw_ie8: true,
} }
input: { input: {
var x = 3; var x = 3;
@@ -318,7 +360,7 @@ issue_186_bracketize_ie8: {
beautify = { beautify = {
beautify: false, beautify: false,
bracketize: true, bracketize: true,
ie8: true, screw_ie8: false,
} }
input: { input: {
var x = 3; var x = 3;
@@ -338,7 +380,7 @@ issue_186_beautify_bracketize: {
beautify = { beautify = {
beautify: true, beautify: true,
bracketize: true, bracketize: true,
ie8: false, screw_ie8: true,
} }
input: { input: {
var x = 3; var x = 3;
@@ -370,7 +412,7 @@ issue_186_beautify_bracketize_ie8: {
beautify = { beautify = {
beautify: true, beautify: true,
bracketize: true, bracketize: true,
ie8: true, screw_ie8: false,
} }
input: { input: {
var x = 3; var x = 3;
@@ -438,57 +480,3 @@ do_switch: {
} while (false); } while (false);
} }
} }
in_parenthesis_1: {
input: {
for (("foo" in {});0;);
}
expect_exact: 'for(("foo"in{});0;);'
}
in_parenthesis_2: {
input: {
for ((function(){ "foo" in {}; });0;);
}
expect_exact: 'for(function(){"foo"in{}};0;);'
}
init_side_effects: {
options = {
loops: true,
side_effects: true,
};
input: {
for (function() {}(), i = 0; i < 5; i++) console.log(i);
for (function() {}(); i < 10; i++) console.log(i);
}
expect: {
for (i = 0; i < 5; i++) console.log(i);
for (; i < 10; i++) console.log(i);
}
expect_stdout: true
}
dead_code_condition: {
options = {
dead_code: true,
evaluate: true,
loops: true,
sequences: true,
}
input: {
for (var a = 0, b = 5; (a += 1, 3) - 3 && b > 0; b--) {
var c = function() {
b--;
}(a++);
}
console.log(a);
}
expect: {
var c;
var a = 0, b = 5;
a += 1, 0,
console.log(a);
}
expect_stdout: "1"
}

View File

@@ -22,25 +22,27 @@ negate_iife_1_off: {
negate_iife_2: { negate_iife_2: {
options = { options = {
inline: true, negate_iife: true
negate_iife: true,
}; };
input: { input: {
(function(){ return {} })().x = 10; // should not transform this one
}
expect: {
(function(){ return {} })().x = 10; (function(){ return {} })().x = 10;
} }
expect_exact: "({}).x=10;"
} }
negate_iife_2_side_effects: { negate_iife_2_side_effects: {
options = { options = {
inline: true,
negate_iife: true, negate_iife: true,
side_effects: true, side_effects: true,
} }
input: { input: {
(function(){ return {} })().x = 10; // should not transform this one
}
expect: {
(function(){ return {} })().x = 10; (function(){ return {} })().x = 10;
} }
expect_exact: "({}).x=10;"
} }
negate_iife_3: { negate_iife_3: {
@@ -60,7 +62,6 @@ negate_iife_3_evaluate: {
options = { options = {
conditionals: true, conditionals: true,
evaluate: true, evaluate: true,
inline: true,
negate_iife: true, negate_iife: true,
} }
input: { input: {
@@ -103,7 +104,6 @@ negate_iife_3_off_evaluate: {
options = { options = {
conditionals: true, conditionals: true,
evaluate: true, evaluate: true,
inline: true,
negate_iife: false, negate_iife: false,
} }
input: { input: {

View File

@@ -82,19 +82,3 @@ new_with_unary_prefix: {
} }
expect_exact: 'var bar=(+new Date).toString(32);'; expect_exact: 'var bar=(+new Date).toString(32);';
} }
dot_parenthesis_1: {
input: {
console.log(new (Math.random().constructor) instanceof Number);
}
expect_exact: "console.log(new(Math.random().constructor)instanceof Number);"
expect_stdout: "true"
}
dot_parenthesis_2: {
input: {
console.log(typeof new function(){Math.random()}.constructor);
}
expect_exact: "console.log(typeof new function(){Math.random()}.constructor);"
expect_stdout: "function"
}

View File

@@ -1,38 +0,0 @@
eval_let_6: {
input: {
eval("let a;");
console.log();
}
expect: {
eval("let a;");
console.log();
}
expect_stdout: ""
node_version: ">=6"
}
eval_let_4: {
input: {
eval("let a;");
console.log();
}
expect: {
eval("let a;");
console.log();
}
expect_stdout: SyntaxError("Block-scoped declarations (let, const, function, class) not yet supported outside strict mode")
node_version: "4"
}
eval_let_0: {
input: {
eval("let a;");
console.log();
}
expect: {
eval("let a;");
console.log();
}
expect_stdout: SyntaxError("Unexpected identifier")
node_version: "<=0.12"
}

View File

@@ -1,8 +1,7 @@
keep_properties: { keep_properties: {
options = { options = {
evaluate: true, properties: false
properties: false, };
}
input: { input: {
a["foo"] = "bar"; a["foo"] = "bar";
} }
@@ -13,12 +12,9 @@ keep_properties: {
dot_properties: { dot_properties: {
options = { options = {
evaluate: true,
properties: true, properties: true,
} screw_ie8: false
beautify = { };
ie8: true,
}
input: { input: {
a["foo"] = "bar"; a["foo"] = "bar";
a["if"] = "if"; a["if"] = "if";
@@ -39,12 +35,9 @@ dot_properties: {
dot_properties_es5: { dot_properties_es5: {
options = { options = {
evaluate: true,
properties: true, properties: true,
} screw_ie8: true
beautify = { };
ie8: false,
}
input: { input: {
a["foo"] = "bar"; a["foo"] = "bar";
a["if"] = "if"; a["if"] = "if";
@@ -64,8 +57,8 @@ dot_properties_es5: {
sub_properties: { sub_properties: {
options = { options = {
evaluate: true, evaluate: true,
properties: true, properties: true
} };
input: { input: {
a[0] = 0; a[0] = 0;
a["0"] = 1; a["0"] = 1;
@@ -84,18 +77,18 @@ sub_properties: {
a[3.14] = 3; a[3.14] = 3;
a.if = 4; a.if = 4;
a["foo bar"] = 5; a["foo bar"] = 5;
a.NaN = 6; a[NaN] = 6;
a.null = 7; a[null] = 7;
a[void 0] = 8; a[void 0] = 8;
} }
} }
evaluate_array_length: { evaluate_array_length: {
options = { options = {
evaluate: true,
properties: true, properties: true,
unsafe: true, unsafe: true,
} evaluate: true
};
input: { input: {
a = [1, 2, 3].length; a = [1, 2, 3].length;
a = [1, 2, 3].join()["len" + "gth"]; a = [1, 2, 3].join()["len" + "gth"];
@@ -112,10 +105,10 @@ evaluate_array_length: {
evaluate_string_length: { evaluate_string_length: {
options = { options = {
evaluate: true,
properties: true, properties: true,
unsafe: true, unsafe: true,
} evaluate: true
};
input: { input: {
a = "foo".length; a = "foo".length;
a = ("foo" + "bar")["len" + "gth"]; a = ("foo" + "bar")["len" + "gth"];
@@ -131,11 +124,9 @@ evaluate_string_length: {
} }
mangle_properties: { mangle_properties: {
mangle = { mangle_props = {
properties: { ignore_quoted: false
keep_quoted: false, };
},
}
input: { input: {
a["foo"] = "bar"; a["foo"] = "bar";
a.color = "red"; a.color = "red";
@@ -146,21 +137,18 @@ mangle_properties: {
expect: { expect: {
a["a"] = "bar"; a["a"] = "bar";
a.b = "red"; a.b = "red";
x = {o: 10}; x = {c: 10};
a.r(x.o, a.a); a.d(x.c, a.a);
a['r']({b: "blue", a: "baz"}); a['d']({b: "blue", a: "baz"});
} }
} }
mangle_unquoted_properties: { mangle_unquoted_properties: {
options = { options = {
evaluate: true, properties: false
properties: false,
} }
mangle = { mangle_props = {
properties: { ignore_quoted: true
keep_quoted: true,
},
} }
beautify = { beautify = {
beautify: false, beautify: false,
@@ -189,26 +177,24 @@ mangle_unquoted_properties: {
function f1() { function f1() {
a["foo"] = "bar"; a["foo"] = "bar";
a.color = "red"; a.color = "red";
a.r = 2; a.b = 2;
x = {"bar": 10, b: 7}; x = {"bar": 10, c: 7};
a.b = 9; a.c = 9;
} }
function f2() { function f2() {
a.foo = "bar"; a.foo = "bar";
a['color'] = "red"; a['color'] = "red";
x = {bar: 10, b: 7}; x = {bar: 10, c: 7};
a.b = 9; a.c = 9;
a.r = 3; a.b = 3;
} }
} }
} }
mangle_debug: { mangle_debug: {
mangle = { mangle_props = {
properties: { debug: ""
debug: "", };
},
}
input: { input: {
a.foo = "bar"; a.foo = "bar";
x = { baz: "ban" }; x = { baz: "ban" };
@@ -220,11 +206,9 @@ mangle_debug: {
} }
mangle_debug_true: { mangle_debug_true: {
mangle = { mangle_props = {
properties: { debug: true
debug: true, };
},
}
input: { input: {
a.foo = "bar"; a.foo = "bar";
x = { baz: "ban" }; x = { baz: "ban" };
@@ -236,11 +220,9 @@ mangle_debug_true: {
} }
mangle_debug_suffix: { mangle_debug_suffix: {
mangle = { mangle_props = {
properties: { debug: "XYZ"
debug: "XYZ", };
},
}
input: { input: {
a.foo = "bar"; a.foo = "bar";
x = { baz: "ban" }; x = { baz: "ban" };
@@ -251,17 +233,14 @@ mangle_debug_suffix: {
} }
} }
mangle_debug_suffix_keep_quoted: { mangle_debug_suffix_ignore_quoted: {
options = { options = {
evaluate: true, properties: false
properties: false,
} }
mangle = { mangle_props = {
properties: { ignore_quoted: true,
debug: "XYZ", debug: "XYZ",
keep_quoted: true, reserved: []
reserved: [],
},
} }
beautify = { beautify = {
beautify: false, beautify: false,
@@ -576,521 +555,3 @@ native_prototype: {
"".indexOf.call(e, "bar"); "".indexOf.call(e, "bar");
} }
} }
accessor_boolean: {
input: {
var a = 1;
var b = {
get true() {
return a;
},
set false(c) {
a = c;
}
};
console.log(b.true, b.false = 2, b.true);
}
expect_exact: 'var a=1;var b={get true(){return a},set false(c){a=c}};console.log(b.true,b.false=2,b.true);'
expect_stdout: "1 2 2"
}
accessor_get_set: {
input: {
var a = 1;
var b = {
get set() {
return a;
},
set get(c) {
a = c;
}
};
console.log(b.set, b.get = 2, b.set);
}
expect_exact: 'var a=1;var b={get set(){return a},set get(c){a=c}};console.log(b.set,b.get=2,b.set);'
expect_stdout: "1 2 2"
}
accessor_null_undefined: {
input: {
var a = 1;
var b = {
get null() {
return a;
},
set undefined(c) {
a = c;
}
};
console.log(b.null, b.undefined = 2, b.null);
}
expect_exact: 'var a=1;var b={get null(){return a},set undefined(c){a=c}};console.log(b.null,b.undefined=2,b.null);'
expect_stdout: "1 2 2"
}
accessor_number: {
input: {
var a = 1;
var b = {
get 42() {
return a;
},
set 42(c) {
a = c;
}
};
console.log(b[42], b[42] = 2, b[42]);
}
expect_exact: 'var a=1;var b={get 42(){return a},set 42(c){a=c}};console.log(b[42],b[42]=2,b[42]);'
expect_stdout: "1 2 2"
}
accessor_string: {
input: {
var a = 1;
var b = {
get "a-b"() {
return a;
},
set "a-b"(c) {
a = c;
}
};
console.log(b["a-b"], b["a-b"] = 2, b["a-b"]);
}
expect_exact: 'var a=1;var b={get"a-b"(){return a},set"a-b"(c){a=c}};console.log(b["a-b"],b["a-b"]=2,b["a-b"]);'
expect_stdout: "1 2 2"
}
accessor_this: {
input: {
var a = 1;
var b = {
get this() {
return a;
},
set this(c) {
a = c;
}
};
console.log(b.this, b.this = 2, b.this);
}
expect_exact: 'var a=1;var b={get this(){return a},set this(c){a=c}};console.log(b.this,b.this=2,b.this);'
expect_stdout: "1 2 2"
}
issue_2208_1: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
console.log({
p: function() {
return 42;
}
}.p());
}
expect: {
console.log(42);
}
expect_stdout: "42"
}
issue_2208_2: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
console.log({
a: 42,
p: function() {
return this.a;
}
}.p());
}
expect: {
console.log({
a: 42,
p: function() {
return this.a;
}
}.p());
}
expect_stdout: "42"
}
issue_2208_3: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
a = 42;
console.log({
p: function() {
return function() {
return this.a;
}();
}
}.p());
}
expect: {
a = 42;
console.log(function() {
return this.a;
}());
}
expect_stdout: "42"
}
issue_2208_4: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
function foo() {}
console.log({
a: foo(),
p: function() {
return 42;
}
}.p());
}
expect: {
function foo() {}
console.log((foo(), function() {
return 42;
})());
}
expect_stdout: "42"
}
issue_2208_5: {
options = {
inline: true,
properties: true,
side_effects: true,
}
input: {
console.log({
p: "FAIL",
p: function() {
return 42;
}
}.p());
}
expect: {
console.log(42);
}
expect_stdout: "42"
}
issue_2256: {
options = {
side_effects: true,
}
mangle = {
properties: {
keep_quoted: true,
},
}
input: {
({ "keep": 1 });
g.keep = g.change;
}
expect: {
g.keep = g.g;
}
}
lhs_prop_1: {
options = {
evaluate: true,
properties: true,
}
input: {
console.log(++{
a: 1
}.a);
}
expect: {
console.log(++{
a: 1
}.a);
}
expect_stdout: "2"
}
lhs_prop_2: {
options = {
evaluate: true,
inline: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
[1][0] = 42;
(function(a) {
a.b = "g";
})("abc");
(function(a) {
a[2] = "g";
})("def");
(function(a) {
a[""] = "g";
})("ghi");
}
expect: {
[1][0] = 42;
"abc".b = "g";
"def"[2] = "g";
"ghi"[""] = "g";
}
}
literal_duplicate_key_side_effects: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log({
a: "FAIL",
a: console.log ? "PASS" : "FAIL"
}.a);
}
expect: {
console.log(console.log ? "PASS" : "FAIL");
}
expect_stdout: "PASS"
}
prop_side_effects_1: {
options = {
evaluate: true,
inline: true,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var C = 1;
console.log(C);
var obj = {
bar: function() {
return C + C;
}
};
console.log(obj.bar());
}
expect: {
console.log(1);
var obj = {
bar: function() {
return 2;
}
};
console.log(obj.bar());
}
expect_stdout: [
"1",
"2",
]
}
prop_side_effects_2: {
options = {
evaluate: true,
inline: true,
passes: 2,
properties: true,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var C = 1;
console.log(C);
var obj = {
"": function() {
return C + C;
}
};
console.log(obj[""]());
}
expect: {
console.log(1);
console.log(2);
}
expect_stdout: [
"1",
"2",
]
}
accessor_1: {
options = {
properties: true,
}
input: {
console.log({
a: "FAIL",
get a() {
return "PASS";
}
}.a);
}
expect: {
console.log({
a: "FAIL",
get a() {
return "PASS";
}
}.a);
}
expect_stdout: "PASS"
node_version: ">=4"
}
accessor_2: {
options = {
properties: true,
}
input: {
console.log({
get a() {
return "PASS";
},
set a(v) {},
a: "FAIL"
}.a);
}
expect: {
console.log({
get a() {
return "PASS";
},
set a(v) {},
a: "FAIL"
}.a);
}
expect_stdout: true
}
array_hole: {
options = {
properties: true,
side_effects: true,
}
input: {
console.log(
[ 1, 2, , 3][1],
[ 1, 2, , 3][2],
[ 1, 2, , 3][3]
);
}
expect: {
console.log(2, void 0, 3);
}
expect_stdout: "2 undefined 3"
}
new_this: {
options = {
properties: true,
side_effects: true,
}
input: {
new {
f: function(a) {
this.a = a;
}
}.f(42);
}
expect: {
new function(a) {
this.a = a;
}(42);
}
}
issue_2513: {
options = {
evaluate: true,
properties: true,
}
input: {
!function(Infinity, NaN, undefined) {
console.log("a"[1/0], "b"["Infinity"]);
console.log("c"[0/0], "d"["NaN"]);
console.log("e"[void 0], "f"["undefined"]);
}(0, 0, 0);
}
expect: {
!function(Infinity, NaN, undefined) {
console.log("a"[1/0], "b"[1/0]);
console.log("c".NaN, "d".NaN);
console.log("e"[void 0], "f"[void 0]);
}(0, 0, 0);
}
expect_stdout: [
"undefined undefined",
"undefined undefined",
"undefined undefined",
]
}
const_prop_assign_strict: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
function Simulator() {
/abc/.index = 1;
this._aircraft = [];
}
(function() {}).prototype.destroy = x();
}
expect: {
function Simulator() {
this._aircraft = [];
}
x();
}
}
const_prop_assign_pure: {
options = {
pure_getters: true,
side_effects: true,
}
input: {
function Simulator() {
/abc/.index = 1;
this._aircraft = [];
}
(function() {}).prototype.destroy = x();
}
expect: {
function Simulator() {
this._aircraft = [];
}
x();
}
}

View File

@@ -293,124 +293,3 @@ unary: {
bar(); bar();
} }
} }
issue_2629_1: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/ a();
/*@__PURE__*/ (b());
(/*@__PURE__*/ c)();
(/*@__PURE__*/ d());
}
expect_exact: [
"/* */c();",
]
}
issue_2629_2: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/ a(1)(2)(3);
/*@__PURE__*/ (b(1))(2)(3);
/*@__PURE__*/ (c(1)(2))(3);
/*@__PURE__*/ (d(1)(2)(3));
(/*@__PURE__*/ e)(1)(2)(3);
(/*@__PURE__*/ f(1))(2)(3);
(/*@__PURE__*/ g(1)(2))(3);
(/*@__PURE__*/ h(1)(2)(3));
}
expect_exact: [
"/* */e(1)(2)(3);",
"/* */f(1)(2)(3);",
"/* */g(1)(2)(3);",
]
}
issue_2629_3: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/ a.x(1).y(2).z(3);
/*@__PURE__*/ (b.x)(1).y(2).z(3);
/*@__PURE__*/ (c.x(1)).y(2).z(3);
/*@__PURE__*/ (d.x(1).y)(2).z(3);
/*@__PURE__*/ (e.x(1).y(2)).z(3);
/*@__PURE__*/ (f.x(1).y(2).z)(3);
/*@__PURE__*/ (g.x(1).y(2).z(3));
(/*@__PURE__*/ h).x(1).y(2).z(3);
(/*@__PURE__*/ i.x)(1).y(2).z(3);
(/*@__PURE__*/ j.x(1)).y(2).z(3);
(/*@__PURE__*/ k.x(1).y)(2).z(3);
(/*@__PURE__*/ l.x(1).y(2)).z(3);
(/*@__PURE__*/ m.x(1).y(2).z)(3);
(/*@__PURE__*/ n.x(1).y(2).z(3));
}
expect_exact: [
"/* */h.x(1).y(2).z(3);",
"/* */i.x(1).y(2).z(3);",
"/* */j.x(1).y(2).z(3);",
"/* */k.x(1).y(2).z(3);",
"/* */l.x(1).y(2).z(3);",
"/* */m.x(1).y(2).z(3);",
]
}
issue_2629_4: {
options = {
side_effects: true,
}
input: {
(/*@__PURE__*/ x(), y());
(w(), /*@__PURE__*/ x(), y());
}
expect: {
y();
w(), y();
}
}
issue_2629_5: {
options = {
side_effects: true,
}
input: {
[ /*@__PURE__*/ x() ];
[ /*@__PURE__*/ x(), y() ];
[ w(), /*@__PURE__*/ x(), y() ];
}
expect: {
y();
w(), y();
}
}
issue_2638: {
options = {
side_effects: true,
}
beautify = {
comments: "all",
}
input: {
/*@__PURE__*/(g() || h())(x(), y());
(/*@__PURE__*/ (a() || b()))(c(), d());
}
expect_exact: [
"/* */x(),y();",
"/* */(a()||b())(c(),d());",
]
}

View File

@@ -1,7 +1,6 @@
strict: { strict: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: false,
reduce_vars: false, reduce_vars: false,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -31,7 +30,6 @@ strict: {
strict_reduce_vars: { strict_reduce_vars: {
options = { options = {
pure_getters: "strict", pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -60,7 +58,6 @@ strict_reduce_vars: {
unsafe: { unsafe: {
options = { options = {
pure_getters: true, pure_getters: true,
reduce_funcs: false,
reduce_vars: false, reduce_vars: false,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -87,7 +84,6 @@ unsafe: {
unsafe_reduce_vars: { unsafe_reduce_vars: {
options = { options = {
pure_getters: true, pure_getters: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
toplevel: true, toplevel: true,
@@ -123,491 +119,3 @@ chained: {
a.b.c; a.b.c;
} }
} }
impure_getter_1: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
({
get a() {
console.log(1);
},
b: 1
}).a;
({
get a() {
console.log(1);
},
b: 1
}).b;
}
expect: {
({
get a() {
console.log(1);
},
b: 1
}).a;
({
get a() {
console.log(1);
},
b: 1
}).b;
}
expect_stdout: "1"
}
impure_getter_2: {
options = {
pure_getters: true,
side_effects: true,
}
input: {
// will produce incorrect output because getter is not pure
({
get a() {
console.log(1);
},
b: 1
}).a;
({
get a() {
console.log(1);
},
b: 1
}).b;
}
expect: {}
}
issue_2110_1: {
options = {
collapse_vars: true,
pure_getters: "strict",
sequences: true,
side_effects: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
function f() {}
function g() {
return this;
}
f.g = g;
return f.g();
}
console.log(typeof f());
}
expect: {
function f() {
function f() {}
return f.g = function() {
return this;
}, f.g();
}
console.log(typeof f());
}
expect_stdout: "function"
}
issue_2110_2: {
options = {
collapse_vars: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
function f() {}
function g() {
return this;
}
f.g = g;
return f.g();
}
console.log(typeof f());
}
expect: {
function f() {
function f() {}
f.g = function() {
return this;
};
return f.g();
}
console.log(typeof f());
}
expect_stdout: "function"
}
set_immutable_1: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var a = 1;
a.foo += "";
if (a.foo) console.log("FAIL");
else console.log("PASS");
}
expect: {
1..foo += "";
if (1..foo) console.log("FAIL");
else console.log("PASS");
}
expect_stdout: "PASS"
}
set_immutable_2: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
}
input: {
var a = 1;
a.foo += "";
if (a.foo) console.log("FAIL");
else console.log("PASS");
}
expect: {
var a = 1;
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
}
expect_stdout: "PASS"
}
set_immutable_3: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
"use strict";
var a = 1;
a.foo += "";
if (a.foo) console.log("FAIL");
else console.log("PASS");
}
expect: {
"use strict";
1..foo += "";
if (1..foo) console.log("FAIL");
else console.log("PASS");
}
expect_stdout: true
}
set_immutable_4: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
}
input: {
"use strict";
var a = 1;
a.foo += "";
if (a.foo) console.log("FAIL");
else console.log("PASS");
}
expect: {
"use strict";
var a = 1;
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
}
expect_stdout: true
}
set_mutable_1: {
options = {
collapse_vars: true,
evaluate: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
!function a() {
a.foo += "";
if (a.foo) console.log("PASS");
else console.log("FAIL");
}();
}
expect: {
!function a() {
if (a.foo += "") console.log("PASS");
else console.log("FAIL");
}();
}
expect_stdout: "PASS"
}
set_mutable_2: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
}
input: {
!function a() {
a.foo += "";
if (a.foo) console.log("PASS");
else console.log("FAIL");
}();
}
expect: {
!function a() {
(a.foo += "") ? console.log("PASS") : console.log("FAIL");
}();
}
expect_stdout: "PASS"
}
issue_2313_1: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
sequences: true,
side_effects: true,
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
return console.log(1), {
y: function() {
return console.log(2), {
z: 0
};
}
};
}
x().y().z++,
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_2: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: true,
sequences: true,
side_effects: true,
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
return console.log(1), {
y: function() {
return console.log(2), {
z: 0
};
}
};
}
x().y().z++,
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_3: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: "strict",
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_4: {
options = {
collapse_vars: true,
conditionals: true,
pure_getters: true,
}
input: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
if (x().y().z) {
console.log(3);
}
}
expect: {
function x() {
console.log(1);
return {
y: function() {
console.log(2);
return {
z: 0
};
}
};
}
x().y().z++;
x().y().z && console.log(3);
}
expect_stdout: [
"1",
"2",
"1",
"2",
]
}
issue_2313_5: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
x().y++;
x().y;
}
expect: {
x().y++;
x().y;
}
}
issue_2313_6: {
options = {
pure_getters: true,
side_effects: true,
}
input: {
x().y++;
x().y;
}
expect: {
x().y++;
x();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,536 +0,0 @@
mangle_catch: {
rename = true
options = {
ie8: false,
toplevel: false,
}
mangle = {
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(o){a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_ie8: {
rename = true
options = {
ie8: true,
toplevel: false,
}
mangle = {
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(args){a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_var: {
rename = true
options = {
ie8: false,
toplevel: false,
}
mangle = {
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(o){var a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_var_ie8: {
rename = true
options = {
ie8: true,
toplevel: false,
}
mangle = {
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(args){var a="PASS"}console.log(a);'
expect_stdout: "PASS"
}
mangle_catch_toplevel: {
rename = true
options = {
ie8: false,
toplevel: true,
}
mangle = {
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_ie8_toplevel: {
rename = true
options = {
ie8: true,
toplevel: true,
}
mangle = {
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_var_toplevel: {
rename = true
options = {
ie8: false,
toplevel: true,
}
mangle = {
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_var_ie8_toplevel: {
rename = true
options = {
ie8: true,
toplevel: true,
}
mangle = {
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_redef_1: {
rename = true
options = {
ie8: false,
toplevel: false,
}
mangle = {
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_ie8: {
rename = true
options = {
ie8: true,
toplevel: false,
}
mangle = {
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_toplevel: {
rename = true
options = {
ie8: false,
toplevel: true,
}
mangle = {
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_1_ie8_toplevel: {
rename = true
options = {
ie8: true,
toplevel: true,
}
mangle = {
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_2: {
rename = true
options = {
ie8: false,
toplevel: false,
}
mangle = {
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_ie8: {
rename = true
options = {
ie8: true,
toplevel: false,
}
mangle = {
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_toplevel: {
rename = true
options = {
ie8: false,
toplevel: true,
}
mangle = {
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"
}
mangle_catch_redef_2_ie8_toplevel: {
rename = true
options = {
ie8: true,
toplevel: true,
}
mangle = {
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"
}
issue_2120_1: {
rename = true
mangle = {
ie8: false,
}
input: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (c) {
try {
throw 0;
} catch (a) {
if (c) b = "PASS";
}
}
console.log(b);
}
expect: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (t) {
try {
throw 0;
} catch (a) {
if (t) b = "PASS";
}
}
console.log(b);
}
expect_stdout: "PASS"
}
issue_2120_2: {
rename = true
mangle = {
ie8: true,
}
input: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (c) {
try {
throw 0;
} catch (a) {
if (c) b = "PASS";
}
}
console.log(b);
}
expect: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (c) {
try {
throw 0;
} catch (a) {
if (c) b = "PASS";
}
}
console.log(b);
}
expect_stdout: "PASS"
}
function_iife_catch: {
rename = true
mangle = {
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(c){var o=1;console.log(c,o)}}()}f();"
expect_stdout: "0 1"
}
function_iife_catch_ie8: {
rename = true
mangle = {
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(o){var c=1;console.log(o,c)}}()}f();"
expect_stdout: "0 1"
}
function_catch_catch: {
rename = true
mangle = {
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",
]
}
function_catch_catch_ie8: {
rename = true
mangle = {
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",
]
}

View File

@@ -17,6 +17,7 @@ return_undefined: {
keep_fnames : false, keep_fnames : false,
hoist_vars : true, hoist_vars : true,
join_vars : true, join_vars : true,
cascade : true,
negate_iife : true negate_iife : true
}; };
input: { input: {
@@ -121,25 +122,3 @@ return_undefined: {
} }
} }
} }
return_void: {
options = {
if_return: true,
inline: true,
reduce_vars: true,
unused: true,
}
input: {
function f() {
function g() {
h();
}
return g();
}
}
expect: {
function f() {
h();
}
}
}

View File

@@ -1,14 +0,0 @@
console_log: {
input: {
console.log("%% %s");
console.log("%% %s", "%s");
}
expect: {
console.log("%% %s");
console.log("%% %s", "%s");
}
expect_stdout: [
"%% %s",
"% %s",
]
}

View File

@@ -1,9 +1,9 @@
do_screw: { do_screw: {
options = { options = {
ie8: false, screw_ie8: true,
} }
beautify = { beautify = {
ie8: false, screw_ie8: true,
ascii_only: true, ascii_only: true,
} }
input: { input: {
@@ -14,10 +14,10 @@ do_screw: {
dont_screw: { dont_screw: {
options = { options = {
ie8: true, screw_ie8: false,
} }
beautify = { beautify = {
ie8: true, screw_ie8: false,
ascii_only: true, ascii_only: true,
} }
input: { input: {
@@ -28,7 +28,7 @@ dont_screw: {
do_screw_constants: { do_screw_constants: {
options = { options = {
ie8: false, screw_ie8: true,
} }
input: { input: {
f(undefined, Infinity); f(undefined, Infinity);
@@ -38,7 +38,7 @@ do_screw_constants: {
dont_screw_constants: { dont_screw_constants: {
options = { options = {
ie8: true, screw_ie8: false,
} }
input: { input: {
f(undefined, Infinity); f(undefined, Infinity);
@@ -47,15 +47,9 @@ dont_screw_constants: {
} }
do_screw_try_catch: { do_screw_try_catch: {
options = { options = { screw_ie8: true };
ie8: false, mangle = { screw_ie8: true };
} beautify = { screw_ie8: true };
mangle = {
ie8: false,
}
beautify = {
ie8: false,
}
input: { input: {
good = function(e){ good = function(e){
return function(error){ return function(error){
@@ -81,15 +75,9 @@ do_screw_try_catch: {
} }
dont_screw_try_catch: { dont_screw_try_catch: {
options = { options = { screw_ie8: false };
ie8: true, mangle = { screw_ie8: false };
} beautify = { screw_ie8: false };
mangle = {
ie8: true,
}
beautify = {
ie8: true,
}
input: { input: {
bad = function(e){ bad = function(e){
return function(error){ return function(error){
@@ -115,15 +103,9 @@ dont_screw_try_catch: {
} }
do_screw_try_catch_undefined: { do_screw_try_catch_undefined: {
options = { options = { screw_ie8: true };
ie8: false, mangle = { screw_ie8: true };
} beautify = { screw_ie8: true };
mangle = {
ie8: false,
}
beautify = {
ie8: false,
}
input: { input: {
function a(b){ function a(b){
try { try {
@@ -150,15 +132,9 @@ do_screw_try_catch_undefined: {
} }
dont_screw_try_catch_undefined: { dont_screw_try_catch_undefined: {
options = { options = { screw_ie8: false };
ie8: true, mangle = { screw_ie8: false };
} beautify = { screw_ie8: false };
mangle = {
ie8: true,
}
beautify = {
ie8: true,
}
input: { input: {
function a(b){ function a(b){
try { try {
@@ -187,13 +163,12 @@ dont_screw_try_catch_undefined: {
reduce_vars: { reduce_vars: {
options = { options = {
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
ie8: true, screw_ie8: false,
unused: true, unused: true,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
} }
input: { input: {
function f() { function f() {
@@ -221,10 +196,10 @@ reduce_vars: {
issue_1586_1: { issue_1586_1: {
options = { options = {
ie8: true, screw_ie8: false,
} }
mangle = { mangle = {
ie8: true, screw_ie8: false,
} }
input: { input: {
function f() { function f() {
@@ -240,10 +215,10 @@ issue_1586_1: {
issue_1586_2: { issue_1586_2: {
options = { options = {
ie8: false, screw_ie8: true,
} }
mangle = { mangle = {
ie8: false, screw_ie8: true,
} }
input: { input: {
function f() { function f() {
@@ -256,139 +231,3 @@ issue_1586_2: {
} }
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}" expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
} }
issue_2120_1: {
mangle = {
ie8: false,
}
input: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (c) {
try {
throw 0;
} catch (a) {
if (c) b = "PASS";
}
}
console.log(b);
}
expect: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (t) {
try {
throw 0;
} catch (a) {
if (t) b = "PASS";
}
}
console.log(b);
}
expect_stdout: "PASS"
}
issue_2120_2: {
mangle = {
ie8: true,
}
input: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (c) {
try {
throw 0;
} catch (a) {
if (c) b = "PASS";
}
}
console.log(b);
}
expect: {
"aaaaaaaa";
var a = 1, b = "FAIL";
try {
throw 1;
} catch (c) {
try {
throw 0;
} catch (a) {
if (c) b = "PASS";
}
}
console.log(b);
}
expect_stdout: "PASS"
}
issue_2254_1: {
mangle = {
ie8: false,
}
input: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(s) {
try {
throw "FAIL";
} catch (e) {
return s;
}
}
}
expect: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(e) {
try {
throw "FAIL";
} catch (t) {
return e;
}
}
}
expect_stdout: "PASS"
}
issue_2254_2: {
mangle = {
ie8: true,
}
input: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(s) {
try {
throw "FAIL";
} catch (e) {
return s;
}
}
}
expect: {
"eeeeee";
try {
console.log(f("PASS"));
} catch (e) {}
function f(t) {
try {
throw "FAIL";
} catch (e) {
return t;
}
}
}
expect_stdout: "PASS"
}

View File

@@ -176,11 +176,6 @@ for_sequences: {
// 4 // 4
x = (foo in bar); x = (foo in bar);
for (y = 5; false;); for (y = 5; false;);
// 5
x = function() {
foo in bar;
};
for (y = 5; false;);
} }
expect: { expect: {
// 1 // 1
@@ -193,10 +188,6 @@ for_sequences: {
// 4 // 4
x = (foo in bar); x = (foo in bar);
for (y = 5; false;); for (y = 5; false;);
// 5
for (x = function() {
foo in bar;
}, y = 5; false;);
} }
} }
@@ -252,12 +243,13 @@ negate_iife_for: {
input: { input: {
(function() {})(); (function() {})();
for (i = 0; i < 5; i++) console.log(i); for (i = 0; i < 5; i++) console.log(i);
(function() {})(); (function() {})();
for (; i < 10; i++) console.log(i); for (; i < 5; i++) console.log(i);
} }
expect: { expect: {
for (!function() {}(), i = 0; i < 5; i++) console.log(i); for (!function() {}(), i = 0; i < 5; i++) console.log(i);
for (!function() {}(); i < 10; i++) console.log(i); for (function() {}(); i < 5; i++) console.log(i);
} }
expect_stdout: true expect_stdout: true
} }
@@ -317,7 +309,7 @@ unsafe_undefined: {
issue_1685: { issue_1685: {
options = { options = {
collapse_vars: true, cascade: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -341,7 +333,7 @@ issue_1685: {
func_def_1: { func_def_1: {
options = { options = {
collapse_vars: true, cascade: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -361,7 +353,7 @@ func_def_1: {
func_def_2: { func_def_2: {
options = { options = {
collapse_vars: true, cascade: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -379,7 +371,7 @@ func_def_2: {
func_def_3: { func_def_3: {
options = { options = {
collapse_vars: true, cascade: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -401,7 +393,7 @@ func_def_3: {
func_def_4: { func_def_4: {
options = { options = {
collapse_vars: true, cascade: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -427,7 +419,7 @@ func_def_4: {
func_def_5: { func_def_5: {
options = { options = {
collapse_vars: true, cascade: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -468,7 +460,7 @@ issue_1758: {
console.log(function(c) { console.log(function(c) {
var undefined = 42; var undefined = 42;
return function() { return function() {
return c--, c--, void c.toString(); return c--, c--, c.toString(), void 0;
}(); }();
}()); }());
} }
@@ -489,12 +481,12 @@ delete_seq_1: {
console.log(delete (1, 0 / 0)); console.log(delete (1, 0 / 0));
} }
expect: { expect: {
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((NaN, !0));
console.log(!0); console.log((0 / 0, !0));
} }
expect_stdout: true expect_stdout: true
} }
@@ -513,12 +505,12 @@ delete_seq_2: {
console.log(delete (1, 2, 0 / 0)); console.log(delete (1, 2, 0 / 0));
} }
expect: { expect: {
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((NaN, !0));
console.log(!0); console.log((0 / 0, !0));
} }
expect_stdout: true expect_stdout: true
} }
@@ -538,12 +530,12 @@ delete_seq_3: {
console.log(delete (1, 2, 0 / 0)); console.log(delete (1, 2, 0 / 0));
} }
expect: { expect: {
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((void 0, !0));
console.log(!0); console.log((Infinity, !0));
console.log(!0); console.log((1 / 0, !0));
console.log(!0); console.log((NaN, !0));
console.log(!0); console.log((0 / 0, !0));
} }
expect_stdout: true expect_stdout: true
} }
@@ -614,185 +606,31 @@ delete_seq_6: {
} }
expect: { expect: {
var a; var a;
console.log(!0); console.log((a, !0));
} }
expect_stdout: true expect_stdout: true
} }
side_effects: { reassign_const: {
options = { options = {
cascade: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
} }
input: { input: {
0, a(), 1, b(), 2, c(), 3; function f() {
} const a = 1;
expect: {
a(), b(), c();
}
}
side_effects_cascade_1: {
options = {
collapse_vars: true,
conditionals: true,
sequences: true,
side_effects: true,
}
input: {
function f(a, b) {
a -= 42;
if (a < 0) a = 0;
b.a = a;
}
}
expect: {
function f(a, b) {
(a -= 42) < 0 && (a = 0), b.a = a;
}
}
}
side_effects_cascade_2: {
options = {
collapse_vars: true,
side_effects: true,
}
input: {
function f(a, b) {
b = a,
!a + (b += a) || (b += a),
b = a,
b;
}
}
expect: {
function f(a, b) {
b = a,
!a + (b += a) || (b += a),
b = a;
}
}
}
side_effects_cascade_3: {
options = {
collapse_vars: true,
conditionals: true,
side_effects: true,
}
input: {
function f(a, b) {
"foo" ^ (b += a),
b ? false : (b = a) ? -1 : (b -= a) - (b ^= a),
a-- || !a,
a;
}
}
expect: {
function f(a, b) {
!(b += a) && ((b = a) || (b -= a, b ^= a)),
a--;
}
}
}
issue_27: {
options = {
collapse_vars: true,
passes: 2,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function(jQuery) {
var $;
$ = jQuery;
$("body").addClass("foo");
})(jQuery);
}
expect: {
(function(jQuery) {
jQuery("body").addClass("foo");
})(jQuery);
}
}
issue_2062: {
options = {
booleans: true,
collapse_vars: true,
conditionals: true,
side_effects: true,
}
input: {
var a = 1;
if ([ a || a++ + a--, a++ + a--, a && a.var ]);
console.log(a);
}
expect: {
var a = 1;
a || (a++, a--), a++, --a && a.var;
console.log(a);
}
expect_stdout: "1"
}
issue_2313: {
options = {
collapse_vars: true,
sequences: true,
side_effects: true,
}
input: {
var a = 0, b = 0;
var foo = {
get c() {
a++; a++;
return 42; return a;
},
set c(c) {
b++;
},
d: function() {
this.c++;
if (this.c) console.log(a, b);
} }
} console.log(f());
foo.d();
} }
expect: { expect: {
var a = 0, b = 0; function f() {
var foo = { const a = 1;
get c() { return a++, a;
return a++, 42;
},
set c(c) {
b++;
},
d: function() {
if (this.c++, this.c) console.log(a, b);
}
}
foo.d();
}
expect_stdout: "2 1"
}
cascade_assignment_in_return: {
options = {
collapse_vars: true,
unused: true,
}
input: {
function f(a, b) {
return a = x(), b(a);
}
}
expect: {
function f(a, b) {
return b(x());
} }
console.log(f());
} }
expect_stdout: true
} }

View File

@@ -8,12 +8,3 @@ octal_escape_sequence: {
var border_check = "\x20\x30\x38\x30\x00\x30\xc0\x30"; var border_check = "\x20\x30\x38\x30\x00\x30\xc0\x30";
} }
} }
issue_1929: {
input: {
function f(s) {
return s.split(/[\\/]/);
}
}
expect_exact: "function f(s){return s.split(/[\\\\/]/)}"
}

View File

@@ -714,7 +714,6 @@ issue_1705_2: {
options = { options = {
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@@ -817,50 +816,3 @@ issue_1758: {
} }
expect_stdout: "0 3" expect_stdout: "0 3"
} }
issue_2535: {
options = {
evaluate: true,
dead_code: true,
switches: true,
}
input: {
switch(w(), 42) {
case 13: x();
case 42: y();
default: z();
}
}
expect: {
w(), 42;
42;
y();
z();
}
}
issue_1750: {
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;
true;
a, true;
b = 2;
console.log(a, b);
}
expect_stdout: "0 2"
}

View File

@@ -45,9 +45,9 @@ condition_evaluate: {
if (void 0 == null); if (void 0 == null);
} }
expect: { expect: {
while (0); while (!1);
for (; 1;); for (; !0;);
if (1); if (!0);
} }
} }
@@ -68,7 +68,6 @@ label_if_break: {
conditionals: true, conditionals: true,
dead_code: true, dead_code: true,
evaluate: true, evaluate: true,
side_effects: true,
} }
input: { input: {
L: if (true) { L: if (true) {

View File

@@ -1,7 +1,6 @@
typeof_evaluation: { typeof_evaluation: {
options = { options = {
evaluate: true, evaluate: true
typeofs: true,
}; };
input: { input: {
a = typeof 1; a = typeof 1;
@@ -45,7 +44,7 @@ typeof_in_boolean_context: {
function f2() { return g(), "Yes"; } function f2() { return g(), "Yes"; }
foo(); foo();
console.log(1); console.log(1);
var a = !(console.log(2), 1); var a = !(console.log(2), !0);
foo(); foo();
} }
} }
@@ -58,83 +57,6 @@ issue_1668: {
if (typeof bar); if (typeof bar);
} }
expect: { expect: {
if (1); if (!0);
} }
} }
typeof_defun_1: {
options = {
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
typeofs: true,
unused: true,
}
input: {
function f() {
console.log("YES");
}
function g() {
h = 42;
console.log("NOPE");
}
function h() {
console.log("YUP");
}
g = 42;
"function" == typeof f && f();
"function" == typeof g && g();
"function" == typeof h && h();
}
expect: {
function g() {
h = 42;
console.log("NOPE");
}
function h() {
console.log("YUP");
}
g = 42;
console.log("YES");
"function" == typeof g && g();
h();
}
expect_stdout: [
"YES",
"YUP",
]
}
typeof_defun_2: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
typeofs: true,
}
input: {
var f = function() {
console.log(x);
};
var x = 0;
x++ < 2 && typeof f == "function" && f();
x++ < 2 && typeof f == "function" && f();
x++ < 2 && typeof f == "function" && f();
}
expect: {
var f = function() {
console.log(x);
};
var x = 0;
x++ < 2 && f();
x++ < 2 && f();
x++ < 2 && f();
}
expect_stdout: [
"1",
"2",
]
}

View File

@@ -15,50 +15,3 @@ unicode_parse_variables: {
var l = 3; var l = 3;
} }
} }
issue_2242_1: {
beautify = {
ascii_only: false,
}
input: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\ud83d\ude00","\\ud83d@\\ude00");'
}
issue_2242_2: {
beautify = {
ascii_only: true,
}
input: {
console.log("\ud83d", "\ude00", "\ud83d\ude00", "\ud83d@\ude00");
}
expect_exact: 'console.log("\\ud83d","\\ude00","\\ud83d\\ude00","\\ud83d@\\ude00");'
}
issue_2242_3: {
options = {
evaluate: false,
}
input: {
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
}
expect_exact: 'console.log("\\ud83d"+"\\ude00","\\ud83d"+"@"+"\\ude00");'
}
issue_2242_4: {
options = {
evaluate: true,
}
input: {
console.log("\ud83d" + "\ude00", "\ud83d" + "@" + "\ude00");
}
expect_exact: 'console.log("\ud83d\ude00","\\ud83d@\\ude00");'
}
issue_2569: {
input: {
new RegExp("[\udc42-\udcaa\udd74-\udd96\ude45-\ude4f\udea3-\udecc]");
}
expect_exact: 'new RegExp("[\\udc42-\\udcaa\\udd74-\\udd96\\ude45-\\ude4f\\udea3-\\udecc]");'
}

View File

@@ -1,14 +0,0 @@
exports["Compressor"] = Compressor;
exports["JS_Parse_Error"] = JS_Parse_Error;
exports["OutputStream"] = OutputStream;
exports["SourceMap"] = SourceMap;
exports["TreeWalker"] = TreeWalker;
exports["base54"] = base54;
exports["defaults"] = defaults;
exports["mangle_properties"] = mangle_properties;
exports["minify"] = minify;
exports["parse"] = parse;
exports["reserve_quoted_keys"] = reserve_quoted_keys;
exports["string_template"] = string_template;
exports["tokenizer"] = tokenizer;
exports["is_identifier"] = is_identifier;

View File

@@ -1,31 +0,0 @@
var fs = require("fs");
var path = require("path");
try {
fs.mkdirSync("./tmp");
} catch (e) {
if (e.code != "EEXIST") throw e;
}
function local(url) {
return path.join("./tmp", encodeURIComponent(url));
}
function read(url) {
return fs.createReadStream(local(url));
}
module.exports = function(url, callback) {
var result = read(url);
result.on("error", function(e) {
if (e.code != "ENOENT") return callback(e);
require(url.slice(0, url.indexOf(":"))).get(url, function(res) {
if (res.statusCode !== 200) return callback(res);
res.pipe(fs.createWriteStream(local(url)).on("close", function() {
callback(null, read(url));
}));
});
}).on("open", function() {
callback(null, result);
});
};

View File

@@ -1 +0,0 @@
++null

View File

@@ -1,14 +0,0 @@
function f(x) {
delete 42;
delete (0, x);
delete null;
delete x;
}
function g(x) {
"use strict";
delete 42;
delete (0, x);
delete null;
delete x;
}

View File

@@ -1 +0,0 @@
a.=

View File

@@ -1 +0,0 @@
%.a;

View File

@@ -1 +0,0 @@
a./();

View File

@@ -1 +0,0 @@
if (0) else 1;

View File

@@ -1,4 +0,0 @@
var a, b = [1, 2];
for (1, 2, a in b) {
console.log(a, b[a]);
}

View File

@@ -1,4 +0,0 @@
var c = [1, 2];
for (var a, b in c) {
console.log(a, c[a]);
}

View File

@@ -1,6 +0,0 @@
function f(arguments) {
}
function g(arguments) {
"use strict";
}

View File

@@ -1,6 +0,0 @@
function arguments() {
}
function eval() {
"use strict";
}

View File

@@ -1,6 +0,0 @@
!function eval() {
}();
!function arguments() {
"use strict";
}();

View File

@@ -1 +0,0 @@
console.log({%: 1});

View File

@@ -1 +0,0 @@
return 42;

View File

@@ -1,8 +0,0 @@
function f() {
try {} catch (eval) {}
}
function g() {
"use strict";
try {} catch (eval) {}
}

View File

@@ -1,8 +0,0 @@
function f() {
var eval;
}
function g() {
"use strict";
var eval;
}

Some files were not shown because too many files have changed in this diff Show More