Compare commits

..

45 Commits

Author SHA1 Message Date
Alex Lam S.L
3bc7cc82bb v3.5.12 2019-05-12 10:40:13 +08:00
Alex Lam S.L
45fbdbc2dc improve tests (#3408) 2019-05-12 09:44:02 +08:00
Alex Lam S.L
54cb678055 fix corner case in assignments (#3407)
fixes #3406
2019-05-12 03:52:46 +08:00
Alex Lam S.L
e88c439eac improve tests (#3405) 2019-05-11 22:06:14 +08:00
Alex Lam S.L
9fc8cd4076 fix corner case in functions (#3403)
fixes #3402
2019-05-11 18:55:45 +08:00
Alex Lam S.L
5476cb8f05 fix corner case in inline (#3401)
fixes #3400
2019-05-10 01:22:44 +08:00
Alex Lam S.L
6a30e1d6be improve tests (#3399) 2019-05-09 07:18:22 +08:00
Alex Lam S.L
e4881245d9 v3.5.11 2019-05-07 01:45:40 +08:00
Alex Lam S.L
354fec8a9c make enclose & wrap work with sourceMap (#3396)
fixes #3313
2019-05-04 20:25:52 +08:00
Alex Lam S.L
11cdab745d fix corner cases in sourceMap (#3397)
fixes #3255
fixes #3294
2019-05-04 20:08:57 +08:00
Alex Lam S.L
a89d424a0b render comments in custom ASTs gracefully (#3393)
fixes #3246
2019-05-02 13:50:51 +08:00
Alex Lam S.L
429d2b56b7 v3.5.10 2019-05-02 00:01:40 +08:00
Alex Lam S.L
2ea96549c5 unify logging functionality (#3392)
fixes #3253
fixes #3254
2019-04-30 06:32:24 +08:00
Alex Lam S.L
fba008e298 remove blanket safeguard from source-map (#3391)
Things has stabilised since 80a18fe2fa, so it makes sense to remove the unconditional masking for ease of debugging.
2019-04-30 02:40:36 +08:00
Alex Lam S.L
c37a8e927e fix corner case in properties (#3390)
fixes #3389
2019-04-29 17:23:00 +08:00
Alex Lam S.L
413bbe0480 fix corner case in evaluate (#3388)
fixes #3387
2019-04-29 08:55:46 +08:00
Alex Lam S.L
34075fc4c4 v3.5.9 2019-04-27 17:00:58 +08:00
Alex Lam S.L
e5436ca566 enhance side_effects (#3384) 2019-04-25 15:15:50 +08:00
Alex Lam S.L
cfde686eab v3.5.8 2019-04-25 12:33:13 +08:00
Alex Lam S.L
a206964c0a enhance side_effects (#3383) 2019-04-25 04:14:21 +08:00
Alex Lam S.L
c56d89f804 enhance unsafe (#3382) 2019-04-25 02:42:54 +08:00
Alex Lam S.L
c215706350 enhance unsafe comparisons (#3381) 2019-04-25 00:08:08 +08:00
Alex Lam S.L
d3b93ec682 fix corner case in unsafe (#3380) 2019-04-24 22:21:28 +08:00
Alex Lam S.L
6fe20dbe33 enhance comparisons (#3379) 2019-04-24 21:38:55 +08:00
Alex Lam S.L
7ccdf3337b v3.5.7 2019-04-24 14:05:07 +08:00
Alex Lam S.L
dafed54764 fix corner case in reduce_vars (#3378)
fixes #3377
2019-04-24 14:01:01 +08:00
Alex Lam S.L
a84beafd1b fix corner case in assignments (#3376)
fixes #3375
2019-04-24 02:50:15 +08:00
Alex Lam S.L
f01cc1e413 unwind IIFE class patterns (#3373)
fixes #2332
2019-04-21 09:49:07 +08:00
Alex Lam S.L
338dd144b8 v3.5.6 2019-04-21 07:19:29 +08:00
Alex Lam S.L
c719552317 fix corner cases in functions (#3372)
fixes #3371
2019-04-21 02:16:05 +08:00
Alex Lam S.L
855964a87a enhance unsafe evaluate (#3370) 2019-04-20 19:42:41 +08:00
Alex Lam S.L
a438e2fca9 update domprops (#3369)
fixes #2343
fixes #3037
2019-04-20 07:16:14 +08:00
Alex Lam S.L
00833e893a enhance functions (#3368) 2019-04-19 19:01:47 +08:00
Alex Lam S.L
f1a77e4fc0 v3.5.5 2019-04-19 15:22:46 +08:00
Alex Lam S.L
b55a2fd531 fix corner case in functions (#3367)
fixes #3366
2019-04-19 02:55:43 +08:00
Alex Lam S.L
e8a2c0b5bf fix corner case in functions (#3365)
fixes #3364
2019-04-18 17:03:52 +08:00
Alex Lam S.L
21cd7e3f57 reduce test exports (#3361) 2019-04-17 16:19:08 +08:00
Alex Lam S.L
5172ba5f2a introduce functions (#3360)
`var f = function() {};` => `function f() {}`
2019-04-15 22:23:11 +08:00
Alex Lam S.L
a57b069409 v3.5.4 2019-04-10 02:40:42 +08:00
Alex Lam S.L
4454656c3b update dependencies (#3358)
- commander@2.20.0
- semver@6.0.0
2019-04-10 02:39:56 +08:00
Alex Lam S.L
fa43768ce0 v3.5.3 2019-04-01 18:12:03 +08:00
Alex Lam S.L
a74e600fa0 mangle shadowed lambda under ie8 correctly (#3356)
fixes #3355
2019-04-01 15:22:00 +08:00
Ruben Bridgewater
4b21526310 Fix test expectation (#3357)
The test expects a specific precision value that is not met on all V8 versions anymore due to a recent consolidation of different algorithms across the V8 code base.

This makes sure the preceision is tested against one digit less to keep the test working on all V8 versions.

Refs: 98453126c1
Refs: https://github.com/nodejs/node/issues/25060#issuecomment-477953457
2019-03-30 02:08:27 +08:00
Alex Lam S.L
a7a7b1daed v3.5.2 2019-03-23 14:25:14 +08:00
Alex Lam S.L
7436977aa5 fix infinite loop triggered by #3347 (#3354)
fixes #3353
2019-03-23 14:21:54 +08:00
46 changed files with 3894 additions and 797 deletions

View File

@@ -1,35 +1,46 @@
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libstdc++-4.9-dev
cache: cache:
directories: tmp directories: tmp
language: generic language: generic
matrix: matrix:
fast_finish: true fast_finish: true
sudo: false
env: env:
global: - NODE=0.10 TYPE=compress
- UGLIFYJS_TEST_ALL=1 - NODE=0.10 TYPE=mocha
matrix: - NODE=0.10 TYPE=release/benchmark
- NODEJS_VER=node/0.10 - NODE=0.10 TYPE=release/jetstream
- NODEJS_VER=node/0.12 - NODE=0.12 TYPE=compress
- NODEJS_VER=node/4 - NODE=0.12 TYPE=mocha
- NODEJS_VER=node/6 - NODE=0.12 TYPE=release/benchmark
- NODEJS_VER=node/8 - NODE=0.12 TYPE=release/jetstream
- NODEJS_VER=node/10 - NODE=4 TYPE=compress
- NODEJS_VER=node/latest - NODE=4 TYPE=mocha
- NODE=4 TYPE=release/benchmark
- NODE=4 TYPE=release/jetstream
- NODE=6 TYPE=compress
- NODE=6 TYPE=mocha
- NODE=6 TYPE=release/benchmark
- NODE=6 TYPE=release/jetstream
- NODE=8 TYPE=compress
- NODE=8 TYPE=mocha
- NODE=8 TYPE=release/benchmark
- NODE=8 TYPE=release/jetstream
- NODE=10 TYPE=compress
- NODE=10 TYPE=mocha
- NODE=10 TYPE=release/benchmark
- NODE=10 TYPE=release/jetstream
- NODE=latest TYPE=compress
- NODE=latest TYPE=mocha
- NODE=latest TYPE=release/benchmark
- NODE=latest TYPE=release/jetstream
before_install: before_install:
- git clone --branch v1.4.2 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs - git clone --branch v1.5.2 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
- . ~/.nvs/nvs.sh - . ~/.nvs/nvs.sh
- nvs --version - nvs --version
install: install:
- nvs add $NODEJS_VER - nvs add node/$NODE
- nvs use $NODEJS_VER - nvs use node/$NODE
- node --version - node --version
- npm --version --no-update-notifier - npm --version --no-update-notifier
- npm install --no-optional --no-save --no-update-notifier - npm install --no-audit --no-optional --no-save --no-update-notifier
script: script:
- npm test --no-update-notifier - node test/$TYPE

View File

@@ -636,6 +636,9 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `expression` (default: `false`) -- Pass `true` to preserve completion values - `expression` (default: `false`) -- Pass `true` to preserve completion values
from terminal statements without `return`, e.g. in bookmarklets. from terminal statements without `return`, e.g. in bookmarklets.
- `functions` (default: `true`) -- convert declarations from `var`to `function`
whenever possible.
- `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation) - `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation)
- `hoist_funs` (default: `false`) -- hoist function declarations - `hoist_funs` (default: `false`) -- hoist function declarations
@@ -764,9 +767,6 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple - `unused` (default: `true`) -- drop unreferenced functions and variables (simple
direct variable assignments do not count as references unless set to `"keep_assign"`) direct variable assignments do not count as references unless set to `"keep_assign"`)
- `warnings` (default: `false`) -- display warnings when dropping unreachable
code or unused declarations etc.
## Mangle options ## Mangle options
- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes - `eval` (default `false`) -- Pass `true` to mangle names visible in scopes

View File

@@ -1,26 +1,74 @@
environment:
UGLIFYJS_TEST_ALL: 1
matrix:
- NODEJS_VER: node/0.10
- NODEJS_VER: node/0.12
- NODEJS_VER: node/4
- NODEJS_VER: node/6
- NODEJS_VER: node/8
- NODEJS_VER: node/10
- NODEJS_VER: node/latest
install:
- git clone --branch v1.4.2 --depth 1 https://github.com/jasongin/nvs.git %LOCALAPPDATA%\nvs
- set PATH=%LOCALAPPDATA%\nvs;%PATH%
- nvs --version
- nvs add %NODEJS_VER%
- nvs use %NODEJS_VER%
- node --version
- npm --version --no-update-notifier
- npm install --no-optional --no-save --no-update-notifier
build: off build: off
cache: cache:
- tmp - tmp
matrix: matrix:
fast_finish: true fast_finish: true
environment:
matrix:
- NODE: 0.10
TYPE: compress
- NODE: 0.10
TYPE: mocha
- NODE: 0.10
TYPE: release/benchmark
- NODE: 0.10
TYPE: release/jetstream
- NODE: 0.12
TYPE: compress
- NODE: 0.12
TYPE: mocha
- NODE: 0.12
TYPE: release/benchmark
- NODE: 0.12
TYPE: release/jetstream
- NODE: 4
TYPE: compress
- NODE: 4
TYPE: mocha
- NODE: 4
TYPE: release/benchmark
- NODE: 4
TYPE: release/jetstream
- NODE: 6
TYPE: compress
- NODE: 6
TYPE: mocha
- NODE: 6
TYPE: release/benchmark
- NODE: 6
TYPE: release/jetstream
- NODE: 8
TYPE: compress
- NODE: 8
TYPE: mocha
- NODE: 8
TYPE: release/benchmark
- NODE: 8
TYPE: release/jetstream
- NODE: 10
TYPE: compress
- NODE: 10
TYPE: mocha
- NODE: 10
TYPE: release/benchmark
- NODE: 10
TYPE: release/jetstream
- NODE: latest
TYPE: compress
- NODE: latest
TYPE: mocha
- NODE: latest
TYPE: release/benchmark
- NODE: latest
TYPE: release/jetstream
install:
- git clone --branch v1.5.2 --depth 1 https://github.com/jasongin/nvs.git %LOCALAPPDATA%\nvs
- set PATH=%LOCALAPPDATA%\nvs;%PATH%
- nvs --version
- nvs add node/%NODE%
- nvs use node/%NODE%
- node --version
- npm --version --no-update-notifier
- npm install --no-audit --no-optional --no-save --no-update-notifier
test_script: test_script:
- npm test --no-update-notifier - node test/%TYPE%

View File

@@ -63,7 +63,7 @@ if (program.configFile) {
} }
} }
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") { if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
fatal("ERROR: cannot write source map to STDOUT"); fatal("cannot write source map to STDOUT");
} }
[ [
"compress", "compress",
@@ -78,6 +78,15 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
options[name] = program[name]; options[name] = program[name];
} }
}); });
if (program.verbose) {
options.warnings = "verbose";
} else if (program.warn) {
options.warnings = true;
}
if (options.warnings) {
UglifyJS.AST_Node.log_function(print_error, options.warnings == "verbose");
delete options.warnings;
}
if (program.beautify) { if (program.beautify) {
options.output = typeof program.beautify == "object" ? program.beautify : {}; options.output = typeof program.beautify == "object" ? program.beautify : {};
if (!("beautify" in options.output)) { if (!("beautify" in options.output)) {
@@ -124,7 +133,7 @@ if (program.parse) {
if (!program.parse.acorn && !program.parse.spidermonkey) { if (!program.parse.acorn && !program.parse.spidermonkey) {
options.parse = program.parse; options.parse = program.parse;
} else if (program.sourceMap && program.sourceMap.content == "inline") { } else if (program.sourceMap && program.sourceMap.content == "inline") {
fatal("ERROR: inline source map only works with built-in parser"); fatal("inline source map only works with built-in parser");
} }
} }
if (~program.rawArgs.indexOf("--rename")) { if (~program.rawArgs.indexOf("--rename")) {
@@ -144,15 +153,8 @@ if (typeof program.sourceMap == "object" && "base" in program.sourceMap) {
}; };
}(); }();
} }
if (program.verbose) {
options.warnings = "verbose";
} else if (program.warn) {
options.warnings = true;
}
if (program.self) { if (program.self) {
if (program.args.length) { if (program.args.length) UglifyJS.AST_Node.warn("Ignoring input files since --self was passed");
print_error("WARN: Ignoring input files since --self was passed");
}
if (!options.wrap) options.wrap = "UglifyJS"; if (!options.wrap) options.wrap = "UglifyJS";
simple_glob(UglifyJS.FILES).forEach(function(name) { simple_glob(UglifyJS.FILES).forEach(function(name) {
files[convert_path(name)] = read_file(name); files[convert_path(name)] = read_file(name);
@@ -180,12 +182,9 @@ function convert_ast(fn) {
} }
function run() { function run() {
UglifyJS.AST_Node.warn_function = function(msg) {
print_error("WARN: " + msg);
};
var content = program.sourceMap && program.sourceMap.content; var content = program.sourceMap && program.sourceMap.content;
if (content && content != "inline") { if (content && content != "inline") {
print_error("INFO: Using input source map: " + content); UglifyJS.AST_Node.info("Using input source map: " + content);
options.sourceMap.content = read_file(content, content); options.sourceMap.content = read_file(content, content);
} }
if (program.timings) options.timings = true; if (program.timings) options.timings = true;
@@ -216,24 +215,26 @@ function run() {
var ex = result.error; var ex = result.error;
if (ex.name == "SyntaxError") { if (ex.name == "SyntaxError") {
print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col); print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
var col = ex.col; var file = files[ex.filename];
var lines = files[ex.filename].split(/\r?\n/); if (file) {
var line = lines[ex.line - 1]; var col = ex.col;
if (!line && !col) { var lines = file.split(/\r?\n/);
line = lines[ex.line - 2]; var line = lines[ex.line - 1];
col = line.length; if (!line && !col) {
} line = lines[ex.line - 2];
if (line) { col = line.length;
var limit = 70; }
if (col > limit) { if (line) {
line = line.slice(col - limit); var limit = 70;
col = limit; if (col > limit) {
line = line.slice(col - limit);
col = limit;
}
print_error(line.slice(0, 80));
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
} }
print_error(line.slice(0, 80));
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
} }
} } else if (ex.defs) {
if (ex.defs) {
print_error("Supported options:"); print_error("Supported options:");
print_error(format_object(ex.defs)); print_error(format_object(ex.defs));
} }
@@ -293,7 +294,11 @@ function run() {
} }
function fatal(message) { function fatal(message) {
if (message instanceof Error) message = message.stack.replace(/^\S*?Error:/, "ERROR:") if (message instanceof Error) {
message = message.stack.replace(/^\S*?Error:/, "ERROR:")
} else {
message = "ERROR: " + message;
}
print_error(message); print_error(message);
process.exit(1); process.exit(1);
} }
@@ -370,9 +375,9 @@ function parse_js(flag) {
}); });
} }
})); }));
} catch(ex) { } catch (ex) {
if (flag) { if (flag) {
fatal("Error parsing arguments for '" + flag + "': " + value); fatal("cannot parse arguments for '" + flag + "': " + value);
} else { } else {
options[value] = null; options[value] = null;
} }

View File

@@ -118,9 +118,25 @@ var AST_Node = DEFNODE("Node", "start end", {
} }
}, null); }, null);
AST_Node.warn = function(txt, props) { (AST_Node.log_function = function(fn, verbose) {
if (AST_Node.warn_function) AST_Node.warn_function(string_template(txt, props)); var printed = Object.create(null);
}; if (fn) {
AST_Node.info = verbose ? function(text, props) {
log("INFO: " + string_template(text, props));
} : noop;
AST_Node.warn = function(text, props) {
log("WARN: " + string_template(text, props));
};
} else {
AST_Node.info = AST_Node.warn = noop;
}
function log(msg) {
if (printed[msg]) return;
printed[msg] = true;
fn(msg);
}
})();
/* -----[ statements ]----- */ /* -----[ statements ]----- */
@@ -321,18 +337,25 @@ 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: function(name) {
var body = this.body; var body = this.body;
var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");"; return parse([
wrapped_tl = parse(wrapped_tl); "(function(exports){'$ORIG';})(typeof ",
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function(node) { name,
"=='undefined'?(",
name,
"={}):",
name,
");"
].join(""), {
filename: "wrap=" + JSON.stringify(name)
}).transform(new TreeTransformer(function(node) {
if (node instanceof AST_Directive && node.value == "$ORIG") { if (node instanceof AST_Directive && node.value == "$ORIG") {
return MAP.splice(body); return MAP.splice(body);
} }
})); }));
return wrapped_tl;
}, },
wrap_enclose: function(args_values) { enclose: function(args_values) {
if (typeof args_values != "string") args_values = ""; if (typeof args_values != "string") args_values = "";
var index = args_values.indexOf(":"); var index = args_values.indexOf(":");
if (index < 0) index = args_values.length; if (index < 0) index = args_values.length;
@@ -343,7 +366,9 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
'){"$ORIG"})(', '){"$ORIG"})(',
args_values.slice(index + 1), args_values.slice(index + 1),
")" ")"
].join("")).transform(new TreeTransformer(function(node) { ].join(""), {
filename: "enclose=" + JSON.stringify(args_values)
}).transform(new TreeTransformer(function(node) {
if (node instanceof AST_Directive && node.value == "$ORIG") { if (node instanceof AST_Directive && node.value == "$ORIG") {
return MAP.splice(body); return MAP.splice(body);
} }
@@ -773,7 +798,7 @@ var AST_Label = DEFNODE("Label", "references", {
} }
}, AST_Symbol); }, AST_Symbol);
var AST_SymbolRef = DEFNODE("SymbolRef", null, { var AST_SymbolRef = DEFNODE("SymbolRef", "fixed", {
$documentation: "Reference to some symbol (not definition/declaration)", $documentation: "Reference to some symbol (not definition/declaration)",
}, AST_Symbol); }, AST_Symbol);

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ var to_base64 = typeof btoa == "undefined" ? function(str) {
} : btoa; } : btoa;
function read_source_map(name, code) { function read_source_map(name, code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code); var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(\S+)\s*$/.exec(code);
if (!match) { if (!match) {
AST_Node.warn("inline source map not found: " + name); AST_Node.warn("inline source map not found: " + name);
return null; return null;
@@ -51,7 +51,6 @@ function to_json(cache) {
} }
function minify(files, options) { function minify(files, options) {
var warn_function = AST_Node.warn_function;
try { try {
options = defaults(options, { options = defaults(options, {
compress: {}, compress: {},
@@ -78,7 +77,6 @@ function minify(files, options) {
set_shorthand("ie8", options, [ "compress", "mangle", "output" ]); set_shorthand("ie8", options, [ "compress", "mangle", "output" ]);
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]); set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
set_shorthand("toplevel", options, [ "compress", "mangle" ]); set_shorthand("toplevel", options, [ "compress", "mangle" ]);
set_shorthand("warnings", options, [ "compress" ]);
var quoted_props; var quoted_props;
if (options.mangle) { if (options.mangle) {
options.mangle = defaults(options.mangle, { options.mangle = defaults(options.mangle, {
@@ -116,11 +114,9 @@ function minify(files, options) {
}, true); }, true);
} }
var warnings = []; var warnings = [];
if (options.warnings && !AST_Node.warn_function) { if (options.warnings) AST_Node.log_function(function(warning) {
AST_Node.warn_function = function(warning) { warnings.push(warning);
warnings.push(warning); }, options.warnings == "verbose");
};
}
if (timings) timings.parse = Date.now(); if (timings) timings.parse = Date.now();
var source_maps, toplevel; var source_maps, toplevel;
if (files instanceof AST_Toplevel) { if (files instanceof AST_Toplevel) {
@@ -155,12 +151,13 @@ function minify(files, options) {
if (quoted_props) { if (quoted_props) {
reserve_quoted_keys(toplevel, quoted_props); reserve_quoted_keys(toplevel, quoted_props);
} }
if (options.wrap) { [ "enclose", "wrap" ].forEach(function(action) {
toplevel = toplevel.wrap_commonjs(options.wrap); var option = options[action];
} if (!option) return;
if (options.enclose) { var orig = toplevel.print_to_string().slice(0, -1);
toplevel = toplevel.wrap_enclose(options.enclose); toplevel = toplevel[action](option);
} files[toplevel.start.file] = toplevel.print_to_string().replace(orig, "");
});
if (timings) timings.rename = Date.now(); if (timings) timings.rename = Date.now();
if (options.rename) { if (options.rename) {
toplevel.figure_out_scope(options.mangle); toplevel.figure_out_scope(options.mangle);
@@ -208,10 +205,14 @@ function minify(files, options) {
result.code = stream.get(); result.code = stream.get();
if (options.sourceMap) { if (options.sourceMap) {
result.map = options.output.source_map.toString(); result.map = options.output.source_map.toString();
if (options.sourceMap.url == "inline") { var url = options.sourceMap.url;
result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(result.map); if (url) {
} else if (options.sourceMap.url) { result.code = result.code.replace(/\n\/\/# sourceMappingURL=\S+\s*$/, "");
result.code += "\n//# sourceMappingURL=" + options.sourceMap.url; if (url == "inline") {
result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(result.map);
} else {
result.code += "\n//# sourceMappingURL=" + url;
}
} }
} }
} }
@@ -240,7 +241,5 @@ function minify(files, options) {
return result; return result;
} catch (ex) { } catch (ex) {
return { error: ex }; return { error: ex };
} finally {
AST_Node.warn_function = warn_function;
} }
} }

View File

@@ -123,7 +123,7 @@ function OutputStream(options) {
}); });
} : function(str) { } : function(str) {
var s = ""; var s = "";
for (var i = 0, len = str.length; i < len; i++) { for (var i = 0; i < str.length; i++) {
if (is_surrogate_pair_head(str[i]) && !is_surrogate_pair_tail(str[i + 1]) 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])) { || is_surrogate_pair_tail(str[i]) && !is_surrogate_pair_head(str[i - 1])) {
s += "\\u" + str.charCodeAt(i).toString(16); s += "\\u" + str.charCodeAt(i).toString(16);
@@ -217,23 +217,12 @@ function OutputStream(options) {
var flush_mappings = mappings ? function() { var flush_mappings = mappings ? function() {
mappings.forEach(function(mapping) { mappings.forEach(function(mapping) {
try { options.source_map.add(
options.source_map.add( mapping.token.file,
mapping.token.file, mapping.line, mapping.col,
mapping.line, mapping.col, mapping.token.line, mapping.token.col,
mapping.token.line, mapping.token.col, !mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name
!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 = []; mappings = [];
} : noop; } : noop;
@@ -462,16 +451,11 @@ function OutputStream(options) {
function prepend_comments(node) { function prepend_comments(node) {
var self = this; var self = this;
var start = node.start; var scan = node instanceof AST_Exit && node.value;
if (!start) return; var comments = dump(node);
if (start.comments_before && start.comments_before._dumped === self) return; if (!comments) return;
var comments = start.comments_before;
if (!comments) {
comments = start.comments_before = [];
}
comments._dumped = self;
if (node instanceof AST_Exit && node.value) { if (scan) {
var tw = new TreeWalker(function(node) { var tw = new TreeWalker(function(node) {
var parent = tw.parent(); var parent = tw.parent();
if (parent instanceof AST_Exit if (parent instanceof AST_Exit
@@ -482,11 +466,8 @@ function OutputStream(options) {
|| parent instanceof AST_Sequence && parent.expressions[0] === node || parent instanceof AST_Sequence && parent.expressions[0] === node
|| parent instanceof AST_Sub && parent.expression === node || parent instanceof AST_Sub && parent.expression === node
|| parent instanceof AST_UnaryPostfix) { || parent instanceof AST_UnaryPostfix) {
var text = node.start.comments_before; var before = dump(node);
if (text && text._dumped !== self) { if (before) comments = comments.concat(before);
text._dumped = self;
comments = comments.concat(text);
}
} else { } else {
return true; return true;
} }
@@ -529,13 +510,29 @@ function OutputStream(options) {
} }
}); });
if (!last_nlb) { if (!last_nlb) {
if (start.nlb) { if (node.start.nlb) {
print("\n"); print("\n");
indent(); indent();
} else { } else {
space(); space();
} }
} }
function dump(node) {
var token = node.start;
if (!token) {
if (!scan) return;
node.start = token = new AST_Token();
}
var comments = token.comments_before;
if (!comments) {
if (!scan) return;
token.comments_before = comments = [];
}
if (comments._dumped === self) return;
comments._dumped = self;
return comments;
}
} }
function append_comments(node, tail) { function append_comments(node, tail) {

View File

@@ -164,10 +164,6 @@ function is_unicode_connector_punctuation(ch) {
return UNICODE.connector_punctuation.test(ch); return UNICODE.connector_punctuation.test(ch);
} }
function is_identifier(name) {
return !RESERVED_WORDS[name] && /^[a-z_$][a-z0-9_$]*$/i.test(name);
}
function is_identifier_start(code) { function is_identifier_start(code) {
return code == 36 || code == 95 || is_letter(code); return code == 36 || code == 95 || is_letter(code);
} }
@@ -272,10 +268,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function find_eol() { function find_eol() {
var text = S.text; var text = S.text;
for (var i = S.pos, n = S.text.length; i < n; ++i) { for (var i = S.pos; i < S.text.length; ++i) {
var ch = text[i]; if (NEWLINE_CHARS[text[i]]) return i;
if (NEWLINE_CHARS[ch])
return i;
} }
return -1; return -1;
} }
@@ -510,7 +504,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var regexp = new RegExp(source, mods); var regexp = new RegExp(source, mods);
regexp.raw_source = source; regexp.raw_source = source;
return token("regexp", regexp); return token("regexp", regexp);
} catch(e) { } catch (e) {
parse_error(e.message); parse_error(e.message);
} }
}); });
@@ -562,7 +556,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
return function(x) { return function(x) {
try { try {
return cont(x); return cont(x);
} catch(ex) { } catch (ex) {
if (ex === EX_EOF) parse_error(eof_error); if (ex === EX_EOF) parse_error(eof_error);
else throw ex; else throw ex;
} }

View File

@@ -61,8 +61,6 @@ SymbolDef.next_id = 1;
SymbolDef.prototype = { SymbolDef.prototype = {
unmangleable: function(options) { unmangleable: function(options) {
if (!options) options = {};
return this.global && !options.toplevel return this.global && !options.toplevel
|| this.undeclared || this.undeclared
|| !options.eval && this.scope.pinned() || !options.eval && this.scope.pinned()
@@ -198,24 +196,20 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
} }
if (node instanceof AST_SymbolLambda) { if (node instanceof AST_SymbolLambda) {
var def = node.thedef; var def = node.thedef;
if (def.orig.length == 1) { redefine(node, node.scope.parent_scope);
redefine(node, node.scope.parent_scope); node.thedef.init = def.init;
node.thedef.init = def.init;
}
return true; return true;
} }
})); }));
function redefine(node, scope) { function redefine(node, scope) {
var name = node.name; var name = node.name;
var refs = node.thedef.references; var old_def = node.thedef;
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node); var new_def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
refs.forEach(function(ref) { old_def.orig.concat(old_def.references).forEach(function(node) {
ref.thedef = def; node.thedef = new_def;
ref.reference(options); node.reference(options);
}); });
node.thedef = def;
node.reference(options);
} }
}); });
@@ -300,7 +294,7 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
AST_Lambda.DEFMETHOD("resolve", return_this); AST_Lambda.DEFMETHOD("resolve", return_this);
AST_Scope.DEFMETHOD("resolve", function() { AST_Scope.DEFMETHOD("resolve", function() {
return this.parent_scope; return this.parent_scope.resolve();
}); });
AST_Toplevel.DEFMETHOD("resolve", return_this); AST_Toplevel.DEFMETHOD("resolve", return_this);
@@ -337,7 +331,7 @@ function next_mangled_name(scope, options, def) {
} while (scope = scope.parent_scope); } while (scope = scope.parent_scope);
}); });
var name; var name;
for (var i = 0, len = holes.length; i < len; i++) { for (var i = 0; i < holes.length; i++) {
name = base54(holes[i]); name = base54(holes[i]);
if (names[name]) continue; if (names[name]) continue;
holes.splice(i, 1); holes.splice(i, 1);
@@ -346,7 +340,7 @@ function next_mangled_name(scope, options, def) {
} }
while (true) { while (true) {
name = base54(++scope.cname); name = base54(++scope.cname);
if (in_use[name] || !is_identifier(name) || options.reserved.has[name]) continue; if (in_use[name] || RESERVED_WORDS[name] || options.reserved.has[name]) continue;
if (!names[name]) break; if (!names[name]) break;
holes.push(scope.cname); holes.push(scope.cname);
} }
@@ -426,7 +420,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
var name; var name;
do { do {
name = base54(++lname); name = base54(++lname);
} while (!is_identifier(name)); } while (RESERVED_WORDS[name]);
node.mangled_name = name; node.mangled_name = name;
return true; return true;
} }
@@ -497,7 +491,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
var name; var name;
do { do {
name = base54(cname++); name = base54(cname++);
} while (avoid[name] || !is_identifier(name)); } while (avoid[name] || RESERVED_WORDS[name]);
return name; return name;
} }
@@ -559,7 +553,7 @@ var base54 = (function() {
var freq = Object.create(null); var freq = Object.create(null);
function init(chars) { function init(chars) {
var array = []; var array = [];
for (var i = 0, len = chars.length; i < len; i++) { for (var i = 0; i < chars.length; i++) {
var ch = chars[i]; var ch = chars[i];
array.push(ch); array.push(ch);
freq[ch] = -1e-2 * i; freq[ch] = -1e-2 * i;

View File

@@ -70,7 +70,7 @@ function configure_error_stack(fn) {
err.name = this.name; err.name = this.name;
try { try {
throw err; throw err;
} catch(e) { } catch (e) {
return e.stack; return e.stack;
} }
} }

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit", "description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)", "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"version": "3.5.1", "version": "3.5.12",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },
@@ -23,15 +23,15 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"commander": "~2.19.0", "commander": "~2.20.0",
"source-map": "~0.6.1" "source-map": "~0.6.1"
}, },
"devDependencies": { "devDependencies": {
"acorn": "~6.1.1", "acorn": "~6.1.1",
"semver": "~5.6.0" "semver": "~6.0.0"
}, },
"scripts": { "scripts": {
"test": "node test/run-tests.js" "test": "node test/compress.js && node test/mocha.js"
}, },
"keywords": [ "keywords": [
"cli", "cli",

383
test/run-tests.js → test/compress.js Executable file → Normal file
View File

@@ -1,25 +1,32 @@
#! /usr/bin/env node #! /usr/bin/env node
var U = require("./node");
var path = require("path");
var fs = require("fs");
var assert = require("assert"); var assert = require("assert");
var fs = require("fs");
var path = require("path");
var sandbox = require("./sandbox"); var sandbox = require("./sandbox");
var semver = require("semver"); var semver = require("semver");
var U = require("./node");
var tests_dir = path.dirname(module.filename);
var failures = 0; var failures = 0;
var failed_files = {}; var failed_files = Object.create(null);
var minify_options = require("./ufuzz.json").map(JSON.stringify); var minify_options = require("./ufuzz.json").map(JSON.stringify);
var dir = path.resolve(path.dirname(module.filename), "compress");
run_compress_tests(); fs.readdirSync(dir).filter(function(name) {
return /\.js$/i.test(name);
}).forEach(function(file) {
log("--- {file}", { file: file });
var tests = parse_test(path.resolve(dir, file));
for (var i in tests) if (!test_case(tests[i])) {
failures++;
failed_files[file] = 1;
}
});
if (failures) { if (failures) {
console.error("\n!!! Failed " + failures + " test cases."); console.error();
console.error("!!! Failed " + failures + " test case(s).");
console.error("!!! " + Object.keys(failed_files).join(", ")); console.error("!!! " + Object.keys(failed_files).join(", "));
process.exit(1); process.exit(1);
} }
console.log();
require("./mocha.js");
/* -----[ utils ]----- */ /* -----[ utils ]----- */
@@ -46,11 +53,11 @@ function parse_test(file) {
filename: file filename: file
}); });
} catch (e) { } catch (e) {
console.log("Caught error while parsing tests in " + file + "\n"); console.error("Caught error while parsing tests in " + file);
console.log(e); console.error(e);
throw e; process.exit(1);
} }
var tests = {}; var tests = Object.create(null);
var tw = new U.TreeWalker(function(node, descend) { var tw = new U.TreeWalker(function(node, descend) {
if (node instanceof U.AST_LabeledStatement if (node instanceof U.AST_LabeledStatement
&& tw.parent() instanceof U.AST_Toplevel) { && tw.parent() instanceof U.AST_Toplevel) {
@@ -167,7 +174,17 @@ function reminify(orig_options, input_code, input_formatted, expect_stdout) {
var options_formatted = JSON.stringify(options, null, 4); var options_formatted = JSON.stringify(options, null, 4);
var result = U.minify(input_code, options); var result = U.minify(input_code, options);
if (result.error) { if (result.error) {
log("!!! failed input reminify\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n--ERROR---\n{error}\n\n", { log([
"!!! failed input reminify",
"---INPUT---",
"{input}",
"---OPTIONS---",
"{options}",
"--ERROR---",
"{error}",
"",
"",
].join("\n"), {
input: input_formatted, input: input_formatted,
options: options_formatted, options: options_formatted,
error: result.error, error: result.error,
@@ -179,7 +196,21 @@ function reminify(orig_options, input_code, input_formatted, expect_stdout) {
stdout = expect_stdout; stdout = expect_stdout;
} }
if (!sandbox.same_stdout(expect_stdout, stdout)) { if (!sandbox.same_stdout(expect_stdout, stdout)) {
log("!!! failed running reminified input\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n---OUTPUT---\n{output}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", { log([
"!!! failed running reminified input",
"---INPUT---",
"{input}",
"---OPTIONS---",
"{options}",
"---OUTPUT---",
"{output}",
"---EXPECTED {expected_type}---",
"{expected}",
"---ACTUAL {actual_type}---",
"{actual}",
"",
"",
].join("\n"), {
input: input_formatted, input: input_formatted,
options: options_formatted, options: options_formatted,
output: result.code, output: result.code,
@@ -200,148 +231,186 @@ function run_code(code) {
return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result; return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result;
} }
function run_compress_tests() { function test_case(test) {
var dir = path.resolve(tests_dir, "compress"); log(" Running test [{name}]", { name: test.name });
fs.readdirSync(dir).filter(function(name) { var output_options = test.beautify || {};
return /\.js$/i.test(name); var expect;
}).forEach(function(file) { if (test.expect) {
log("--- {file}", { file: file }); expect = make_code(to_toplevel(test.expect, test.mangle), output_options);
function test_case(test) { } else {
log(" Running test [{name}]", { name: test.name }); expect = test.expect_exact;
var output_options = test.beautify || {}; }
var expect; var input = to_toplevel(test.input, test.mangle);
if (test.expect) { var input_code = make_code(input);
expect = make_code(to_toplevel(test.expect, test.mangle), output_options); var input_formatted = make_code(test.input, {
} else { beautify: true,
expect = test.expect_exact; comments: "all",
} keep_quoted_props: true,
var input = to_toplevel(test.input, test.mangle); quote_style: 3,
var input_code = make_code(input);
var input_formatted = make_code(test.input, {
beautify: true,
quote_style: 3,
keep_quoted_props: true
});
try {
U.parse(input_code);
} catch (ex) {
log("!!! Cannot parse input\n---INPUT---\n{input}\n--PARSE ERROR--\n{error}\n\n", {
input: input_formatted,
error: ex,
});
return false;
}
var options = U.defaults(test.options, {
warnings: false
});
var warnings_emitted = [];
var original_warn_function = U.AST_Node.warn_function;
if (test.expect_warnings) {
U.AST_Node.warn_function = function(text) {
warnings_emitted.push("WARN: " + text);
};
if (!options.warnings) options.warnings = true;
}
if (test.mangle && test.mangle.properties && test.mangle.properties.keep_quoted) {
var quoted_props = test.mangle.properties.reserved;
if (!Array.isArray(quoted_props)) quoted_props = [];
test.mangle.properties.reserved = quoted_props;
U.reserve_quoted_keys(input, quoted_props);
}
if (test.rename) {
input.figure_out_scope(test.mangle);
input.expand_names(test.mangle);
}
var cmp = new U.Compressor(options, true);
var output = cmp.compress(input);
output.figure_out_scope(test.mangle);
if (test.mangle) {
output.compute_char_frequency(test.mangle);
output.mangle_names(test.mangle);
if (test.mangle.properties) {
output = U.mangle_properties(output, test.mangle.properties);
}
}
output = make_code(output, output_options);
if (expect != output) {
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
input: input_formatted,
output: output,
expected: expect
});
return false;
}
// expect == output
try {
U.parse(output);
} catch (ex) {
log("!!! Test matched expected result but cannot parse output\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n--REPARSE ERROR--\n{error}\n\n", {
input: input_formatted,
output: output,
error: ex,
});
return false;
}
if (test.expect_warnings) {
U.AST_Node.warn_function = original_warn_function;
var expected_warnings = make_code(test.expect_warnings, {
beautify: false,
quote_style: 2, // force double quote to match JSON
});
warnings_emitted = warnings_emitted.map(function(input) {
return input.split(process.cwd() + path.sep).join("").split(path.sep).join("/");
});
var actual_warnings = JSON.stringify(warnings_emitted);
if (expected_warnings != actual_warnings) {
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED WARNINGS---\n{expected_warnings}\n---ACTUAL WARNINGS---\n{actual_warnings}\n\n", {
input: input_formatted,
expected_warnings: expected_warnings,
actual_warnings: actual_warnings,
});
return false;
}
}
if (test.expect_stdout
&& (!test.node_version || semver.satisfies(process.version, test.node_version))) {
var stdout = run_code(input_code);
if (test.expect_stdout === true) {
test.expect_stdout = stdout;
}
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
log("!!! Invalid input or expected stdout\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
input: input_formatted,
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
expected: test.expect_stdout,
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
actual: stdout,
});
return false;
}
stdout = run_code(output);
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
input: input_formatted,
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
expected: test.expect_stdout,
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
actual: stdout,
});
return false;
}
if (!reminify(test.options, input_code, input_formatted, test.expect_stdout)) {
return false;
}
}
return true;
}
var tests = parse_test(path.resolve(dir, file));
for (var i in tests) if (tests.hasOwnProperty(i)) {
if (!test_case(tests[i])) {
failures++;
failed_files[file] = 1;
}
}
}); });
try {
U.parse(input_code);
} catch (ex) {
log([
"!!! Cannot parse input",
"---INPUT---",
"{input}",
"--PARSE ERROR--",
"{error}",
"",
"",
].join("\n"), {
input: input_formatted,
error: ex,
});
return false;
}
var warnings_emitted = [];
if (test.expect_warnings) {
var expected_warnings = make_code(test.expect_warnings, {
beautify: false,
quote_style: 2, // force double quote to match JSON
});
U.AST_Node.log_function(function(text) {
warnings_emitted.push(text);
}, /"INFO: /.test(expected_warnings));
}
if (test.mangle && test.mangle.properties && test.mangle.properties.keep_quoted) {
var quoted_props = test.mangle.properties.reserved;
if (!Array.isArray(quoted_props)) quoted_props = [];
test.mangle.properties.reserved = quoted_props;
U.reserve_quoted_keys(input, quoted_props);
}
if (test.rename) {
input.figure_out_scope(test.mangle);
input.expand_names(test.mangle);
}
var cmp = new U.Compressor(test.options, true);
var output = cmp.compress(input);
output.figure_out_scope(test.mangle);
if (test.mangle) {
output.compute_char_frequency(test.mangle);
output.mangle_names(test.mangle);
if (test.mangle.properties) {
output = U.mangle_properties(output, test.mangle.properties);
}
}
output = make_code(output, output_options);
if (expect != output) {
log([
"!!! failed",
"---INPUT---",
"{input}",
"---OUTPUT---",
"{output}",
"---EXPECTED---",
"{expected}",
"",
"",
].join("\n"), {
input: input_formatted,
output: output,
expected: expect
});
return false;
}
// expect == output
try {
U.parse(output);
} catch (ex) {
log([
"!!! Test matched expected result but cannot parse output",
"---INPUT---",
"{input}",
"---OUTPUT---",
"{output}",
"--REPARSE ERROR--",
"{error}",
"",
"",
].join("\n"), {
input: input_formatted,
output: output,
error: ex,
});
return false;
}
if (test.expect_warnings) {
warnings_emitted = warnings_emitted.map(function(input) {
return input.split(process.cwd() + path.sep).join("").split(path.sep).join("/");
});
var actual_warnings = JSON.stringify(warnings_emitted);
if (expected_warnings != actual_warnings) {
log([
"!!! failed",
"---INPUT---",
"{input}",
"---EXPECTED WARNINGS---",
"{expected_warnings}",
"---ACTUAL WARNINGS---",
"{actual_warnings}",
"",
"",
].join("\n"), {
input: input_formatted,
expected_warnings: expected_warnings,
actual_warnings: actual_warnings,
});
return false;
}
}
if (test.expect_stdout
&& (!test.node_version || semver.satisfies(process.version, test.node_version))) {
var stdout = run_code(input_code);
if (test.expect_stdout === true) {
test.expect_stdout = stdout;
}
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
log([
"!!! Invalid input or expected stdout",
"---INPUT---",
"{input}",
"---EXPECTED {expected_type}---",
"{expected}",
"---ACTUAL {actual_type}---",
"{actual}",
"",
"",
].join("\n"), {
input: input_formatted,
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
expected: test.expect_stdout,
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
actual: stdout,
});
return false;
}
stdout = run_code(output);
if (!sandbox.same_stdout(test.expect_stdout, stdout)) {
log([
"!!! failed",
"---INPUT---",
"{input}",
"---EXPECTED {expected_type}---",
"{expected}",
"---ACTUAL {actual_type}---",
"{actual}",
"",
"",
].join("\n"), {
input: input_formatted,
expected_type: typeof test.expect_stdout == "string" ? "STDOUT" : "ERROR",
expected: test.expect_stdout,
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
actual: stdout,
});
return false;
}
if (!reminify(test.options, input_code, input_formatted, test.expect_stdout)) {
return false;
}
}
return true;
} }
function tmpl() { function tmpl() {

View File

@@ -289,3 +289,25 @@ increment_decrement_2: {
} }
expect_stdout: "42" expect_stdout: "42"
} }
issue_3375: {
options = {
assignments: true,
reduce_vars: true,
}
input: {
console.log(typeof function(b) {
var a = b += 1;
--b;
return a;
}("object"));
}
expect: {
console.log(typeof function(b) {
var a = b += 1;
--b;
return a;
}("object"));
}
expect_stdout: "string"
}

View File

@@ -3497,10 +3497,10 @@ issue_2437_1: {
return Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}), return Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
result; result;
} }
var req, detectFunc = function(){}; var req = new XMLHttpRequest(), detectFunc = function(){};
(req = new XMLHttpRequest()).onreadystatechange = detectFunc; return req.onreadystatechange = detectFunc,
result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc; result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc,
return req.onreadystatechange = null, result; req.onreadystatechange = null, result;
}()); }());
} }
} }
@@ -3545,8 +3545,8 @@ issue_2437_2: {
if (xhrDesc) if (xhrDesc)
return (req = new XMLHttpRequest()).onreadystatechange, return (req = new XMLHttpRequest()).onreadystatechange,
Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}); Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {});
var req; var req = new XMLHttpRequest();
(req = new XMLHttpRequest).onreadystatechange = function(){}, req.onreadystatechange = function(){},
req[SYMBOL_FAKE_ONREADYSTATECHANGE_1], req[SYMBOL_FAKE_ONREADYSTATECHANGE_1],
req.onreadystatechange = null; req.onreadystatechange = null;
}(); }();
@@ -4194,7 +4194,7 @@ may_throw_2: {
var a = x(); var a = x();
++b; ++b;
return b(a); return b(a);
} catch(e) {} } catch (e) {}
console.log(b); console.log(b);
} }
f(0); f(0);
@@ -4204,7 +4204,7 @@ may_throw_2: {
try { try {
var a = x(); var a = x();
return (++b)(a); return (++b)(a);
} catch(e) {} } catch (e) {}
console.log(b); console.log(b);
} }
f(0); f(0);
@@ -6157,3 +6157,24 @@ sub_property: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
assign_undeclared: {
options = {
collapse_vars: true,
toplevel: true,
unused: true,
}
input: {
var A = (console.log(42), function() {});
B = new A();
console.log(typeof B);
}
expect: {
B = new (console.log(42), function() {})();
console.log(typeof B);
}
expect_stdout: [
"42",
"object",
]
}

