Compare commits

...

95 Commits

Author SHA1 Message Date
Alex Lam S.L
69931574e1 v3.3.27 2018-05-22 17:09:12 +00:00
Alex Lam S.L
b5af8a1914 fix corner case in reduce_vars (#3141)
fixes #3140
2018-05-21 15:53:51 +08:00
Alex Lam S.L
c14d09ba84 v3.3.26 2018-05-20 17:32:32 +00:00
Alex Lam S.L
4fc39d8dad fix corner case in collapse_vars (#3139) 2018-05-19 05:45:14 +08:00
exvisory
0b7c70f726 Update README.md to clarify --source-map filename option (#3137)
Clarify that the --source-map filename option does NOT change the source map output filename but does set the 'file' attribute within the output source map. This was already documented in the API section of the README so I just copied that to the CLI options section, and a fragment to the CLI summary.
2018-05-18 15:50:36 +08:00
Alex Lam S.L
f72d3029dd v3.3.25 2018-05-12 23:50:40 +00:00
Alex Lam S.L
1a0d6edc81 remove colors dependency (#3133) 2018-05-13 07:50:02 +08:00
Alex Lam S.L
7b59b2f5b2 replace mocha dependency (#3131) 2018-05-11 20:15:34 +08:00
Alex Lam S.L
7bc7704edf fix corner case in reduce_vars (#3129) 2018-05-10 18:45:20 +08:00
Alex Lam S.L
14e712ee80 fix corner case in call binding (#3128)
fixes #3127
2018-05-10 06:16:35 +08:00
Alex Lam S.L
f83adcc995 v3.3.24 2018-05-07 20:17:34 +00:00
Alex Lam S.L
df8a99439a fix various corner cases (#3126)
- augment ufuzz/reminify test options

fixes #3125
2018-05-07 07:36:25 +08:00
Alex Lam S.L
6b91d12ec3 fix corner case in reduce_vars (#3124) 2018-05-06 16:42:35 +08:00
Alex Lam S.L
f37b91879f fix various corner cases (#3123) 2018-05-05 13:17:50 +08:00
Alex Lam S.L
d835c72c80 speed up collapse_vars (#3119) 2018-05-04 18:38:13 +08:00
Alex Lam S.L
c4cebb4b01 fix reduce_vars on nested invocations (#3118) 2018-05-04 06:05:38 +08:00
Alex Lam S.L
d51a00a450 compress AST_Sequence within AST_Call (#3117) 2018-05-03 19:14:56 +08:00
Alex Lam S.L
fc0f168a0c better fix for #3113 (#3115) 2018-05-03 15:51:51 +08:00
Alex Lam S.L
a0ca595c2c fix TreeWalker scan order (#3114)
fixes #3113
2018-05-03 00:27:45 +08:00
Alex Lam S.L
1a314e9f60 improve reduce_vars (#3112)
fixes #3110
2018-05-02 15:11:45 +08:00
Alex Lam S.L
6fcbd5e217 v3.3.23 2018-04-28 17:14:52 +00:00
Alex Lam S.L
22cea023d1 improve numeral compression (#3108) 2018-04-28 02:47:49 +08:00
Alex Lam S.L
70d4477e05 workaround vm context issue in node-chakracore (#3106) 2018-04-27 07:40:34 +08:00
Alex Lam S.L
838f837379 improve general performance (#3104) 2018-04-27 04:30:29 +08:00
Alex Lam S.L
82a8b6f612 improve collapse_vars (#3103) 2018-04-26 19:26:01 +08:00
Alex Lam S.L
69fc7ca8da workaround test failures in Node.js 10 (#3102) 2018-04-26 17:44:37 +08:00
Alex Lam S.L
0a79496e0a workaround stack overflow in ChakraCore (#3101) 2018-04-26 15:02:17 +08:00
Alex Lam S.L
9e87edfc2e better fix for #2506 (#3099) 2018-04-25 04:46:07 +08:00
Alex Lam S.L
27211cf2d5 handle RHS side-effects in collapse_vars (#3097)
fixes #3096
2018-04-24 20:31:50 +08:00
Alex Lam S.L
b5ce199711 improve max_line_len (#3095)
fixes #304
2018-04-24 15:19:45 +08:00
Alex Lam S.L
c71ed91e63 update AST documentation (#3094)
fixes #2622
2018-04-24 14:39:12 +08:00
alexlamsl
f7545d0f1c remove unsupported platform 2018-04-24 13:32:54 +08:00
Alex Lam S.L
59eecb6bf5 v3.3.22 2018-04-20 19:50:16 +00:00
Alex Lam S.L
d83c6490ab fix corner case in strip_func_ids() (#3090) 2018-04-19 04:51:42 +08:00
Alex Lam S.L
7362f57966 improve performance when handling unused variables in collapse_vars (#3084)
fixes #3082
2018-04-15 12:38:31 +08:00
Alex Lam S.L
eaa2c1f6af v3.3.21 2018-04-12 07:08:53 +00:00
Alex Lam S.L
6a916523d4 fix inline of catch-scoped variables (#3077)
fixes #3076
2018-04-11 15:44:43 +08:00
Alex Lam S.L
ba7069d52b suppress hoist_props for embedded assignments (#3074) 2018-04-11 05:19:16 +08:00
Alex Lam S.L
4dd7d0e39b extend hoist_props (#3073)
- handle `AST_Assign` the same way as `AST_VarDef`
- inject `AST_Var` as succeeding statement

fixes #3071
2018-04-11 02:48:15 +08:00
Alex Lam S.L
90199d0a96 extend join_vars on object assignments (#3072) 2018-04-11 01:35:42 +08:00
Alex Lam S.L
b82fd0ad41 handle flow control in loops with reduce_vars (#3069)
fixes #3068
2018-04-10 06:51:03 +08:00
Alex Lam S.L
183da16896 handle pure_funcs under inline & reduce_vars correctly (#3066)
fixes #3065
2018-04-10 02:46:38 +08:00
Alex Lam S.L
87857b0f1b v3.3.20 2018-04-08 03:06:15 +08:00
Alex Lam S.L
e5f6a88233 fix corner case in reuse of mangle options (#3062) 2018-04-08 02:29:37 +08:00
Alex Lam S.L
8d0b00317e v3.3.19 2018-04-07 22:27:55 +08:00
Alex Lam S.L
db49daf365 mangle Object.defineProperty() (#3059)
fixes #869
2018-04-06 17:10:36 +08:00
Alex Lam S.L
923deeff35 support inline source map from multiple files (#3058)
fixes #145
2018-04-06 16:04:15 +08:00
Alex Lam S.L
0b62a28b47 improve usability of includeSources (#3057)
Exclude source contents from input source map if `includeSources=false`

fixes #3041
2018-04-06 13:32:26 +08:00
Alex Lam S.L
44116c6d2b fix AST corruption during inline of simple return (#3056)
fixes #3054
2018-04-06 05:39:07 +08:00
Alex Lam S.L
b5bab254ce speed up has_parens() (take 2) (#3052)
fixes #3050
2018-04-05 04:12:04 +08:00
Alex Lam S.L
81603ecd15 improve performance through makePredicate() (#3048) 2018-04-03 15:15:01 +08:00
Alex Lam S.L
e67553fa55 fix tree traversal on AST_Do (#3047)
fixes #3046
2018-04-02 22:31:23 +08:00
Alex Lam S.L
fcf542f262 v3.3.18 2018-04-02 04:26:28 +00:00
b-fuze
8adfc29f91 Don't load source map until the JS source is fully received (#3040) 2018-03-31 20:26:40 +09:00
Alex Lam S.L
02f47e1713 give sensible error against invalid input source map (#3044) 2018-03-31 18:48:20 +09:00
Alex Lam S.L
07f64d4050 fix escape analysis on AST_New (#3043)
fixes #3042
2018-03-31 15:03:46 +09:00
Alex Lam S.L
6982a0554c v3.3.17 2018-03-31 04:13:45 +00:00
Alex Lam S.L
fa3250199a mangle unused nested AST_SymbolCatch correctly (#3038)
fixes #3035
2018-03-30 16:23:09 +09:00
Alex Lam S.L
06b9894c19 handle modifications to this correctly (#3036)
fixes #3032
2018-03-30 15:07:36 +09:00
Alex Lam S.L
9f9db504d7 improve test for #3023 (#3031) 2018-03-29 23:36:40 +09:00
Alex Lam S.L
82ae95c334 improve source map granularity (#3030)
fixes #3023
2018-03-29 14:47:55 +09:00
Fábio Santos
9a5e2052c4 fix extra regex slash when going through mozilla AST I/O (#3025)
This relates to #1929, but in the context of mozilla AST input/output.
2018-03-27 03:22:01 +09:00
Alex Lam S.L
b1410be443 speed up has_parens() (#3014) 2018-03-24 04:05:28 +08:00
Alex Lam S.L
12985d86c2 fix corner case in hoist_props (#3022)
fixes #3021
2018-03-23 07:27:35 +08:00
Alex Lam S.L
49bfc6b555 improve performance (#3020)
- replace `find_if()` with `all()` wherever possible
- move ESTree-specific logic out of `figure_out_scope()`
2018-03-23 03:43:52 +08:00
Alex Lam S.L
d1c6bb8c7c fix nested inline within loop (#3019)
fixes #3018
2018-03-23 02:31:59 +08:00
Alex Lam S.L
5c169615a8 fix corner case in inline (#3017)
fixes #3016
2018-03-22 23:46:26 +08:00
Alex Lam S.L
73d77f4f64 v3.3.16 2018-03-19 06:53:51 +00:00
Alex Lam S.L
ccf0e2ef4f extend fuzzy RHS folding (#3006)
- `a = []; if (1) x();` => `if (a = []) x();`
2018-03-17 03:10:21 +08:00
Alex Lam S.L
20ca0f5906 improve truthy compression (#3009) 2018-03-16 06:12:59 +08:00
Alex Lam S.L
b29d435bb5 refactor brackets to braces (#3005) 2018-03-15 15:46:45 +08:00
Alex Lam S.L
90585e29c2 v3.3.15 2018-03-14 16:45:38 +00:00
Alex Lam S.L
d8fc281915 update dependencies (#3002)
acorn 5.5.3
commander 2.15.0

Miscellaneous
- drop unmaintained package from README
2018-03-14 15:54:41 +08:00
Alex Lam S.L
188c39e8d5 retain comments within brackets (#2999)
fixes #2998
2018-03-13 18:44:21 +08:00
Alex Lam S.L
5429234138 preserve non-constant value assignments with modifications (#2997)
fixes #2995
2018-03-13 17:35:34 +08:00
Alex Lam S.L
b9f72a4a81 handle case correctly under reduce_vars (#2993)
fixes #2992
2018-03-11 15:54:43 +08:00
Alex Lam S.L
fc6ebd04a5 preserve case when inline_script (#2991)
fixes #2989
2018-03-11 05:11:12 +08:00
Alex Lam S.L
7e00a12741 v3.3.14 2018-03-10 13:20:14 +00:00
Alex Lam S.L
10b3752b1e fix mangle of AST_SymbolLambda under ie8 (#2978)
fixes #2976
2018-03-07 17:20:38 +08:00
Alex Lam S.L
fe51a91395 handle negated constants correctly in collapse_vars (#2975)
fixes #2974
2018-03-06 00:45:58 +08:00
Alex Lam S.L
951d87ca94 v3.3.13 2018-03-04 07:38:49 +00:00
Alex Lam S.L
798fc21530 improve test/run-test.js performance (#2971)
- allow reuse of contextified sandbox
- minimise bottleneck from `vm.createContext()`
2018-03-04 04:50:00 +08:00
Alex Lam S.L
a75a046abb compress arguments[index] (#2967)
- always replace with existing parameter
- only introduce new parameter if `keep_fargs` is disabled
2018-03-02 11:22:09 +08:00
Alex Lam S.L
38f2b4579f fix value reference caching in evaluate (#2969)
fixes #2968
2018-03-02 04:04:29 +08:00
Alex Lam S.L
56e2a369d0 enhance conditionals (#2966)
- `x ? (y, w) : (z, w)` => `x ? y : z, w`
2018-02-28 23:34:48 +08:00
Alex Lam S.L
0daa199fa8 migrate safe transformations out of unsafe_comps (#2962)
fixes #2959
2018-02-28 22:02:24 +08:00
Alex Lam S.L
73e98dcda4 drop side_effects-free return values (#2965) 2018-02-28 19:59:19 +08:00
Alex Lam S.L
36bca6934d enhance collapse_vars (#2952)
- `a = b, b` => `a = b`
- `a.b = c, c()` => `(a.b = c)()`
2018-02-28 15:19:32 +08:00
Alex Lam S.L
ace5811691 drop lone "use strict" in function body (#2963)
fixes #2961
2018-02-26 15:22:52 +08:00
Dan
ba7bad0dbd show benchmark subtotal (#2960)
At the end of the benchmark, sums of the input, output and
gzip values are shown, such as:

    Subtotal

    Original: 7785102 bytes
    Uglified: 2283862 bytes
    GZipped:  662354 bytes
2018-02-26 11:46:26 +08:00
Alex Lam S.L
b8b2ac5230 improve fix for #2954 (#2958) 2018-02-26 03:14:22 +08:00
Alex Lam S.L
ea2359381b fix collapse_vars on nested exception (#2955)
fixes #2954
2018-02-25 15:39:00 +08:00
Alex Lam S.L
52de64cf16 deduplicate parenthesis around object and function literals (#2953) 2018-02-25 02:14:33 +08:00
Alex Lam S.L
455790202a minor clean-ups (#2951) 2018-02-24 02:24:47 +08:00
Alex Lam S.L
f40f5eb228 improve mangle (#2948) 2018-02-23 23:51:49 +08:00
64 changed files with 5188 additions and 1267 deletions

View File

@@ -1,11 +1,7 @@
**Bug report or feature request?**
**Bug report or feature request?**
<!-- Note: sub-optimal but correct code is not a bug -->
**ES5 or ES6+ input?**
<!-- Note: for ES6 see: https://github.com/mishoo/UglifyJS2/tree/harmony#harmony -->
**Uglify version (`uglifyjs -V`)**
**JavaScript input**
@@ -24,6 +20,6 @@
**JavaScript output or error produced.**
<!--
Note: `uglify-js` only supports ES5.
Those wishing to minify ES6 should use `uglify-es`.
Note: `uglify-js` only supports JavaScript.
Those wishing to minify ES6+ should transpile first.
-->

View File

@@ -6,9 +6,8 @@ UglifyJS is a JavaScript parser, minifier, compressor and beautifier toolkit.
#### Note:
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage) that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
- `uglify-js` only supports ECMAScript 5 (ES5).
- Those wishing to minify
ES2015+ (ES6+) should use the `npm` package [**uglify-es**](https://github.com/mishoo/UglifyJS2/tree/harmony).
- `uglify-js` only supports JavaScript (ECMAScript 5).
- To minify ECMAScript 2015 or above, transpile using tools like [Babel](https://babeljs.io/).
Install
-------
@@ -119,7 +118,8 @@ a double dash to prevent input files being used as option arguments:
JS that was generated from some other original
code. Specify "inline" if the source map is
included within the sources.
`filename` Name and/or location of the output source.
`filename` Filename and/or location of the output source
(sets `file` attribute in source map).
`includeSources` Pass this flag if you want to include
the content of source files in the
source map as sourcesContent property.
@@ -150,7 +150,9 @@ debugging your compressed JavaScript. To get a source map, pass
Additional options:
- `--source-map "filename='<NAME>'"` to specify the name of the source map.
- `--source-map "filename='<NAME>'"` to specify the name of the source map. The value of
`filename` is only used to set `file` attribute (see [the spec][sm-spec])
in source map file.
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
@@ -598,6 +600,9 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
## Compress options
- `arguments` (default: `true`) -- replace `arguments[index]` with function
parameter name whenever possible.
- `booleans` (default: `true`) -- various optimizations for boolean context,
for example `!!a ? b : c → a ? b : c`
@@ -605,8 +610,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
side effects permitting.
- `comparisons` (default: `true`) -- apply certain optimizations to binary nodes,
e.g. `!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
e.g. `!(a <= b) → a > b`, attempts to negate binary nodes, e.g.
`a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
- `conditionals` (default: `true`) -- apply optimizations for `if`-s and conditional
expressions
@@ -683,7 +688,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
pass `pure_funcs: [ 'Math.floor' ]` to let it know that this
function won't produce any side effect, in which case the whole
statement would get discarded. The current implementation adds some
overhead (compression will be slower).
overhead (compression will be slower). Make sure symbols under `pure_funcs`
are also under `mangle.reserved` to avoid mangling.
- `pure_getters` (default: `"strict"`) -- If you pass `true` for
this, UglifyJS will assume that object property access
@@ -730,12 +736,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `unsafe` (default: `false`) -- apply "unsafe" transformations (discussion below)
- `unsafe_comps` (default: `false`) -- Reverse `<` and `<=` to `>` and `>=` to
allow improved compression. This might be unsafe when an at least one of two
operands is an object with computed values due the use of methods like `get`,
or `valueOf`. This could cause change in execution order after operands in the
comparison are switching. Compression only works if both `comparisons` and
`unsafe_comps` are both set to true.
- `unsafe_comps` (default: `false`) -- compress expressions like `a <= b` assuming
none of the operands can be (coerced to) `NaN`.
- `unsafe_Function` (default: `false`) -- compress and mangle `Function(args, code)`
when both `args` and `code` are string literals.
@@ -826,7 +828,7 @@ can pass additional arguments that control the code output:
when you want to generate minified code, in order to specify additional
arguments, so you can use `-b beautify=false` to override it.
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
- `braces` (default `false`) -- always insert braces in `if`, `for`,
`do`, `while` or `with` statements, even if their body is a single
statement.
@@ -838,8 +840,8 @@ can pass additional arguments that control the code output:
- `indent_start` (default `0`) -- prefix all lines by that many spaces
- `inline_script` (default `false`) -- escape the slash in occurrences of
`</script` in strings
- `inline_script` (default `true`) -- escape HTML comments and the slash in
occurrences of `</script>` in strings
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
quotes from property names in object literals.
@@ -1042,8 +1044,9 @@ var result = UglifyJS.minify(ast, {
### Working with Uglify AST
Transversal and transformation of the native AST can be performed through
[`TreeWalker`](http://lisperator.net/uglifyjs/walk) and
[`TreeTransformer`](http://lisperator.net/uglifyjs/transform) respectively.
[`TreeWalker`](https://github.com/mishoo/UglifyJS2/blob/master/lib/ast.js) and
[`TreeTransformer`](https://github.com/mishoo/UglifyJS2/blob/master/lib/transform.js)
respectively.
### ESTree / SpiderMonkey AST

View File

@@ -46,7 +46,7 @@ program.option("--name-cache <file>", "File to hold mangled name mappings.");
program.option("--rename", "Force symbol expansion.");
program.option("--no-rename", "Disable symbol expansion.");
program.option("--self", "Build UglifyJS as a library (implies --wrap UglifyJS)");
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_source_map());
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js());
program.option("--timings", "Display operations run time on STDERR.")
program.option("--toplevel", "Compress and/or mangle variables in toplevel scope.");
program.option("--verbose", "Print diagnostic messages.");
@@ -176,6 +176,11 @@ function run() {
UglifyJS.AST_Node.warn_function = function(msg) {
print_error("WARN: " + msg);
};
var content = program.sourceMap && program.sourceMap.content;
if (content && content != "inline") {
print_error("INFO: Using input source map: " + content);
options.sourceMap.content = read_file(content, content);
}
if (program.timings) options.timings = true;
try {
if (program.parse) {
@@ -377,19 +382,6 @@ function parse_js(flag) {
}
}
function parse_source_map() {
var parse = parse_js();
return function(value, options) {
var hasContent = options && "content" in options;
var settings = parse(value, options);
if (!hasContent && settings.content && settings.content != "inline") {
print_error("INFO: Using input source map: " + settings.content);
settings.content = read_file(settings.content, settings.content);
}
return settings;
}
}
function skip_key(key) {
return skip_keys.indexOf(key) >= 0;
}

View File

@@ -165,7 +165,7 @@ function walk_body(node, visitor) {
};
var AST_Block = DEFNODE("Block", "body", {
$documentation: "A body of statements (usually bracketed)",
$documentation: "A body of statements (usually braced)",
$propdoc: {
body: "[AST_Statement*] an array of statements"
},
@@ -543,12 +543,11 @@ var AST_Call = DEFNODE("Call", "expression args", {
args: "[AST_Node*] array of arguments"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
var args = this.args;
for (var i = 0, len = args.length; i < len; i++) {
args[i]._walk(visitor);
}
return visitor._visit(this, function() {
this.expression._walk(visitor);
this.args.forEach(function(node) {
node._walk(visitor);
});
});
}
});
@@ -916,5 +915,25 @@ TreeWalker.prototype = {
|| node instanceof AST_Break && x instanceof AST_Switch)
return x;
}
},
in_boolean_context: function() {
var self = this.self();
for (var i = 0, p; p = this.parent(i); i++) {
if (p instanceof AST_SimpleStatement
|| p instanceof AST_Conditional && p.condition === self
|| p instanceof AST_DWLoop && p.condition === self
|| p instanceof AST_For && p.condition === self
|| p instanceof AST_If && p.condition === self
|| p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) {
return true;
}
if (p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||")
|| p instanceof AST_Conditional
|| p.tail_node() === self) {
self = p;
} else {
return false;
}
}
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -7,15 +7,23 @@ var to_base64 = typeof btoa == "undefined" ? function(str) {
return new Buffer(str).toString("base64");
} : btoa;
function read_source_map(code) {
function read_source_map(name, code) {
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
if (!match) {
AST_Node.warn("inline source map not found");
AST_Node.warn("inline source map not found: " + name);
return null;
}
return to_ascii(match[2]);
}
function parse_source_map(content) {
try {
return JSON.parse(content);
} catch (ex) {
throw new Error("invalid input source map: " + content);
}
}
function set_shorthand(name, options, keys) {
if (options[name]) {
keys.forEach(function(key) {
@@ -113,7 +121,7 @@ function minify(files, options) {
};
}
if (timings) timings.parse = Date.now();
var toplevel;
var source_maps, toplevel;
if (files instanceof AST_Toplevel) {
toplevel = files;
} else {
@@ -122,13 +130,23 @@ function minify(files, options) {
}
options.parse = options.parse || {};
options.parse.toplevel = null;
var source_map_content = options.sourceMap && options.sourceMap.content;
if (typeof source_map_content == "string" && source_map_content != "inline") {
source_map_content = parse_source_map(source_map_content);
}
source_maps = source_map_content && Object.create(null);
for (var name in files) if (HOP(files, name)) {
options.parse.filename = name;
options.parse.toplevel = parse(files[name], options.parse);
if (options.sourceMap && options.sourceMap.content == "inline") {
if (Object.keys(files).length > 1)
throw new Error("inline source map only works with singular input");
options.sourceMap.content = read_source_map(files[name]);
if (source_maps) {
if (source_map_content == "inline") {
var inlined_content = read_source_map(name, files[name]);
if (inlined_content) {
source_maps[name] = parse_source_map(inlined_content);
}
} else {
source_maps[name] = source_map_content;
}
}
}
toplevel = options.parse.toplevel;
@@ -150,7 +168,6 @@ function minify(files, options) {
if (options.mangle) toplevel.figure_out_scope(options.mangle);
if (timings) timings.mangle = Date.now();
if (options.mangle) {
base54.reset();
toplevel.compute_char_frequency(options.mangle);
toplevel.mangle_names(options.mangle);
}
@@ -165,12 +182,9 @@ function minify(files, options) {
}
if (!HOP(options.output, "code") || options.output.code) {
if (options.sourceMap) {
if (typeof options.sourceMap.content == "string") {
options.sourceMap.content = JSON.parse(options.sourceMap.content);
}
options.output.source_map = SourceMap({
file: options.sourceMap.filename,
orig: options.sourceMap.content,
orig: source_maps,
root: options.sourceMap.root
});
if (options.sourceMap.includeSources) {
@@ -179,6 +193,8 @@ function minify(files, options) {
} else for (var name in files) if (HOP(files, name)) {
options.output.source_map.get().setSourceContent(name, files[name]);
}
} else {
options.output.source_map.get()._sourcesContents = null;
}
}
delete options.output.ast;

View File

@@ -180,6 +180,17 @@
end : my_end_token(M)
};
if (val === null) return new AST_Null(args);
var rx = M.regex;
if (rx && rx.pattern) {
// RegExpLiteral as per ESTree AST spec
args.value = new RegExp(rx.pattern, rx.flags);
args.value.raw_source = rx.pattern;
return new AST_RegExp(args);
} else if (rx) {
// support legacy RegExp
args.value = M.regex && M.raw ? M.raw : val;
return new AST_RegExp(args);
}
switch (typeof val) {
case "string":
args.value = val;
@@ -189,16 +200,6 @@
return new AST_Number(args);
case "boolean":
return new (val ? AST_True : AST_False)(args);
default:
var rx = M.regex;
if (rx && rx.pattern) {
// RegExpLiteral as per ESTree AST spec
args.value = new RegExp(rx.pattern, rx.flags).toString();
} else {
// support legacy RegExp
args.value = M.regex && M.raw ? M.raw : val;
}
return new AST_RegExp(args);
}
},
Identifier: function(M) {
@@ -410,14 +411,15 @@
});
def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
var value = M.value;
var flags = M.value.toString().match(/[gimuy]*$/)[0];
var value = "/" + M.value.raw_source + "/" + flags;
return {
type: "Literal",
value: value,
raw: value.toString(),
raw: value,
regex: {
pattern: value.source,
flags: value.toString().match(/[gimuy]*$/)[0]
pattern: M.value.raw_source,
flags: flags
}
};
});
@@ -564,6 +566,21 @@
FROM_MOZ_STACK = [];
var ast = from_moz(node);
FROM_MOZ_STACK = save_stack;
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_LabelRef) {
for (var level = 0, parent; parent = this.parent(level); level++) {
if (parent instanceof AST_Scope) break;
if (parent instanceof AST_LabeledStatement && parent.label.name == node.name) {
node.thedef = parent.label;
break;
}
}
if (!node.thedef) {
var s = node.start;
js_error("Undefined label " + node.name, s.file, s.line, s.col, s.pos);
}
}
}));
return ast;
};

View File

@@ -56,7 +56,7 @@ function OutputStream(options) {
options = defaults(options, {
ascii_only : false,
beautify : false,
bracketize : false,
braces : false,
comments : false,
ie8 : false,
indent_level : 4,
@@ -173,30 +173,31 @@ function OutputStream(options) {
default:
return dq > sq ? quote_single() : quote_double();
}
};
}
function encode_string(str, quote) {
var ret = make_string(str, quote);
if (options.inline_script) {
ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
ret = ret.replace(/<\x2f(script)([>\/\t\n\f\r ])/gi, "<\\/$1$2");
ret = ret.replace(/\x3c!--/g, "\\x3c!--");
ret = ret.replace(/--\x3e/g, "--\\x3e");
}
return ret;
};
}
function make_name(name) {
name = name.toString();
name = to_utf8(name, true);
return name;
};
}
function make_indent(back) {
return repeat_string(" ", options.indent_start + indentation - back * options.indent_level);
};
}
/* -----[ beautification/minification ]----- */
var has_parens = false;
var might_need_space = false;
var might_need_semicolon = false;
var might_add_newline = 0;
@@ -280,7 +281,7 @@ function OutputStream(options) {
might_need_semicolon = false;
if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") {
if (options.semicolons || requireSemicolonChars(ch)) {
if (options.semicolons || requireSemicolonChars[ch]) {
OUTPUT += ";";
current_col++;
current_pos++;
@@ -340,6 +341,7 @@ function OutputStream(options) {
}
OUTPUT += str;
has_parens = str[str.length - 1] == "(";
current_pos += str.length;
var a = str.split(/\r?\n/), n = a.length - 1;
current_line += n;
@@ -349,7 +351,7 @@ function OutputStream(options) {
current_col = a[n].length;
}
last = str;
};
}
var space = options.beautify ? function() {
print(" ");
@@ -372,6 +374,11 @@ function OutputStream(options) {
return ret;
} : function(col, cont) { return cont() };
var may_add_newline = options.max_line_len ? function() {
ensure_line_len();
might_add_newline = OUTPUT.length;
} : noop;
var newline = options.beautify ? function() {
if (newline_insert < 0) return print("\n");
if (OUTPUT[newline_insert] != "\n") {
@@ -380,10 +387,7 @@ function OutputStream(options) {
current_line++;
}
newline_insert++;
} : options.max_line_len ? function() {
ensure_line_len();
might_add_newline = OUTPUT.length;
} : noop;
} : may_add_newline;
var semicolon = options.beautify ? function() {
print(";");
@@ -394,11 +398,11 @@ function OutputStream(options) {
function force_semicolon() {
might_need_semicolon = false;
print(";");
};
}
function next_indent() {
return indentation + options.indent_level;
};
}
function with_block(cont) {
var ret;
@@ -410,34 +414,40 @@ function OutputStream(options) {
indent();
print("}");
return ret;
};
}
function with_parens(cont) {
print("(");
may_add_newline();
//XXX: still nice to have that for argument lists
//var ret = with_indent(current_col, cont);
var ret = cont();
may_add_newline();
print(")");
return ret;
};
}
function with_square(cont) {
print("[");
may_add_newline();
//var ret = with_indent(current_col, cont);
var ret = cont();
may_add_newline();
print("]");
return ret;
};
}
function comma() {
may_add_newline();
print(",");
may_add_newline();
space();
};
}
function colon() {
print(":");
space();
};
}
var add_mapping = mappings ? function(token, name) {
mapping_token = token;
@@ -449,7 +459,7 @@ function OutputStream(options) {
ensure_line_len();
}
return OUTPUT;
};
}
function has_nlb() {
var index = OUTPUT.lastIndexOf("\n");
@@ -576,6 +586,7 @@ function OutputStream(options) {
indentation : function() { return indentation },
current_width : function() { return current_col - indentation },
should_break : function() { return options.width && this.current_width() >= options.width },
has_parens : function() { return has_parens },
newline : newline,
print : print,
space : space,
@@ -616,8 +627,7 @@ function OutputStream(options) {
return stack[stack.length - 2 - (n || 0)];
}
};
};
}
/* -----[ code generators ]----- */
@@ -627,7 +637,7 @@ function OutputStream(options) {
function DEFPRINT(nodetype, generator) {
nodetype.DEFMETHOD("_codegen", generator);
};
}
var in_directive = false;
var active_scope = null;
@@ -676,14 +686,14 @@ function OutputStream(options) {
} else {
nodetype.DEFMETHOD("needs_parens", func);
}
};
}
PARENS(AST_Node, return_false);
// a function expression needs parens around it when it's provably
// the first token to appear in a statement.
PARENS(AST_Function, function(output){
if (first_in_statement(output)) {
if (!output.has_parens() && first_in_statement(output)) {
return true;
}
@@ -704,7 +714,9 @@ function OutputStream(options) {
// same goes for an object literal, because otherwise it would be
// interpreted as a block of code.
PARENS(AST_Object, first_in_statement);
PARENS(AST_Object, function(output){
return !output.has_parens() && first_in_statement(output);
});
PARENS(AST_Unary, function(output){
var p = output.parent();
@@ -860,7 +872,7 @@ function OutputStream(options) {
}
});
in_directive = false;
};
}
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
force_statement(this.body, output);
@@ -883,21 +895,22 @@ function OutputStream(options) {
self.body.print(output);
output.semicolon();
});
function print_bracketed(self, output, allow_directives) {
function print_braced_empty(self, output) {
output.print("{");
output.with_indent(output.next_indent(), function() {
output.append_comments(self, true);
});
output.print("}");
}
function print_braced(self, output, allow_directives) {
if (self.body.length > 0) {
output.with_block(function() {
display_body(self.body, false, output, allow_directives);
});
} else {
output.print("{");
output.with_indent(output.next_indent(), function() {
output.append_comments(self, true);
});
output.print("}");
}
};
} else print_braced_empty(self, output);
}
DEFPRINT(AST_BlockStatement, function(self, output){
print_bracketed(self, output);
print_braced(self, output);
});
DEFPRINT(AST_EmptyStatement, function(self, output){
output.semicolon();
@@ -992,7 +1005,7 @@ function OutputStream(options) {
});
});
output.space();
print_bracketed(self, output, true);
print_braced(self, output, true);
});
DEFPRINT(AST_Lambda, function(self, output){
self._do_print(output);
@@ -1033,7 +1046,7 @@ function OutputStream(options) {
/* -----[ if ]----- */
function make_then(self, output) {
var b = self.body;
if (output.option("bracketize")
if (output.option("braces")
|| output.option("ie8") && b instanceof AST_Do)
return make_block(b, output);
// The squeezer replaces "block"-s that contain only a single
@@ -1042,7 +1055,7 @@ function OutputStream(options) {
// IF having an ELSE clause where the THEN clause ends in an
// IF *without* an ELSE block (then the outer ELSE would refer
// to the inner IF). This function checks for this case and
// adds the block brackets if needed.
// adds the block braces if needed.
if (!b) return output.force_semicolon();
while (true) {
if (b instanceof AST_If) {
@@ -1058,7 +1071,7 @@ function OutputStream(options) {
else break;
}
force_statement(self.body, output);
};
}
DEFPRINT(AST_If, function(self, output){
output.print("if");
output.space();
@@ -1089,7 +1102,7 @@ function OutputStream(options) {
});
output.space();
var last = self.body.length - 1;
if (last < 0) output.print("{}");
if (last < 0) print_braced_empty(self, output);
else output.with_block(function(){
self.body.forEach(function(branch, i){
output.indent(true);
@@ -1123,7 +1136,7 @@ function OutputStream(options) {
DEFPRINT(AST_Try, function(self, output){
output.print("try");
output.space();
print_bracketed(self, output);
print_braced(self, output);
if (self.bcatch) {
output.space();
self.bcatch.print(output);
@@ -1140,12 +1153,12 @@ function OutputStream(options) {
self.argname.print(output);
});
output.space();
print_bracketed(self, output);
print_braced(self, output);
});
DEFPRINT(AST_Finally, function(self, output){
output.print("finally");
output.space();
print_bracketed(self, output);
print_braced(self, output);
});
/* -----[ var/const ]----- */
@@ -1178,7 +1191,7 @@ function OutputStream(options) {
}
}));
node.print(output, parens);
};
}
DEFPRINT(AST_VarDef, function(self, output){
self.name.print(output);
@@ -1240,7 +1253,7 @@ function OutputStream(options) {
var expr = self.expression;
expr.print(output);
var prop = self.property;
if (output.option("ie8") && RESERVED_WORDS(prop)) {
if (output.option("ie8") && RESERVED_WORDS[prop]) {
output.print("[");
output.add_mapping(self.end);
output.print_string(prop);
@@ -1344,7 +1357,7 @@ function OutputStream(options) {
});
output.newline();
});
else output.print("{}");
else print_braced_empty(self, output);
});
function print_property_name(key, quote, output) {
@@ -1352,7 +1365,7 @@ function OutputStream(options) {
output.print_string(key);
} else if ("" + +key == key && key >= 0) {
output.print(make_num(key));
} else if (RESERVED_WORDS(key) ? !output.option("ie8") : is_identifier_string(key)) {
} else if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
if (quote && output.option("keep_quoted_props")) {
output.print_string(key, quote);
} else {
@@ -1416,7 +1429,7 @@ function OutputStream(options) {
});
function force_statement(stat, output) {
if (output.option("bracketize")) {
if (output.option("braces")) {
make_block(stat, output);
} else {
if (!stat || stat instanceof AST_EmptyStatement)
@@ -1424,7 +1437,7 @@ function OutputStream(options) {
else
stat.print(output);
}
};
}
// self should be AST_New. decide if we want to show parens or not.
function need_constructor_parens(self, output) {
@@ -1432,7 +1445,7 @@ function OutputStream(options) {
if (self.args.length > 0) return true;
return output.option("beautify");
};
}
function best_of(a) {
var best = a[0], len = best.length;
@@ -1443,27 +1456,31 @@ function OutputStream(options) {
}
}
return best;
};
}
function make_num(num) {
var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;
var str = num.toString(10).replace(/^0\./, ".").replace("e+", "e");
var candidates = [ str ];
if (Math.floor(num) === num) {
if (num >= 0) {
a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
"0" + num.toString(8)); // same.
if (num < 0) {
candidates.push("-0x" + (-num).toString(16).toLowerCase());
} else {
a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless
"-0" + (-num).toString(8)); // same.
candidates.push("0x" + num.toString(16).toLowerCase());
}
if ((m = /^(.*?)(0+)$/.exec(num))) {
a.push(m[1] + "e" + m[2].length);
}
} else if ((m = /^0?\.(0+)(.*)$/.exec(num))) {
a.push(m[2] + "e-" + (m[1].length + m[2].length),
str.substr(str.indexOf(".")));
}
return best_of(a);
};
var match, len, digits;
if (match = /^\.0+/.exec(str)) {
len = match[0].length;
digits = str.slice(len);
candidates.push(digits + "e-" + (digits.length + len - 1));
} else if (match = /0+$/.exec(str)) {
len = match[0].length;
candidates.push(str.slice(0, -len) + "e" + len);
} else if (match = /^(\d)\.(\d+)e(-?\d+)$/.exec(str)) {
candidates.push(match[1] + match[2] + "e" + (match[3] - match[2].length));
}
return best_of(candidates);
}
function make_block(stmt, output) {
if (!stmt || stmt instanceof AST_EmptyStatement)
@@ -1475,52 +1492,57 @@ function OutputStream(options) {
stmt.print(output);
output.newline();
});
};
}
/* -----[ source map generators ]----- */
function DEFMAP(nodetype, generator) {
nodetype.DEFMETHOD("add_source_map", function(stream){
generator(this, stream);
nodetype.forEach(function(nodetype) {
nodetype.DEFMETHOD("add_source_map", generator);
});
};
}
// We could easily add info for ALL nodes, but it seems to me that
// would be quite wasteful, hence this noop in the base class.
DEFMAP(AST_Node, noop);
function basic_sourcemap_gen(self, output) {
output.add_mapping(self.start);
};
DEFMAP([
// We could easily add info for ALL nodes, but it seems to me that
// would be quite wasteful, hence this noop in the base class.
AST_Node,
// since the label symbol will mark it
AST_LabeledStatement,
AST_Toplevel,
], noop);
// XXX: I'm not exactly sure if we need it for all of these nodes,
// or if we should add even more.
DEFMAP(AST_Directive, basic_sourcemap_gen);
DEFMAP(AST_Debugger, basic_sourcemap_gen);
DEFMAP(AST_Symbol, basic_sourcemap_gen);
DEFMAP(AST_Jump, basic_sourcemap_gen);
DEFMAP(AST_StatementWithBody, basic_sourcemap_gen);
DEFMAP(AST_LabeledStatement, noop); // since the label symbol will mark it
DEFMAP(AST_Lambda, basic_sourcemap_gen);
DEFMAP(AST_Switch, basic_sourcemap_gen);
DEFMAP(AST_SwitchBranch, basic_sourcemap_gen);
DEFMAP(AST_BlockStatement, basic_sourcemap_gen);
DEFMAP(AST_Toplevel, noop);
DEFMAP(AST_New, basic_sourcemap_gen);
DEFMAP(AST_Try, basic_sourcemap_gen);
DEFMAP(AST_Catch, basic_sourcemap_gen);
DEFMAP(AST_Finally, basic_sourcemap_gen);
DEFMAP(AST_Definitions, basic_sourcemap_gen);
DEFMAP(AST_Constant, basic_sourcemap_gen);
DEFMAP(AST_ObjectSetter, function(self, output){
output.add_mapping(self.start, self.key.name);
});
DEFMAP(AST_ObjectGetter, function(self, output){
output.add_mapping(self.start, self.key.name);
});
DEFMAP(AST_ObjectProperty, function(self, output){
output.add_mapping(self.start, self.key);
DEFMAP([
AST_Array,
AST_BlockStatement,
AST_Catch,
AST_Constant,
AST_Debugger,
AST_Definitions,
AST_Directive,
AST_Finally,
AST_Jump,
AST_Lambda,
AST_New,
AST_Object,
AST_StatementWithBody,
AST_Symbol,
AST_Switch,
AST_SwitchBranch,
AST_Try,
], function(output) {
output.add_mapping(this.start);
});
DEFMAP([
AST_ObjectGetter,
AST_ObjectSetter,
], function(output) {
output.add_mapping(this.start, this.key.name);
});
DEFMAP([ AST_ObjectProperty ], function(output) {
output.add_mapping(this.start, this.key);
});
})();

View File

@@ -165,7 +165,7 @@ function is_unicode_connector_punctuation(ch) {
};
function is_identifier(name) {
return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name);
return !RESERVED_WORDS[name] && /^[a-z_$][a-z0-9_$]*$/i.test(name);
};
function is_identifier_start(code) {
@@ -245,7 +245,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var ch = S.text.charAt(S.pos++);
if (signal_eof && !ch)
throw EX_EOF;
if (NEWLINE_CHARS(ch)) {
if (NEWLINE_CHARS[ch]) {
S.newline_before = S.newline_before || !in_string;
++S.line;
S.col = 0;
@@ -272,7 +272,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var text = S.text;
for (var i = S.pos, n = S.text.length; i < n; ++i) {
var ch = text[i];
if (NEWLINE_CHARS(ch))
if (NEWLINE_CHARS[ch])
return i;
}
return -1;
@@ -292,9 +292,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var prev_was_dot = false;
function token(type, value, is_comment) {
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
(type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX[value]) ||
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION[value]) ||
(type == "punc" && PUNC_BEFORE_EXPRESSION[value]));
if (type == "punc" && value == ".") {
prev_was_dot = true;
} else if (!is_comment) {
@@ -324,7 +324,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
};
function skip_whitespace() {
while (WHITESPACE_CHARS(peek()))
while (WHITESPACE_CHARS[peek()])
next();
};
@@ -424,7 +424,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
for (;;) {
var ch = next(true, true);
if (ch == "\\") ch = read_escaped_char(true);
else if (NEWLINE_CHARS(ch)) parse_error("Unterminated string constant");
else if (NEWLINE_CHARS[ch]) parse_error("Unterminated string constant");
else if (ch == quote) break;
ret += ch;
}
@@ -476,7 +476,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
backslash = false;
}
}
if (KEYWORDS(name) && escaped) {
if (KEYWORDS[name] && escaped) {
hex = name.charCodeAt(0).toString(16).toUpperCase();
name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
}
@@ -485,7 +485,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
var read_regexp = with_eof_error("Unterminated regular expression", function(source) {
var prev_backslash = false, ch, in_class = false;
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
while ((ch = next(true))) if (NEWLINE_CHARS[ch]) {
parse_error("Unexpected line terminator");
} else if (prev_backslash) {
source += "\\" + ch;
@@ -517,7 +517,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function grow(op) {
if (!peek()) return op;
var bigger = op + peek();
if (OPERATORS(bigger)) {
if (OPERATORS[bigger]) {
next();
return grow(bigger);
} else {
@@ -550,9 +550,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
function read_word() {
var word = read_name();
if (prev_was_dot) return token("name", word);
return KEYWORDS_ATOM(word) ? token("atom", word)
: !KEYWORDS(word) ? token("name", word)
: OPERATORS(word) ? token("operator", word)
return KEYWORDS_ATOM[word] ? token("atom", word)
: !KEYWORDS[word] ? token("name", word)
: OPERATORS[word] ? token("operator", word)
: token("keyword", word);
};
@@ -603,8 +603,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
}
if (is_digit(code)) return read_num();
if (PUNC_CHARS(ch)) return token("punc", next());
if (OPERATOR_CHARS(ch)) return read_operator();
if (PUNC_CHARS[ch]) return token("punc", next());
if (OPERATOR_CHARS[ch]) return read_operator();
if (code == 92 || is_identifier_start(code)) return read_word();
break;
}
@@ -969,7 +969,9 @@ function parse($TEXT, options) {
function labeled_statement() {
var label = as_symbol(AST_Label);
if (find_if(function(l){ return l.name == label.name }, S.labels)) {
if (!all(S.labels, function(l) {
return l.name != label.name;
})) {
// ECMA-262, 12.12: An ECMAScript program is considered
// syntactically incorrect if it contains a
// LabelledStatement that is enclosed by a
@@ -1319,7 +1321,7 @@ function parse($TEXT, options) {
func.end = prev();
return subscripts(func, allow_calls);
}
if (ATOMIC_START_TOKEN(S.token.type)) {
if (ATOMIC_START_TOKEN[S.token.type]) {
return subscripts(as_atom_node(), allow_calls);
}
unexpected();
@@ -1404,7 +1406,7 @@ function parse($TEXT, options) {
var tmp = S.token;
switch (tmp.type) {
case "operator":
if (!KEYWORDS(tmp.value)) unexpected();
if (!KEYWORDS[tmp.value]) unexpected();
case "num":
case "string":
case "name":
@@ -1502,7 +1504,7 @@ function parse($TEXT, options) {
var maybe_unary = function(allow_calls) {
var start = S.token;
if (is("operator") && UNARY_PREFIX(start.value)) {
if (is("operator") && UNARY_PREFIX[start.value]) {
next();
handle_regexp();
var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls));
@@ -1511,7 +1513,7 @@ function parse($TEXT, options) {
return ex;
}
var val = expr_atom(allow_calls);
while (is("operator") && UNARY_POSTFIX(S.token.value) && !has_newline_before(S.token)) {
while (is("operator") && UNARY_POSTFIX[S.token.value] && !has_newline_before(S.token)) {
val = make_unary(AST_UnaryPostfix, S.token, val);
val.start = start;
val.end = S.token;
@@ -1583,7 +1585,7 @@ function parse($TEXT, options) {
var maybe_assign = function(no_in) {
var start = S.token;
var left = maybe_conditional(no_in), val = S.token.value;
if (is("operator") && ASSIGNMENT(val)) {
if (is("operator") && ASSIGNMENT[val]) {
if (is_assignable(left)) {
next();
return new AST_Assign({

View File

@@ -150,6 +150,10 @@ function mangle_properties(ast, options) {
else if (node instanceof AST_Sub) {
addStrings(node.property, add);
}
else if (node instanceof AST_Call
&& node.expression.print_to_string() == "Object.defineProperty") {
addStrings(node.args[1], add);
}
}));
// step 2: transform the tree, renaming properties
@@ -167,6 +171,10 @@ function mangle_properties(ast, options) {
else if (!options.keep_quoted && node instanceof AST_Sub) {
node.property = mangleStrings(node.property);
}
else if (node instanceof AST_Call
&& node.expression.print_to_string() == "Object.defineProperty") {
node.args[1] = mangleStrings(node.args[1]);
}
}));
// only function declarations after this line

View File

@@ -55,7 +55,7 @@ function SymbolDef(scope, orig, init) {
this.mangled_name = null;
this.undeclared = false;
this.id = SymbolDef.next_id++;
};
}
SymbolDef.next_id = 1;
@@ -74,17 +74,13 @@ SymbolDef.prototype = {
var cache = options.cache && options.cache.props;
if (this.global && cache && cache.has(this.name)) {
this.mangled_name = cache.get(this.name);
}
else if (!this.mangled_name && !this.unmangleable(options)) {
var s = this.scope;
var sym = this.orig[0];
if (options.ie8 && sym instanceof AST_SymbolLambda)
s = s.parent_scope;
} else if (!this.mangled_name && !this.unmangleable(options)) {
var def;
if (def = this.redefined()) {
this.mangled_name = def.mangled_name || def.name;
} else
this.mangled_name = s.next_mangled(options, this);
} else {
this.mangled_name = next_mangled_name(this.scope, options, this);
}
if (this.global && cache) {
cache.set(this.name, this.mangled_name);
}
@@ -104,7 +100,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// pass 1: setup scope chaining and handle definitions
var self = this;
var scope = self.parent_scope = null;
var labels = new Dictionary();
var defun = null;
var tw = new TreeWalker(function(node, descend){
if (node instanceof AST_Catch) {
@@ -119,25 +114,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
node.init_scope_vars(scope);
var save_scope = scope;
var save_defun = defun;
var save_labels = labels;
defun = scope = node;
labels = new Dictionary();
descend();
scope = save_scope;
defun = save_defun;
labels = save_labels;
return true; // don't descend again in TreeWalker
}
if (node instanceof AST_LabeledStatement) {
var l = node.label;
if (labels.has(l.name)) {
throw new Error(string_template("Label {name} defined twice", l));
}
labels.set(l.name, l);
descend();
labels.del(l.name);
return true; // no descend again
}
if (node instanceof AST_With) {
for (var s = scope; s; s = s.parent_scope)
s.uses_with = true;
@@ -168,22 +150,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var def = scope.find_variable(node);
if (node.thedef !== def) {
node.thedef = def;
node.reference(options);
}
node.reference(options);
}
}
else if (node instanceof AST_SymbolCatch) {
scope.def_variable(node).defun = defun;
}
else if (node instanceof AST_LabelRef) {
var sym = labels.get(node.name);
if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
name: node.name,
line: node.start.line,
col: node.start.col
}));
node.thedef = sym;
}
});
self.walk(tw);
@@ -325,56 +298,62 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init){
return symbol.thedef = def;
});
function next_mangled(scope, options) {
var ext = scope.enclosed;
out: while (true) {
var m = base54(++scope.cname);
if (!is_identifier(m)) continue; // skip over "do"
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
// shadow a name reserved from mangling.
if (member(m, options.reserved)) continue;
// we must ensure that the mangled name does not shadow a name
// from some parent scope that is referenced in this or in
// inner scopes.
for (var i = ext.length; --i >= 0;) {
var sym = ext[i];
var name = sym.mangled_name || (sym.unmangleable(options) && sym.name);
if (m == name) continue out;
}
return m;
function names_in_use(scope, options) {
var names = scope.names_in_use;
if (!names) {
scope.names_in_use = names = Object.create(scope.mangled_names || null);
scope.cname_holes = [];
scope.enclosed.forEach(function(def) {
if (def.unmangleable(options)) names[def.name] = true;
});
}
return names;
}
AST_Scope.DEFMETHOD("next_mangled", function(options){
return next_mangled(this, options);
});
AST_Toplevel.DEFMETHOD("next_mangled", function(options){
var name;
do {
name = next_mangled(this, options);
} while (member(name, this.mangled_names));
return name;
});
AST_Function.DEFMETHOD("next_mangled", function(options, def){
function next_mangled_name(scope, options, def) {
var in_use = names_in_use(scope, options);
var holes = scope.cname_holes;
var names = Object.create(null);
// #179, #326
// in Safari strict mode, something like (function x(x){...}) is a syntax error;
// a function expression's argument cannot shadow the function expression's name
var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition();
// the function's mangled_name is null when keep_fnames is true
var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null;
while (true) {
var name = next_mangled(this, options);
if (!tricky_name || tricky_name != name)
return name;
if (scope instanceof AST_Function && scope.name && def.orig[0] instanceof AST_SymbolFunarg) {
var tricky_def = scope.name.definition();
// the function's mangled_name is null when keep_fnames is true
names[tricky_def.mangled_name || tricky_def.name] = true;
}
});
var scopes = [ scope ];
def.references.forEach(function(sym) {
var scope = sym.scope;
do {
if (scopes.indexOf(scope) < 0) {
for (var name in names_in_use(scope, options)) {
names[name] = true;
}
scopes.push(scope);
} else break;
} while (scope = scope.parent_scope);
});
var name;
for (var i = 0, len = holes.length; i < len; i++) {
name = base54(holes[i]);
if (names[name]) continue;
holes.splice(i, 1);
scope.names_in_use[name] = true;
return name;
}
while (true) {
name = base54(++scope.cname);
if (in_use[name] || !is_identifier(name) || options.reserved.has[name]) continue;
if (!names[name]) break;
holes.push(scope.cname);
}
scope.names_in_use[name] = true;
if (options.ie8 && def.orig[0] instanceof AST_SymbolLambda) {
names_in_use(scope.parent_scope, options)[name] = true;
}
return name;
}
AST_Symbol.DEFMETHOD("unmangleable", function(options){
var def = this.definition();
@@ -397,7 +376,7 @@ AST_Symbol.DEFMETHOD("global", function(){
return this.definition().global;
});
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
function _default_mangler_options(options) {
options = defaults(options, {
eval : false,
ie8 : false,
@@ -408,29 +387,27 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) {
if (!Array.isArray(options.reserved)) options.reserved = [];
// Never mangle arguments
push_uniq(options.reserved, "arguments");
options.reserved.has = makePredicate(options.reserved);
return options;
});
}
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
options = this._default_mangler_options(options);
options = _default_mangler_options(options);
// We only need to mangle declaration nodes. Special logic wired
// into the code generator will display the mangled name if it's
// present (and for AST_SymbolRef-s it'll use the mangled name of
// the AST_SymbolDeclaration that it points to).
var lname = -1;
var to_mangle = [];
var mangled_names = this.mangled_names = [];
if (options.cache) {
this.globals.each(collect);
if (options.cache.props) {
options.cache.props.each(function(mangled_name) {
push_uniq(mangled_names, mangled_name);
});
}
if (options.cache && options.cache.props) {
var mangled_names = this.mangled_names = Object.create(null);
options.cache.props.each(function(mangled_name) {
mangled_names[mangled_name] = true;
});
}
var redefined = [];
var tw = new TreeWalker(function(node, descend){
if (node instanceof AST_LabeledStatement) {
// lname is incremented when we get to the AST_Label
@@ -440,8 +417,12 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
return true; // don't descend again in TreeWalker
}
if (node instanceof AST_Scope) {
node.variables.each(collect);
return;
descend();
if (options.cache && node instanceof AST_Toplevel) {
node.globals.each(mangle);
}
node.variables.each(mangle);
return true;
}
if (node instanceof AST_Label) {
var name;
@@ -449,18 +430,31 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
node.mangled_name = name;
return true;
}
if (!options.ie8 && node instanceof AST_SymbolCatch) {
to_mangle.push(node.definition());
return;
if (!options.ie8 && node instanceof AST_Catch) {
var def = node.argname.definition();
var redef = def.redefined();
if (redef) {
redefined.push(def);
reference(node.argname);
def.references.forEach(reference);
}
descend();
if (!redef) mangle(def);
return true;
}
function reference(sym) {
sym.thedef = redef;
sym.reference(options);
sym.thedef = def;
}
});
this.walk(tw);
to_mangle.forEach(function(def){ def.mangle(options) });
redefined.forEach(mangle);
function collect(symbol) {
if (!member(symbol.name, options.reserved)) {
to_mangle.push(symbol);
}
function mangle(def) {
if (options.reserved.has[def.name]) return;
def.mangle(options);
}
});
@@ -490,7 +484,7 @@ AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
AST_Toplevel.DEFMETHOD("expand_names", function(options) {
base54.reset();
base54.sort();
options = this._default_mangler_options(options);
options = _default_mangler_options(options);
var avoid = this.find_colliding_names(options);
var cname = 0;
this.globals.each(rename);
@@ -510,7 +504,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
function rename(def) {
if (def.global && options.cache) return;
if (def.unmangleable(options)) return;
if (member(def.name, options.reserved)) return;
if (options.reserved.has[def.name]) return;
var d = def.redefined();
def.name = d ? d.name : next_name();
def.orig.forEach(function(sym) {
@@ -528,7 +522,8 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
});
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
options = this._default_mangler_options(options);
options = _default_mangler_options(options);
base54.reset();
try {
AST_Node.prototype.print = function(stream, force_parens) {
this._print(stream, force_parens);
@@ -561,17 +556,21 @@ AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
});
var base54 = (function() {
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
var digits = "0123456789".split("");
var freq = Object.create(null);
function init(chars) {
var array = [];
for (var i = 0, len = chars.length; i < len; i++) {
var ch = chars[i];
array.push(ch);
freq[ch] = -1e-2 * i;
}
return array;
}
var digits = init("0123456789");
var leading = init("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_");
var chars, frequency;
function reset() {
frequency = Object.create(null);
leading.forEach(function(ch) {
frequency[ch] = 0;
});
digits.forEach(function(ch) {
frequency[ch] = 0;
});
frequency = Object.create(freq);
}
base54.consider = function(str, delta) {
for (var i = str.length; --i >= 0;) {
@@ -582,7 +581,7 @@ var base54 = (function() {
return frequency[b] - frequency[a];
}
base54.sort = function() {
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
chars = leading.sort(compare).concat(digits.sort(compare));
};
base54.reset = reset;
reset();
@@ -596,6 +595,6 @@ var base54 = (function() {
base = 64;
} while (num > 0);
return ret;
};
}
return base54;
})();

View File

@@ -57,26 +57,26 @@ function SourceMap(options) {
file : options.file,
sourceRoot : options.root
});
var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
if (orig_map && Array.isArray(options.orig.sources)) {
orig_map._sources.toArray().forEach(function(source) {
var sourceContent = orig_map.sourceContentFor(source, true);
if (sourceContent) {
generator.setSourceContent(source, sourceContent);
}
});
var maps = options.orig && Object.create(null);
if (maps) for (var source in options.orig) {
var map = new MOZ_SourceMap.SourceMapConsumer(options.orig[source]);
if (Array.isArray(options.orig[source].sources)) {
map._sources.toArray().forEach(function(source) {
var sourceContent = map.sourceContentFor(source, true);
if (sourceContent) generator.setSourceContent(source, sourceContent);
});
}
maps[source] = map;
}
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
if (orig_map) {
var info = orig_map.originalPositionFor({
var map = maps && maps[source];
if (map) {
var info = map.originalPositionFor({
line: orig_line,
column: orig_col
});
if (info.source === null) {
return;
}
if (info.source === null) return;
source = info.source;
orig_line = info.line;
orig_col = info.column;

View File

@@ -93,7 +93,12 @@ TreeTransformer.prototype = new TreeWalker;
self.body = do_list(self.body, tw);
});
_(AST_DWLoop, function(self, tw){
_(AST_Do, function(self, tw){
self.body = self.body.transform(tw);
self.condition = self.condition.transform(tw);
});
_(AST_While, function(self, tw){
self.condition = self.condition.transform(tw);
self.body = self.body.transform(tw);
});

View File

@@ -45,27 +45,25 @@
function characters(str) {
return str.split("");
};
}
function member(name, array) {
return array.indexOf(name) >= 0;
};
}
function find_if(func, array) {
for (var i = 0, n = array.length; i < n; ++i) {
if (func(array[i]))
return array[i];
if (func(array[i])) return array[i];
}
};
}
function repeat_string(str, i) {
if (i <= 0) return "";
if (i == 1) return str;
var d = repeat_string(str, i >> 1);
d += d;
if (i & 1) d += str;
return d;
};
return i & 1 ? d + str : d;
}
function configure_error_stack(fn) {
Object.defineProperty(fn.prototype, "stack", {
@@ -84,27 +82,23 @@ function configure_error_stack(fn) {
function DefaultsError(msg, defs) {
this.message = msg;
this.defs = defs;
};
}
DefaultsError.prototype = Object.create(Error.prototype);
DefaultsError.prototype.constructor = DefaultsError;
DefaultsError.prototype.name = "DefaultsError";
configure_error_stack(DefaultsError);
DefaultsError.croak = function(msg, defs) {
throw new DefaultsError(msg, defs);
};
function defaults(args, defs, croak) {
if (args === true)
args = {};
if (args === true) args = {};
var ret = args || {};
if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i))
DefaultsError.croak("`" + i + "` is not a supported option", defs);
if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i)) {
throw new DefaultsError("`" + i + "` is not a supported option", defs);
}
for (var i in defs) if (HOP(defs, i)) {
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
}
return ret;
};
}
function merge(obj, ext) {
var count = 0;
@@ -113,7 +107,7 @@ function merge(obj, ext) {
count++;
}
return count;
};
}
function noop() {}
function return_false() { return false; }
@@ -145,7 +139,7 @@ var MAP = (function(){
}
return is_last;
};
if (a instanceof Array) {
if (Array.isArray(a)) {
if (backwards) {
for (i = a.length; --i >= 0;) if (doit()) break;
ret.reverse();
@@ -172,101 +166,40 @@ var MAP = (function(){
function push_uniq(array, el) {
if (array.indexOf(el) < 0)
array.push(el);
};
}
function string_template(text, props) {
return text.replace(/\{(.+?)\}/g, function(str, p){
return props && props[p];
});
};
}
function remove(array, el) {
for (var i = array.length; --i >= 0;) {
if (array[i] === el) array.splice(i, 1);
}
};
}
function mergeSort(array, cmp) {
if (array.length < 2) return array.slice();
function merge(a, b) {
var r = [], ai = 0, bi = 0, i = 0;
while (ai < a.length && bi < b.length) {
cmp(a[ai], b[bi]) <= 0
? r[i++] = a[ai++]
: r[i++] = b[bi++];
}
if (ai < a.length) r.push.apply(r, a.slice(ai));
if (bi < b.length) r.push.apply(r, b.slice(bi));
return r;
};
function _ms(a) {
if (a.length <= 1)
return a;
var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
left = _ms(left);
right = _ms(right);
return merge(left, right);
};
return _ms(array);
};
// this function is taken from Acorn [1], written by Marijn Haverbeke
// [1] https://github.com/marijnh/acorn
function makePredicate(words) {
if (!(words instanceof Array)) words = words.split(" ");
var f = "", cats = [];
out: for (var i = 0; i < words.length; ++i) {
for (var j = 0; j < cats.length; ++j)
if (cats[j][0].length == words[i].length) {
cats[j].push(words[i]);
continue out;
}
cats.push([words[i]]);
}
function quote(word) {
return JSON.stringify(word).replace(/[\u2028\u2029]/g, function(s) {
switch (s) {
case "\u2028": return "\\u2028";
case "\u2029": return "\\u2029";
}
return s;
});
}
function compareTo(arr) {
if (arr.length == 1) return f += "return str === " + quote(arr[0]) + ";";
f += "switch(str){";
for (var i = 0; i < arr.length; ++i) f += "case " + quote(arr[i]) + ":";
f += "return true}return false;";
}
// When there are more than three length categories, an outer
// switch first dispatches on the lengths, to save on comparisons.
if (cats.length > 3) {
cats.sort(function(a, b) {return b.length - a.length;});
f += "switch(str.length){";
for (var i = 0; i < cats.length; ++i) {
var cat = cats[i];
f += "case " + cat[0].length + ":";
compareTo(cat);
}
f += "}";
// Otherwise, simply generate a flat `switch` statement.
} else {
compareTo(words);
}
return new Function("str", f);
};
if (!Array.isArray(words)) words = words.split(" ");
var map = Object.create(null);
words.forEach(function(word) {
map[word] = true;
});
return map;
}
function all(array, predicate) {
for (var i = array.length; --i >= 0;)
if (!predicate(array[i]))
return false;
return true;
};
}
function Dictionary() {
this._values = Object.create(null);
this._size = 0;
};
}
Dictionary.prototype = {
set: function(key, val) {
if (!this.has(key)) ++this._size;
@@ -327,20 +260,22 @@ function HOP(obj, prop) {
// a statement.
function first_in_statement(stack) {
var node = stack.parent(-1);
for (var i = 0, p; p = stack.parent(i); i++) {
if (p instanceof AST_Statement && p.body === node)
return true;
if ((p instanceof AST_Sequence && p.expressions[0] === node) ||
(p.TYPE == "Call" && p.expression === node ) ||
(p instanceof AST_Dot && p.expression === node ) ||
(p instanceof AST_Sub && p.expression === node ) ||
(p instanceof AST_Conditional && p.condition === node ) ||
(p instanceof AST_Binary && p.left === node ) ||
(p instanceof AST_UnaryPostfix && p.expression === node ))
{
node = p;
} else {
return false;
for (var i = 0, p; p = stack.parent(i++); node = p) {
if (p.TYPE == "Call") {
if (p.expression === node) continue;
} else if (p instanceof AST_Binary) {
if (p.left === node) continue;
} else if (p instanceof AST_Conditional) {
if (p.condition === node) continue;
} else if (p instanceof AST_PropAccess) {
if (p.expression === node) continue;
} else if (p instanceof AST_Sequence) {
if (p.expressions[0] === node) continue;
} else if (p instanceof AST_Statement) {
return p.body === node;
} else if (p instanceof AST_UnaryPostfix) {
if (p.expression === node) continue;
}
return false;
}
}

View File

@@ -1,10 +1,9 @@
{
"name": "uglify-js",
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"homepage": "http://lisperator.net/uglifyjs",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.3.12",
"version": "3.3.27",
"engines": {
"node": ">=0.8.0"
},
@@ -24,16 +23,38 @@
"LICENSE"
],
"dependencies": {
"commander": "~2.14.1",
"commander": "~2.15.0",
"source-map": "~0.6.1"
},
"devDependencies": {
"acorn": "~5.4.1",
"mocha": "~3.5.1",
"acorn": "~5.5.3",
"semver": "~5.5.0"
},
"scripts": {
"test": "node test/run-tests.js"
},
"keywords": ["uglify", "uglify-js", "minify", "minifier", "es5"]
"keywords": [
"cli",
"compress",
"compressor",
"ecma",
"ecmascript",
"es",
"es5",
"javascript",
"js",
"jsmin",
"min",
"minification",
"minifier",
"minify",
"optimize",
"optimizer",
"pack",
"packer",
"parse",
"parser",
"uglifier",
"uglify"
]
}

View File

@@ -28,6 +28,7 @@ var remaining = 2 * urls.length;
function done() {
if (!--remaining) {
var failures = [];
var sum = { input: 0, output: 0, gzip: 0 };
urls.forEach(function(url) {
var info = results[url];
console.log();
@@ -40,6 +41,9 @@ function done() {
if (info.code) {
failures.push(url);
}
sum.input += info.input;
sum.output += info.output;
sum.gzip += info.gzip;
});
if (failures.length) {
console.error("Benchmark failed:");
@@ -47,6 +51,13 @@ function done() {
console.error(url);
});
process.exit(1);
} else {
console.log();
console.log("Subtotal");
console.log();
console.log("Original:", sum.input, "bytes");
console.log("Uglified:", sum.output, "bytes");
console.log("GZipped: ", sum.gzip, "bytes");
}
}
}

119
test/compress/arguments.js Normal file
View File

@@ -0,0 +1,119 @@
replace_index: {
options = {
arguments: true,
evaluate: true,
properties: true,
}
input: {
console.log(arguments && arguments[0]);
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(a, b) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
}
expect: {
console.log(arguments && arguments[0]);
(function() {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function(a, b) {
console.log(b, b, arguments.foo);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
}
expect_stdout: [
"undefined",
"42 42 undefined",
"42 42 undefined",
"a a undefined",
"42 42 undefined",
]
}
replace_index_keep_fargs: {
options = {
arguments: true,
evaluate: true,
keep_fargs: false,
properties: true,
}
input: {
console.log(arguments && arguments[0]);
(function() {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(a, b) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments["1"], arguments["foo"]);
})("bar", 42);
}
expect: {
console.log(arguments && arguments[0]);
(function(argument_0, argument_1) {
console.log(argument_1, argument_1, arguments.foo);
})("bar", 42);
(function(a, b) {
console.log(b, b, arguments.foo);
})("bar", 42);
(function(arguments) {
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
(function() {
var arguments;
console.log(arguments[1], arguments[1], arguments.foo);
})("bar", 42);
}
expect_stdout: [
"undefined",
"42 42 undefined",
"42 42 undefined",
"a a undefined",
"42 42 undefined",
]
}
modified: {
options = {
arguments: true,
}
input: {
(function(a, b) {
var c = arguments[0];
var d = arguments[1];
a = "foo";
b++;
console.log(a, b, c, d, arguments[0], arguments[1]);
})("bar", 42);
}
expect: {
(function(a, b) {
var c = a;
var d = b;
a = "foo";
b++;
console.log(a, b, c, d, a, b);
})("bar", 42);
}
expect_stdout: "foo 43 bar 42 foo 43"
}

View File

@@ -913,15 +913,15 @@ collapse_vars_unary: {
return delete x;
}
function f1(n) {
return n > +!!n
return +!!n < n;
}
function f2(n) {
var k = 7;
return k--
return k--;
}
function f3(n) {
var k = 7;
return ++k
return ++k;
}
function f4(n) {
var k = 8 - n;
@@ -2219,8 +2219,8 @@ unused_orig: {
console.log(function(b) {
var c = b;
for (var d in c) {
var a = c[0];
return --b + a;
var a;
return --b + c[0];
}
a && a.NaN;
}([2]), a);
@@ -3124,7 +3124,57 @@ issue_2425_3: {
expect_stdout: "15"
}
issue_2437: {
issue_2437_1: {
options = {
collapse_vars: true,
conditionals: true,
inline: true,
join_vars: true,
passes: 2,
reduce_funcs: true,
reduce_vars: true,
side_effects: true,
sequences: 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;
}
var req, detectFunc = function() {};
(req = new XMLHttpRequest()).onreadystatechange = detectFunc;
result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
return req.onreadystatechange = null, result;
}());
}
}
issue_2437_2: {
options = {
collapse_vars: true,
conditionals: true,
@@ -3161,14 +3211,12 @@ issue_2437: {
}
expect: {
!function() {
if (xhrDesc) {
var result = !!(req = new XMLHttpRequest()).onreadystatechange;
return Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
result;
}
var req, detectFunc = function() {};
(req = new XMLHttpRequest()).onreadystatechange = detectFunc;
result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
if (xhrDesc)
return (req = new XMLHttpRequest()).onreadystatechange,
Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {});
var req;
(req = new XMLHttpRequest).onreadystatechange = function(){},
req[SYMBOL_FAKE_ONREADYSTATECHANGE_1],
req.onreadystatechange = null;
}();
}
@@ -4008,6 +4056,36 @@ replace_all_var: {
expect_stdout: "PASS"
}
replace_all_var_scope: {
rename = true;
options = {
collapse_vars: true,
unused: true,
}
mangle = {}
input: {
var a = 100, b = 10;
(function(r, a) {
switch (~a) {
case (b += a):
case a++:
}
})(--b, a);
console.log(a, b);
}
expect: {
var a = 100, b = 10;
(function(c, o) {
switch (~a) {
case (b += a):
case o++:
}
})(--b, a);
console.log(a, b);
}
expect_stdout: "100 109"
}
cascade_statement: {
options = {
collapse_vars: true,
@@ -4665,3 +4743,659 @@ issue_2931: {
}
expect_stdout: "undefined"
}
issue_2954_1: {
options = {
collapse_vars: true,
}
input: {
var a = "PASS", b;
try {
do {
b = function() {
throw 0;
}();
a = "FAIL";
b && b.c;
} while (0);
} catch (e) {
}
console.log(a);
}
expect: {
var a = "PASS", b;
try {
do {
b = function() {
throw 0;
}();
a = "FAIL";
b && b.c;
} while (0);
} catch (e) {
}
console.log(a);
}
expect_stdout: "PASS"
}
issue_2954_2: {
options = {
collapse_vars: true,
}
input: {
var a = "FAIL_1", b;
try {
throw 0;
} catch (e) {
do {
b = function() {
throw new Error("PASS");
}();
a = "FAIL_2";
b && b.c;
} while (0);
}
console.log(a);
}
expect: {
var a = "FAIL_1", b;
try {
throw 0;
} catch (e) {
do {
a = "FAIL_2";
(b = function() {
throw new Error("PASS");
}()) && b.c;
} while (0);
}
console.log(a);
}
expect_stdout: Error("PASS")
}
issue_2954_3: {
options = {
collapse_vars: true,
}
input: {
var a = "FAIL_1", b;
try {
} finally {
do {
b = function() {
throw new Error("PASS");
}();
a = "FAIL_2";
b && b.c;
} while (0);
}
console.log(a);
}
expect: {
var a = "FAIL_1", b;
try {
} finally {
do {
a = "FAIL_2";
(b = function() {
throw new Error("PASS");
}()) && b.c;
} while (0);
}
console.log(a);
}
expect_stdout: Error("PASS")
}
collapse_rhs_conditional_1: {
options = {
collapse_vars: true,
}
input: {
var a = "PASS", b = "FAIL";
b = a;
"function" == typeof f && f(a);
console.log(a, b);
}
expect: {
var a = "PASS", b = "FAIL";
b = a;
"function" == typeof f && f(a);
console.log(a, b);
}
expect_stdout: "PASS PASS"
}
collapse_rhs_conditional_2: {
options = {
collapse_vars: true,
}
input: {
var a = "FAIL", b;
while ((a = "PASS", --b) && "PASS" == b);
console.log(a, b);
}
expect: {
var a = "FAIL", b;
while ((a = "PASS", --b) && "PASS" == b);
console.log(a, b);
}
expect_stdout: "PASS NaN"
}
collapse_rhs_lhs_1: {
options = {
collapse_vars: true,
}
input: {
var c = 0;
new function() {
this[c++] = 1;
c += 1;
}();
console.log(c);
}
expect: {
var c = 0;
new function() {
this[c++] = 1;
c += 1;
}();
console.log(c);
}
expect_stdout: "2"
}
collapse_rhs_lhs_2: {
options = {
collapse_vars: true,
}
input: {
var b = 1;
(function f(f) {
f = b;
f[b] = 0;
})();
console.log("PASS");
}
expect: {
var b = 1;
(function f(f) {
f = b;
f[b] = 0;
})();
console.log("PASS");
}
expect_stdout: "PASS"
}
collapse_rhs_loop: {
options = {
collapse_vars: true,
}
input: {
var s;
s = "<tpl>PASS</tpl>";
for (var m, r = /<tpl>(.*)<\/tpl>/; m = s.match(r);)
s = s.replace(m[0], m[1]);
console.log(s);
}
expect: {
var s;
s = "<tpl>PASS</tpl>";
for (var m, r = /<tpl>(.*)<\/tpl>/; m = s.match(r);)
s = s.replace(m[0], m[1]);
console.log(s);
}
expect_stdout: "PASS"
}
collapse_rhs_side_effects: {
options = {
collapse_vars: true,
}
input: {
var a = 1, c = 0;
new function f() {
this[a-- && f()] = 1;
c += 1;
}();
console.log(c);
}
expect: {
var a = 1, c = 0;
new function f() {
this[a-- && f()] = 1;
c += 1;
}();
console.log(c);
}
expect_stdout: "2"
}
collapse_rhs_vardef: {
options = {
collapse_vars: true,
}
input: {
var a, b = 1;
a = --b + function c() {
var b;
c[--b] = 1;
}();
b |= a;
console.log(a, b);
}
expect: {
var a, b = 1;
a = --b + function c() {
var b;
c[--b] = 1;
}();
b |= a;
console.log(a, b);
}
expect_stdout: "NaN 0"
}
collapse_rhs_array: {
options = {
collapse_vars: true,
}
input: {
var a, b;
function f() {
a = [];
b = [];
return [];
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect: {
var a, b;
function f() {
a = [];
b = [];
return [];
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect_stdout: "false false false"
}
collapse_rhs_boolean_1: {
options = {
collapse_vars: true,
}
input: {
var a, b;
function f() {
a = !0;
b = !0;
return !0;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect: {
var a, b;
function f() {
return b = a = !0;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect_stdout: "true true true"
}
collapse_rhs_boolean_2: {
options = {
collapse_vars: true,
}
input: {
var a;
(function f1() {
a = function() {};
if (/foo/)
console.log(typeof a);
})();
console.log(function f2() {
a = [];
return !1;
}());
}
expect: {
var a;
(function f1() {
if (a = function() {})
console.log(typeof a);
})();
console.log(function f2() {
return !(a = []);
}());
}
expect_stdout: [
"function",
"false",
]
}
collapse_rhs_boolean_3: {
options = {
booleans: true,
collapse_vars: true,
conditionals: true,
}
input: {
var a, f, g, h, i, n, s, t, x, y;
if (x()) {
n = a;
} else if (y()) {
n = f();
} else if (s) {
i = false;
n = g(true);
} else if (t) {
i = false;
n = h(true);
} else {
n = [];
}
}
expect: {
var a, f, g, h, i, n, s, t, x, y;
n = x() ? a : y() ? f() : s ? g(!(i = !1)) : t ? h(!(i = !1)) : [];
}
}
collapse_rhs_function: {
options = {
collapse_vars: true,
}
input: {
var a, b;
function f() {
a = function() {};
b = function() {};
return function() {};
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect: {
var a, b;
function f() {
a = function() {};
b = function() {};
return function() {};
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect_stdout: "false false false"
}
collapse_rhs_number: {
options = {
collapse_vars: true,
}
input: {
var a, b;
function f() {
a = 42;
b = 42;
return 42;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect: {
var a, b;
function f() {
return b = a = 42;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect_stdout: "true true true"
}
collapse_rhs_object: {
options = {
collapse_vars: true,
}
input: {
var a, b;
function f() {
a = {};
b = {};
return {};
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect: {
var a, b;
function f() {
a = {};
b = {};
return {};
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect_stdout: "false false false"
}
collapse_rhs_regexp: {
options = {
collapse_vars: true,
}
input: {
var a, b;
function f() {
a = /bar/;
b = /bar/;
return /bar/;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect: {
var a, b;
function f() {
a = /bar/;
b = /bar/;
return /bar/;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect_stdout: "false false false"
}
collapse_rhs_string: {
options = {
collapse_vars: true,
}
input: {
var a, b;
function f() {
a = "foo";
b = "foo";
return "foo";
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect: {
var a, b;
function f() {
return b = a = "foo";
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect_stdout: "true true true"
}
collapse_rhs_var: {
options = {
collapse_vars: true,
}
input: {
var a, b;
function f() {
a = f;
b = f;
return f;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect: {
var a, b;
function f() {
return b = a = f;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect_stdout: "true true true"
}
collapse_rhs_this: {
options = {
collapse_vars: true,
}
input: {
var a, b;
function f() {
a = this;
b = this;
return this;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect: {
var a, b;
function f() {
return b = a = this;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect_stdout: "true true true"
}
collapse_rhs_undefined: {
options = {
collapse_vars: true,
}
input: {
var a, b;
function f() {
a = void 0;
b = void 0;
return void 0;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect: {
var a, b;
function f() {
b = a = void 0;
return;
}
var c = f();
console.log(a === b, b === c, c === a);
}
expect_stdout: "true true true"
}
issue_2974: {
options = {
booleans: true,
collapse_vars: true,
evaluate: true,
loops: true,
passes: 2,
pure_getters: "strict",
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
var c = 0;
(function f(b) {
var a = 2;
do {
b && b[b];
b && (b.null = -4);
c++;
} while (b.null && --a > 0);
})(true);
console.log(c);
}
expect: {
var c = 0;
(function(b) {
var a = 2;
for (; b.null = -4, c++, b.null && --a > 0;);
})(!0),
console.log(c);
}
expect_stdout: "1"
}
issue_3032: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
console.log({
f: function() {
this.a = 42;
return [ this.a, !1 ];
}
}.f()[0]);
}
expect: {
console.log({
f: function() {
this.a = 42;
return [ this.a, !1 ];
}
}.f()[0]);
}
expect_stdout: "42"
}
issue_3096: {
options = {
collapse_vars: true,
}
input: {
console.log(function() {
var ar = ["a", "b"];
var first = ar.pop();
return ar + "" + first;
}());
}
expect: {
console.log(function() {
var ar = ["a", "b"];
var first = ar.pop();
return ar + "" + first;
}());
}
expect_stdout: "ab"
}

View File

@@ -1,62 +1,42 @@
keep_comparisons: {
comparisons: {
options = {
comparisons: true,
unsafe_comps: false
}
input: {
var obj1 = {
valueOf: function() {triggeredFirst();}
}
var obj2 = {
valueOf: function() {triggeredSecond();}
}
var obj1, obj2;
var result1 = obj1 <= obj2;
var result2 = obj1 < obj2;
var result3 = obj1 >= obj2;
var result4 = obj1 > obj2;
}
expect: {
var obj1 = {
valueOf: function() {triggeredFirst();}
}
var obj2 = {
valueOf: function() {triggeredSecond();}
}
var obj1, obj2;
var result1 = obj1 <= obj2;
var result2 = obj1 < obj2;
var result3 = obj1 >= obj2;
var result4 = obj1 > obj2;
var result3 = obj2 <= obj1;
var result4 = obj2 < obj1;
}
}
keep_comparisons_with_unsafe_comps: {
unsafe_comps: {
options = {
comparisons: true,
unsafe_comps: true
conditionals: true,
unsafe_comps: true,
}
input: {
var obj1 = {
valueOf: function() {triggeredFirst();}
}
var obj2 = {
valueOf: function() {triggeredSecond();}
}
var result1 = obj1 <= obj2;
var result2 = obj1 < obj2;
var result3 = obj1 >= obj2;
var result4 = obj1 > obj2;
var obj1, obj2;
obj1 <= obj2 ? f1() : g1();
obj1 < obj2 ? f2() : g2();
obj1 >= obj2 ? f3() : g3();
obj1 > obj2 ? f4() : g4();
}
expect: {
var obj1 = {
valueOf: function() {triggeredFirst();}
}
var obj2 = {
valueOf: function() {triggeredSecond();}
}
var result1 = obj2 >= obj1;
var result2 = obj2 > obj1;
var result3 = obj1 >= obj2;
var result4 = obj1 > obj2;
var obj1, obj2;
obj2 < obj1 ? g1() : f1();
obj1 < obj2 ? f2() : g2();
obj1 < obj2 ? g3() : f3();
obj2 < obj1 ? f4() : g4();
}
}

View File

@@ -332,7 +332,7 @@ cond_7: {
x = 'foo';
x = 'foo';
x = (condition(), 20);
x = z ? 'fuji' : (condition(), 'fuji');
x = (z || condition(), 'fuji');
x = (condition(), 'foobar');
x = y ? a : b;
x = y ? 'foo' : 'fo';
@@ -703,10 +703,11 @@ ternary_boolean_alternative: {
trivial_boolean_ternary_expressions : {
options = {
booleans: true,
conditionals: true,
evaluate : true,
booleans : true
};
evaluate: true,
side_effects: true,
}
input: {
f('foo' in m ? true : false);
f('foo' in m ? false : true);

View File

@@ -1785,3 +1785,32 @@ issue_805_2: {
"bar",
]
}
issue_2995: {
options = {
pure_getters: "strict",
reduce_vars: true,
unused: true,
}
input: {
function f(a) {
var b;
a.b = b = function() {};
b.c = "PASS";
}
var o = {};
f(o);
console.log(o.b.c);
}
expect: {
function f(a) {
var b;
a.b = b = function() {};
b.c = "PASS";
}
var o = {};
f(o);
console.log(o.b.c);
}
expect_stdout: "PASS"
}

View File

@@ -745,7 +745,7 @@ in_boolean_context: {
!b("foo"),
!b([1, 2]),
!b(/foo/),
![1, foo()],
(foo(), !1),
(foo(), !1)
);
}
@@ -1535,3 +1535,74 @@ issue_2926_2: {
}
expect_stdout: "function"
}
issue_2968: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
unused: true,
}
input: {
var c = "FAIL";
(function() {
(function(a, b) {
a <<= 0;
a && (a[(c = "PASS", 0 >>> (b += 1))] = 0);
})(42, -42);
})();
console.log(c);
}
expect: {
var c = "FAIL";
(function() {
b = -(a = 42),
void ((a <<= 0) && (a[(c = "PASS", 0 >>> (b += 1))] = 0));
var a, b;
})();
console.log(c);
}
expect_stdout: "PASS"
}
truthy_conditionals: {
options = {
conditionals: true,
evaluate: true,
}
input: {
if (a = {}) x();
(b = /foo/) && y();
(c = function() {}) || z();
}
expect: {
a = {}, x();
b = /foo/, y();
c = function() {};
}
}
truthy_loops: {
options = {
evaluate: true,
loops: true,
}
input: {
while ([]) x();
do {
y();
} while(a = {});
}
expect: {
for (;;) {
[];
x();
}
for (;;) {
y();
a = {};
}
}
}

View File

@@ -2012,3 +2012,310 @@ issue_2898: {
}
expect_stdout: "2"
}
deduplicate_parenthesis: {
input: {
({}).a = b;
(({}).a = b)();
(function() {}).a = b;
((function() {}).a = b)();
}
expect_exact: "({}).a=b;({}.a=b)();(function(){}).a=b;(function(){}.a=b)();"
}
drop_lone_use_strict: {
options = {
side_effects: true,
}
input: {
function f1() {
"use strict";
}
function f2() {
"use strict";
function f3() {
"use strict";
}
}
(function f4() {
"use strict";
})();
}
expect: {
function f1() {
}
function f2() {
"use strict";
function f3() {
}
}
}
}
issue_3016_1: {
options = {
inline: true,
toplevel: true,
}
input: {
var b = 1;
do {
(function(a) {
return a[b];
var a;
})(3);
} while (0);
console.log(b);
}
expect: {
var b = 1;
do {
a = 3,
a[b];
} while(0);
var a;
console.log(b);
}
expect_stdout: "1"
}
issue_3016_2: {
options = {
dead_code: true,
inline: true,
toplevel: true,
}
input: {
var b = 1;
do {
(function(a) {
return a[b];
try {
a = 2;
} catch (a) {
var a;
}
})(3);
} while (0);
console.log(b);
}
expect: {
var b = 1;
do {
a = 3,
a[b];
} while(0);
var a;
console.log(b);
}
expect_stdout: "1"
}
issue_3016_2_ie8: {
options = {
dead_code: true,
ie8: true,
inline: true,
toplevel: true,
}
input: {
var b = 1;
do {
(function(a) {
return a[b];
try {
a = 2;
} catch (a) {
var a;
}
})(3);
} while (0);
console.log(b);
}
expect: {
var b = 1;
do {
a = 3,
a[b];
} while(0);
var a;
console.log(b);
}
expect_stdout: "1"
}
issue_3016_3: {
options = {
dead_code: true,
inline: true,
toplevel: true,
}
input: {
var b = 1;
do {
console.log(function() {
return a ? "FAIL" : a = "PASS";
try {
a = 2;
} catch (a) {
var a;
}
}());
} while (b--);
}
expect: {
var b = 1;
do {
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
} while(b--);
var a;
}
expect_stdout: [
"PASS",
"PASS",
]
}
issue_3016_3_ie8: {
options = {
dead_code: true,
ie8: true,
inline: true,
toplevel: true,
}
input: {
var b = 1;
do {
console.log(function() {
return a ? "FAIL" : a = "PASS";
try {
a = 2;
} catch (a) {
var a;
}
}());
} while (b--);
}
expect: {
var b = 1;
do {
console.log((a = void 0, a ? "FAIL" : a = "PASS"));
} while(b--);
var a;
}
expect_stdout: [
"PASS",
"PASS",
]
}
issue_3018: {
options = {
inline: true,
side_effects: true,
toplevel: true,
}
input: {
var b = 1, c = "PASS";
do {
(function() {
(function(a) {
a = 0 != (a && (c = "FAIL"));
})();
})();
} while (b--);
console.log(c);
}
expect: {
var b = 1, c = "PASS";
do {
a = void 0,
a = 0 != (a && (c = "FAIL"));
} while (b--);
var a;
console.log(c);
}
expect_stdout: "PASS"
}
issue_3054: {
options = {
booleans: true,
collapse_vars: true,
inline: 1,
reduce_vars: true,
toplevel: true,
}
input: {
"use strict";
function f() {
return { a: true };
}
console.log(function(b) {
b = false;
return f();
}().a, f.call().a);
}
expect: {
"use strict";
function f() {
return { a: !0 };
}
console.log(function(b) {
return { a: !(b = !1) };
}().a, f.call().a);
}
expect_stdout: "true true"
}
issue_3076: {
options = {
dead_code: true,
inline: true,
sequences: true,
unused: true,
}
input: {
var c = "PASS";
(function(b) {
var n = 2;
while (--b + function() {
e && (c = "FAIL");
e = 5;
return 1;
try {
var a = 5;
} catch (e) {
var e;
}
}().toString() && --n > 0);
})(2);
console.log(c);
}
expect: {
var c = "PASS";
(function(b) {
var n = 2;
while (--b + (e = void 0, e && (c = "FAIL"), e = 5, 1).toString() && --n > 0);
var e;
})(2),
console.log(c);
}
expect_stdout: "PASS"
}
issue_3125: {
options = {
inline: true,
unsafe: true,
}
input: {
console.log(function() {
return "PASS";
}.call());
}
expect: {
console.log("PASS");
}
expect_stdout: "PASS"
}

View File

@@ -239,14 +239,14 @@ name_collision_2: {
input: {
var o = {
p: 1,
0: function(x) {
"+": function(x) {
return x;
},
1: function(x) {
"-": function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
console.log(o.p === o.p, o[0](4), o[1](5), o__$0, o__$1);
console.log(o.p === o.p, o["+"](4), o["-"](5), o__$0, o__$1);
}
expect: {
var o_p = 1,
@@ -273,14 +273,14 @@ name_collision_3: {
input: {
var o = {
p: 1,
0: function(x) {
"+": function(x) {
return x;
},
1: function(x) {
"-": function(x) {
return x + 1;
}
}, o__$0 = 2, o__$1 = 3;
console.log(o.p === o.p, o[0](4), o[1](5));
console.log(o.p === o.p, o["+"](4), o["-"](5));
}
expect: {
var o_p = 1,
@@ -686,3 +686,173 @@ undefined_key: {
}
expect_stdout: "3"
}
issue_3021: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
var a = 1, b = 2;
(function() {
b = a;
if (a++ + b--)
return 1;
return;
var b = {};
})();
console.log(a, b);
}
expect: {
var a = 1, b = 2;
(function() {
b = a;
if (a++ + b--)
return 1;
return;
var b = {};
})();
console.log(a, b);
}
expect_stdout: "2 2"
}
issue_3046: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
console.log(function(a) {
do {
var b = {
c: a++
};
} while (b.c && a);
return a;
}(0));
}
expect: {
console.log(function(a) {
do {
var b_c = a++;
} while (b_c && a);
return a;
}(0));
}
expect_stdout: "1"
}
issue_3071_1: {
options = {
evaluate: true,
inline: true,
join_vars: true,
hoist_props: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
(function() {
var obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_2: {
options = {
evaluate: true,
inline: true,
join_vars: true,
hoist_props: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
var obj;
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_2_toplevel: {
options = {
evaluate: true,
inline: true,
join_vars: true,
hoist_props: true,
passes: 3,
reduce_vars: true,
sequences: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
(function() {
obj = {};
obj.one = 1;
obj.two = 2;
console.log(obj.one);
var obj;
})();
}
expect: {
console.log(1);
}
expect_stdout: "1"
}
issue_3071_3: {
options = {
hoist_props: true,
reduce_vars: true,
}
input: {
var c = 0;
(function(a, b) {
(function f(o) {
var n = 2;
while (--b + (o = {
p: c++,
}) && --n > 0);
})();
})();
console.log(c);
}
expect: {
var c = 0;
(function(a, b) {
(function f(o) {
var n = 2;
while (--b + (o = {
p: c++,
}) && --n > 0);
})();
})();
console.log(c);
}
expect_stdout: "2"
}

View File

@@ -102,12 +102,12 @@ dont_screw_try_catch: {
};
}
expect: {
bad = function(n){
return function(t){
bad = function(t){
return function(n){
try{
n()
} catch(n) {
t(n)
t()
} catch(t) {
n(t)
}
}
};
@@ -349,11 +349,11 @@ issue_2254_1: {
try {
console.log(f("PASS"));
} catch (e) {}
function f(e) {
function f(t) {
try {
throw "FAIL";
} catch (t) {
return e;
} catch (e) {
return t;
}
}
}
@@ -392,3 +392,149 @@ issue_2254_2: {
}
expect_stdout: "PASS"
}
issue_24_1: {
mangle = {
ie8: false,
}
input: {
(function(a) {
console.log(typeof function f(){} === typeof a ? "FAIL" : "PASS");
})();
}
expect: {
(function(o) {
console.log(typeof function o(){} === typeof o ? "FAIL" : "PASS");
})();
}
expect_stdout: "PASS"
}
issue_24_2: {
mangle = {
ie8: true,
}
input: {
(function(a) {
console.log(typeof function f(){} === typeof a ? "FAIL" : "PASS");
})();
}
expect: {
(function(n) {
console.log(typeof function o(){} === typeof n ? "FAIL" : "PASS");
})();
}
expect_stdout: "PASS"
}
issue_2976_1: {
mangle = {
ie8: false,
}
input: {
console.log(function f() {
var a;
return a === f ? "FAIL" : "PASS";
}());
}
expect: {
console.log(function n() {
var o;
return o === n ? "FAIL" : "PASS";
}());
}
expect_stdout: "PASS"
}
issue_2976_2: {
mangle = {
ie8: true,
}
input: {
console.log(function f() {
var a;
return a === f ? "FAIL" : "PASS";
}());
}
expect: {
console.log(function n() {
var o;
return o === n ? "FAIL" : "PASS";
}());
}
expect_stdout: "PASS"
}
issue_3035: {
mangle = {
ie8: false,
}
input: {
var c = "FAIL";
(function(a) {
try {
throw 1;
} catch (b) {
try {
throw 0;
} catch (a) {
b && (c = "PASS");
}
}
})();
console.log(c);
}
expect: {
var c = "FAIL";
(function(o) {
try {
throw 1;
} catch (t) {
try {
throw 0;
} catch (o) {
t && (c = "PASS");
}
}
})();
console.log(c);
}
expect_stdout: "PASS"
}
issue_3035_ie8: {
mangle = {
ie8: true,
}
input: {
var c = "FAIL";
(function(a) {
try {
throw 1;
} catch (b) {
try {
throw 0;
} catch (a) {
b && (c = "PASS");
}
}
})();
console.log(c);
}
expect: {
var c = "FAIL";
(function(t) {
try {
throw 1;
} catch (o) {
try {
throw 0;
} catch (t) {
o && (c = "PASS");
}
}
})();
console.log(c);
}
expect_stdout: "PASS"
}

View File

@@ -243,7 +243,7 @@ issue_1089: {
expect: {
function x() {
var f = document.getElementById("fname");
if (f.files[0].size > 12345)
if (12345 < f.files[0].size)
return alert("alert"), f.focus(), !1;
}
}

View File

@@ -175,8 +175,8 @@ should_warn: {
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:141,31]",
"WARN: Condition always true [test/compress/issue-1261.js:141,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:142,23]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:143,24]",
"WARN: Condition always true [test/compress/issue-1261.js:143,8]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:143,24]",
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:144,31]",
"WARN: Condition always false [test/compress/issue-1261.js:144,8]",
]

View File

@@ -104,7 +104,7 @@ mangle_catch_toplevel: {
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
expect_exact: 'var c="FAIL";try{throw 1}catch(o){c="PASS"}console.log(c);'
expect_stdout: "PASS"
}
@@ -148,7 +148,7 @@ mangle_catch_var_toplevel: {
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
expect_exact: 'var r="FAIL";try{throw 1}catch(o){var r="PASS"}console.log(r);'
expect_stdout: "PASS"
}
@@ -345,3 +345,95 @@ mangle_catch_redef_2_ie8_toplevel: {
expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "undefined"
}
mangle_catch_redef_3: {
mangle = {
ie8: false,
toplevel: false,
}
input: {
var o = "PASS";
try {
throw 0;
} catch (o) {
(function() {
function f() {
o = "FAIL";
}
f(), f();
})();
}
console.log(o);
}
expect_exact: 'var o="PASS";try{throw 0}catch(o){(function(){function c(){o="FAIL"}c(),c()})()}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_redef_3_toplevel: {
mangle = {
ie8: false,
toplevel: true,
}
input: {
var o = "PASS";
try {
throw 0;
} catch (o) {
(function() {
function f() {
o = "FAIL";
}
f(), f();
})();
}
console.log(o);
}
expect_exact: 'var c="PASS";try{throw 0}catch(c){(function(){function o(){c="FAIL"}o(),o()})()}console.log(c);'
expect_stdout: "PASS"
}
mangle_catch_redef_ie8_3: {
mangle = {
ie8: true,
toplevel: false,
}
input: {
var o = "PASS";
try {
throw 0;
} catch (o) {
(function() {
function f() {
o = "FAIL";
}
f(), f();
})();
}
console.log(o);
}
expect_exact: 'var o="PASS";try{throw 0}catch(o){(function(){function c(){o="FAIL"}c(),c()})()}console.log(o);'
expect_stdout: "PASS"
}
mangle_catch_redef_3_ie8_toplevel: {
mangle = {
ie8: true,
toplevel: true,
}
input: {
var o = "PASS";
try {
throw 0;
} catch (o) {
(function() {
function f() {
o = "FAIL";
}
f(), f();
})();
}
console.log(o);
}
expect_exact: 'var c="PASS";try{throw 0}catch(c){(function(){function o(){c="FAIL"}o(),o()})()}console.log(c);'
expect_stdout: "PASS"
}

View File

@@ -15,7 +15,7 @@ function_iife_catch: {
}
f();
}
expect_exact: "function f(o){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
expect_stdout: "0 1"
}
@@ -36,7 +36,7 @@ function_iife_catch_ie8: {
}
f();
}
expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
expect_exact: "function f(c){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
expect_stdout: "0 1"
}
@@ -61,7 +61,7 @@ function_catch_catch: {
}
f();
}
expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
expect_exact: "var o=0;function f(){try{throw 1}catch(o){try{throw 2}catch(c){var c=3;console.log(c)}}console.log(c)}f();"
expect_stdout: [
"3",
"undefined",

View File

@@ -0,0 +1,21 @@
inline_script_off: {
beautify = {
inline_script: false,
}
input: {
console.log("</sCrIpT>");
}
expect_exact: 'console.log("</sCrIpT>");'
expect_stdout: "</sCrIpT>"
}
inline_script_on: {
beautify = {
inline_script: true,
}
input: {
console.log("</sCrIpT>");
}
expect_exact: 'console.log("<\\/sCrIpT>");'
expect_stdout: "</sCrIpT>"
}

View File

@@ -1,11 +1,31 @@
remove_redundant_sequence_items: {
options = { side_effects: true };
remove_sequence: {
options = {
side_effects: true,
}
input: {
(0, 1, eval)();
(0, 1, logThis)();
(0, 1, _decorators.logThis)();
}
expect: {
eval();
logThis();
(0, _decorators.logThis)();
}
}
remove_redundant_sequence_items: {
options = {
side_effects: true,
}
input: {
"use strict";
(0, 1, eval)();
(0, 1, logThis)();
(0, 1, _decorators.logThis)();
}
expect: {
"use strict";
(0, eval)();
logThis();
(0, _decorators.logThis)();
@@ -13,13 +33,17 @@ remove_redundant_sequence_items: {
}
dont_remove_this_binding_sequence: {
options = { side_effects: true };
options = {
side_effects: true,
}
input: {
"use strict";
(0, eval)();
(0, logThis)();
(0, _decorators.logThis)();
}
expect: {
"use strict";
(0, eval)();
logThis();
(0, _decorators.logThis)();

View File

@@ -3,8 +3,9 @@ this_binding_conditionals: {
conditionals: true,
evaluate: true,
side_effects: true,
};
}
input: {
"use strict";
(1 && a)();
(0 || a)();
(0 || 1 && a)();
@@ -26,6 +27,7 @@ this_binding_conditionals: {
(1 ? eval : 0)();
}
expect: {
"use strict";
a();
a();
a();
@@ -53,13 +55,15 @@ this_binding_collapse_vars: {
collapse_vars: true,
toplevel: true,
unused: true,
};
}
input: {
"use strict";
var c = a; c();
var d = a.b; d();
var e = eval; e();
}
expect: {
"use strict";
a();
(0, a.b)();
(0, eval)();
@@ -69,31 +73,88 @@ this_binding_collapse_vars: {
this_binding_side_effects: {
options = {
side_effects : true
};
}
input: {
(function (foo) {
(function(foo) {
(0, foo)();
(0, foo.bar)();
(0, eval)('console.log(foo);');
(0, eval)("console.log(foo);");
}());
(function (foo) {
(function(foo) {
"use strict";
(0, foo)();
(0, foo.bar)();
(0, eval)("console.log(foo);");
}());
(function(foo) {
var eval = console;
(0, foo)();
(0, foo.bar)();
(0, eval)('console.log(foo);');
(0, eval)("console.log(foo);");
}());
}
expect: {
(function (foo) {
(function(foo) {
foo();
(0, foo.bar)();
(0, eval)('console.log(foo);');
eval("console.log(foo);");
}());
(function (foo) {
(function(foo) {
"use strict";
foo();
(0, foo.bar)();
(0, eval)("console.log(foo);");
}());
(function(foo) {
var eval = console;
foo();
(0, foo.bar)();
(0, eval)('console.log(foo);');
eval("console.log(foo);");
}());
}
}
}
this_binding_sequences: {
options = {
sequences: true,
side_effects: true,
}
input: {
console.log(typeof function() {
return eval("this");
}());
console.log(typeof function() {
"use strict";
return eval("this");
}());
console.log(typeof function() {
return (0, eval)("this");
}());
console.log(typeof function() {
"use strict";
return (0, eval)("this");
}());
}
expect: {
console.log(typeof function() {
return eval("this");
}()),
console.log(typeof function() {
"use strict";
return eval("this");
}()),
console.log(typeof function() {
return eval("this");
}()),
console.log(typeof function() {
"use strict";
return (0, eval)("this");
}());
}
expect_stdout: [
"object",
"undefined",
"object",
"object",
]
}

View File

@@ -294,10 +294,10 @@ issue_186_beautify_ie8: {
]
}
issue_186_bracketize: {
issue_186_braces: {
beautify = {
beautify: false,
bracketize: true,
braces: true,
ie8: false,
}
input: {
@@ -314,10 +314,10 @@ issue_186_bracketize: {
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}'
}
issue_186_bracketize_ie8: {
issue_186_braces_ie8: {
beautify = {
beautify: false,
bracketize: true,
braces: true,
ie8: true,
}
input: {
@@ -334,10 +334,10 @@ issue_186_bracketize_ie8: {
expect_exact: 'var x=3;if(foo()){do{do{alert(x)}while(--x)}while(x)}else{bar()}'
}
issue_186_beautify_bracketize: {
issue_186_beautify_braces: {
beautify = {
beautify: true,
bracketize: true,
braces: true,
ie8: false,
}
input: {
@@ -366,10 +366,10 @@ issue_186_beautify_bracketize: {
]
}
issue_186_beautify_bracketize_ie8: {
issue_186_beautify_braces_ie8: {
beautify = {
beautify: true,
bracketize: true,
braces: true,
ie8: true,
}
input: {

View File

@@ -8,14 +8,14 @@ too_short: {
}
}
expect_exact: [
'function f(a){',
'return{',
'c:42,',
'd:a(),',
'e:"foo"}}',
"function f(",
"a){return{",
"c:42,d:a(",
'),e:"foo"}',
"}",
]
expect_warnings: [
"WARN: Output exceeds 10 characters"
"WARN: Output exceeds 10 characters",
]
}
@@ -29,11 +29,25 @@ just_enough: {
}
}
expect_exact: [
'function f(a){',
'return{c:42,',
"function f(a){",
"return{c:42,",
'd:a(),e:"foo"}',
'}',
]
expect_warnings: [
"}",
]
expect_warnings: []
}
issue_304: {
beautify = {
max_line_len: 10,
}
input: {
var a = 0, b = 0, c = 0, d = 0, e = 0;
}
expect_exact: [
"var a=0,",
"b=0,c=0,",
"d=0,e=0;",
]
expect_warnings: []
}

View File

@@ -67,7 +67,7 @@ negate_iife_3_evaluate: {
(function(){ return true })() ? console.log(true) : console.log(false);
}
expect: {
console.log(true);
true, console.log(true);
}
expect_stdout: true
}
@@ -110,7 +110,7 @@ negate_iife_3_off_evaluate: {
(function(){ return true })() ? console.log(true) : console.log(false);
}
expect: {
console.log(true);
true, console.log(true);
}
expect_stdout: true
}

View File

@@ -1,21 +1,49 @@
hex_numbers_in_parentheses_for_prototype_functions: {
input: {
(-2);
(-2).toFixed(0);
(2);
(2).toFixed(0);
(0.2);
(0.2).toFixed(0);
(0.00000002);
(0.00000002).toFixed(0);
(1000000000000000128);
(1000000000000000128).toFixed(0);
beautify = {
beautify: true,
}
expect_exact: "-2;(-2).toFixed(0);2;2..toFixed(0);.2;.2.toFixed(0);2e-8;2e-8.toFixed(0);0xde0b6b3a7640080;(0xde0b6b3a7640080).toFixed(0);"
input: {
function f() {
(-2);
(-2).toFixed(0);
(2);
(2).toFixed(0);
(0.2);
(0.2).toFixed(0);
(2.34e20);
(2.34e20).toFixed(0);
(0.00000002);
(0.00000002).toFixed(0);
(1000000000000000128);
(1000000000000000128).toFixed(0);
(-1000000000000000128);
(-1000000000000000128).toFixed(0);
}
}
expect_exact: [
"function f() {",
" -2;",
" (-2).toFixed(0);",
" 2;",
" 2..toFixed(0);",
" .2;",
" .2.toFixed(0);",
" 234e18;",
" 234e18.toFixed(0);",
" 2e-8;",
" 2e-8.toFixed(0);",
" 0xde0b6b3a7640080;",
" (0xde0b6b3a7640080).toFixed(0);",
" -0xde0b6b3a7640080;",
" (-0xde0b6b3a7640080).toFixed(0);",
"}",
]
}
comparisons: {

View File

@@ -1208,6 +1208,37 @@ join_object_assignments_3: {
expect_stdout: "PASS"
}
join_object_assignments_4: {
options = {
join_vars: true,
sequences: true,
}
input: {
var o;
console.log(o);
o = {};
o.a = "foo";
console.log(o.b);
o.b = "bar";
console.log(o.a);
}
expect: {
var o;
console.log(o),
o = {
a: "foo",
},
console.log(o.b),
o.b = "bar",
console.log(o.a);
}
expect_stdout: [
"undefined",
"undefined",
"foo",
]
}
join_object_assignments_return_1: {
options = {
join_vars: true,
@@ -1640,3 +1671,61 @@ issue_2893_2: {
}
expect_stdout: "PASS"
}
issue_869_1: {
mangle = {
properties: {
reserved: [ "get" ]
},
}
input: {
var o = { p: "FAIL" };
Object.defineProperty(o, "p", {
get: function() {
return "PASS";
}
});
console.log(o.p);
}
expect: {
var o = { o: "FAIL" };
Object.defineProperty(o, "o", {
get: function() {
return "PASS";
}
});
console.log(o.o);
}
expect_stdout: "PASS"
}
issue_869_2: {
mangle = {
properties: {
reserved: [ "get" ]
},
}
input: {
var o = { p: "FAIL" };
Object.defineProperties(o, {
p: {
get: function() {
return "PASS";
}
}
});
console.log(o.p);
}
expect: {
var o = { o: "FAIL" };
Object.defineProperties(o, {
o: {
get: function() {
return "PASS";
}
}
});
console.log(o.o);
}
expect_stdout: "PASS"
}

View File

@@ -535,3 +535,110 @@ issue_2705_6: {
"/* */new(/* */a()||b())(c(),d());",
]
}
issue_3065_1: {
options = {
inline: true,
pure_funcs: [ "pureFunc" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function modifyWrapper(a, f, wrapper) {
wrapper.a = a;
wrapper.f = f;
return wrapper;
}
function pureFunc(fun) {
return modifyWrapper(1, fun, function(a) {
return fun(a);
});
}
var unused = pureFunc(function(x) {
return x;
});
}
expect: {}
}
issue_3065_2: {
rename = true
options = {
inline: true,
pure_funcs: [ "pureFunc" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
mangle = {
reserved: [ "pureFunc" ],
toplevel: true,
}
input: {
function modifyWrapper(a, f, wrapper) {
wrapper.a = a;
wrapper.f = f;
return wrapper;
}
function pureFunc(fun) {
return modifyWrapper(1, fun, function(a) {
return fun(a);
});
}
var unused = pureFunc(function(x) {
return x;
});
}
expect: {}
}
issue_3065_3: {
options = {
pure_funcs: [ "debug" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
function debug(msg) {
console.log(msg);
}
debug(function() {
console.log("PASS");
return "FAIL";
}());
}
expect: {
(function() {
console.log("PASS");
})();
}
}
issue_3065_4: {
options = {
pure_funcs: [ "debug" ],
reduce_vars: true,
side_effects: true,
toplevel: true,
unused: true,
}
input: {
var debug = function(msg) {
console.log(msg);
};
debug(function() {
console.log("PASS");
return "FAIL";
}());
}
expect: {
(function() {
console.log("PASS");
})();
}
}

View File

@@ -830,3 +830,334 @@ issue_2938_4: {
}
expect_stdout: "PASS"
}
collapse_vars_1_true: {
options = {
collapse_vars: true,
pure_getters: true,
unused: true,
}
input: {
function f(a, b) {
for (;;) {
var c = a.g();
var d = b.p;
if (c || d) break;
}
}
}
expect: {
function f(a, b) {
for (;;) {
if (a.g() || b.p) break;
}
}
}
}
collapse_vars_1_false: {
options = {
collapse_vars: true,
pure_getters: false,
unused: true,
}
input: {
function f(a, b) {
for (;;) {
var c = a.g();
var d = b.p;
if (c || d) break;
}
}
}
expect: {
function f(a, b) {
for (;;) {
var c = a.g();
var d = b.p;
if (c || d) break;
}
}
}
}
collapse_vars_1_strict: {
options = {
collapse_vars: true,
pure_getters: "strict",
unused: true,
}
input: {
function f(a, b) {
for (;;) {
var c = a.g();
var d = b.p;
if (c || d) break;
}
}
}
expect: {
function f(a, b) {
for (;;) {
var c = a.g();
var d = b.p;
if (c || d) break;
}
}
}
}
collapse_vars_2_true: {
options = {
collapse_vars: true,
pure_getters: true,
reduce_vars: true,
}
input: {
function f() {
function g() {}
g.a = function() {};
g.b = g.a;
return g;
}
}
expect: {
function f() {
function g() {}
g.b = g.a = function() {};
return g;
}
}
}
collapse_vars_2_false: {
options = {
collapse_vars: true,
pure_getters: false,
reduce_vars: true,
}
input: {
function f() {
function g() {}
g.a = function() {};
g.b = g.a;
return g;
}
}
expect: {
function f() {
function g() {}
g.a = function() {};
g.b = g.a;
return g;
}
}
}
collapse_vars_2_strict: {
options = {
collapse_vars: true,
pure_getters: "strict",
reduce_vars: true,
}
input: {
function f() {
function g() {}
g.a = function() {};
g.b = g.a;
return g;
}
}
expect: {
function f() {
function g() {}
g.b = g.a = function() {};
return g;
}
}
}
collapse_rhs_true: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
console.log((42..length = "PASS", "PASS"));
console.log(("foo".length = "PASS", "PASS"));
console.log((false.length = "PASS", "PASS"));
console.log((function() {}.length = "PASS", "PASS"));
console.log(({
get length() {
return "FAIL";
}
}.length = "PASS", "PASS"));
}
expect: {
console.log(42..length = "PASS");
console.log("foo".length = "PASS");
console.log(false.length = "PASS");
console.log(function() {}.length = "PASS");
console.log({
get length() {
return "FAIL";
}
}.length = "PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
]
}
collapse_rhs_false: {
options = {
collapse_vars: true,
pure_getters: false,
}
input: {
console.log((42..length = "PASS", "PASS"));
console.log(("foo".length = "PASS", "PASS"));
console.log((false.length = "PASS", "PASS"));
console.log((function() {}.length = "PASS", "PASS"));
console.log(({
get length() {
return "FAIL";
}
}.length = "PASS", "PASS"));
}
expect: {
console.log(42..length = "PASS");
console.log("foo".length = "PASS");
console.log(false.length = "PASS");
console.log(function() {}.length = "PASS");
console.log({
get length() {
return "FAIL";
}
}.length = "PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
]
}
collapse_rhs_strict: {
options = {
collapse_vars: true,
pure_getters: "strict",
}
input: {
console.log((42..length = "PASS", "PASS"));
console.log(("foo".length = "PASS", "PASS"));
console.log((false.length = "PASS", "PASS"));
console.log((function() {}.length = "PASS", "PASS"));
console.log(({
get length() {
return "FAIL";
}
}.length = "PASS", "PASS"));
}
expect: {
console.log(42..length = "PASS");
console.log("foo".length = "PASS");
console.log(false.length = "PASS");
console.log(function() {}.length = "PASS");
console.log({
get length() {
return "FAIL";
}
}.length = "PASS");
}
expect_stdout: [
"PASS",
"PASS",
"PASS",
"PASS",
"PASS",
]
}
collapse_rhs_setter: {
options = {
collapse_vars: true,
pure_getters: "strict",
}
input: {
try {
console.log(({
set length(v) {
throw "PASS";
}
}.length = "FAIL", "FAIL"));
} catch (e) {
console.log(e);
}
}
expect: {
try {
console.log({
set length(v) {
throw "PASS";
}
}.length = "FAIL");
} catch (e) {
console.log(e);
}
}
expect_stdout: "PASS"
}
collapse_rhs_call: {
options = {
collapse_vars: true,
passes: 2,
pure_getters: "strict",
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {};
function f() {
console.log("PASS");
}
o.f = f;
f();
}
expect: {
({}.f = function() {
console.log("PASS");
})();
}
expect_stdout: "PASS"
}
collapse_rhs_lhs: {
options = {
collapse_vars: true,
pure_getters: true,
}
input: {
function f(a, b) {
a.b = b, b += 2;
console.log(a.b, b);
}
f({}, 1);
}
expect: {
function f(a, b) {
a.b = b, b += 2;
console.log(a.b, b);
}
f({}, 1);
}
expect_stdout: "1 3"
}

View File

@@ -55,7 +55,7 @@ reduce_vars: {
console.log(a - 5);
eval("console.log(a);");
})(eval);
"yes";
true, "yes";
console.log(A + 1);
}
expect_stdout: true
@@ -147,7 +147,7 @@ modified: {
}
function f4() {
var b = 2, c = 3;
b = c;
1, b = c;
console.log(1 + b);
console.log(b + c);
console.log(1 + c);
@@ -715,10 +715,12 @@ passes: {
passes: 2,
reduce_funcs: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
function f() {
(function() {
var a = 1, b = 2, c = 3;
if (a) {
b = c;
@@ -729,17 +731,22 @@ passes: {
console.log(b + c);
console.log(a + c);
console.log(a + b + c);
}
})();
}
expect: {
function f() {
3;
console.log(4);
console.log(6);
console.log(4);
(function() {
console.log(4),
console.log(6),
console.log(4),
console.log(7);
}
})();
}
expect_stdout: [
"4",
"6",
"4",
"7",
]
}
iife: {
@@ -1469,18 +1476,18 @@ defun_redefine: {
};
return g() + h();
}
console.log(f());
}
expect: {
function f() {
function g() {
return 1;
}
g = function() {
(function() {
return 3;
};
return g() + 2;
});
return 3 + 2;
}
console.log(f());
}
expect_stdout: "5"
}
func_inline: {
@@ -1520,23 +1527,37 @@ func_modified: {
}
input: {
function f(a) {
function a() { return 1; }
function b() { return 2; }
function c() { return 3; }
function a() {
return 1;
}
function b() {
return 2;
}
function c() {
return 3;
}
b.inject = [];
c = function() { return 4; };
c = function() {
return 4;
};
return a() + b() + c();
}
console.log(f());
}
expect: {
function f(a) {
function b() { return 2; }
function c() { return 3; }
function b() {
return 2;
}
b.inject = [];
c = function() { return 4; };
return 1 + 2 + c();
(function() {
return 4;
});
return 1 + 2 + 4;
}
console.log(f());
}
expect_stdout: "7"
}
defun_label: {
@@ -5047,9 +5068,7 @@ defun_var_1: {
console.log(typeof a, typeof b);
}
expect: {
var a = 42;
function a() {}
console.log(typeof a, "function");
console.log("number", "function");
}
expect_stdout: "number function"
}
@@ -5069,9 +5088,7 @@ defun_var_2: {
console.log(typeof a, typeof b);
}
expect: {
function a() {}
var a = 42;
console.log(typeof a, "function");
console.log("number", "function");
}
expect_stdout: "number function"
}
@@ -5545,3 +5562,808 @@ issue_2919: {
}
expect_stdout: "function"
}
issue_2992: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var c = "PASS";
(function f(b) {
switch (0) {
case 0:
case b = 1:
b && (c = "FAIL");
}
})();
console.log(c);
}
expect: {
var c = "PASS";
(function f(b) {
switch (0) {
case 0:
case b = 1:
b && (c = "FAIL");
}
})();
console.log(c);
}
expect_stdout: "PASS"
}
issue_3042_1: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {}
var a = [ 1, 2 ].map(function() {
return new f();
});
console.log(a[0].constructor === a[1].constructor);
}
expect: {
function f() {}
var a = [ 1, 2 ].map(function() {
return new f();
});
console.log(a[0].constructor === a[1].constructor);
}
expect_stdout: "true"
}
issue_3042_2: {
options = {
reduce_funcs: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function Foo() {
this.isFoo = function(o) {
return o instanceof Foo;
};
}
function FooCollection() {
this.foos = [1, 1].map(function() {
return new Foo();
});
}
var fooCollection = new FooCollection();
console.log(fooCollection.foos[0].isFoo(fooCollection.foos[0]));
console.log(fooCollection.foos[0].isFoo(fooCollection.foos[1]));
console.log(fooCollection.foos[1].isFoo(fooCollection.foos[0]));
console.log(fooCollection.foos[1].isFoo(fooCollection.foos[1]));
}
expect: {
function Foo() {
this.isFoo = function(o) {
return o instanceof Foo;
};
}
var fooCollection = new function() {
this.foos = [1, 1].map(function() {
return new Foo();
});
}();
console.log(fooCollection.foos[0].isFoo(fooCollection.foos[0]));
console.log(fooCollection.foos[0].isFoo(fooCollection.foos[1]));
console.log(fooCollection.foos[1].isFoo(fooCollection.foos[0]));
console.log(fooCollection.foos[1].isFoo(fooCollection.foos[1]));
}
expect_stdout: [
"true",
"true",
"true",
"true",
]
}
issue_3068_1: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
(function() {
do {
continue;
var b = "defined";
} while (b && b.c);
})();
}
expect: {
(function() {
do {
continue;
var b = "defined";
} while (b && b.c);
})();
}
expect_stdout: true
}
issue_3068_2: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
(function() {
do {
try {
while ("" == typeof a);
} finally {
continue;
}
var b = "defined";
} while (b && b.c);
})();
}
expect: {
(function() {
do {
try {
while ("" == typeof a);
} finally {
continue;
}
var b = "defined";
} while (b && b.c);
})();
}
expect_stdout: true
}
issue_3110_1: {
options = {
conditionals: true,
evaluate: true,
inline: true,
passes: 3,
properties: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
function foo() {
return isDev ? "foo" : "bar";
}
var isDev = true;
var obj = {
foo: foo
};
console.log(foo());
console.log(obj.foo());
})();
}
expect: {
console.log("foo"),
console.log("foo");
}
expect_stdout: [
"foo",
"foo",
]
}
issue_3110_2: {
options = {
conditionals: true,
evaluate: true,
inline: true,
passes: 4,
properties: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
function foo() {
return isDev ? "foo" : "bar";
}
var isDev = true;
console.log(foo());
var obj = {
foo: foo
};
console.log(obj.foo());
})();
}
expect: {
console.log("foo"),
console.log("foo");
}
expect_stdout: [
"foo",
"foo",
]
}
issue_3110_3: {
options = {
conditionals: true,
evaluate: true,
inline: true,
properties: true,
reduce_vars: true,
sequences: true,
side_effects: true,
unused: true,
}
input: {
(function() {
function foo() {
return isDev ? "foo" : "bar";
}
console.log(foo());
var isDev = true;
var obj = {
foo: foo
};
console.log(obj.foo());
})();
}
expect: {
(function() {
function foo() {
return isDev ? "foo" : "bar";
}
console.log(foo());
var isDev = true;
var obj = {
foo: foo
};
console.log(obj.foo());
})();
}
expect_stdout: [
"bar",
"foo",
]
}
issue_3113_1: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var c = 0;
(function() {
function f() {
while (g());
}
var a = f();
function g() {
a && a[c++];
}
g(a = 1);
})();
console.log(c);
}
expect: {
var c = 0;
(function() {
function f() {
while (g());
}
var a = f();
function g() {
a && a[c++];
}
g(a = 1);
})();
console.log(c);
}
expect_stdout: "1"
}
issue_3113_2: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var c = 0;
(function() {
function f() {
while (g());
}
var a = f();
function g() {
a && a[c++];
}
a = 1;
g();
})();
console.log(c);
}
expect: {
var c = 0;
(function() {
function f() {
while (g());
}
var a = f();
function g() {
a && a[c++];
}
a = 1;
g();
})();
console.log(c);
}
expect_stdout: "1"
}
issue_3113_3: {
options = {
evaluate: true,
inline: true,
passes: 2,
pure_getters: "strict",
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
var c = 0;
(function() {
function f() {
while (g());
}
var a;
function g() {
a && a[c++];
}
g(a = 1);
})();
console.log(c);
}
expect: {
var c = 0;
c++;
console.log(c);
}
expect_stdout: "1"
}
issue_3113_4: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 0, b = 0;
function f() {
b += a;
}
f(f(), ++a);
console.log(a, b);
}
expect: {
var a = 0, b = 0;
function f() {
b += a;
}
f(f(), ++a);
console.log(a, b);
}
expect_stdout: "1 1"
}
issue_3113_5: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
function f() {
console.log(a);
}
function g() {
f();
}
while (g());
var a = 1;
f();
}
expect: {
function f() {
console.log(a);
}
function g() {
f();
}
while (g());
var a = 1;
f();
}
expect_stdout: [
"undefined",
"1",
]
}
conditional_nested_1: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var a = 1, b = 0;
(function f(c) {
function g() {
c && (c.a = 0);
c && (c.a = 0);
c && (c[b++] *= 0);
}
g(a-- && f(g(c = 42)));
})();
console.log(b);
}
expect: {
var a = 1, b = 0;
(function f(c) {
function g() {
c && (c.a = 0);
c && (c.a = 0);
c && (c[b++] *= 0);
}
g(a-- && f(g(c = 42)));
})();
console.log(b);
}
expect_stdout: "2"
}
conditional_nested_2: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var c = 0;
(function(a) {
function f() {
a && c++;
}
f(!c && f(), a = 1);
})();
console.log(c);
}
expect: {
var c = 0;
(function(a) {
function f() {
a && c++;
}
f(!c && f(), a = 1);
})();
console.log(c);
}
expect_stdout: "1"
}
conditional_nested_3: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var n = 2, c = 0;
(function f(a) {
0 < n-- && g(a = 1);
function g() {
a && c++;
}
g();
0 < n-- && f();
})();
console.log(c);
}
expect: {
var n = 2, c = 0;
(function f(a) {
0 < n-- && g(a = 1);
function g() {
a && c++;
}
g();
0 < n-- && f();
})();
console.log(c);
}
expect_stdout: "2"
}
issue_2436: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var c;
console.log(((c = {
a: 1,
b: 2
}).a = 3, {
x: c.a,
y: c.b
}));
}
expect: {
var c;
console.log(((c = {
a: 1,
b: 2
}).a = 3, {
x: c.a,
y: c.b
}));
}
expect_stdout: true
}
issue_2916: {
options = {
collapse_vars: true,
evaluate: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
unsafe: true,
unused: true,
}
input: {
var c = "FAIL";
(function(b) {
(function(d) {
d[0] = 1;
})(b);
+b && (c = "PASS");
})([]);
console.log(c);
}
expect: {
var c = "FAIL";
(function(b) {
b[0] = 1;
+b && (c = "PASS");
})([]);
console.log(c);
}
expect_stdout: "PASS"
}
issue_3125: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
unsafe: true,
}
input: {
var o;
console.log((function() {
this.p++;
}.call(o = {
p: 6
}), o.p));
}
expect: {
var o;
console.log((function() {
this.p++;
}.call(o = {
p: 6
}), o.p));
}
expect_stdout: "7"
}
issue_3140_1: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
function f() {
}
f.g = function g() {
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
this();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect: {
(function() {
var a;
function f() {
}
f.g = function g() {
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
this();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect_stdout: "PASS"
}
issue_3140_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
function f() {
}
f.g = function g() {
var self = this;
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
self();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect: {
(function() {
var a;
function f() {
}
f.g = function g() {
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
this();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect_stdout: "PASS"
}
issue_3140_3: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
function f() {
}
f.g = function g() {
var self = this;
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
(function() {
return self;
})()();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect: {
(function() {
var a;
function f() {
}
f.g = function g() {
var self = this;
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
(function() {
return self;
})()();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect_stdout: "PASS"
}
issue_3140_4: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function() {
var a;
function f() {
}
f.g = function g() {
var o = {
p: this
};
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
o.p();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect: {
(function() {
var a;
function f() {
}
f.g = function g() {
var o = {
p: this
};
function h() {
console.log(a ? "PASS" : "FAIL");
}
a = true;
o.p();
a = false;
h.g = g;
return h;
};
return f;
})().g().g();
}
expect_stdout: "PASS"
}

View File

@@ -109,7 +109,7 @@ mangle_catch_toplevel: {
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
expect_exact: 'var c="FAIL";try{throw 1}catch(o){c="PASS"}console.log(c);'
expect_stdout: "PASS"
}
@@ -155,7 +155,7 @@ mangle_catch_var_toplevel: {
}
console.log(a);
}
expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
expect_exact: 'var r="FAIL";try{throw 1}catch(o){var r="PASS"}console.log(r);'
expect_stdout: "PASS"
}
@@ -451,7 +451,7 @@ function_iife_catch: {
}
f();
}
expect_exact: "function f(o){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
expect_stdout: "0 1"
}
@@ -473,7 +473,7 @@ function_iife_catch_ie8: {
}
f();
}
expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
expect_exact: "function f(c){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
expect_stdout: "0 1"
}
@@ -499,7 +499,7 @@ function_catch_catch: {
}
f();
}
expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
expect_exact: "var o=0;function f(){try{throw 1}catch(o){try{throw 2}catch(c){var c=3;console.log(c)}}console.log(c)}f();"
expect_stdout: [
"3",
"undefined",

View File

@@ -668,8 +668,7 @@ side_effects_cascade_2: {
}
expect: {
function f(a, b) {
b = a,
!a + (b += a) || (b += a),
!(b = a) + (b += a) || (b += a),
b = a;
}
}
@@ -877,3 +876,59 @@ forin: {
}
expect_stdout: "PASS"
}
call: {
options = {
sequences: true,
}
input: {
var a = function() {
return this;
}();
function b() {
console.log("foo");
}
b.c = function() {
console.log(this === b ? "bar" : "baz");
};
(a, b)();
(a, b.c)();
(a, function() {
console.log(this === a);
})();
new (a, b)();
new (a, b.c)();
new (a, function() {
console.log(this === a);
})();
}
expect: {
var a = function() {
return this;
}();
function b() {
console.log("foo");
}
b.c = function() {
console.log(this === b ? "bar" : "baz");
},
a, b(),
(a, b.c)(),
a, function() {
console.log(this === a);
}(),
a, new b(),
a, new b.c(),
a, new function() {
console.log(this === a);
}();
}
expect_stdout: [
"foo",
"baz",
"true",
"foo",
"baz",
"false",
]
}

View File

@@ -59,7 +59,7 @@ if_else_empty: {
if ({} ? a : b); else {}
}
expect: {
!{} ? b : a;
({}), a;
}
}
@@ -104,6 +104,7 @@ if_return: {
conditionals: true,
if_return: true,
sequences: true,
side_effects: true,
}
input: {
function f(w, x, y, z) {
@@ -124,7 +125,7 @@ if_return: {
if (w) {
if (y) return;
} else if (z) return;
return x == y || (x && w(), y && z(), !0);
return x == y || (x && w(), y && z()), !0;
}
}
}

View File

@@ -90,17 +90,11 @@ typeof_defun_1: {
"function" == typeof h && h();
}
expect: {
function g() {
h = 42;
console.log("NOPE");
}
function h() {
console.log("YUP");
}
g = 42;
console.log("YES");
"function" == typeof g && g();
"function" == typeof h && h();
h();
}
expect_stdout: [
"YES",

View File

@@ -1,5 +1,5 @@
function test(a){
"aaaaaaaaaaaaaaaa"
;a(err,data),a(err,data)
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsS0FBS0M7QUFDVjtDQUNBQSxFQUFTQyxJQUFLQyxNQUNkRixFQUFTQyxJQUFLQyJ9
;a(err,data),a(err,
data)}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsidGVzdCIsImNhbGxiYWNrIiwiZXJyIiwiZGF0YSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsS0FBS0M7QUFDVjtDQUNBQSxFQUFTQyxJQUFLQyxNQUNkRixFQUFTQztBQUFLQyJ9

View File

@@ -0,0 +1,2 @@
function _toConsumableArray(arr){if(Array.isArray(arr)){for(var i=0,arr2=Array(arr.length);i<arr.length;i++){arr2[i]=arr[i]}return arr2}else{return Array.from(arr)}}var _require=require("bar"),foo=_require.foo;var _require2=require("world"),hello=_require2.hello;foo.x.apply(foo,_toConsumableArray(foo.y(hello.z)));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0Mi5qcyJdLCJuYW1lcyI6WyJyZXF1aXJlIiwiYXJyIl0sIm1hcHBpbmdzIjoiMEpBQWNBLEtBQVFDIiwic291cmNlc0NvbnRlbnQiOlsiY29uc3Qge2Zvb30gPSByZXF1aXJlKFwiYmFyXCIpO1xuY29uc3Qge2hlbGxvfSA9IHJlcXVpcmUoXCJ3b3JsZFwiKTtcblxuZm9vLngoLi4uZm9vLnkoaGVsbG8ueikpO1xuIl19

View File

@@ -0,0 +1,11 @@
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var _require = require("bar"),
foo = _require.foo;
var _require2 = require("world"),
hello = _require2.hello;
foo.x.apply(foo, _toConsumableArray(foo.y(hello.z)));
//# sourceMappingURL=input.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["input2.js"],"names":["require","foo","hello","x","apply","_toConsumableArray","y","z"],"mappings":"kLAAcA,QAAQ,OAAfC,aAAAA,kBACSD,QAAQ,SAAjBE,gBAAAA,MAEPD,IAAIE,EAAJC,MAAAH,IAAAI,mBAASJ,IAAIK,EAAEJ,MAAMK","sourcesContent":["const {foo} = require(\"bar\");\nconst {hello} = require(\"world\");\n\nfoo.x(...foo.y(hello.z));\n"]}

View File

@@ -1,24 +1,109 @@
var fs = require("fs");
var Mocha = require("mocha");
var path = require("path");
// Instantiate a Mocha instance
var mocha = new Mocha({
timeout: 5000
});
var testDir = __dirname + "/mocha/";
var config = {
limit: 5000,
timeout: function(limit) {
this.limit = limit;
}
};
var tasks = [];
var titles = [];
describe = function(title, fn) {
config = Object.create(config);
titles.push(title);
fn.call(config);
titles.pop();
config = Object.getPrototypeOf(config);
};
it = function(title, fn) {
fn.limit = config.limit;
fn.titles = titles.slice();
fn.titles.push(title);
tasks.push(fn);
};
// Add each .js file to the Mocha instance
fs.readdirSync(testDir).filter(function(file) {
fs.readdirSync("test/mocha").filter(function(file) {
return /\.js$/.test(file);
}).forEach(function(file) {
mocha.addFile(path.join(testDir, file));
require("./mocha/" + file);
});
module.exports = function() {
mocha.run(function(failures) {
if (failures) process.on("exit", function() {
process.exit(failures);
function log_titles(log, current, marker) {
var indent = "";
var writing = false;
for (var i = 0; i < current.length; i++, indent += " ") {
if (titles[i] != current[i]) writing = true;
if (writing) log(indent + (i == current.length - 1 && marker || "") + current[i]);
}
titles = current;
}
function red(text) {
return "\u001B[31m" + text + "\u001B[39m";
}
function green(text) {
return "\u001B[32m" + text + "\u001B[39m";
}
var errors = [];
var total = tasks.length;
titles = [];
process.nextTick(function run() {
var task = tasks.shift();
if (task) try {
var elapsed = Date.now();
var timer;
var done = function() {
clearTimeout(timer);
done = function() {};
elapsed = Date.now() - elapsed;
if (elapsed > task.limit) {
throw new Error("Timed out: " + elapsed + "ms > " + task.limit + "ms");
}
log_titles(console.log, task.titles, green('\u221A '));
process.nextTick(run);
};
if (task.length) {
task.timeout = function(limit) {
clearTimeout(timer);
task.limit = limit;
timer = setTimeout(function() {
raise(new Error("Timed out: exceeds " + limit + "ms"));
}, limit);
};
task.timeout(task.limit);
task.call(task, done);
} else {
task.timeout = config.timeout;
task.call(task);
done();
}
} catch (err) {
raise(err);
} else if (errors.length) {
console.error();
console.log(red(errors.length + " test(s) failed!"));
titles = [];
errors.forEach(function(titles, index) {
console.error();
log_titles(console.error, titles, (index + 1) + ") ");
var lines = titles.error.stack.split('\n');
console.error(red(lines[0]));
console.error(lines.slice(1).join("\n"));
});
});
};
process.exit(1);
} else {
console.log();
console.log(green(total + " test(s) passed."));
}
function raise(err) {
clearTimeout(timer);
done = function() {};
task.titles.error = err;
errors.push(task.titles);
log_titles(console.log, task.titles, red('\u00D7 '));
process.nextTick(run);
}
});

View File

@@ -1,9 +1,9 @@
var assert = require("assert");
var exec = require("child_process").exec;
var readFileSync = require("fs").readFileSync;
var fs = require("fs");
function read(path) {
return readFileSync(path, "utf8");
return fs.readFileSync(path, "utf8");
}
describe("bin/uglifyjs", function () {
@@ -56,6 +56,18 @@ describe("bin/uglifyjs", 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";
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.deepEqual(stderr.split(/\n/).slice(0, 2), [
"INFO: Using input source map: blah",
"ERROR: invalid input source map: blah",
]);
done();
});
});
it("Should append source map to output when using --source-map url=inline", function (done) {
var command = uglifyjscmd + " test/input/issue-1323/sample.js --source-map url=inline";
@@ -88,12 +100,42 @@ describe("bin/uglifyjs", function () {
exec(command, function (err, stdout, stderr) {
if (err) throw err;
var stderrLines = stderr.split('\n');
assert.strictEqual(stderrLines[0], 'INFO: Using input source map: test/input/issue-2082/sample.js.map');
var stderrLines = stderr.split("\n");
assert.strictEqual(stderrLines[0], "INFO: Using input source map: test/input/issue-2082/sample.js.map");
assert.notStrictEqual(stderrLines[1], 'INFO: Using input source map: {"version": 3,"sources": ["index.js"],"mappings": ";"}');
done();
});
});
it("Should not load source map before finish reading from STDIN", function(done) {
var mapFile = "tmp/input.js.map";
try {
fs.mkdirSync("./tmp");
} catch (e) {
if (e.code != "EEXIST") throw e;
}
try {
fs.unlinkSync(mapFile);
} catch (e) {
if (e.code != "ENOENT") throw e;
}
var command = [
uglifyjscmd,
"--source-map", "content=" + mapFile,
"--source-map", "includeSources=true",
"--source-map", "url=inline",
].join(" ");
var child = exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, read("test/input/pr-3040/expect.js"));
done();
});
setTimeout(function() {
fs.writeFileSync(mapFile, read("test/input/pr-3040/input.js.map"));
child.stdin.end(read("test/input/pr-3040/input.js"));
}, 1000);
});
it("Should work with --keep-fnames (mangle only)", function (done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m';
@@ -164,18 +206,25 @@ describe("bin/uglifyjs", function () {
done();
});
});
it("Should work with `--beautify bracketize`", function (done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b bracketize';
it("Should work with `--beautify braces`", function (done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b braces';
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, read("test/input/issue-1482/bracketize.js"));
assert.strictEqual(stdout, read("test/input/issue-1482/braces.js"));
done();
});
});
it("Should process inline source map", function(done) {
var command = uglifyjscmd + " test/input/issue-520/input.js -mc toplevel --source-map content=inline,url=inline";
var command = [
uglifyjscmd,
"test/input/issue-520/input.js",
"-mc", "toplevel",
"--source-map", "content=inline",
"--source-map", "includeSources=true",
"--source-map", "url=inline",
].join(" ");
exec(command, function (err, stdout) {
if (err) throw err;
@@ -195,16 +244,29 @@ describe("bin/uglifyjs", function () {
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
"",
].join("\n"));
assert.strictEqual(stderr, "WARN: inline source map not found\n");
var stderrLines = stderr.split("\n");
assert.strictEqual(stderrLines[0], "WARN: inline source map not found: test/input/issue-1323/sample.js");
done();
});
});
it("Should fail with multiple input and inline source map", function(done) {
var command = uglifyjscmd + " test/input/issue-520/input.js test/input/issue-520/output.js --source-map content=inline,url=inline";
it("Should handle multiple input and inline source map", function(done) {
var command = [
uglifyjscmd,
"test/input/issue-520/input.js",
"test/input/issue-1323/sample.js",
"--source-map", "content=inline,url=inline",
].join(" ");
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr.split(/\n/)[0], "ERROR: inline source map only works with singular input");
if (err) throw err;
assert.strictEqual(stdout, [
"var Foo=function Foo(){console.log(1+2)};new Foo;var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUFBLE1BQWdCQyxRQUFRQyxJQUFJLEVBQUUsSUFBTyxJQUFJRixJQ0FuRCxJQUFJRyxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
"",
].join("\n"));
var stderrLines = stderr.split("\n");
assert.strictEqual(stderrLines[0], "WARN: inline source map not found: test/input/issue-1323/sample.js");
done();
});
});

View File

@@ -139,6 +139,26 @@ describe("Comment", function() {
assert.strictEqual(result.code, code);
});
it("Should retain comments within braces", function() {
var code = [
"{/* foo */}",
"a({/* foo */});",
"while (a) {/* foo */}",
"switch (a) {/* foo */}",
"if (a) {/* foo */} else {/* bar */}",
].join("\n\n");
var result = uglify.minify(code, {
compress: false,
mangle: false,
output: {
beautify: true,
comments: "all",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, code);
});
it("Should correctly preserve new lines around comments", function() {
var tests = [
[

View File

@@ -1,66 +1,68 @@
var Uglify = require('../../');
var assert = require("assert");
var Uglify = require("../../");
var SourceMapConsumer = require("source-map").SourceMapConsumer;
function getMap() {
return {
"version": 3,
"sources": ["index.js"],
"names": [],
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
"file": "bundle.js",
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
};
}
function prepareMap(sourceMap) {
var code = [
'"use strict";',
"",
"var foo = function foo(x) {",
' return "foo " + x;',
"};",
'console.log(foo("bar"));',
"",
"//# sourceMappingURL=bundle.js.map",
].join("\n");
var result = Uglify.minify(code, {
sourceMap: {
content: sourceMap,
includeSources: true,
}
});
if (result.error) throw result.error;
return new SourceMapConsumer(result.map);
}
describe("input sourcemaps", function() {
var transpilemap, map;
function getMap() {
return {
"version": 3,
"sources": ["index.js"],
"names": [],
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
"file": "bundle.js",
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
};
}
function prepareMap(sourceMap) {
var transpiled = '"use strict";\n\n' +
'var foo = function foo(x) {\n return "foo " + x;\n};\n' +
'console.log(foo("bar"));\n\n' +
'//# sourceMappingURL=bundle.js.map';
transpilemap = sourceMap || getMap();
var result = Uglify.minify(transpiled, {
sourceMap: {
content: transpilemap
}
});
map = new SourceMapConsumer(result.map);
}
beforeEach(function () {
prepareMap();
});
it("Should copy over original sourcesContent", function() {
assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]);
var orig = getMap();
var map = prepareMap(orig);
assert.equal(map.sourceContentFor("index.js"), orig.sourcesContent[0]);
});
it("Should copy sourcesContent if sources are relative", function () {
it("Should copy sourcesContent if sources are relative", function() {
var relativeMap = getMap();
relativeMap.sources = ['./index.js'];
prepareMap(relativeMap);
var map = prepareMap(relativeMap);
assert.notEqual(map.sourcesContent, null);
assert.equal(map.sourcesContent.length, 1);
assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]);
assert.equal(map.sourceContentFor("index.js"), relativeMap.sourcesContent[0]);
});
it("Final sourcemap should not have invalid mappings from inputSourceMap (issue #882)", function() {
it("Should not have invalid mappings from inputSourceMap (issue #882)", function() {
var map = prepareMap(getMap());
// The original source has only 2 lines, check that mappings don't have more lines
var msg = "Mapping should not have higher line number than the original file had";
map.eachMapping(function(mapping) {
assert.ok(mapping.originalLine <= 2, msg)
assert.ok(mapping.originalLine <= 2, msg);
});
map.allGeneratedPositionsFor({source: "index.js", line: 1, column: 1}).forEach(function(pos) {
map.allGeneratedPositionsFor({
source: "index.js",
line: 1,
column: 1
}).forEach(function(pos) {
assert.ok(pos.line <= 2, msg);
})
});
});
});

View File

@@ -46,10 +46,10 @@ describe("minify", function() {
assert.strictEqual(compressed, [
"function n(n){return 3*n}",
"function r(n){return n/2}",
"var o=console.log.bind(console);",
'function c(n){o("Foo:",2*n)}',
"var c=console.log.bind(console);",
'function o(o){c("Foo:",2*o)}',
"var a=n(3),b=r(12);",
'o("qux",a,b),c(11);',
'c("qux",a,b),o(11);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
});
@@ -79,10 +79,10 @@ describe("minify", function() {
assert.strictEqual(compressed, [
"function n(n){return 3*n}",
"function r(n){return n/2}",
"var o=console.log.bind(console);",
'function c(n){o("Foo:",2*n)}',
"var c=console.log.bind(console);",
'function o(o){c("Foo:",2*o)}',
"var a=n(3),b=r(12);",
'o("qux",a,b),c(11);',
'c("qux",a,b),o(11);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
});
@@ -186,99 +186,6 @@ describe("minify", function() {
});
});
describe("inSourceMap", function() {
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled (#1236)", function() {
var result = Uglify.minify(read("./test/input/issue-1236/simple.js"), {
sourceMap: {
content: read("./test/input/issue-1236/simple.js.map"),
filename: "simple.min.js",
includeSources: true
}
});
var map = JSON.parse(result.map);
assert.equal(map.file, 'simple.min.js');
assert.equal(map.sourcesContent.length, 1);
assert.equal(map.sourcesContent[0],
'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
});
it("Should process inline source map", function() {
var code = Uglify.minify(read("./test/input/issue-520/input.js"), {
compress: { toplevel: true },
sourceMap: {
content: "inline",
url: "inline"
}
}).code + "\n";
assert.strictEqual(code, readFileSync("test/input/issue-520/output.js", "utf8"));
});
it("Should warn for missing inline source map", function() {
var warn_function = Uglify.AST_Node.warn_function;
var warnings = [];
Uglify.AST_Node.warn_function = function(txt) {
warnings.push(txt);
};
try {
var result = Uglify.minify(read("./test/input/issue-1323/sample.js"), {
mangle: false,
sourceMap: {
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");
} finally {
Uglify.AST_Node.warn_function = warn_function;
}
});
it("Should fail with multiple input and inline source map", function() {
var result = Uglify.minify([
read("./test/input/issue-520/input.js"),
read("./test/input/issue-520/output.js")
], {
sourceMap: {
content: "inline",
url: "inline"
}
});
var err = result.error;
assert.ok(err instanceof Error);
assert.strictEqual(err.stack.split(/\n/)[0], "Error: inline source map only works with singular input");
});
});
describe("sourceMapInline", function() {
it("should append source map to output js when sourceMapInline is enabled", function() {
var result = Uglify.minify('var a = function(foo) { return foo; };', {
sourceMap: {
url: "inline"
}
});
var code = result.code;
assert.strictEqual(code, "var a=function(n){return n};\n" +
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BIn0=");
});
it("should not append source map to output js when sourceMapInline is not enabled", function() {
var result = Uglify.minify('var a = function(foo) { return foo; };');
var code = result.code;
assert.strictEqual(code, "var a=function(n){return n};");
});
it("should work with max_line_len", function() {
var result = Uglify.minify(read("./test/input/issue-505/input.js"), {
output: {
max_line_len: 20
},
sourceMap: {
url: "inline"
}
});
assert.strictEqual(result.error, undefined);
assert.strictEqual(result.code, read("./test/input/issue-505/output.js"));
});
});
describe("#__PURE__", function() {
it("should drop #__PURE__ hint after use", function() {
var result = Uglify.minify('//@__PURE__ comment1 #__PURE__ comment2\n foo(), bar();', {
@@ -312,6 +219,15 @@ describe("minify", function() {
assert.strictEqual(err.line, 1);
assert.strictEqual(err.col, 12);
});
it("should reject duplicated label name", function() {
var result = Uglify.minify("L:{L:{}}");
var err = result.error;
assert.ok(err instanceof Error);
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Label L defined twice");
assert.strictEqual(err.filename, "0");
assert.strictEqual(err.line, 1);
assert.strictEqual(err.col, 4);
});
});
describe("global_defs", function() {

View File

@@ -1,7 +1,7 @@
var assert = require("assert");
var uglify = require("../../");
describe("New", function() {
describe("parentheses", function() {
it("Should add trailing parentheses for new expressions with zero arguments in beautify mode", function() {
var tests = [
"new x(1);",
@@ -83,4 +83,23 @@ describe("New", function() {
);
}
});
});
it("Should compress leading parenthesis with reasonable performance", function() {
this.timeout(30000);
var code = [
"({}?0:1)&&x();",
"(function(){}).name;",
];
for (var i = 16; --i >= 0;) {
code = code.concat(code);
}
code = code.join("");
var result = uglify.minify(code, {
compress: false,
mangle: false,
});
if (result.error) throw result.error;
// Dismal performance for `assert.strictEqual()` in Node.js 6
assert.ok(result.code === code);
});
});

View File

@@ -17,7 +17,7 @@ describe("test/benchmark.js", function() {
this.timeout(10 * 60 * 1000);
[
"-b",
"-b bracketize",
"-b braces",
"-m",
"-mc passes=3",
"-mc passes=3,toplevel",

180
test/mocha/sourcemaps.js Normal file
View File

@@ -0,0 +1,180 @@
var assert = require("assert");
var readFileSync = require("fs").readFileSync;
var Uglify = require("../../");
function read(path) {
return readFileSync(path, "utf8");
}
function source_map(code) {
return JSON.parse(Uglify.minify(code, {
compress: false,
mangle: false,
sourceMap: true,
}).map);
}
describe("sourcemaps", function() {
it("Should give correct version", function() {
var map = source_map("var x = 1 + 1;");
assert.strictEqual(map.version, 3);
assert.deepEqual(map.names, [ "x" ]);
});
it("Should give correct names", function() {
var map = source_map([
"({",
" get enabled() {",
" return 3;",
" },",
" set enabled(x) {",
" ;",
" }",
"});",
].join("\n"));
assert.deepEqual(map.names, [ "enabled", "x" ]);
});
it("Should mark array/object literals", function() {
var result = Uglify.minify([
"var obj = {};",
"obj.wat([]);",
].join("\n"), {
sourceMap: true,
toplevel: true,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "({}).wat([]);");
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["wat"],"mappings":"CAAU,IACNA,IAAI"}');
});
describe("inSourceMap", function() {
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled (#1236)", function() {
var result = Uglify.minify(read("./test/input/issue-1236/simple.js"), {
sourceMap: {
content: read("./test/input/issue-1236/simple.js.map"),
filename: "simple.min.js",
includeSources: true
}
});
var map = JSON.parse(result.map);
assert.equal(map.file, 'simple.min.js');
assert.equal(map.sourcesContent.length, 1);
assert.equal(map.sourcesContent[0],
'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
});
it("Should process inline source map", function() {
var code = Uglify.minify(read("./test/input/issue-520/input.js"), {
compress: { toplevel: true },
sourceMap: {
content: "inline",
includeSources: true,
url: "inline"
}
}).code + "\n";
assert.strictEqual(code, readFileSync("test/input/issue-520/output.js", "utf8"));
});
it("Should warn for missing inline source map", function() {
var warn_function = Uglify.AST_Node.warn_function;
var warnings = [];
Uglify.AST_Node.warn_function = function(txt) {
warnings.push(txt);
};
try {
var result = Uglify.minify(read("./test/input/issue-1323/sample.js"), {
mangle: false,
sourceMap: {
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 {
Uglify.AST_Node.warn_function = warn_function;
}
});
it("Should handle multiple input and inline source map", function() {
var warn_function = Uglify.AST_Node.warn_function;
var warnings = [];
Uglify.AST_Node.warn_function = function(txt) {
warnings.push(txt);
};
try {
var result = Uglify.minify([
read("./test/input/issue-520/input.js"),
read("./test/input/issue-1323/sample.js"),
], {
sourceMap: {
content: "inline",
url: "inline",
}
});
if (result.error) throw result.error;
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 {
Uglify.AST_Node.warn_function = warn_function;
}
});
it("Should drop source contents for includeSources=false", function() {
var result = Uglify.minify(read("./test/input/issue-520/input.js"), {
compress: false,
mangle: false,
sourceMap: {
content: "inline",
includeSources: true,
},
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
assert.strictEqual(map.sourcesContent.length, 1);
result = Uglify.minify(result.code, {
compress: false,
mangle: false,
sourceMap: {
content: result.map,
},
});
if (result.error) throw result.error;
map = JSON.parse(result.map);
assert.ok(!("sourcesContent" in map));
});
});
describe("sourceMapInline", function() {
it("should append source map to output js when sourceMapInline is enabled", function() {
var result = Uglify.minify('var a = function(foo) { return foo; };', {
sourceMap: {
url: "inline"
}
});
var code = result.code;
assert.strictEqual(code, "var a=function(n){return n};\n" +
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BIn0=");
});
it("should not append source map to output js when sourceMapInline is not enabled", function() {
var result = Uglify.minify('var a = function(foo) { return foo; };');
var code = result.code;
assert.strictEqual(code, "var a=function(n){return n};");
});
it("should work with max_line_len", function() {
var result = Uglify.minify(read("./test/input/issue-505/input.js"), {
output: {
max_line_len: 20
},
sourceMap: {
url: "inline"
}
});
assert.strictEqual(result.error, undefined);
assert.strictEqual(result.code, read("./test/input/issue-505/output.js"));
});
});
});

View File

@@ -23,6 +23,15 @@ describe("spidermonkey export/import sanity test", function() {
});
});
it("should not add unnecessary escape slashes to regexps", function() {
var input = "/[\\\\/]/;";
var ast = uglify.parse(input).to_mozilla_ast();
assert.equal(
uglify.AST_Node.from_mozilla_ast(ast).print_to_string(),
input
);
});
it("Should judge between directives and strings correctly on import", function() {
var tests = [
{

View File

@@ -11,7 +11,7 @@ function try_beautify(code) {
mangle: false,
output: {
beautify: true,
bracketize: true
braces: true
}
});
if (beautified.error) {

View File

@@ -18,12 +18,8 @@ if (failures) {
console.error("!!! " + Object.keys(failed_files).join(", "));
process.exit(1);
}
var mocha_tests = require("./mocha.js");
mocha_tests();
var run_sourcemaps_tests = require('./sourcemaps');
run_sourcemaps_tests();
console.log();
require("./mocha.js");
/* -----[ utils ]----- */
@@ -49,16 +45,9 @@ function log_test(name) {
}
function find_test_files(dir) {
var files = fs.readdirSync(dir).filter(function(name){
return fs.readdirSync(dir).filter(function(name) {
return /\.js$/i.test(name);
});
if (process.argv.length > 2) {
var x = process.argv.slice(2);
files = files.filter(function(f){
return x.indexOf(f) >= 0;
});
}
return files;
}
function test_directory(dir) {
@@ -135,7 +124,6 @@ function run_compress_tests() {
var output = cmp.compress(input);
output.figure_out_scope(test.mangle);
if (test.mangle) {
U.base54.reset();
output.compute_char_frequency(test.mangle);
output.mangle_names(test.mangle);
if (test.mangle.properties) {
@@ -183,7 +171,7 @@ function run_compress_tests() {
}
if (test.expect_stdout
&& (!test.node_version || semver.satisfies(process.version, test.node_version))) {
var stdout = sandbox.run_code(input_code);
var stdout = run_code(input_code);
if (test.expect_stdout === true) {
test.expect_stdout = stdout;
}
@@ -197,7 +185,7 @@ function run_compress_tests() {
});
return false;
}
stdout = sandbox.run_code(output);
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,
@@ -344,7 +332,6 @@ function parse_test(file) {
}
function make_code(ast, options) {
options.inline_script = true;
var stream = U.OutputStream(options);
ast.print(stream);
return stream.get();
@@ -356,6 +343,11 @@ function evaluate(code) {
return new Function("return(" + code + ")")();
}
function run_code(code) {
var result = sandbox.run_code(code, true);
return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result;
}
// Try to reminify original input with standard options
// to see if it matches expect_stdout.
function reminify(orig_options, input_code, input_formatted, expect_stdout) {
@@ -379,7 +371,7 @@ function reminify(orig_options, input_code, input_formatted, expect_stdout) {
});
return false;
} else {
var stdout = sandbox.run_code(result.code);
var stdout = run_code(result.code);
if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) {
stdout = expect_stdout;
}

View File

@@ -1,6 +1,21 @@
var semver = require("semver");
var vm = require("vm");
function createContext() {
return vm.createContext(Object.defineProperty({}, "console", {
value: {
log: function(msg) {
if (arguments.length == 1 && typeof msg == "string") {
return console.log("%s", msg);
}
return console.log.apply(console, [].map.call(arguments, function(arg) {
return safe_log(arg, 3);
}));
}
}
}));
}
function safe_log(arg, level) {
if (arg) switch (typeof arg) {
case "function":
@@ -9,7 +24,8 @@ function safe_log(arg, level) {
if (/Error$/.test(arg.name)) return arg.toString();
arg.constructor.toString();
if (level--) for (var key in arg) {
if (!Object.getOwnPropertyDescriptor(arg, key).get) {
var desc = Object.getOwnPropertyDescriptor(arg, key);
if (!desc || !desc.get) {
arg[key] = safe_log(arg[key], level);
}
}
@@ -18,9 +34,10 @@ function safe_log(arg, level) {
}
function strip_func_ids(text) {
return text.toString().replace(/F[0-9]{6}N/g, "<F<>N>");
return ("" + text).replace(/F[0-9]{6}N/g, "<F<>N>");
}
var context;
var FUNC_TOSTRING = [
"[ Array, Boolean, Error, Function, Number, Object, RegExp, String].forEach(function(f) {",
" f.toString = Function.prototype.toString;",
@@ -43,35 +60,30 @@ var FUNC_TOSTRING = [
" };",
"}();",
]).join("\n");
exports.run_code = function(code) {
exports.run_code = function(code, reuse) {
var stdout = "";
var original_write = process.stdout.write;
process.stdout.write = function(chunk) {
stdout += chunk;
};
try {
vm.runInNewContext([
if (!reuse || !context) context = createContext();
vm.runInContext([
FUNC_TOSTRING,
"!function() {",
code,
"}();",
].join("\n"), {
console: {
log: function(msg) {
if (arguments.length == 1 && typeof msg == "string") {
return console.log("%s", msg);
}
return console.log.apply(console, [].map.call(arguments, function(arg) {
return safe_log(arg, 3);
}));
}
}
}, { timeout: 5000 });
].join("\n"), context, { timeout: 5000 });
return stdout;
} catch (ex) {
return ex;
} finally {
process.stdout.write = original_write;
if (!reuse || /prototype/.test(code)) {
context = null;
} else for (var key in context) {
delete context[key];
}
}
};
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {

View File

@@ -1,40 +0,0 @@
var UglifyJS = require("..");
var ok = require("assert");
module.exports = function () {
console.log("--- Sourcemaps tests");
var basic = source_map([
'var x = 1 + 1;'
].join('\n'));
ok.equal(basic.version, 3);
ok.deepEqual(basic.names, ['x']);
var issue836 = source_map([
"({",
" get enabled() {",
" return 3;",
" },",
" set enabled(x) {",
" ;",
" }",
"});",
].join("\n"));
ok.deepEqual(issue836.names, ['enabled', 'x']);
}
function source_map(js) {
return JSON.parse(UglifyJS.minify(js, {
compress: false,
mangle: false,
sourceMap: true
}).map);
}
// Run standalone
if (module.parent === null) {
module.exports();
}

View File

@@ -975,7 +975,7 @@ function try_beautify(code, result, printfn) {
mangle: false,
output: {
beautify: true,
bracketize: true,
braces: true,
},
});
if (beautified.error) {

View File

@@ -4,7 +4,7 @@
"mangle": false,
"output": {
"beautify": true,
"bracketize": true
"braces": true
},
"rename": true
},
@@ -18,6 +18,13 @@
{
"toplevel": true
},
{
"compress": {
"passes": 1e6,
"unsafe": true
},
"toplevel": true
},
{
"compress": {
"keep_fargs": false,