View File

@@ -345,3 +345,38 @@ is_boolean_var: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
is_defined: {
options = {
comparisons: true,
}
input: {
console.log(function a() {
return void 0 === a;
}());
}
expect: {
console.log(function a() {
return a, false;
}());
}
expect_stdout: "false"
expect_warnings: [
"WARN: Expression always defined [test/compress/comparisons.js:2,19]",
]
}
unsafe_indexOf: {
options = {
booleans: true,
comparisons: true,
unsafe: true,
}
input: {
if (Object.keys({ foo: 42 }).indexOf("foo") >= 0) console.log("PASS");
}
expect: {
if (~Object.keys({ foo: 42 }).indexOf("foo")) console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -1416,3 +1416,58 @@ issue_3271: {
} }
expect_stdout: "1 1" expect_stdout: "1 1"
} }
iife_condition: {
options = {
conditionals: true,
side_effects: true,
}
input: {
if (function() {
return console;
}())
console.log("PASS");
}
expect: {
!function() {
return console;
}() || console.log("PASS");
}
expect_stdout: "PASS"
}
angularjs_chain: {
options = {
conditionals: true,
passes: 2,
side_effects: true,
}
input: {
function nonComputedMember(left, right, context, create) {
var lhs = left();
if (create && create !== 1) {
if (lhs && lhs[right] == null) {
lhs[right] = {};
}
}
var value = lhs != null ? lhs[right] : undefined;
if (context) {
return { context: lhs, name: right, value: value };
} else {
return value;
}
}
}
expect: {
function nonComputedMember(left, right, context, create) {
var lhs = left();
create && 1 !== create && lhs && null == lhs[right] && (lhs[right] = {});
var value = null != lhs ? lhs[right] : void 0;
return context ? {
context: lhs,
name: right,
value: value
} : value;
}
}
}

View File

@@ -942,3 +942,74 @@ issue_2929: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
unsafe_string_replace: {
options = {
side_effects: true,
unsafe: true,
}
input: {
"foo".replace("f", function() {
console.log("PASS");
});
}
expect: {
"foo".replace("f", function() {
console.log("PASS");
});
}
expect_stdout: "PASS"
}
issue_3402: {
options = {
dead_code: true,
evaluate: true,
functions: true,
passes: 2,
reduce_vars: true,
side_effects: true,
toplevel: true,
typeofs: true,
unused: true,
}
input: {
var f = function f() {
f = 42;
console.log(typeof f);
};
"function" == typeof f && f();
"function" == typeof f && f();
console.log(typeof f);
}
expect: {
function f() {
console.log(typeof f);
}
f();
f();
console.log(typeof f);
}
expect_stdout: [
"function",
"function",
"function",
]
}
issue_3406: {
options = {
dead_code: true,
}
input: {
console.log(function f(a) {
return delete (f = a);
}());
}
expect: {
console.log(function f(a) {
return delete (0, a);
}());
}
expect_stdout: "true"
}

View File

@@ -144,7 +144,7 @@ unused_var_in_catch: {
function foo() { function foo() {
try { try {
foo(); foo();
} catch(ex) { } catch (ex) {
var x = 10; var x = 10;
} }
} }
@@ -153,7 +153,7 @@ unused_var_in_catch: {
function foo() { function foo() {
try { try {
foo(); foo();
} catch(ex) {} } catch (ex) {}
} }
} }
} }
@@ -166,7 +166,7 @@ used_var_in_catch: {
function foo() { function foo() {
try { try {
foo(); foo();
} catch(ex) { } catch (ex) {
var x = 10; var x = 10;
} }
return x; return x;
@@ -176,7 +176,7 @@ used_var_in_catch: {
function foo() { function foo() {
try { try {
foo(); foo();
} catch(ex) { } catch (ex) {
var x = 10; var x = 10;
} }
return x; return x;
@@ -797,6 +797,7 @@ assign_chain: {
issue_1583: { issue_1583: {
options = { options = {
keep_fargs: true, keep_fargs: true,
passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
unused: true, unused: true,
@@ -1004,7 +1005,7 @@ issue_1715_4: {
delete_assign_1: { delete_assign_1: {
options = { options = {
booleans: true, booleans: true,
side_effects: true, evaluate: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@@ -1023,7 +1024,7 @@ delete_assign_1: {
console.log((1 / 0, !0)); console.log((1 / 0, !0));
console.log((1 / 0, !0)); console.log((1 / 0, !0));
console.log((NaN, !0)); console.log((NaN, !0));
console.log((0 / 0, !0)); console.log((NaN, !0));
} }
expect_stdout: true expect_stdout: true
} }
@@ -1031,8 +1032,8 @@ delete_assign_1: {
delete_assign_2: { delete_assign_2: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
keep_infinity: true, keep_infinity: true,
side_effects: true,
toplevel: true, toplevel: true,
unused: true, unused: true,
} }
@@ -1051,7 +1052,7 @@ delete_assign_2: {
console.log((Infinity, !0)); console.log((Infinity, !0));
console.log((1 / 0, !0)); console.log((1 / 0, !0));
console.log((NaN, !0)); console.log((NaN, !0));
console.log((0 / 0, !0)); console.log((NaN, !0));
} }
expect_stdout: true expect_stdout: true
} }
@@ -1144,6 +1145,7 @@ var_catch_toplevel: {
options = { options = {
conditionals: true, conditionals: true,
negate_iife: true, negate_iife: true,
passes: 2,
reduce_funcs: true, reduce_funcs: true,
reduce_vars: true, reduce_vars: true,
side_effects: true, side_effects: true,
@@ -1156,7 +1158,7 @@ var_catch_toplevel: {
try { try {
a++; a++;
x(); x();
} catch(a) { } catch (a) {
if (a) var a; if (a) var a;
var a = 10; var a = 10;
} }
@@ -1167,7 +1169,7 @@ var_catch_toplevel: {
!function() { !function() {
try { try {
x(); x();
} catch(a) { } catch (a) {
var a; var a;
} }
}(); }();
@@ -2005,3 +2007,24 @@ issue_3233: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3375: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var b = 1;
var a = c = [], c = --b + ("function" == typeof f && f());
var a = c && c[a];
console.log(a, b);
}
expect: {
var b = 1;
var a = [], c = --b + ("function" == typeof f && f());
a = c && c[a];
console.log(a, b);
}
expect_stdout: "0 0"
}

View File

@@ -246,7 +246,7 @@ unsafe_constant: {
} }
expect: { expect: {
console.log( console.log(
true.a, void 0,
false.a, false.a,
null.a, null.a,
(void 0).a (void 0).a
@@ -278,7 +278,7 @@ unsafe_object: {
o + 1, o + 1,
2, 2,
o.b + 1, o.b + 1,
1..b + 1 NaN
); );
} }
expect_stdout: true expect_stdout: true
@@ -365,7 +365,7 @@ unsafe_object_repeated: {
o + 1, o + 1,
2, 2,
o.b + 1, o.b + 1,
1..b + 1 NaN
); );
} }
expect_stdout: true expect_stdout: true
@@ -444,8 +444,8 @@ unsafe_integer_key: {
2, 2,
2, 2,
({0:1})[1] + 1, ({0:1})[1] + 1,
1[1] + 1, NaN,
1["1"] + 1 NaN
); );
} }
expect_stdout: true expect_stdout: true
@@ -500,8 +500,8 @@ unsafe_float_key: {
2, 2,
2, 2,
({2.72:1})[3.14] + 1, ({2.72:1})[3.14] + 1,
1[3.14] + 1, NaN,
1["3.14"] + 1 NaN
); );
} }
expect_stdout: true expect_stdout: true
@@ -635,12 +635,12 @@ unsafe_string_bad_index: {
} }
expect: { expect: {
console.log( console.log(
"1234".a + 1, NaN,
"1234"["a"] + 1, NaN,
"1234"[3.14] + 1 NaN
); );
} }
expect_stdout: true expect_stdout: "NaN NaN NaN"
} }
prototype_function: { prototype_function: {
@@ -820,8 +820,8 @@ unsafe_charAt_noop: {
} }
expect: { expect: {
console.log( console.log(
s.charAt(0), s[0],
"string".charAt(x), "string"[0 | x],
(typeof x)[0] (typeof x)[0]
); );
} }
@@ -1124,14 +1124,14 @@ issue_2207_1: {
console.log(Math.max(3, 6, 2, 7, 3, 4)); console.log(Math.max(3, 6, 2, 7, 3, 4));
console.log(Math.cos(1.2345)); console.log(Math.cos(1.2345));
console.log(Math.cos(1.2345) - Math.sin(4.321)); console.log(Math.cos(1.2345) - Math.sin(4.321));
console.log(Math.pow(Math.PI, Math.E - Math.LN10)); console.log(Math.pow(Math.PI, Math.E - Math.LN10).toFixed(15));
} }
expect: { expect: {
console.log("A"); console.log("A");
console.log(7); console.log(7);
console.log(Math.cos(1.2345)); console.log(Math.cos(1.2345));
console.log(1.2543732512566947); console.log(1.2543732512566947);
console.log(1.6093984514472044); console.log("1.609398451447204");
} }
expect_stdout: true expect_stdout: true
} }
@@ -1687,3 +1687,73 @@ try_increment: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
unsafe_escaped: {
options = {
evaluate: true,
inline: true,
passes: 3,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
(function(a) {
console.log(function(index) {
return a[index];
}(function(term) {
return a.indexOf(term);
}("PASS")));
})([ "PASS" ]);
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}
unsafe_string_replace: {
options = {
evaluate: true,
unsafe: true,
}
input: {
"foo".replace("f", function() {
console.log("PASS");
});
}
expect: {
"foo".replace("f", function() {
console.log("PASS");
});
}
expect_stdout: "PASS"
}
issue_3387_1: {
options = {
evaluate: true,
}
input: {
console.log(1 + (2 + "3"[4]));
}
expect: {
console.log(1 + (2 + "3"[4]));
}
expect_stdout: "NaN"
}
issue_3387_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(1 + (2 + "3"[4]));
}
expect: {
console.log(NaN);
}
expect_stdout: "NaN"
}

View File

@@ -2703,3 +2703,448 @@ loop_inline: {
} }
expect_stdout: "undefined" expect_stdout: "undefined"
} }
functions: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
!function() {
var a = function a() {
return a && "a";
};
var b = function x() {
return !!x;
};
var c = function(c) {
return c;
};
if (c(b(a()))) {
var d = function() {};
var e = function y() {
return typeof y;
};
var f = function(f) {
return f;
};
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
}
}();
}
expect: {
!function() {
function a() {
return a && "a";
}
function b() {
return !!b;
}
var c = function(c) {
return c;
};
if (c(b(a()))) {
function d() {}
function e() {
return typeof e;
}
var f = function(f) {
return f;
};
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
}
}();
}
expect_stdout: "a true 42 function function function"
}
functions_use_strict: {
options = {
functions: true,
reduce_vars: true,
unused: true,
}
input: {
"use strict";
!function() {
var a = function a() {
return a && "a";
};
var b = function x() {
return !!x;
};
var c = function(c) {
return c;
};
if (c(b(a()))) {
var d = function() {};
var e = function y() {
return typeof y;
};
var f = function(f) {
return f;
};
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
}
}();
}
expect: {
"use strict";
!function() {
function a() {
return a && "a";
}
function b() {
return !!b;
}
var c = function(c) {
return c;
};
if (c(b(a()))) {
var d = function() {};
var e = function y() {
return typeof y;
};
var f = function(f) {
return f;
};
console.log(a(d()), b(e()), c(f(42)), typeof d, e(), typeof f);
}
}();
}
expect_stdout: "a true 42 function function function"
}
issue_2437: {
options = {
collapse_vars: true,
conditionals: true,
functions: true,
inline: true,
join_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function foo() {
return bar();
}
function bar() {
if (xhrDesc) {
var req = new XMLHttpRequest();
var result = !!req.onreadystatechange;
Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {});
return result;
} else {
var req = new XMLHttpRequest();
var detectFunc = function(){};
req.onreadystatechange = detectFunc;
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
req.onreadystatechange = null;
return result;
}
}
console.log(foo());
}
expect: {
console.log(function() {
if (xhrDesc) {
var result = !!(req = new XMLHttpRequest()).onreadystatechange;
return Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
result;
}
function detectFunc() {}
var req = new XMLHttpRequest();
return req.onreadystatechange = detectFunc,
result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc,
req.onreadystatechange = null, result;
}());
}
}
issue_2485: {
options = {
functions: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
var foo = function(bar) {
var n = function(a, b) {
return a + b;
};
var sumAll = function(arg) {
return arg.reduce(n, 0);
};
var runSumAll = function(arg) {
return sumAll(arg);
};
bar.baz = function(arg) {
var n = runSumAll(arg);
return (n.get = 1), n;
};
return bar;
};
var bar = foo({});
console.log(bar.baz([1, 2, 3]));
}
expect: {
var foo = function(bar) {
function n(a, b) {
return a + b;
}
function runSumAll(arg) {
return function(arg) {
return arg.reduce(n, 0);
}(arg);
}
bar.baz = function(arg) {
var n = runSumAll(arg);
return (n.get = 1), n;
};
return bar;
};
var bar = foo({});
console.log(bar.baz([1, 2, 3]));
}
expect_stdout: "6"
}
issue_3364: {
options = {
functions: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
mangle = {}
input: {
var s = 2, a = 100, b = 10, c = 0;
function f(p, e, r) {
try {
for (var i = 1; i-- > 0;)
var a = function(x) {
function g(y) {
y && y[a++];
}
var x = g(--s >= 0 && f(c++));
for (var j = 1; --j > 0;);
}();
} catch (e) {
try {
return;
} catch (z) {
for (var k = 1; --k > 0;) {
for (var l = 1; l > 0; --l) {
var n = function() {};
for (var k in n)
var o = (n, k);
}
}
}
}
}
var r = f();
console.log(c);
}
expect: {
var s = 2, c = 0;
(function n(r, o, a) {
try {
for (var f = 1; f-- >0;)
var t = function(r) {
(function(r) {
r && r[t++];
})(--s >= 0 && n(c++));
for (var o = 1; --o > 0;);
}();
} catch (o) {
try {
return;
} catch (r) {
for (var v = 1; --v > 0;)
for (var i = 1; i > 0;--i) {
function u() {}
for (var v in u);
}
}
}
})();
console.log(c);
}
expect_stdout: "2"
}
issue_3366: {
options = {
functions: true,
inline: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {
return function() {};
}
var a = g();
(function() {
this && a && console.log("PASS");
})();
}
f();
}
expect: {
void function() {
this && a && console.log("PASS");
}();
function a() {}
}
expect_stdout: "PASS"
}
issue_3371: {
options = {
functions: true,
inline: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
(function() {
var a = function f() {
(function() {
console.log(typeof f);
})();
};
while (a());
})();
}
expect: {
(function() {
function a() {
console.log(typeof a);
}
while (a());
})();
}
expect_stdout: "function"
}
class_iife: {
options = {
inline: true,
sequences: true,
toplevel: true,
}
input: {
var A = function() {
function B() {}
B.prototype.m = function() {
console.log("PASS");
};
return B;
}();
new A().m();
}
expect: {
var A = (B.prototype.m = function() {
console.log("PASS");
}, B);
function B() {}
new A().m();
}
expect_stdout: "PASS"
}
issue_3400: {
options = {
collapse_vars: true,
inline: true,
reduce_funcs: true,
reduce_vars: true,
unused: true,
}
input: {
(function(f) {
console.log(f()()[0].p);
})(function() {
function g() {
function h(u) {
var o = {
p: u
};
return console.log(o[g]), o;
}
function e() {
return [ 42 ].map(function(v) {
return h(v);
});
}
return e();
}
return g;
});
}
expect: {
void console.log(function g() {
function e() {
return [42].map(function(v) {
return o = {
p: v
}, console.log(o[g]) , o;
var o;
});
}
return e();
}()[0].p);
}
expect_stdout: [
"undefined",
"42",
]
}
issue_3402: {
options = {
evaluate: true,
functions: true,
reduce_vars: true,
side_effects: true,
toplevel: true,
typeofs: true,
unused: true,
}
input: {
var f = function f() {
f = 42;
console.log(typeof f);
};
"function" == typeof f && f();
"function" == typeof f && f();
console.log(typeof f);
}
expect: {
var f = function f() {
f = 42;
console.log(typeof f);
};
f();
f();
console.log(typeof f);
}
expect_stdout: [
"function",
"function",
"function",
]
}

View File

@@ -59,9 +59,9 @@ do_screw_try_catch: {
input: { input: {
good = function(e){ good = function(e){
return function(error){ return function(error){
try{ try {
e() e()
} catch(e) { } catch (e) {
error(e) error(e)
} }
} }
@@ -70,9 +70,9 @@ do_screw_try_catch: {
expect: { expect: {
good = function(n){ good = function(n){
return function(t){ return function(t){
try{ try {
n() n()
} catch(n) { } catch (n) {
t(n) t(n)
} }
} }
@@ -93,9 +93,9 @@ dont_screw_try_catch: {
input: { input: {
bad = function(e){ bad = function(e){
return function(error){ return function(error){
try{ try {
e() e()
} catch(e) { } catch (e) {
error(e) error(e)
} }
} }
@@ -104,9 +104,9 @@ dont_screw_try_catch: {
expect: { expect: {
bad = function(t){ bad = function(t){
return function(n){ return function(n){
try{ try {
t() t()
} catch(t) { } catch (t) {
n(t) n(t)
} }
} }
@@ -137,7 +137,7 @@ do_screw_try_catch_undefined: {
} }
expect: { expect: {
function a(o){ function a(o){
try{ try {
throw "Stuff" throw "Stuff"
} catch (o) { } catch (o) {
console.log("caught: "+o) console.log("caught: "+o)
@@ -172,7 +172,7 @@ dont_screw_try_catch_undefined: {
} }
expect: { expect: {
function a(n){ function a(n){
try{ try {
throw "Stuff" throw "Stuff"
} catch (undefined) { } catch (undefined) {
console.log("caught: " + undefined) console.log("caught: " + undefined)
@@ -861,3 +861,111 @@ issue_3215_4: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3355_1: {
mangle = {
ie8: false,
}
input: {
(function f() {
var f;
})();
(function g() {
})();
console.log(typeof f === typeof g);
}
expect: {
(function o() {
var o;
})();
(function o() {
})();
console.log(typeof f === typeof g);
}
expect_stdout: "true"
}
issue_3355_2: {
mangle = {
ie8: true,
}
input: {
(function f() {
var f;
})();
(function g() {
})();
console.log(typeof f === typeof g);
}
expect: {
(function f() {
var f;
})();
(function g() {
})();
console.log(typeof f === typeof g);
}
expect_stdout: "true"
}
issue_3355_3: {
mangle = {
ie8: false,
}
input: {
!function(a) {
"aaaaaaaaaa";
a();
var b = function c() {
var c = 42;
console.log("FAIL");
};
}(function() {
console.log("PASS");
});
}
expect: {
!function(a) {
"aaaaaaaaaa";
a();
var o = function a() {
var a = 42;
console.log("FAIL");
};
}(function() {
console.log("PASS");
});
}
expect_stdout: "PASS"
}
issue_3355_4: {
mangle = {
ie8: true,
}
input: {
!function(a) {
"aaaaaaaaaa";
a();
var b = function c() {
var c = 42;
console.log("FAIL");
};
}(function() {
console.log("PASS");
});
}
expect: {
!function(a) {
"aaaaaaaaaa";
a();
var o = function n() {
var n = 42;
console.log("FAIL");
};
}(function() {
console.log("PASS");
});
}
expect_stdout: "PASS"
}

View File

@@ -59,7 +59,6 @@ non_hoisted_function_after_return_2a: {
passes: 2, passes: 2,
side_effects: true, side_effects: true,
unused: true, unused: true,
warnings: "verbose",
} }
input: { input: {
function foo(x) { function foo(x) {
@@ -91,13 +90,13 @@ non_hoisted_function_after_return_2a: {
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]", "WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
"WARN: pass 0: last_count: Infinity, count: 37", "INFO: pass 0: last_count: Infinity, count: 37",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:7,20]", "INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:9,16]", "INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
"WARN: pass 1: last_count: 37, count: 18", "INFO: pass 1: last_count: 37, count: 18",
] ]
} }
@@ -213,7 +212,6 @@ non_hoisted_function_after_return_2a_strict: {
passes: 2, passes: 2,
side_effects: true, side_effects: true,
unused: true, unused: true,
warnings: "verbose",
} }
input: { input: {
"use strict"; "use strict";
@@ -250,13 +248,13 @@ non_hoisted_function_after_return_2a_strict: {
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]", "WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
"WARN: pass 0: last_count: Infinity, count: 48", "INFO: pass 0: last_count: Infinity, count: 48",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:8,20]", "INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:10,16]", "INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
"WARN: pass 1: last_count: 48, count: 29", "INFO: pass 1: last_count: 48, count: 29",
] ]
} }

View File

@@ -1,4 +1,3 @@
issue_1639_1: { issue_1639_1: {
options = { options = {
booleans: true, booleans: true,
@@ -12,7 +11,6 @@ issue_1639_1: {
} }
input: { input: {
var a = 100, b = 10; var a = 100, b = 10;
var L1 = 5; var L1 = 5;
while (--L1 > 0) { while (--L1 > 0) {
if ((--b), false) { if ((--b), false) {
@@ -21,7 +19,6 @@ issue_1639_1: {
} }
} }
} }
console.log(a, b); console.log(a, b);
} }
expect: { expect: {
@@ -29,7 +26,7 @@ issue_1639_1: {
if (--b, 0) var ignore = 0; if (--b, 0) var ignore = 0;
console.log(a, b); console.log(a, b);
} }
expect_stdout: true expect_stdout: "100 6"
} }
issue_1639_2: { issue_1639_2: {
@@ -44,25 +41,23 @@ issue_1639_2: {
} }
input: { input: {
var a = 100, b = 10; var a = 100, b = 10;
function f19() { function f19() {
if (++a, false) if (++a, false)
if (a) if (a)
if (++a); if (++a);
} }
f19(); f19();
console.log(a, b); console.log(a, b);
} }
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);
} }
expect_stdout: true expect_stdout: "101 10"
} }
issue_1639_3: { issue_1639_3: {
@@ -84,5 +79,5 @@ issue_1639_3: {
a++, a++,
console.log(a, b); console.log(a, b);
} }
expect_stdout: true expect_stdout: "101 10"
} }

View File

@@ -646,3 +646,30 @@ issue_2904: {
} }
expect_stdout: "1" expect_stdout: "1"
} }
issue_3371: {
options = {
functions: true,
join_vars: true,
loops: true,
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a = function() {
console.log("PASS");
};
while (a());
})();
}
expect: {
(function() {
function a() {
console.log("PASS");
}
for (; a(); );
})();
}
expect_stdout: "PASS"
}

View File

@@ -1862,3 +1862,29 @@ join_expr: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3389: {
options = {
evaluate: true,
properties: true,
reduce_vars: true,
unsafe: true,
}
input: {
(function() {
var a = "PASS";
if (delete b)
b = a[null] = 42;
console.log(a);
})();
}
expect: {
(function() {
var a = "PASS";
if (delete b)
b = a.null = 42;
console.log(a);
})();
}
expect_stdout: "PASS"
}

View File

@@ -192,38 +192,35 @@ unsafe_evaluate: {
unused: true, unused: true,
} }
input: { input: {
function f0(){ function f0() {
var a = { var a = { b: 1 };
b:1
};
console.log(a.b + 3); console.log(a.b + 3);
} }
function f1() {
function f1(){
var a = { var a = {
b:{ b: { c: 1 },
c:1 d: 2
},
d:2
}; };
console.log(a.b + 3, a.d + 4, a.b.c + 5, a.d.c + 6); console.log(a.b + 3, a.d + 4, a.b.c + 5, a.d.c + 6);
} }
f0();
f1();
} }
expect: { expect: {
function f0(){ function f0() {
console.log(4); console.log(4);
} }
function f1() {
function f1(){
var a = { var a = {
b:{ b: { c: 1 },
c:1 d: 2
},
d:2
}; };
console.log(a.b + 3, 6, 6, 2..c + 6); console.log(a.b + 3, 6, 6, NaN);
} }
f0();
f1();
} }
expect_stdout: true
} }
unsafe_evaluate_side_effect_free_1: { unsafe_evaluate_side_effect_free_1: {
@@ -281,8 +278,8 @@ unsafe_evaluate_escaped: {
console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }()); console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }());
} }
expect: { expect: {
console.log(function(){ var o={p:1}; console.log(o, o.p); return o.p; }()); console.log(function(){ var o={p:1}; console.log(o, 1); return o.p; }());
console.log(function(){ var o={p:2}; console.log(o.p, o); return o.p; }()); console.log(function(){ var o={p:2}; console.log(2, o); return o.p; }());
console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }()); console.log(function(){ var o={p:3},a=[o]; console.log(a[0].p++); return o.p; }());
} }
expect_stdout: true expect_stdout: true
@@ -6737,3 +6734,21 @@ drop_side_effect_free: {
} }
expect_stdout: "123" expect_stdout: "123"
} }
issue_3377: {
options = {
reduce_vars: true,
unused: true,
}
input: {
console.log(function f() {
return f[0], (f = 42);
}());
}
expect: {
console.log(function f() {
return f[0], (f = 42);
}());
}
expect_stdout: "42"
}

View File

@@ -490,6 +490,7 @@ issue_1758: {
delete_seq_1: { delete_seq_1: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -514,6 +515,7 @@ delete_seq_1: {
delete_seq_2: { delete_seq_2: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -538,6 +540,7 @@ delete_seq_2: {
delete_seq_3: { delete_seq_3: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
keep_infinity: true, keep_infinity: true,
side_effects: true, side_effects: true,
} }
@@ -563,6 +566,7 @@ delete_seq_3: {
delete_seq_4: { delete_seq_4: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
} }
@@ -590,6 +594,7 @@ delete_seq_4: {
delete_seq_5: { delete_seq_5: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
keep_infinity: true, keep_infinity: true,
sequences: true, sequences: true,
side_effects: true, side_effects: true,
@@ -618,6 +623,7 @@ delete_seq_5: {
delete_seq_6: { delete_seq_6: {
options = { options = {
booleans: true, booleans: true,
evaluate: true,
side_effects: true, side_effects: true,
} }
input: { input: {
@@ -702,7 +708,7 @@ side_effects_cascade_3: {
} }
expect: { expect: {
function f(a, b) { function f(a, b) {
!(b += a) && ((b = a) || (b -= a, b ^= a)), (b += a) || (b = a) || (b -= a, b ^= a),
a--; a--;
} }
} }
@@ -964,3 +970,39 @@ missing_link: {
console.log(a); console.log(a);
} }
} }
angularjs_chain: {
options = {
conditionals: true,
sequences: true,
side_effects: true,
}
input: {
function nonComputedMember(left, right, context, create) {
var lhs = left();
if (create && create !== 1) {
if (lhs && lhs[right] == null) {
lhs[right] = {};
}
}
var value = lhs != null ? lhs[right] : undefined;
if (context) {
return { context: lhs, name: right, value: value };
} else {
return value;
}
}
}
expect: {
function nonComputedMember(left, right, context, create) {
var lhs = left();
create && 1 !== create && lhs && null == lhs[right] && (lhs[right] = {});
var value = null != lhs ? lhs[right] : void 0;
return context ? {
context: lhs,
name: right,
value: value
} : value;
}
}
}

View File

@@ -1,7 +1,5 @@
exports["base54"] = base54;
exports["Compressor"] = Compressor; exports["Compressor"] = Compressor;
exports["defaults"] = defaults; exports["defaults"] = defaults;
exports["is_identifier"] = is_identifier;
exports["JS_Parse_Error"] = JS_Parse_Error; exports["JS_Parse_Error"] = JS_Parse_Error;
exports["mangle_properties"] = mangle_properties; exports["mangle_properties"] = mangle_properties;
exports["minify"] = minify; exports["minify"] = minify;
@@ -9,7 +7,6 @@ exports["OutputStream"] = OutputStream;
exports["parse"] = parse; exports["parse"] = parse;
exports["push_uniq"] = push_uniq; exports["push_uniq"] = push_uniq;
exports["reserve_quoted_keys"] = reserve_quoted_keys; exports["reserve_quoted_keys"] = reserve_quoted_keys;
exports["SourceMap"] = SourceMap;
exports["string_template"] = string_template; exports["string_template"] = string_template;
exports["tokenizer"] = tokenizer; exports["tokenizer"] = tokenizer;
exports["TreeTransformer"] = TreeTransformer; exports["TreeTransformer"] = TreeTransformer;

View File

@@ -0,0 +1,6 @@
var Foo = function Foo(){console.log(1+2);}; new Foo();
//# sourceMappingURL=data:application/json;charset=utf-8;base64,DeadBeef
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjpudWxsLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQU0sR0FBRyxHQUFDLEFBQUUsWUFBVyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBLEFBQUUsQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFDOyJ9

View File

@@ -0,0 +1,2 @@
new function(){console.log(3)};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19

View File

@@ -3,7 +3,7 @@
"use strict"; "use strict";
var site = "https://browserbench.org/JetStream"; var site = "https://browserbench.org/JetStream1.1";
if (typeof phantom == "undefined") { if (typeof phantom == "undefined") {
require("../tools/exit"); require("../tools/exit");
var args = process.argv.slice(2); var args = process.argv.slice(2);
@@ -62,8 +62,17 @@ if (typeof phantom == "undefined") {
if (debug) { if (debug) {
console.log("http://localhost:" + port + "/"); console.log("http://localhost:" + port + "/");
} else { } else {
child_process.exec("npm install phantomjs-prebuilt@2.1.14 --no-save", function(error) { child_process.spawn(process.platform == "win32" ? "npm.cmd" : "npm", [
if (error) throw error; "install",
"phantomjs-prebuilt@2.1.14",
"--no-audit",
"--no-optional",
"--no-save",
"--no-update-notifier",
], {
stdio: [ "ignore", 1, 2 ]
}).on("exit", function(code) {
if (code) throw new Error("npm install failed!");
var program = require("phantomjs-prebuilt").exec(process.argv[1], port); var program = require("phantomjs-prebuilt").exec(process.argv[1], port);
program.stdout.pipe(process.stdout); program.stdout.pipe(process.stdout);
program.stderr.pipe(process.stderr); program.stderr.pipe(process.stderr);

View File

@@ -47,7 +47,7 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should give sensible error against invalid input source map", function(done) { it("Should give sensible error against invalid input source map", function(done) {
var command = uglifyjscmd + " test/mocha.js --source-map content=blah,url=inline"; var command = uglifyjscmd + " test/mocha.js --source-map content=blah,url=inline --verbose";
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.deepEqual(stderr.split(/\n/).slice(0, 2), [ assert.deepEqual(stderr.split(/\n/).slice(0, 2), [
@@ -83,6 +83,7 @@ describe("bin/uglifyjs", function() {
"test/input/issue-2082/sample.js", "test/input/issue-2082/sample.js",
"--source-map", "content=test/input/issue-2082/sample.js.map", "--source-map", "content=test/input/issue-2082/sample.js.map",
"--source-map", "url=inline", "--source-map", "url=inline",
"--verbose",
].join(" "); ].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
@@ -113,13 +114,12 @@ describe("bin/uglifyjs", function() {
var child = exec(command, function(err, stdout) { var child = exec(command, function(err, stdout) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, read("test/input/issue-3040/expect.js"));
assert.strictEqual(stdout, read("test/input/pr-3040/expect.js"));
done(); done();
}); });
setTimeout(function() { setTimeout(function() {
fs.writeFileSync(mapFile, read("test/input/pr-3040/input.js.map")); fs.writeFileSync(mapFile, read("test/input/issue-3040/input.js.map"));
child.stdin.end(read("test/input/pr-3040/input.js")); child.stdin.end(read("test/input/issue-3040/input.js"));
}, 1000); }, 1000);
}); });
it("Should work with --keep-fnames (mangle only)", function(done) { it("Should work with --keep-fnames (mangle only)", function(done) {
@@ -202,7 +202,7 @@ describe("bin/uglifyjs", function() {
}); });
}); });
it("Should warn for missing inline source map", function(done) { it("Should warn for missing inline source map", function(done) {
var command = uglifyjscmd + " test/input/issue-1323/sample.js --source-map content=inline,url=inline"; var command = uglifyjscmd + " test/input/issue-1323/sample.js --source-map content=inline,url=inline --warn";
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, [ assert.strictEqual(stdout, [
@@ -221,6 +221,7 @@ describe("bin/uglifyjs", function() {
"test/input/issue-520/input.js", "test/input/issue-520/input.js",
"test/input/issue-1323/sample.js", "test/input/issue-1323/sample.js",
"--source-map", "content=inline,url=inline", "--source-map", "content=inline,url=inline",
"--warn",
].join(" "); ].join(" ");
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
@@ -466,7 +467,7 @@ describe("bin/uglifyjs", function() {
done(); done();
}); });
}); });
it("Should throw syntax error (catch(eval))", function(done) { it("Should throw syntax error (catch (eval))", function(done) {
var command = uglifyjscmd + ' test/input/invalid/try.js'; var command = uglifyjscmd + ' test/input/invalid/try.js';
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
@@ -647,7 +648,7 @@ describe("bin/uglifyjs", function() {
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.strictEqual(stdout, ""); assert.strictEqual(stdout, "");
assert.strictEqual(stderr, "Error parsing arguments for 'define': a-b\n"); assert.strictEqual(stderr, "ERROR: cannot parse arguments for 'define': a-b\n");
done(); done();
}); });
}); });
@@ -711,7 +712,7 @@ describe("bin/uglifyjs", function() {
var command = uglifyjscmd + " test/input/enclose/input.js --enclose window,undefined:window --wrap exports"; var command = uglifyjscmd + " test/input/enclose/input.js --enclose window,undefined:window --wrap exports";
exec(command, function(err, stdout, stderr) { exec(command, function(err, stdout, stderr) {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, '(function(window,undefined){(function(exports){function enclose(){console.log("test enclose")}enclose()})(typeof exports=="undefined"?exports={}:exports)})(window);\n'); assert.strictEqual(stdout, '(function(exports){(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window)})(typeof exports=="undefined"?exports={}:exports);\n');
done(); done();
}); });
}); });

View File

@@ -260,6 +260,60 @@ describe("comments", function() {
].join("\n")); ].join("\n"));
}); });
it("Should handle programmatic AST insertions gracefully", function() {
var ast = UglifyJS.parse([
"function f() {",
" //foo",
" bar;",
" return;",
"}",
].join("\n"));
ast.body[0].body[0] = new UglifyJS.AST_Throw({value: ast.body[0].body[0].body});
ast.body[0].body[1].value = new UglifyJS.AST_Number({value: 42});
assert.strictEqual(ast.print_to_string({comments: "all"}), [
"function f(){",
"//foo",
"throw bar;return 42}",
].join("\n"));
});
it("Should not duplicate sourceMappingURL", function() {
var code = [
"//# sourceMappingURL=input.map",
"print(42);",
"//# sourceMappingURL=input.map",
"",
"//# sourceMappingURL=input.map",
"//# sourceMappingURL=input.map",
"",
].join("\n");
var result = UglifyJS.minify(code, {
output: { comments: true },
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"//# sourceMappingURL=input.map",
"print(42);",
"//# sourceMappingURL=input.map",
"//# sourceMappingURL=input.map",
"//# sourceMappingURL=input.map",
].join("\n"));
result = UglifyJS.minify(code, {
output: { comments: true },
sourceMap: { url: "output.map" },
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"//# sourceMappingURL=input.map",
"print(42);",
"//# sourceMappingURL=input.map",
"//# sourceMappingURL=input.map",
"//# sourceMappingURL=output.map",
].join("\n"));
});
describe("comment before constant", function() { describe("comment before constant", function() {
var js = 'function f() { /*c1*/ var /*c2*/ foo = /*c3*/ false; return foo; }'; var js = 'function f() { /*c1*/ var /*c2*/ foo = /*c3*/ false; return foo; }';

View File

@@ -365,7 +365,7 @@ describe("minify", function() {
wrap: 'exports', wrap: 'exports',
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(window,undefined){(function(exports){function enclose(){console.log("test enclose")}enclose()})(typeof exports=="undefined"?exports={}:exports)})(window);'); assert.strictEqual(result.code, '(function(exports){(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window)})(typeof exports=="undefined"?exports={}:exports);');
}); });
}); });
}); });

View File

@@ -1,50 +0,0 @@
var assert = require("assert");
var semver = require("semver");
var spawn = require("child_process").spawn;
if (!process.env.UGLIFYJS_TEST_ALL) return;
function run(command, args, done) {
spawn(command, args, {
stdio: [ "ignore", 1, 2 ]
}).on("exit", function(code) {
assert.strictEqual(code, 0);
done();
});
}
describe("test/benchmark.js", function() {
this.timeout(10 * 60 * 1000);
[
"-b",
"-b braces",
"-m",
"-mc passes=3",
"-mc passes=3,toplevel",
"-mc passes=3,unsafe",
"-mc keep_fargs=false,passes=3",
"-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto",
].forEach(function(options) {
it("Should pass with options " + options, function(done) {
var args = options.split(/ /);
args.unshift("test/benchmark.js");
run(process.argv[0], args, done);
});
});
});
if (semver.satisfies(process.version, "0.12")) return;
describe("test/jetstream.js", function() {
this.timeout(20 * 60 * 1000);
[
"-mc",
"-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto",
].forEach(function(options) {
it("Should pass with options " + options, function(done) {
var args = options.split(/ /);
args.unshift("test/jetstream.js");
args.push("-b", "beautify=false,webkit");
run(process.argv[0], args, done);
});
});
});

View File

@@ -118,51 +118,33 @@ describe("sourcemaps", function() {
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-520/output.js", "utf8")); assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-520/output.js", "utf8"));
}); });
it("Should warn for missing inline source map", function() { it("Should warn for missing inline source map", function() {
var warn_function = UglifyJS.AST_Node.warn_function; var result = UglifyJS.minify(read("./test/input/issue-1323/sample.js"), {
var warnings = []; mangle: false,
UglifyJS.AST_Node.warn_function = function(txt) { sourceMap: {
warnings.push(txt); content: "inline"
}; },
try { warnings: true,
var result = UglifyJS.minify(read("./test/input/issue-1323/sample.js"), { });
mangle: false, assert.strictEqual(result.code, "var bar=function(bar){return bar};");
sourceMap: { assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 0" ]);
content: "inline"
}
});
assert.strictEqual(result.code, "var bar=function(bar){return bar};");
assert.strictEqual(warnings.length, 1);
assert.strictEqual(warnings[0], "inline source map not found: 0");
} finally {
UglifyJS.AST_Node.warn_function = warn_function;
}
}); });
it("Should handle multiple input and inline source map", function() { it("Should handle multiple input and inline source map", function() {
var warn_function = UglifyJS.AST_Node.warn_function; var result = UglifyJS.minify([
var warnings = []; read("./test/input/issue-520/input.js"),
UglifyJS.AST_Node.warn_function = function(txt) { read("./test/input/issue-1323/sample.js"),
warnings.push(txt); ], {
}; sourceMap: {
try { content: "inline",
var result = UglifyJS.minify([ url: "inline",
read("./test/input/issue-520/input.js"), },
read("./test/input/issue-1323/sample.js"), warnings: true,
], { });
sourceMap: { if (result.error) throw result.error;
content: "inline", assert.strictEqual(result.code, [
url: "inline", "var Foo=function(){console.log(3)};new Foo;var bar=function(o){return o};",
} "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwiMSJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFdBQWdCQyxRQUFRQyxJQUFJLElBQVMsSUFBSUYsSUNBbkQsSUFBSUcsSUFDQSxTQUFjQSxHQUNWLE9BQU9BIn0=",
}); ].join("\n"));
if (result.error) throw result.error; assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 1" ]);
assert.strictEqual(result.code, [
"var Foo=function(){console.log(3)};new Foo;var bar=function(o){return o};",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwiMSJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFdBQWdCQyxRQUFRQyxJQUFJLElBQVMsSUFBSUYsSUNBbkQsSUFBSUcsSUFDQSxTQUFjQSxHQUNWLE9BQU9BIn0=",
].join("\n"));
assert.strictEqual(warnings.length, 1);
assert.strictEqual(warnings[0], "inline source map not found: 1");
} finally {
UglifyJS.AST_Node.warn_function = warn_function;
}
}); });
it("Should drop source contents for includeSources=false", function() { it("Should drop source contents for includeSources=false", function() {
var result = UglifyJS.minify(read("./test/input/issue-520/input.js"), { var result = UglifyJS.minify(read("./test/input/issue-520/input.js"), {
@@ -187,6 +169,18 @@ describe("sourcemaps", function() {
map = JSON.parse(result.map); map = JSON.parse(result.map);
assert.ok(!("sourcesContent" in map)); assert.ok(!("sourcesContent" in map));
}); });
it("Should parse the correct sourceMappingURL", function() {
var result = UglifyJS.minify(read("./test/input/issue-3294/input.js"), {
compress: { toplevel: true },
sourceMap: {
content: "inline",
includeSources: true,
url: "inline"
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-3294/output.js", "utf8"));
});
}); });
describe("sourceMapInline", function() { describe("sourceMapInline", function() {

14
test/release/benchmark.js Normal file
View File

@@ -0,0 +1,14 @@
require("./run")([
"-b",
"-b braces",
"-m",
"-mc passes=3",
"-mc passes=3,toplevel",
"-mc passes=3,unsafe",
"-mc keep_fargs=false,passes=3",
"-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto",
].map(function(options) {
var args = options.split(/ /);
args.unshift("test/benchmark.js");
return args;
}));

View File

@@ -0,0 +1,9 @@
require("./run")([
"-mc",
"-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto",
].map(function(options) {
var args = options.split(/ /);
args.unshift("test/jetstream.js");
args.push("-b", "beautify=false,webkit");
return args;
}));

16
test/release/run.js Normal file
View File

@@ -0,0 +1,16 @@
var child_process = require("child_process");
module.exports = function(tasks) {
(function next() {
if (!tasks.length) return;
var args = tasks.shift();
console.log();
console.log("\u001B[36m$> " + args.join(" ") + "\u001B[39m");
child_process.spawn(process.argv[0], args, {
stdio: [ "ignore", 1, 2 ]
}).on("exit", function(code) {
if (code) process.exit(code);
next();
});
})();
};

View File

@@ -73,8 +73,10 @@ exports.run_code = function(code, reuse) {
process.stdout.write = original_write; process.stdout.write = original_write;
if (!reuse || code.indexOf(".prototype") >= 0) { if (!reuse || code.indexOf(".prototype") >= 0) {
context = null; context = null;
} else for (var key in context) { } else {
delete context[key]; vm.runInContext(Object.keys(context).map(function(name) {
return "delete " + name;
}).join("\n"), context);
} }
} }
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -1,61 +1,540 @@
<!doctype html>
<html> <html>
<head> <body>
</head> <script>
<body> !function() {
<script>(function(){ var names = [];
var props = {}; var scanned = [];
var to_scan = [];
function addObject(obj) { function scan(obj) {
if (obj == null) return; if (obj && typeof obj == "object" && !~scanned.indexOf(obj)) {
try { scanned.push(obj);
Object.getOwnPropertyNames(obj).forEach(add); to_scan.push(obj);
} catch(ex) {} }
if (obj.prototype) { }
Object.getOwnPropertyNames(obj.prototype).forEach(add);
}
if (typeof obj == "function") {
try {
Object.getOwnPropertyNames(new obj).forEach(add);
} catch(ex) {}
}
}
function add(name) { scan(self);
props[name] = true; [
} "a",
"abbr",
"acronym",
"address",
"applet",
"area",
"article",
"aside",
"audio",
"b",
"base",
"basefont",
"bdi",
"bdo",
"bgsound",
"big",
"blink",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"center",
"checked",
"cite",
"code",
"col",
"colgroup",
"command",
"comment",
"compact",
"content",
"data",
"datalist",
"dd",
"declare",
"defer",
"del",
"details",
"dfn",
"dialog",
"dir",
"disabled",
"div",
"dl",
"dt",
"element",
"em",
"embed",
"fieldset",
"figcaption",
"figure",
"font",
"footer",
"form",
"frame",
"frameset",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hgroup",
"hr",
"html",
"i",
"iframe",
"image",
"img",
"input",
"ins",
"isindex",
"ismap",
"kbd",
"keygen",
"label",
"legend",
"li",
"link",
"listing",
"main",
"map",
"mark",
"marquee",
"math",
"menu",
"menuitem",
"meta",
"meter",
"multicol",
"multiple",
"nav",
"nobr",
"noembed",
"noframes",
"nohref",
"noresize",
"noscript",
"noshade",
"nowrap",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"param",
"picture",
"plaintext",
"pre",
"progress",
"q",
"rb",
"readonly",
"rp",
"rt",
"rtc",
"ruby",
"s",
"samp",
"script",
"section",
"select",
"selected",
"shadow",
"small",
"source",
"spacer",
"span",
"strike",
"strong",
"style",
"sub",
"summary",
"sup",
"svg",
"table",
"tbody",
"td",
"template",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"track",
"tt",
"u",
"ul",
"var",
"video",
"wbr",
"xmp",
"XXX",
].forEach(function(tag) {
scan(document.createElement(tag));
});
[
"abort",
"absolutedeviceorientation",
"activate",
"active",
"addsourcebuffer",
"addstream",
"addtrack",
"afterprint",
"afterscriptexecute",
"afterupdate",
"animationcancel",
"animationend",
"animationiteration",
"animationstart",
"appinstalled",
"audioend",
"audioprocess",
"audiostart",
"autocomplete",
"autocompleteerror",
"auxclick",
"beforeactivate",
"beforecopy",
"beforecut",
"beforedeactivate",
"beforeeditfocus",
"beforeinstallprompt",
"beforepaste",
"beforeprint",
"beforescriptexecute",
"beforeunload",
"beforeupdate",
"blocked",
"blur",
"bounce",
"boundary",
"cached",
"cancel",
"candidatewindowhide",
"candidatewindowshow",
"candidatewindowupdate",
"canplay",
"canplaythrough",
"cellchange",
"change",
"chargingchange",
"chargingtimechange",
"checking",
"click",
"close",
"compassneedscalibration",
"complete",
"connect",
"connecting",
"connectionstatechange",
"contextmenu",
"controllerchange",
"controlselect",
"copy",
"cuechange",
"cut",
"dataavailable",
"datachannel",
"datasetchanged",
"datasetcomplete",
"dblclick",
"deactivate",
"devicechange",
"devicelight",
"devicemotion",
"deviceorientation",
"deviceorientationabsolute",
"deviceproximity",
"dischargingtimechange",
"disconnect",
"display",
"downloading",
"drag",
"dragend",
"dragenter",
"dragexit",
"dragleave",
"dragover",
"dragstart",
"drop",
"durationchange",
"emptied",
"encrypted",
"end",
"ended",
"enter",
"enterpictureinpicture",
"error",
"errorupdate",
"exit",
"filterchange",
"finish",
"focus",
"focusin",
"focusout",
"freeze",
"fullscreenchange",
"fullscreenerror",
"gesturechange",
"gestureend",
"gesturestart",
"gotpointercapture",
"hashchange",
"help",
"icecandidate",
"iceconnectionstatechange",
"icegatheringstatechange",
"inactive",
"input",
"invalid",
"keydown",
"keypress",
"keyup",
"languagechange",
"layoutcomplete",
"leavepictureinpicture",
"levelchange",
"load",
"loadeddata",
"loadedmetadata",
"loadend",
"loading",
"loadingdone",
"loadingerror",
"loadstart",
"losecapture",
"lostpointercapture",
"mark",
"message",
"messageerror",
"mousedown",
"mouseenter",
"mouseleave",
"mousemove",
"mouseout",
"mouseover",
"mouseup",
"mousewheel",
"move",
"moveend",
"movestart",
"mozfullscreenchange",
"mozfullscreenerror",
"mozorientationchange",
"mozpointerlockchange",
"mozpointerlockerror",
"mscontentzoom",
"msfullscreenchange",
"msfullscreenerror",
"msgesturechange",
"msgesturedoubletap",
"msgestureend",
"msgesturehold",
"msgesturestart",
"msgesturetap",
"msgotpointercapture",
"msinertiastart",
"mslostpointercapture",
"msmanipulationstatechanged",
"msneedkey",
"msorientationchange",
"mspointercancel",
"mspointerdown",
"mspointerenter",
"mspointerhover",
"mspointerleave",
"mspointermove",
"mspointerout",
"mspointerover",
"mspointerup",
"mssitemodejumplistitemremoved",
"msthumbnailclick",
"negotiationneeded",
"nomatch",
"noupdate",
"obsolete",
"offline",
"online",
"open",
"orientationchange",
"pagechange",
"pagehide",
"pageshow",
"paste",
"pause",
"play",
"playing",
"pluginstreamstart",
"pointercancel",
"pointerdown",
"pointerenter",
"pointerleave",
"pointerlockchange",
"pointerlockerror",
"pointermove",
"pointerout",
"pointerover",
"pointerup",
"popstate",
"progress",
"propertychange",
"ratechange",
"reading",
"readystatechange",
"rejectionhandled",
"removesourcebuffer",
"removestream",
"removetrack",
"reset",
"resize",
"resizeend",
"resizestart",
"resourcetimingbufferfull",
"result",
"resume",
"rowenter",
"rowexit",
"rowsdelete",
"rowsinserted",
"scroll",
"search",
"seeked",
"seeking",
"select",
"selectionchange",
"selectstart",
"show",
"signalingstatechange",
"soundend",
"soundstart",
"sourceclose",
"sourceclosed",
"sourceended",
"sourceopen",
"speechend",
"speechstart",
"stalled",
"start",
"statechange",
"stop",
"storage",
"storagecommit",
"submit",
"success",
"suspend",
"textinput",
"timeout",
"timeupdate",
"toggle",
"touchcancel",
"touchend",
"touchmove",
"touchstart",
"track",
"transitioncancel",
"transitionend",
"transitionrun",
"transitionstart",
"unhandledrejection",
"unload",
"updateready",
"upgradeneeded",
"userproximity",
"versionchange",
"visibilitychange",
"voiceschanged",
"volumechange",
"vrdisplayactivate",
"vrdisplayconnect",
"vrdisplaydeactivate",
"vrdisplaydisconnect",
"vrdisplaypresentchange",
"waiting",
"waitingforkey",
"warning",
"webkitanimationend",
"webkitanimationiteration",
"webkitanimationstart",
"webkitcurrentplaybacktargetiswirelesschanged",
"webkitfullscreenchange",
"webkitfullscreenerror",
"webkitkeyadded",
"webkitkeyerror",
"webkitkeymessage",
"webkitneedkey",
"webkitorientationchange",
"webkitplaybacktargetavailabilitychanged",
"webkitpointerlockchange",
"webkitpointerlockerror",
"webkitresourcetimingbufferfull",
"webkittransitionend",
"wheel",
"zoom",
].forEach(function(type) {
[
"beforeunloadevent",
"compositionevent",
"customevent",
"devicemotionevent",
"deviceorientationevent",
"dragevent",
"event",
"events",
"focusevent",
"hashchangeevent",
"htmlevents",
"keyboardevent",
"messageevent",
"mouseevent",
"mouseevents",
"storageevent",
"svgevents",
"textevent",
"touchevent",
"uievent",
"uievents",
].forEach(function(interface) {
try {
var event = document.createEvent(interface);
event.initEvent(type, true, true);
scan(event);
} catch (e) {}
});
});
Object.getOwnPropertyNames(window).forEach(function(thing){ var obj;
addObject(window[thing]); while (obj = to_scan.shift()) {
}); var proto = obj;
do {
try { Object.getOwnPropertyNames(proto).forEach(function(name) {
addObject(new Event("click")); var visited = ~names.indexOf(name);
addObject(new Event("contextmenu")); if (!visited) names.push(name);
addObject(new Event("mouseup")); try {
addObject(new Event("mousedown")); scan(obj[name]);
addObject(new Event("keydown")); if (visited) return;
addObject(new Event("keypress")); if (/^create/.test(name)) {
addObject(new Event("keyup")); scan(obj[name]());
} catch(ex) {} }
if (/^[A-Z]/.test(name)) {
var ta = document.createElement("textarea"); scan(new obj[name]());
ta.style.width = "100%"; }
ta.style.height = "20em"; } catch (e) {}
ta.style.boxSizing = "border-box"; });
<!-- ta.value = Object.keys(props).sort(cmp).map(function(name){ --> } while (proto = Object.getPrototypeOf(proto));
<!-- return JSON.stringify(name); --> }
<!-- }).join(",\n"); --> names.sort();
ta.value = JSON.stringify({ document.write('<pre>[\n "');
vars: [], document.write(names.join('",\n "'));
props: Object.keys(props).sort(cmp) document.write('"\n]</pre>');
}, null, 2); }();
document.body.appendChild(ta); </script>
</body>
function cmp(a, b) {
a = a.toLowerCase();
b = b.toLowerCase();
return a < b ? -1 : a > b ? 1 : 0;
}
})();</script>
</body>
</html> </html>