Compare commits

...

79 Commits

Author SHA1 Message Date
Alex Lam S.L
915c7e234d v3.4.1 2018-06-19 18:35:48 +00:00
Alex Lam S.L
e54ddcbb8a fix corner cases in properties (#3189)
fixes #3188
2018-06-19 18:20:11 +08:00
Alex Lam S.L
9e19e63551 general clean-ups (#3175) 2018-06-06 17:50:56 +08:00
Alex Lam S.L
bce7ee5f6a v3.4.0 2018-06-02 05:57:10 +00:00
Jiavan
b39043f3ab re-introduce enclose (#3163)
fixes #2443
2018-06-01 16:47:11 +08:00
Alex Lam S.L
caf96acb08 handle asynchronous test failures (#3164) 2018-05-31 20:21:39 +08:00
Alex Lam S.L
c76749084b update JetStream URL (#3165) 2018-05-31 16:23:49 +08:00
Alex Lam S.L
5843494ee2 v3.3.28 2018-05-29 12:25:42 +00:00
Alex Lam S.L
efa21ae3e6 fix corner case in reduce_vars (#3151) 2018-05-26 05:45:44 +08:00
Alex Lam S.L
24d9633a35 fix corner cases with eval() (#3147)
fixes #3146
2018-05-24 14:29:30 +08:00
Alex Lam S.L
7963b96681 augment tests for inline source maps (#3145) 2018-05-24 02:37:51 +08:00
Alex Lam S.L
8c62d854ce augment tests for RegExp (#3144) 2018-05-23 17:24:13 +08:00
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
57 changed files with 4408 additions and 1885 deletions

View File

@@ -2,10 +2,6 @@
<!-- 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

@@ -104,6 +104,8 @@ a double dash to prevent input files being used as option arguments:
sequences.
--config-file <file> Read `minify()` options from JSON file.
-d, --define <expr>[=value] Global definitions.
-e, --enclose [arg[:value]] Embed everything in a big function, with configurable
argument(s) & value(s).
--ie8 Support non-standard Internet Explorer 8.
Equivalent to setting `ie8: true` in `minify()`
for `compress`, `mangle` and `output` options.
@@ -118,7 +120,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.
@@ -149,7 +152,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.
@@ -685,7 +690,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
@@ -1040,8 +1046,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

@@ -40,14 +40,15 @@ program.option("-o, --output <file>", "Output file (default STDOUT).");
program.option("--comments [filter]", "Preserve copyright comments in the output.");
program.option("--config-file <file>", "Read minify() options from JSON file.");
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
program.option("-e, --enclose [arg[,...][:value[,...]]]", "Embed everything in a big function, with configurable argument(s) & value(s).");
program.option("--ie8", "Support non-standard Internet Explorer 8.");
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
program.option("--name-cache <file>", "File to hold mangled name mappings.");
program.option("--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("--timings", "Display operations run time on STDERR.")
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.");
program.option("--warn", "Print warning messages.");
@@ -61,6 +62,7 @@ if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
}
[
"compress",
"enclose",
"ie8",
"mangle",
"sourceMap",
@@ -176,6 +178,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 +384,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

@@ -44,21 +44,21 @@
"use strict";
function DEFNODE(type, props, methods, base) {
if (arguments.length < 4) base = AST_Node;
if (!props) props = [];
else props = props.split(/\s+/);
if (typeof base === "undefined") base = AST_Node;
props = props ? props.split(/\s+/) : [];
var self_props = props;
if (base && base.PROPS)
props = props.concat(base.PROPS);
var code = "return function AST_" + type + "(props){ if (props) { ";
for (var i = props.length; --i >= 0;) {
code += "this." + props[i] + " = props." + props[i] + ";";
}
if (base && base.PROPS) props = props.concat(base.PROPS);
var code = [
"return function AST_", type, "(props){",
"if(props){",
];
props.forEach(function(prop) {
code.push("this.", prop, "=props.", prop, ";");
});
var proto = base && new base;
if (proto && proto.initialize || (methods && methods.initialize))
code += "this.initialize();";
code += "}}";
var ctor = new Function(code)();
if (proto && proto.initialize || methods && methods.initialize) code.push("this.initialize();");
code.push("}}");
var ctor = new Function(code.join(""))();
if (proto) {
ctor.prototype = proto;
ctor.BASE = base;
@@ -71,11 +71,11 @@ function DEFNODE(type, props, methods, base) {
if (type) {
ctor.prototype.TYPE = ctor.TYPE = type;
}
if (methods) for (i in methods) if (HOP(methods, i)) {
if (/^\$/.test(i)) {
ctor[i.substr(1)] = methods[i];
if (methods) for (var name in methods) if (HOP(methods, name)) {
if (/^\$/.test(name)) {
ctor[name.substr(1)] = methods[name];
} else {
ctor.prototype[i] = methods[i];
ctor.prototype[name] = methods[name];
}
}
ctor.DEFMETHOD = function(name, method) {
@@ -85,7 +85,7 @@ function DEFNODE(type, props, methods, base) {
exports["AST_" + type] = ctor;
}
return ctor;
};
}
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before comments_after file raw", {
}, null);
@@ -148,7 +148,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.body._walk(visitor);
});
}
@@ -158,11 +158,10 @@ function walk_body(node, visitor) {
var body = node.body;
if (body instanceof AST_Statement) {
body._walk(visitor);
}
else for (var i = 0, len = body.length; i < len; i++) {
body[i]._walk(visitor);
}
};
} else body.forEach(function(node) {
node._walk(visitor);
});
}
var AST_Block = DEFNODE("Block", "body", {
$documentation: "A body of statements (usually braced)",
@@ -170,7 +169,7 @@ var AST_Block = DEFNODE("Block", "body", {
body: "[AST_Statement*] an array of statements"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
walk_body(this, visitor);
});
}
@@ -197,7 +196,7 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
label: "[AST_Label] a label definition"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.label._walk(visitor);
this.body._walk(visitor);
});
@@ -233,7 +232,7 @@ var AST_DWLoop = DEFNODE("DWLoop", "condition", {
var AST_Do = DEFNODE("Do", null, {
$documentation: "A `do` statement",
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.body._walk(visitor);
this.condition._walk(visitor);
});
@@ -243,7 +242,7 @@ var AST_Do = DEFNODE("Do", null, {
var AST_While = DEFNODE("While", null, {
$documentation: "A `while` statement",
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.condition._walk(visitor);
this.body._walk(visitor);
});
@@ -258,7 +257,7 @@ var AST_For = DEFNODE("For", "init condition step", {
step: "[AST_Node?] the `for` update clause, or null if empty"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
if (this.init) this.init._walk(visitor);
if (this.condition) this.condition._walk(visitor);
if (this.step) this.step._walk(visitor);
@@ -274,7 +273,7 @@ var AST_ForIn = DEFNODE("ForIn", "init object", {
object: "[AST_Node] the object that we're looping through"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.init._walk(visitor);
this.object._walk(visitor);
this.body._walk(visitor);
@@ -288,7 +287,7 @@ var AST_With = DEFNODE("With", "expression", {
expression: "[AST_Node] the `with` expression"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
this.body._walk(visitor);
});
@@ -314,6 +313,9 @@ var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent
if (this.functions) node.functions = this.functions.clone();
if (this.enclosed) node.enclosed = this.enclosed.slice();
return node;
},
pinned: function() {
return this.uses_eval || this.uses_with;
}
}, AST_Block);
@@ -326,12 +328,29 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
var body = this.body;
var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");";
wrapped_tl = parse(wrapped_tl);
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) {
if (node instanceof AST_Directive && node.value == "$ORIG") {
return MAP.splice(body);
}
}));
return wrapped_tl;
},
wrap_enclose: function(args_values) {
if (typeof args_values != "string") args_values = "";
var index = args_values.indexOf(":");
if (index < 0) index = args_values.length;
var body = this.body;
return parse([
"(function(",
args_values.slice(0, index),
'){"$ORIG"})(',
args_values.slice(index + 1),
")"
].join("")).transform(new TreeTransformer(function(node) {
if (node instanceof AST_Directive && node.value == "$ORIG") {
return MAP.splice(body);
}
}));
}
}, AST_Scope);
@@ -343,12 +362,11 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
uses_arguments: "[boolean/S] tells whether this function accesses the arguments array"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
if (this.name) this.name._walk(visitor);
var argnames = this.argnames;
for (var i = 0, len = argnames.length; i < len; i++) {
argnames[i]._walk(visitor);
}
this.argnames.forEach(function(argname) {
argname._walk(visitor);
});
walk_body(this, visitor);
});
}
@@ -378,7 +396,7 @@ var AST_Exit = DEFNODE("Exit", "value", {
value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
},
_walk: function(visitor) {
return visitor._visit(this, this.value && function(){
return visitor._visit(this, this.value && function() {
this.value._walk(visitor);
});
}
@@ -398,7 +416,7 @@ var AST_LoopControl = DEFNODE("LoopControl", "label", {
label: "[AST_LabelRef?] the label, or null if none",
},
_walk: function(visitor) {
return visitor._visit(this, this.label && function(){
return visitor._visit(this, this.label && function() {
this.label._walk(visitor);
});
}
@@ -421,7 +439,7 @@ var AST_If = DEFNODE("If", "condition alternative", {
alternative: "[AST_Statement?] the `else` part, or null if not present"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.condition._walk(visitor);
this.body._walk(visitor);
if (this.alternative) this.alternative._walk(visitor);
@@ -437,7 +455,7 @@ var AST_Switch = DEFNODE("Switch", "expression", {
expression: "[AST_Node] the `switch` “discriminant”"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
walk_body(this, visitor);
});
@@ -458,7 +476,7 @@ var AST_Case = DEFNODE("Case", "expression", {
expression: "[AST_Node] the `case` expression"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
walk_body(this, visitor);
});
@@ -474,7 +492,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
bfinally: "[AST_Finally?] the finally block, or null if not present"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
walk_body(this, visitor);
if (this.bcatch) this.bcatch._walk(visitor);
if (this.bfinally) this.bfinally._walk(visitor);
@@ -488,7 +506,7 @@ var AST_Catch = DEFNODE("Catch", "argname", {
argname: "[AST_SymbolCatch] symbol for the exception"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.argname._walk(visitor);
walk_body(this, visitor);
});
@@ -507,11 +525,10 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
definitions: "[AST_VarDef*] array of variable definitions"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
var definitions = this.definitions;
for (var i = 0, len = definitions.length; i < len; i++) {
definitions[i]._walk(visitor);
}
return visitor._visit(this, function() {
this.definitions.forEach(function(defn) {
defn._walk(visitor);
});
});
}
}, AST_Statement);
@@ -527,7 +544,7 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
value: "[AST_Node?] initializer, or null of there's no initializer"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.name._walk(visitor);
if (this.value) this.value._walk(visitor);
});
@@ -543,12 +560,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);
});
});
}
});
@@ -563,7 +579,7 @@ var AST_Sequence = DEFNODE("Sequence", "expressions", {
expressions: "[AST_Node*] array of expressions (at least two)"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expressions.forEach(function(node) {
node._walk(visitor);
});
@@ -582,7 +598,7 @@ var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
var AST_Dot = DEFNODE("Dot", null, {
$documentation: "A dotted property access expression",
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
});
}
@@ -591,7 +607,7 @@ var AST_Dot = DEFNODE("Dot", null, {
var AST_Sub = DEFNODE("Sub", null, {
$documentation: "Index-style property access, i.e. `a[\"foo\"]`",
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
this.property._walk(visitor);
});
@@ -605,7 +621,7 @@ var AST_Unary = DEFNODE("Unary", "operator expression", {
expression: "[AST_Node] expression that this unary operator applies to"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.expression._walk(visitor);
});
}
@@ -627,7 +643,7 @@ var AST_Binary = DEFNODE("Binary", "operator left right", {
right: "[AST_Node] right-hand side expression"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.left._walk(visitor);
this.right._walk(visitor);
});
@@ -642,7 +658,7 @@ var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative",
alternative: "[AST_Node]"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.condition._walk(visitor);
this.consequent._walk(visitor);
this.alternative._walk(visitor);
@@ -662,11 +678,10 @@ var AST_Array = DEFNODE("Array", "elements", {
elements: "[AST_Node*] array of elements"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
var elements = this.elements;
for (var i = 0, len = elements.length; i < len; i++) {
elements[i]._walk(visitor);
}
return visitor._visit(this, function() {
this.elements.forEach(function(element) {
element._walk(visitor);
});
});
}
});
@@ -677,11 +692,10 @@ var AST_Object = DEFNODE("Object", "properties", {
properties: "[AST_ObjectProperty*] array of properties"
},
_walk: function(visitor) {
return visitor._visit(this, function(){
var properties = this.properties;
for (var i = 0, len = properties.length; i < len; i++) {
properties[i]._walk(visitor);
}
return visitor._visit(this, function() {
this.properties.forEach(function(prop) {
prop._walk(visitor);
});
});
}
});
@@ -693,7 +707,7 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
value: "[AST_Node] property value. For getters and setters this is an AST_Accessor."
},
_walk: function(visitor) {
return visitor._visit(this, function(){
return visitor._visit(this, function() {
this.value._walk(visitor);
});
}
@@ -820,12 +834,12 @@ var AST_NaN = DEFNODE("NaN", null, {
var AST_Undefined = DEFNODE("Undefined", null, {
$documentation: "The `undefined` value",
value: (function(){}())
value: function(){}()
}, AST_Atom);
var AST_Hole = DEFNODE("Hole", null, {
$documentation: "A hole in an array",
value: (function(){}())
value: function(){}()
}, AST_Atom);
var AST_Infinity = DEFNODE("Infinity", null, {
@@ -853,11 +867,11 @@ function TreeWalker(callback) {
this.visit = callback;
this.stack = [];
this.directives = Object.create(null);
};
}
TreeWalker.prototype = {
_visit: function(node, descend) {
this.push(node);
var ret = this.visit(node, descend ? function(){
var ret = this.visit(node, descend ? function() {
descend.call(node);
} : noop);
if (!ret && descend) {

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) {
@@ -47,6 +55,7 @@ function minify(files, options) {
try {
options = defaults(options, {
compress: {},
enclose: false,
ie8: false,
keep_fnames: false,
mangle: {},
@@ -113,7 +122,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 +131,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;
@@ -139,6 +158,9 @@ function minify(files, options) {
if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap);
}
if (options.enclose) {
toplevel = toplevel.wrap_enclose(options.enclose);
}
if (timings) timings.rename = Date.now();
if (options.rename) {
toplevel.figure_out_scope(options.mangle);
@@ -164,12 +186,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) {
@@ -178,6 +197,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

@@ -43,11 +43,9 @@
"use strict";
(function(){
var normalize_directives = function(body) {
(function() {
function normalize_directives(body) {
var in_directive = true;
for (var i = 0; i < body.length; i++) {
if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) {
body[i] = new AST_Directive({
@@ -59,9 +57,8 @@
in_directive = false;
}
}
return body;
};
}
var MOZ_TO_ME = {
Program: function(M) {
@@ -129,7 +126,7 @@
return new AST_Array({
start : my_start_token(M),
end : my_end_token(M),
elements : M.elements.map(function(elem){
elements : M.elements.map(function(elem) {
return elem === null ? new AST_Hole() : from_moz(elem);
})
});
@@ -138,7 +135,7 @@
return new AST_Object({
start : my_start_token(M),
end : my_end_token(M),
properties : M.properties.map(function(prop){
properties : M.properties.map(function(prop) {
prop.type = "Property";
return from_moz(prop)
})
@@ -180,6 +177,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 +197,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 +408,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
}
};
});
@@ -478,7 +477,7 @@
endpos : range ? range[0] : moznode.start,
raw : raw_token(moznode),
});
};
}
function my_end_token(moznode) {
var loc = moznode.loc, end = loc && loc.end;
@@ -493,7 +492,7 @@
endpos : range ? range[1] : moznode.end,
raw : raw_token(moznode),
});
};
}
function map(moztype, mytype, propmap) {
var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
@@ -505,7 +504,7 @@
me_to_moz += "return {\n" +
"type: " + JSON.stringify(moztype);
if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){
if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop) {
var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
if (!m) throw new Error("Can't understand property map: " + prop);
var moz = m[1], how = m[2], my = m[3];
@@ -548,7 +547,7 @@
);
MOZ_TO_ME[moztype] = moz_to_me;
def_to_moz(mytype, me_to_moz);
};
}
var FROM_MOZ_STACK = null;
@@ -557,13 +556,28 @@
var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
FROM_MOZ_STACK.pop();
return ret;
};
}
AST_Node.from_mozilla_ast = function(node){
AST_Node.from_mozilla_ast = function(node) {
var save_stack = FROM_MOZ_STACK;
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;
};
@@ -583,24 +597,24 @@
}
}
return moznode;
};
}
function def_to_moz(mytype, handler) {
mytype.DEFMETHOD("to_mozilla_ast", function() {
return set_moz_loc(this, handler(this));
});
};
}
function to_moz(node) {
return node != null ? node.to_mozilla_ast() : null;
};
}
function to_moz_block(node) {
return {
type: "BlockStatement",
body: node.body.map(to_moz)
};
};
}
function to_moz_scope(type, node) {
var body = node.body.map(to_moz);
@@ -611,5 +625,5 @@
type: type,
body: body
};
};
}
})();

View File

@@ -137,7 +137,7 @@ function OutputStream(options) {
function make_string(str, quote) {
var dq = 0, sq = 0;
str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g,
function(s, i){
function(s, i) {
switch (s) {
case '"': ++dq; return '"';
case "'": ++sq; return "'";
@@ -173,7 +173,7 @@ function OutputStream(options) {
default:
return dq > sq ? quote_single() : quote_double();
}
};
}
function encode_string(str, quote) {
var ret = make_string(str, quote);
@@ -183,20 +183,21 @@ function OutputStream(options) {
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,50 +398,56 @@ 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;
print("{");
newline();
with_indent(next_indent(), function(){
with_indent(next_indent(), function() {
ret = cont();
});
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,7 +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 OUTPUT.slice(-1) == "(" },
has_parens : function() { return has_parens },
newline : newline,
print : print,
space : space,
@@ -617,24 +627,23 @@ function OutputStream(options) {
return stack[stack.length - 2 - (n || 0)];
}
};
};
}
/* -----[ code generators ]----- */
(function(){
(function() {
/* -----[ utils ]----- */
function DEFPRINT(nodetype, generator) {
nodetype.DEFMETHOD("_codegen", generator);
};
}
var in_directive = false;
var active_scope = null;
var use_asm = null;
AST_Node.DEFMETHOD("print", function(stream, force_parens){
AST_Node.DEFMETHOD("print", function(stream, force_parens) {
var self = this, generator = self._codegen;
if (self instanceof AST_Scope) {
active_scope = self;
@@ -661,7 +670,7 @@ function OutputStream(options) {
});
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
AST_Node.DEFMETHOD("print_to_string", function(options){
AST_Node.DEFMETHOD("print_to_string", function(options) {
var s = OutputStream(options);
this.print(s);
return s.get();
@@ -671,19 +680,19 @@ function OutputStream(options) {
function PARENS(nodetype, func) {
if (Array.isArray(nodetype)) {
nodetype.forEach(function(nodetype){
nodetype.forEach(function(nodetype) {
PARENS(nodetype, func);
});
} 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){
PARENS(AST_Function, function(output) {
if (!output.has_parens() && first_in_statement(output)) {
return true;
}
@@ -705,17 +714,17 @@ function OutputStream(options) {
// same goes for an object literal, because otherwise it would be
// interpreted as a block of code.
PARENS(AST_Object, function(output){
PARENS(AST_Object, function(output) {
return !output.has_parens() && first_in_statement(output);
});
PARENS(AST_Unary, function(output){
PARENS(AST_Unary, function(output) {
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this;
});
PARENS(AST_Sequence, function(output){
PARENS(AST_Sequence, function(output) {
var p = output.parent();
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|| p instanceof AST_Unary // !(foo, bar, baz)
@@ -729,7 +738,7 @@ function OutputStream(options) {
;
});
PARENS(AST_Binary, function(output){
PARENS(AST_Binary, function(output) {
var p = output.parent();
// (foo && bar)()
if (p instanceof AST_Call && p.expression === this)
@@ -752,7 +761,7 @@ function OutputStream(options) {
}
});
PARENS(AST_PropAccess, function(output){
PARENS(AST_PropAccess, function(output) {
var p = output.parent();
if (p instanceof AST_New && p.expression === this) {
// i.e. new (foo.bar().baz)
@@ -773,7 +782,7 @@ function OutputStream(options) {
}
});
PARENS(AST_Call, function(output){
PARENS(AST_Call, function(output) {
var p = output.parent(), p1;
if (p instanceof AST_New && p.expression === this)
return true;
@@ -787,7 +796,7 @@ function OutputStream(options) {
&& p1.left === p;
});
PARENS(AST_New, function(output){
PARENS(AST_New, function(output) {
var p = output.parent();
if (!need_constructor_parens(this, output)
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
@@ -795,7 +804,7 @@ function OutputStream(options) {
return true;
});
PARENS(AST_Number, function(output){
PARENS(AST_Number, function(output) {
var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === this) {
var value = this.getValue();
@@ -805,7 +814,7 @@ function OutputStream(options) {
}
});
PARENS([ AST_Assign, AST_Conditional ], function(output){
PARENS([ AST_Assign, AST_Conditional ], function(output) {
var p = output.parent();
// !(a = false) → true
if (p instanceof AST_Unary)
@@ -826,11 +835,11 @@ function OutputStream(options) {
/* -----[ PRINTERS ]----- */
DEFPRINT(AST_Directive, function(self, output){
DEFPRINT(AST_Directive, function(self, output) {
output.print_string(self.value, self.quote);
output.semicolon();
});
DEFPRINT(AST_Debugger, function(self, output){
DEFPRINT(AST_Debugger, function(self, output) {
output.print("debugger");
output.semicolon();
});
@@ -840,7 +849,7 @@ function OutputStream(options) {
function display_body(body, is_toplevel, output, allow_directives) {
var last = body.length - 1;
in_directive = allow_directives;
body.forEach(function(stmt, i){
body.forEach(function(stmt, i) {
if (in_directive === true && !(stmt instanceof AST_Directive ||
stmt instanceof AST_EmptyStatement ||
(stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String)
@@ -863,26 +872,26 @@ function OutputStream(options) {
}
});
in_directive = false;
};
}
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
force_statement(this.body, output);
});
DEFPRINT(AST_Statement, function(self, output){
DEFPRINT(AST_Statement, function(self, output) {
self.body.print(output);
output.semicolon();
});
DEFPRINT(AST_Toplevel, function(self, output){
DEFPRINT(AST_Toplevel, function(self, output) {
display_body(self.body, true, output, true);
output.print("");
});
DEFPRINT(AST_LabeledStatement, function(self, output){
DEFPRINT(AST_LabeledStatement, function(self, output) {
self.label.print(output);
output.colon();
self.body.print(output);
});
DEFPRINT(AST_SimpleStatement, function(self, output){
DEFPRINT(AST_SimpleStatement, function(self, output) {
self.body.print(output);
output.semicolon();
});
@@ -899,38 +908,38 @@ function OutputStream(options) {
display_body(self.body, false, output, allow_directives);
});
} else print_braced_empty(self, output);
};
DEFPRINT(AST_BlockStatement, function(self, output){
}
DEFPRINT(AST_BlockStatement, function(self, output) {
print_braced(self, output);
});
DEFPRINT(AST_EmptyStatement, function(self, output){
DEFPRINT(AST_EmptyStatement, function(self, output) {
output.semicolon();
});
DEFPRINT(AST_Do, function(self, output){
DEFPRINT(AST_Do, function(self, output) {
output.print("do");
output.space();
make_block(self.body, output);
output.space();
output.print("while");
output.space();
output.with_parens(function(){
output.with_parens(function() {
self.condition.print(output);
});
output.semicolon();
});
DEFPRINT(AST_While, function(self, output){
DEFPRINT(AST_While, function(self, output) {
output.print("while");
output.space();
output.with_parens(function(){
output.with_parens(function() {
self.condition.print(output);
});
output.space();
self._do_print_body(output);
});
DEFPRINT(AST_For, function(self, output){
DEFPRINT(AST_For, function(self, output) {
output.print("for");
output.space();
output.with_parens(function(){
output.with_parens(function() {
if (self.init) {
if (self.init instanceof AST_Definitions) {
self.init.print(output);
@@ -956,10 +965,10 @@ function OutputStream(options) {
output.space();
self._do_print_body(output);
});
DEFPRINT(AST_ForIn, function(self, output){
DEFPRINT(AST_ForIn, function(self, output) {
output.print("for");
output.space();
output.with_parens(function(){
output.with_parens(function() {
self.init.print(output);
output.space();
output.print("in");
@@ -969,10 +978,10 @@ function OutputStream(options) {
output.space();
self._do_print_body(output);
});
DEFPRINT(AST_With, function(self, output){
DEFPRINT(AST_With, function(self, output) {
output.print("with");
output.space();
output.with_parens(function(){
output.with_parens(function() {
self.expression.print(output);
});
output.space();
@@ -980,7 +989,7 @@ function OutputStream(options) {
});
/* -----[ functions ]----- */
AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){
AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
var self = this;
if (!nokeyword) {
output.print("function");
@@ -989,8 +998,8 @@ function OutputStream(options) {
output.space();
self.name.print(output);
}
output.with_parens(function(){
self.argnames.forEach(function(arg, i){
output.with_parens(function() {
self.argnames.forEach(function(arg, i) {
if (i) output.comma();
arg.print(output);
});
@@ -998,40 +1007,31 @@ function OutputStream(options) {
output.space();
print_braced(self, output, true);
});
DEFPRINT(AST_Lambda, function(self, output){
DEFPRINT(AST_Lambda, function(self, output) {
self._do_print(output);
});
/* -----[ exits ]----- */
AST_Exit.DEFMETHOD("_do_print", function(output, kind){
/* -----[ jumps ]----- */
function print_jump(output, kind, target) {
output.print(kind);
if (this.value) {
if (target) {
output.space();
this.value.print(output);
target.print(output);
}
output.semicolon();
});
DEFPRINT(AST_Return, function(self, output){
self._do_print(output, "return");
});
DEFPRINT(AST_Throw, function(self, output){
self._do_print(output, "throw");
});
}
/* -----[ loop control ]----- */
AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){
output.print(kind);
if (this.label) {
output.space();
this.label.print(output);
}
output.semicolon();
DEFPRINT(AST_Return, function(self, output) {
print_jump(output, "return", self.value);
});
DEFPRINT(AST_Break, function(self, output){
self._do_print(output, "break");
DEFPRINT(AST_Throw, function(self, output) {
print_jump(output, "throw", self.value);
});
DEFPRINT(AST_Continue, function(self, output){
self._do_print(output, "continue");
DEFPRINT(AST_Break, function(self, output) {
print_jump(output, "break", self.label);
});
DEFPRINT(AST_Continue, function(self, output) {
print_jump(output, "continue", self.label);
});
/* -----[ if ]----- */
@@ -1062,11 +1062,11 @@ function OutputStream(options) {
else break;
}
force_statement(self.body, output);
};
DEFPRINT(AST_If, function(self, output){
}
DEFPRINT(AST_If, function(self, output) {
output.print("if");
output.space();
output.with_parens(function(){
output.with_parens(function() {
self.condition.print(output);
});
output.space();
@@ -1085,17 +1085,17 @@ function OutputStream(options) {
});
/* -----[ switch ]----- */
DEFPRINT(AST_Switch, function(self, output){
DEFPRINT(AST_Switch, function(self, output) {
output.print("switch");
output.space();
output.with_parens(function(){
output.with_parens(function() {
self.expression.print(output);
});
output.space();
var last = self.body.length - 1;
if (last < 0) print_braced_empty(self, output);
else output.with_block(function(){
self.body.forEach(function(branch, i){
else output.with_block(function() {
self.body.forEach(function(branch, i) {
output.indent(true);
branch.print(output);
if (i < last && branch.body.length > 0)
@@ -1103,19 +1103,19 @@ function OutputStream(options) {
});
});
});
AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){
AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
output.newline();
this.body.forEach(function(stmt){
this.body.forEach(function(stmt) {
output.indent();
stmt.print(output);
output.newline();
});
});
DEFPRINT(AST_Default, function(self, output){
DEFPRINT(AST_Default, function(self, output) {
output.print("default:");
self._do_print_body(output);
});
DEFPRINT(AST_Case, function(self, output){
DEFPRINT(AST_Case, function(self, output) {
output.print("case");
output.space();
self.expression.print(output);
@@ -1124,7 +1124,7 @@ function OutputStream(options) {
});
/* -----[ exceptions ]----- */
DEFPRINT(AST_Try, function(self, output){
DEFPRINT(AST_Try, function(self, output) {
output.print("try");
output.space();
print_braced(self, output);
@@ -1137,37 +1137,30 @@ function OutputStream(options) {
self.bfinally.print(output);
}
});
DEFPRINT(AST_Catch, function(self, output){
DEFPRINT(AST_Catch, function(self, output) {
output.print("catch");
output.space();
output.with_parens(function(){
output.with_parens(function() {
self.argname.print(output);
});
output.space();
print_braced(self, output);
});
DEFPRINT(AST_Finally, function(self, output){
DEFPRINT(AST_Finally, function(self, output) {
output.print("finally");
output.space();
print_braced(self, output);
});
/* -----[ var/const ]----- */
AST_Definitions.DEFMETHOD("_do_print", function(output, kind){
output.print(kind);
DEFPRINT(AST_Var, function(self, output) {
output.print("var");
output.space();
this.definitions.forEach(function(def, i){
self.definitions.forEach(function(def, i) {
if (i) output.comma();
def.print(output);
});
var p = output.parent();
var in_for = p instanceof AST_For || p instanceof AST_ForIn;
var avoid_semicolon = in_for && p.init === this;
if (!avoid_semicolon)
output.semicolon();
});
DEFPRINT(AST_Var, function(self, output){
self._do_print(output, "var");
if (p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon();
});
function parenthesize_for_noin(node, output, noin) {
@@ -1182,9 +1175,9 @@ function OutputStream(options) {
}
}));
node.print(output, parens);
};
}
DEFPRINT(AST_VarDef, function(self, output){
DEFPRINT(AST_VarDef, function(self, output) {
self.name.print(output);
if (self.value) {
output.space();
@@ -1197,28 +1190,27 @@ function OutputStream(options) {
});
/* -----[ other expressions ]----- */
DEFPRINT(AST_Call, function(self, output){
DEFPRINT(AST_Call, function(self, output) {
self.expression.print(output);
if (self instanceof AST_New && !need_constructor_parens(self, output))
return;
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
output.add_mapping(self.start);
}
output.with_parens(function(){
self.args.forEach(function(expr, i){
output.with_parens(function() {
self.args.forEach(function(expr, i) {
if (i) output.comma();
expr.print(output);
});
});
});
DEFPRINT(AST_New, function(self, output){
DEFPRINT(AST_New, function(self, output) {
output.print("new");
output.space();
AST_Call.prototype._codegen(self, output);
});
AST_Sequence.DEFMETHOD("_do_print", function(output){
this.expressions.forEach(function(node, index) {
DEFPRINT(AST_Sequence, function(self, output) {
self.expressions.forEach(function(node, index) {
if (index > 0) {
output.comma();
if (output.should_break()) {
@@ -1229,22 +1221,11 @@ function OutputStream(options) {
node.print(output);
});
});
DEFPRINT(AST_Sequence, function(self, output){
self._do_print(output);
// var p = output.parent();
// if (p instanceof AST_Statement) {
// output.with_indent(output.next_indent(), function(){
// self._do_print(output);
// });
// } else {
// self._do_print(output);
// }
});
DEFPRINT(AST_Dot, function(self, output){
DEFPRINT(AST_Dot, function(self, output) {
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);
@@ -1261,13 +1242,13 @@ function OutputStream(options) {
output.print_name(prop);
}
});
DEFPRINT(AST_Sub, function(self, output){
DEFPRINT(AST_Sub, function(self, output) {
self.expression.print(output);
output.print("[");
self.property.print(output);
output.print("]");
});
DEFPRINT(AST_UnaryPrefix, function(self, output){
DEFPRINT(AST_UnaryPrefix, function(self, output) {
var op = self.operator;
output.print(op);
if (/^[a-z]/i.test(op)
@@ -1278,11 +1259,11 @@ function OutputStream(options) {
}
self.expression.print(output);
});
DEFPRINT(AST_UnaryPostfix, function(self, output){
DEFPRINT(AST_UnaryPostfix, function(self, output) {
self.expression.print(output);
output.print(self.operator);
});
DEFPRINT(AST_Binary, function(self, output){
DEFPRINT(AST_Binary, function(self, output) {
var op = self.operator;
self.left.print(output);
if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
@@ -1308,7 +1289,7 @@ function OutputStream(options) {
}
self.right.print(output);
});
DEFPRINT(AST_Conditional, function(self, output){
DEFPRINT(AST_Conditional, function(self, output) {
self.condition.print(output);
output.space();
output.print("?");
@@ -1320,11 +1301,11 @@ function OutputStream(options) {
});
/* -----[ literals ]----- */
DEFPRINT(AST_Array, function(self, output){
output.with_square(function(){
DEFPRINT(AST_Array, function(self, output) {
output.with_square(function() {
var a = self.elements, len = a.length;
if (len > 0) output.space();
a.forEach(function(exp, i){
a.forEach(function(exp, i) {
if (i) output.comma();
exp.print(output);
// If the final element is a hole, we need to make sure it
@@ -1336,9 +1317,9 @@ function OutputStream(options) {
if (len > 0) output.space();
});
});
DEFPRINT(AST_Object, function(self, output){
if (self.properties.length > 0) output.with_block(function(){
self.properties.forEach(function(prop, i){
DEFPRINT(AST_Object, function(self, output) {
if (self.properties.length > 0) output.with_block(function() {
self.properties.forEach(function(prop, i) {
if (i) {
output.print(",");
output.newline();
@@ -1356,7 +1337,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 {
@@ -1367,7 +1348,7 @@ function OutputStream(options) {
}
}
DEFPRINT(AST_ObjectKeyVal, function(self, output){
DEFPRINT(AST_ObjectKeyVal, function(self, output) {
print_property_name(self.key, self.quote, output);
output.colon();
self.value.print(output);
@@ -1378,27 +1359,27 @@ function OutputStream(options) {
print_property_name(this.key.name, this.quote, output);
this.value._do_print(output, true);
});
DEFPRINT(AST_ObjectSetter, function(self, output){
DEFPRINT(AST_ObjectSetter, function(self, output) {
self._print_getter_setter("set", output);
});
DEFPRINT(AST_ObjectGetter, function(self, output){
DEFPRINT(AST_ObjectGetter, function(self, output) {
self._print_getter_setter("get", output);
});
DEFPRINT(AST_Symbol, function(self, output){
DEFPRINT(AST_Symbol, function(self, output) {
var def = self.definition();
output.print_name(def ? def.mangled_name || def.name : self.name);
});
DEFPRINT(AST_Hole, noop);
DEFPRINT(AST_This, function(self, output){
DEFPRINT(AST_This, function(self, output) {
output.print("this");
});
DEFPRINT(AST_Constant, function(self, output){
DEFPRINT(AST_Constant, function(self, output) {
output.print(self.getValue());
});
DEFPRINT(AST_String, function(self, output){
DEFPRINT(AST_String, function(self, output) {
output.print_string(self.getValue(), self.quote, in_directive);
});
DEFPRINT(AST_Number, function(self, output){
DEFPRINT(AST_Number, function(self, output) {
if (use_asm && self.start && self.start.raw != null) {
output.print(self.start.raw);
} else {
@@ -1406,7 +1387,7 @@ function OutputStream(options) {
}
});
DEFPRINT(AST_RegExp, function(self, output){
DEFPRINT(AST_RegExp, function(self, output) {
var regexp = self.getValue();
var str = regexp.toString();
if (regexp.raw_source) {
@@ -1428,7 +1409,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) {
@@ -1436,7 +1417,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;
@@ -1447,84 +1428,93 @@ 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)
output.print("{}");
else if (stmt instanceof AST_BlockStatement)
stmt.print(output);
else output.with_block(function(){
else output.with_block(function() {
output.indent();
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

@@ -130,7 +130,7 @@ function is_letter(code) {
return (code >= 97 && code <= 122)
|| (code >= 65 && code <= 90)
|| (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code)));
};
}
function is_surrogate_pair_head(code) {
if (typeof code == "string")
@@ -146,11 +146,11 @@ function is_surrogate_pair_tail(code) {
function is_digit(code) {
return code >= 48 && code <= 57;
};
}
function is_alphanumeric_char(code) {
return is_digit(code) || is_letter(code);
};
}
function is_unicode_digit(code) {
return UNICODE.digit.test(String.fromCharCode(code));
@@ -158,19 +158,19 @@ function is_unicode_digit(code) {
function is_unicode_combining_mark(ch) {
return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
};
}
function is_unicode_connector_punctuation(ch) {
return UNICODE.connector_punctuation.test(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) {
return code == 36 || code == 95 || is_letter(code);
};
}
function is_identifier_char(ch) {
var code = ch.charCodeAt(0);
@@ -182,11 +182,11 @@ function is_identifier_char(ch) {
|| is_unicode_connector_punctuation(ch)
|| is_unicode_digit(code)
;
};
}
function is_identifier_string(str){
function is_identifier_string(str) {
return /^[a-z_$][a-z0-9_$]*$/i.test(str);
};
}
function parse_js_number(num) {
if (RE_HEX_NUMBER.test(num)) {
@@ -197,7 +197,7 @@ function parse_js_number(num) {
var val = parseFloat(num);
if (val == num) return val;
}
};
}
function JS_Parse_Error(message, filename, line, col, pos) {
this.message = message;
@@ -205,7 +205,7 @@ function JS_Parse_Error(message, filename, line, col, pos) {
this.line = line;
this.col = col;
this.pos = pos;
};
}
JS_Parse_Error.prototype = Object.create(Error.prototype);
JS_Parse_Error.prototype.constructor = JS_Parse_Error;
JS_Parse_Error.prototype.name = "SyntaxError";
@@ -213,11 +213,11 @@ configure_error_stack(JS_Parse_Error);
function js_error(message, filename, line, col, pos) {
throw new JS_Parse_Error(message, filename, line, col, pos);
};
}
function is_token(token, type, val) {
return token.type == type && (val == null || token.value == val);
};
}
var EX_EOF = {};
@@ -239,13 +239,15 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
directive_stack : []
};
function peek() { return S.text.charAt(S.pos); };
function peek() {
return S.text.charAt(S.pos);
}
function next(signal_eof, in_string) {
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;
@@ -258,43 +260,43 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
++S.col;
}
return ch;
};
}
function forward(i) {
while (i-- > 0) next();
};
}
function looking_at(str) {
return S.text.substr(S.pos, str.length) == str;
};
}
function find_eol() {
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;
};
}
function find(what, signal_eof) {
var pos = S.text.indexOf(what, S.pos);
if (signal_eof && pos == -1) throw EX_EOF;
return pos;
};
}
function start_token() {
S.tokline = S.line;
S.tokcol = S.col;
S.tokpos = S.pos;
};
}
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) {
@@ -321,27 +323,27 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
S.newline_before = false;
return new AST_Token(ret);
};
}
function skip_whitespace() {
while (WHITESPACE_CHARS(peek()))
while (WHITESPACE_CHARS[peek()])
next();
};
}
function read_while(pred) {
var ret = "", ch, i = 0;
while ((ch = peek()) && pred(ch, i++))
ret += next();
return ret;
};
}
function parse_error(err) {
js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
};
}
function read_num(prefix) {
var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
var num = read_while(function(ch, i){
var num = read_while(function(ch, i) {
var code = ch.charCodeAt(0);
switch (code) {
case 120: case 88: // xX
@@ -367,7 +369,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
} else {
parse_error("Invalid syntax: " + num);
}
};
}
function read_escaped_char(in_string) {
var ch = next(true, in_string);
@@ -390,7 +392,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if (ch >= "0" && ch <= "7")
return read_octal_escape_sequence(ch);
return ch;
};
}
function read_octal_escape_sequence(ch) {
// Read
@@ -417,14 +419,14 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
num = (num << 4) | digit;
}
return num;
};
}
var read_string = with_eof_error("Unterminated string constant", function(quote_char){
var read_string = with_eof_error("Unterminated string constant", function(quote_char) {
var quote = next(), ret = "";
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;
}
@@ -447,9 +449,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
S.comments_before.push(token(type, ret, true));
S.regex_allowed = regex_allowed;
return next_token;
};
}
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function() {
var regex_allowed = S.regex_allowed;
var i = find("*/", true);
var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, '\n');
@@ -476,16 +478,16 @@ 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);
}
return name;
};
}
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,15 +519,15 @@ 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 {
return op;
}
};
}
return token("operator", grow(prefix || next()));
};
}
function handle_slash() {
next();
@@ -538,23 +540,23 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
return skip_multiline_comment();
}
return S.regex_allowed ? read_regexp("") : read_operator("/");
};
}
function handle_dot() {
next();
return is_digit(peek().charCodeAt(0))
? read_num(".")
: token("punc", ".");
};
}
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);
};
}
function with_eof_error(eof_error, cont) {
return function(x) {
@@ -565,7 +567,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
else throw ex;
}
};
};
}
function next_token(force_regexp) {
if (force_regexp != null)
@@ -603,13 +605,13 @@ 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;
}
parse_error("Unexpected character '" + ch + "'");
};
}
next_token.context = function(nc) {
if (nc) S = nc;
@@ -645,8 +647,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
return next_token;
};
}
/* -----[ Parser (constants) ]----- */
@@ -666,7 +667,7 @@ var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
var PRECEDENCE = (function(a, ret){
var PRECEDENCE = function(a, ret) {
for (var i = 0; i < a.length; ++i) {
var b = a[i];
for (var j = 0; j < b.length; ++j) {
@@ -674,28 +675,24 @@ var PRECEDENCE = (function(a, ret){
}
}
return ret;
})(
[
["||"],
["&&"],
["|"],
["^"],
["&"],
["==", "===", "!=", "!=="],
["<", ">", "<=", ">=", "in", "instanceof"],
[">>", "<<", ">>>"],
["+", "-"],
["*", "/", "%"]
],
{}
);
}([
["||"],
["&&"],
["|"],
["^"],
["&"],
["==", "===", "!=", "!=="],
["<", ">", "<=", ">=", "in", "instanceof"],
[">>", "<<", ">>>"],
["+", "-"],
["*", "/", "%"]
], {});
var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "string", "regexp", "name" ]);
/* -----[ Parser ]----- */
function parse($TEXT, options) {
options = defaults(options, {
bare_returns : false,
expression : false,
@@ -724,9 +721,11 @@ function parse($TEXT, options) {
function is(type, value) {
return is_token(S.token, type, value);
};
}
function peek() { return S.peeked || (S.peeked = S.input()); };
function peek() {
return S.peeked || (S.peeked = S.input());
}
function next() {
S.prev = S.token;
@@ -740,11 +739,11 @@ function parse($TEXT, options) {
S.token.type == "string" || is("punc", ";")
);
return S.token;
};
}
function prev() {
return S.prev;
};
}
function croak(msg, line, col, pos) {
var ctx = S.input.context();
@@ -753,26 +752,28 @@ function parse($TEXT, options) {
line != null ? line : ctx.tokline,
col != null ? col : ctx.tokcol,
pos != null ? pos : ctx.tokpos);
};
}
function token_error(token, msg) {
croak(msg, token.line, token.col);
};
}
function unexpected(token) {
if (token == null)
token = S.token;
token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
};
}
function expect_token(type, val) {
if (is(type, val)) {
return next();
}
token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
};
}
function expect(punc) { return expect_token("punc", punc); };
function expect(punc) {
return expect_token("punc", punc);
}
function has_newline_before(token) {
return token.nlb || !all(token.comments_before, function(comment) {
@@ -783,19 +784,19 @@ function parse($TEXT, options) {
function can_insert_semicolon() {
return !options.strict
&& (is("eof") || is("punc", "}") || has_newline_before(S.token));
};
}
function semicolon(optional) {
if (is("punc", ";")) next();
else if (!optional && !can_insert_semicolon()) unexpected();
};
}
function parenthesised() {
expect("(");
var exp = expression(true);
expect(")");
return exp;
};
}
function embed_tokens(parser) {
return function() {
@@ -806,14 +807,14 @@ function parse($TEXT, options) {
expr.end = end;
return expr;
};
};
}
function handle_regexp() {
if (is("operator", "/") || is("operator", "/=")) {
S.peeked = null;
S.token = S.input(S.token.value.substr(1)); // force regexp
}
};
}
var statement = embed_tokens(function(strict_defun) {
handle_regexp();
@@ -969,7 +970,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
@@ -984,7 +987,7 @@ function parse($TEXT, options) {
// check for `continue` that refers to this label.
// those should be reported as syntax errors.
// https://github.com/mishoo/UglifyJS2/issues/287
label.references.forEach(function(ref){
label.references.forEach(function(ref) {
if (ref instanceof AST_Continue) {
ref = ref.label.start;
croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
@@ -993,11 +996,11 @@ function parse($TEXT, options) {
});
}
return new AST_LabeledStatement({ body: stat, label: label });
};
}
function simple_statement(tmp) {
return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
};
}
function break_cont(type) {
var label = null, ldef;
@@ -1005,18 +1008,17 @@ function parse($TEXT, options) {
label = as_symbol(AST_LabelRef, true);
}
if (label != null) {
ldef = find_if(function(l){ return l.name == label.name }, S.labels);
if (!ldef)
croak("Undefined label " + label.name);
ldef = find_if(function(l) {
return l.name == label.name;
}, S.labels);
if (!ldef) croak("Undefined label " + label.name);
label.thedef = ldef;
}
else if (S.in_loop == 0)
croak(type.TYPE + " not inside a loop or switch");
} else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch");
semicolon();
var stat = new type({ label: label });
if (ldef) ldef.references.push(stat);
return stat;
};
}
function for_() {
expect("(");
@@ -1037,7 +1039,7 @@ function parse($TEXT, options) {
}
}
return regular_for(init);
};
}
function regular_for(init) {
expect(";");
@@ -1051,7 +1053,7 @@ function parse($TEXT, options) {
step : step,
body : in_loop(statement)
});
};
}
function for_in(init) {
var obj = expression(true);
@@ -1061,7 +1063,7 @@ function parse($TEXT, options) {
object : obj,
body : in_loop(statement)
});
};
}
var function_ = function(ctor) {
var in_statement = ctor === AST_Defun;
@@ -1111,7 +1113,7 @@ function parse($TEXT, options) {
body : body,
alternative : belse
});
};
}
function block_(strict_defun) {
expect("{");
@@ -1122,7 +1124,7 @@ function parse($TEXT, options) {
}
next();
return a;
};
}
function switch_body_() {
expect("{");
@@ -1157,7 +1159,7 @@ function parse($TEXT, options) {
if (branch) branch.end = prev();
next();
return a;
};
}
function try_() {
var body = block_(), bcatch = null, bfinally = null;
@@ -1190,7 +1192,7 @@ function parse($TEXT, options) {
bcatch : bcatch,
bfinally : bfinally
});
};
}
function vardefs(no_in) {
var a = [];
@@ -1206,7 +1208,7 @@ function parse($TEXT, options) {
next();
}
return a;
};
}
var var_ = function(no_in) {
return new AST_Var({
@@ -1272,7 +1274,7 @@ function parse($TEXT, options) {
}
next();
return ret;
};
}
var expr_atom = function(allow_calls) {
if (is("operator", "new")) {
@@ -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();
@@ -1338,7 +1340,7 @@ function parse($TEXT, options) {
}
next();
return a;
};
}
var array_ = embed_tokens(function() {
expect("[");
@@ -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":
@@ -1415,14 +1417,14 @@ function parse($TEXT, options) {
default:
unexpected();
}
};
}
function as_name() {
var tmp = S.token;
if (tmp.type != "name") unexpected();
next();
return tmp.value;
};
}
function _make_symbol(type) {
var name = S.token.value;
@@ -1431,7 +1433,7 @@ function parse($TEXT, options) {
start : S.token,
end : S.token
});
};
}
function strict_verify_symbol(sym) {
if (sym.name == "arguments" || sym.name == "eval")
@@ -1449,7 +1451,7 @@ function parse($TEXT, options) {
}
next();
return sym;
};
}
function mark_pure(call) {
var start = call.start;
@@ -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;
@@ -1534,7 +1536,7 @@ function parse($TEXT, options) {
break;
}
return new ctor({ operator: op, expression: expr });
};
}
var expr_op = function(left, min_prec, no_in) {
var op = is("operator") ? S.token.value : null;
@@ -1556,7 +1558,7 @@ function parse($TEXT, options) {
function expr_ops(no_in) {
return expr_op(maybe_unary(true), 0, no_in);
};
}
var maybe_conditional = function(no_in) {
var start = S.token;
@@ -1578,12 +1580,12 @@ function parse($TEXT, options) {
function is_assignable(expr) {
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
};
}
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({
@@ -1620,13 +1622,13 @@ function parse($TEXT, options) {
var ret = cont();
--S.in_loop;
return ret;
};
}
if (options.expression) {
return expression(true);
}
return (function(){
return function() {
var start = S.token;
var body = [];
S.input.push_directives_stack();
@@ -1642,6 +1644,5 @@ function parse($TEXT, options) {
toplevel = new AST_Toplevel({ start: start, body: body, end: end });
}
return toplevel;
})();
};
}();
}

View File

@@ -56,7 +56,7 @@ function find_builtins(reserved) {
[ Object, Array, Function, Number,
String, Boolean, Error, Math,
Date, RegExp
].forEach(function(ctor){
].forEach(function(ctor) {
Object.getOwnPropertyNames(ctor).map(add);
if (ctor.prototype) {
Object.getOwnPropertyNames(ctor.prototype).map(add);
@@ -136,7 +136,7 @@ function mangle_properties(ast, options) {
var unmangleable = [];
// step 1: find candidates to mangle
ast.walk(new TreeWalker(function(node){
ast.walk(new TreeWalker(function(node) {
if (node instanceof AST_ObjectKeyVal) {
add(node.key);
}
@@ -150,10 +150,14 @@ 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
return ast.transform(new TreeTransformer(function(node){
return ast.transform(new TreeTransformer(function(node) {
if (node instanceof AST_ObjectKeyVal) {
node.key = mangle(node.key);
}
@@ -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
@@ -226,7 +234,7 @@ function mangle_properties(ast, options) {
}
function mangleStrings(node) {
return node.transform(new TreeTransformer(function(node){
return node.transform(new TreeTransformer(function(node) {
if (node instanceof AST_Sequence) {
var last = node.expressions.length - 1;
node.expressions[last] = mangleStrings(node.expressions[last]);

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;
@@ -63,12 +63,12 @@ SymbolDef.prototype = {
unmangleable: function(options) {
if (!options) options = {};
return (this.global && !options.toplevel)
return this.global && !options.toplevel
|| this.undeclared
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|| (options.keep_fnames
|| !options.eval && this.scope.pinned()
|| options.keep_fnames
&& (this.orig[0] instanceof AST_SymbolLambda
|| this.orig[0] instanceof AST_SymbolDefun));
|| this.orig[0] instanceof AST_SymbolDefun);
},
mangle: function(options) {
var cache = options.cache && options.cache.props;
@@ -91,7 +91,7 @@ SymbolDef.prototype = {
}
};
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
options = defaults(options, {
cache: null,
ie8: false,
@@ -100,9 +100,8 @@ 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){
var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_Catch) {
var save_scope = scope;
scope = new AST_Scope(node);
@@ -115,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;
@@ -171,21 +157,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(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);
// pass 2: find back references and eval
self.globals = new Dictionary();
var tw = new TreeWalker(function(node, descend){
var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_LoopControl && node.label) {
node.label.thedef.references.push(node);
return true;
@@ -240,7 +217,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
}
});
AST_Toplevel.DEFMETHOD("def_global", function(node){
AST_Toplevel.DEFMETHOD("def_global", function(node) {
var globals = this.globals, name = node.name;
if (globals.has(name)) {
return globals.get(name);
@@ -253,7 +230,7 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
}
});
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
@@ -263,7 +240,7 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
this.cname = -1; // the current index for mangling functions/variables
});
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
AST_Lambda.DEFMETHOD("init_scope_vars", function() {
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false;
this.def_variable(new AST_SymbolFunarg({
@@ -293,20 +270,20 @@ AST_Symbol.DEFMETHOD("reference", function(options) {
this.mark_enclosed(options);
});
AST_Scope.DEFMETHOD("find_variable", function(name){
AST_Scope.DEFMETHOD("find_variable", function(name) {
if (name instanceof AST_Symbol) name = name.name;
return this.variables.get(name)
|| (this.parent_scope && this.parent_scope.find_variable(name));
});
AST_Scope.DEFMETHOD("def_function", function(symbol, init){
AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
var def = this.def_variable(symbol, init);
if (!def.init || def.init instanceof AST_Defun) def.init = init;
this.functions.set(symbol.name, def);
return def;
});
AST_Scope.DEFMETHOD("def_variable", function(symbol, init){
AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
var def = this.variables.get(symbol.name);
if (def) {
def.orig.push(symbol);
@@ -367,7 +344,7 @@ function next_mangled_name(scope, options, def) {
}
while (true) {
name = base54(++scope.cname);
if (in_use[name] || !is_identifier(name) || member(name, options.reserved)) continue;
if (in_use[name] || !is_identifier(name) || options.reserved.has[name]) continue;
if (!names[name]) break;
holes.push(scope.cname);
}
@@ -378,7 +355,7 @@ function next_mangled_name(scope, options, def) {
return name;
}
AST_Symbol.DEFMETHOD("unmangleable", function(options){
AST_Symbol.DEFMETHOD("unmangleable", function(options) {
var def = this.definition();
return !def || def.unmangleable(options);
});
@@ -386,16 +363,15 @@ AST_Symbol.DEFMETHOD("unmangleable", function(options){
// labels are always mangleable
AST_Label.DEFMETHOD("unmangleable", return_false);
AST_Symbol.DEFMETHOD("unreferenced", function(){
return this.definition().references.length == 0
&& !(this.scope.uses_eval || this.scope.uses_with);
AST_Symbol.DEFMETHOD("unreferenced", function() {
return !this.definition().references.length && !this.scope.pinned();
});
AST_Symbol.DEFMETHOD("definition", function(){
AST_Symbol.DEFMETHOD("definition", function() {
return this.thedef;
});
AST_Symbol.DEFMETHOD("global", function(){
AST_Symbol.DEFMETHOD("global", function() {
return this.definition().global;
});
@@ -410,10 +386,11 @@ function _default_mangler_options(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){
AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
options = _default_mangler_options(options);
// We only need to mangle declaration nodes. Special logic wired
@@ -430,7 +407,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
}
var redefined = [];
var tw = new TreeWalker(function(node, descend){
var tw = new TreeWalker(function(node, descend) {
if (node instanceof AST_LabeledStatement) {
// lname is incremented when we get to the AST_Label
var save_nesting = lname;
@@ -457,24 +434,26 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
var redef = def.redefined();
if (redef) {
redefined.push(def);
def.references.forEach(function(ref) {
ref.thedef = redef;
ref.reference(options);
ref.thedef = 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);
redefined.forEach(mangle);
function mangle(def) {
if (!member(def.name, options.reserved)) {
def.mangle(options);
}
if (options.reserved.has[def.name]) return;
def.mangle(options);
}
});
@@ -524,7 +503,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) {
@@ -541,7 +520,7 @@ AST_Sequence.DEFMETHOD("tail_node", function() {
return this.expressions[this.expressions.length - 1];
});
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
options = _default_mangler_options(options);
base54.reset();
try {
@@ -576,17 +555,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;) {
@@ -597,7 +580,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();
@@ -611,6 +594,6 @@ var base54 = (function() {
base = 64;
} while (num > 0);
return ret;
};
}
return base54;
})();

View File

@@ -46,52 +46,59 @@
// a small wrapper around fitzgen's source-map library
function SourceMap(options) {
options = defaults(options, {
file : null,
root : null,
orig : null,
orig_line_diff : 0,
dest_line_diff : 0,
});
file: null,
root: null,
orig: null,
orig_line_diff: 0,
dest_line_diff: 0,
}, true);
var generator = new MOZ_SourceMap.SourceMapGenerator({
file : options.file,
sourceRoot : options.root
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);
}
});
}
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
if (orig_map) {
var info = orig_map.originalPositionFor({
line: orig_line,
column: orig_col
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);
});
if (info.source === null) {
return;
}
source = info.source;
orig_line = info.line;
orig_col = info.column;
name = info.name || name;
}
generator.addMapping({
generated : { line: gen_line + options.dest_line_diff, column: gen_col },
original : { line: orig_line + options.orig_line_diff, column: orig_col },
source : source,
name : name
});
};
maps[source] = map;
}
return {
add : add,
get : function() { return generator },
toString : function() { return JSON.stringify(generator.toJSON()); }
add: function(source, gen_line, gen_col, orig_line, orig_col, name) {
var map = maps && maps[source];
if (map) {
var info = map.originalPositionFor({
line: orig_line,
column: orig_col
});
if (info.source === null) return;
source = info.source;
orig_line = info.line;
orig_col = info.column;
name = info.name || name;
}
generator.addMapping({
name: name,
source: source,
generated: {
line: gen_line + options.dest_line_diff,
column: gen_col
},
original: {
line: orig_line + options.orig_line_diff,
column: orig_col
}
});
},
get: function() {
return generator;
},
toString: function() {
return JSON.stringify(generator.toJSON());
}
};
};
}

View File

@@ -43,8 +43,6 @@
"use strict";
// Tree transformer helpers.
function TreeTransformer(before, after) {
TreeWalker.call(this);
this.before = before;
@@ -52,163 +50,136 @@ function TreeTransformer(before, after) {
}
TreeTransformer.prototype = new TreeWalker;
(function(undefined){
function _(node, descend) {
node.DEFMETHOD("transform", function(tw, in_list){
var x, y;
tw.push(this);
if (tw.before) x = tw.before(this, descend, in_list);
if (x === undefined) {
x = this;
descend(x, tw);
if (tw.after) {
y = tw.after(x, in_list);
if (y !== undefined) x = y;
}
}
tw.pop();
return x;
});
};
(function(DEF) {
function do_list(list, tw) {
return MAP(list, function(node){
return MAP(list, function(node) {
return node.transform(tw, true);
});
};
}
_(AST_Node, noop);
_(AST_LabeledStatement, function(self, tw){
DEF(AST_Node, noop);
DEF(AST_LabeledStatement, function(self, tw) {
self.label = self.label.transform(tw);
self.body = self.body.transform(tw);
});
_(AST_SimpleStatement, function(self, tw){
DEF(AST_SimpleStatement, function(self, tw) {
self.body = self.body.transform(tw);
});
_(AST_Block, function(self, tw){
DEF(AST_Block, function(self, tw) {
self.body = do_list(self.body, tw);
});
_(AST_DWLoop, function(self, tw){
DEF(AST_Do, function(self, tw) {
self.body = self.body.transform(tw);
self.condition = self.condition.transform(tw);
});
DEF(AST_While, function(self, tw) {
self.condition = self.condition.transform(tw);
self.body = self.body.transform(tw);
});
_(AST_For, function(self, tw){
DEF(AST_For, function(self, tw) {
if (self.init) self.init = self.init.transform(tw);
if (self.condition) self.condition = self.condition.transform(tw);
if (self.step) self.step = self.step.transform(tw);
self.body = self.body.transform(tw);
});
_(AST_ForIn, function(self, tw){
DEF(AST_ForIn, function(self, tw) {
self.init = self.init.transform(tw);
self.object = self.object.transform(tw);
self.body = self.body.transform(tw);
});
_(AST_With, function(self, tw){
DEF(AST_With, function(self, tw) {
self.expression = self.expression.transform(tw);
self.body = self.body.transform(tw);
});
_(AST_Exit, function(self, tw){
DEF(AST_Exit, function(self, tw) {
if (self.value) self.value = self.value.transform(tw);
});
_(AST_LoopControl, function(self, tw){
DEF(AST_LoopControl, function(self, tw) {
if (self.label) self.label = self.label.transform(tw);
});
_(AST_If, function(self, tw){
DEF(AST_If, function(self, tw) {
self.condition = self.condition.transform(tw);
self.body = self.body.transform(tw);
if (self.alternative) self.alternative = self.alternative.transform(tw);
});
_(AST_Switch, function(self, tw){
DEF(AST_Switch, function(self, tw) {
self.expression = self.expression.transform(tw);
self.body = do_list(self.body, tw);
});
_(AST_Case, function(self, tw){
DEF(AST_Case, function(self, tw) {
self.expression = self.expression.transform(tw);
self.body = do_list(self.body, tw);
});
_(AST_Try, function(self, tw){
DEF(AST_Try, function(self, tw) {
self.body = do_list(self.body, tw);
if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
});
_(AST_Catch, function(self, tw){
DEF(AST_Catch, function(self, tw) {
self.argname = self.argname.transform(tw);
self.body = do_list(self.body, tw);
});
_(AST_Definitions, function(self, tw){
DEF(AST_Definitions, function(self, tw) {
self.definitions = do_list(self.definitions, tw);
});
_(AST_VarDef, function(self, tw){
DEF(AST_VarDef, function(self, tw) {
self.name = self.name.transform(tw);
if (self.value) self.value = self.value.transform(tw);
});
_(AST_Lambda, function(self, tw){
DEF(AST_Lambda, function(self, tw) {
if (self.name) self.name = self.name.transform(tw);
self.argnames = do_list(self.argnames, tw);
self.body = do_list(self.body, tw);
});
_(AST_Call, function(self, tw){
DEF(AST_Call, function(self, tw) {
self.expression = self.expression.transform(tw);
self.args = do_list(self.args, tw);
});
_(AST_Sequence, function(self, tw){
DEF(AST_Sequence, function(self, tw) {
self.expressions = do_list(self.expressions, tw);
});
_(AST_Dot, function(self, tw){
DEF(AST_Dot, function(self, tw) {
self.expression = self.expression.transform(tw);
});
_(AST_Sub, function(self, tw){
DEF(AST_Sub, function(self, tw) {
self.expression = self.expression.transform(tw);
self.property = self.property.transform(tw);
});
_(AST_Unary, function(self, tw){
DEF(AST_Unary, function(self, tw) {
self.expression = self.expression.transform(tw);
});
_(AST_Binary, function(self, tw){
DEF(AST_Binary, function(self, tw) {
self.left = self.left.transform(tw);
self.right = self.right.transform(tw);
});
_(AST_Conditional, function(self, tw){
DEF(AST_Conditional, function(self, tw) {
self.condition = self.condition.transform(tw);
self.consequent = self.consequent.transform(tw);
self.alternative = self.alternative.transform(tw);
});
_(AST_Array, function(self, tw){
DEF(AST_Array, function(self, tw) {
self.elements = do_list(self.elements, tw);
});
_(AST_Object, function(self, tw){
DEF(AST_Object, function(self, tw) {
self.properties = do_list(self.properties, tw);
});
_(AST_ObjectProperty, function(self, tw){
DEF(AST_ObjectProperty, function(self, tw) {
self.value = self.value.transform(tw);
});
})();
})(function(node, descend) {
node.DEFMETHOD("transform", function(tw, in_list) {
var x, y;
tw.push(this);
if (tw.before) x = tw.before(this, descend, in_list);
if (typeof x === "undefined") {
x = this;
descend(x, tw);
if (tw.after) {
y = tw.after(x, in_list);
if (typeof y !== "undefined") x = y;
}
}
tw.pop();
return x;
});
});

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; }
@@ -121,7 +115,7 @@ function return_true() { return true; }
function return_this() { return this; }
function return_null() { return null; }
var MAP = (function(){
var MAP = (function() {
function MAP(a, f, backwards) {
var ret = [], top = [], i;
function doit() {
@@ -144,8 +138,8 @@ 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();
@@ -158,115 +152,54 @@ var MAP = (function(){
for (i in a) if (HOP(a, i)) if (doit()) break;
}
return top.concat(ret);
};
}
MAP.at_top = function(val) { return new AtTop(val) };
MAP.splice = function(val) { return new Splice(val) };
MAP.last = function(val) { return new Last(val) };
var skip = MAP.skip = {};
function AtTop(val) { this.v = val };
function Splice(val) { this.v = val };
function Last(val) { this.v = val };
function AtTop(val) { this.v = val }
function Splice(val) { this.v = val }
function Last(val) { this.v = val }
return MAP;
})();
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 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

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.3.16",
"version": "3.4.1",
"engines": {
"node": ">=0.8.0"
},
@@ -28,7 +28,6 @@
},
"devDependencies": {
"acorn": "~5.5.3",
"mocha": "~3.5.1",
"semver": "~5.5.0"
},
"scripts": {

View File

@@ -150,36 +150,36 @@ collapse_vars_issue_721: {
reduce_funcs: true, reduce_vars:true, passes:2
}
input: {
define(["require", "exports", 'handlebars'], function (require, exports, hb) {
define(["require", "exports", 'handlebars'], function(require, exports, hb) {
var win = window;
var _hb = win.Handlebars = hb;
return _hb;
});
def(function (hb) {
def(function(hb) {
var win = window;
var prop = 'Handlebars';
var _hb = win[prop] = hb;
return _hb;
});
def(function (hb) {
def(function(hb) {
var prop = 'Handlebars';
var win = window;
var _hb = win[prop] = hb;
return _hb;
});
def(function (hb) {
def(function(hb) {
var prop = 'Handlebars';
var win = g();
var _hb = win[prop] = hb;
return _hb;
});
def(function (hb) {
def(function(hb) {
var prop = g1();
var win = g2();
var _hb = win[prop] = hb;
return _hb;
});
def(function (hb) {
def(function(hb) {
var win = g2();
var prop = g1();
var _hb = win[prop] = hb;
@@ -196,14 +196,14 @@ collapse_vars_issue_721: {
def(function(hb) {
return window.Handlebars = hb;
}),
def(function (hb) {
def(function(hb) {
return g().Handlebars = hb;
}),
def(function (hb) {
def(function(hb) {
var prop = g1();
return g2()[prop] = hb;
}),
def(function (hb) {
def(function(hb) {
return g2()[g1()] = hb;
});
}
@@ -3150,7 +3150,7 @@ issue_2437_1: {
return result;
} else {
var req = new XMLHttpRequest();
var detectFunc = function () {};
var detectFunc = function(){};
req.onreadystatechange = detectFunc;
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
req.onreadystatechange = null;
@@ -3166,7 +3166,7 @@ issue_2437_1: {
return Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
result;
}
var req, detectFunc = function() {};
var req, detectFunc = function(){};
(req = new XMLHttpRequest()).onreadystatechange = detectFunc;
result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
return req.onreadystatechange = null, result;
@@ -3200,7 +3200,7 @@ issue_2437_2: {
return result;
} else {
var req = new XMLHttpRequest();
var detectFunc = function () {};
var detectFunc = function(){};
req.onreadystatechange = detectFunc;
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
req.onreadystatechange = null;
@@ -4056,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,
@@ -4483,7 +4513,7 @@ issue_2878: {
}
input: {
var c = 0;
(function (a, b) {
(function(a, b) {
function f2() {
if (a) c++;
}
@@ -4496,7 +4526,7 @@ issue_2878: {
}
expect: {
var c = 0;
(function (a, b) {
(function(a, b) {
function f2() {
if (a) c++;
}
@@ -4901,6 +4931,27 @@ collapse_rhs_lhs_2: {
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,
@@ -5303,3 +5354,48 @@ issue_2974: {
}
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

@@ -1814,3 +1814,115 @@ issue_2995: {
}
expect_stdout: "PASS"
}
issue_3146_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect_stdout: "PASS"
}
issue_3146_2: {
options = {
reduce_vars: true,
unused: true,
}
input: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect: {
(function(f) {
f("g()");
})(function(a) {
eval(a);
function g(b) {
if (!b) b = "PASS";
console.log(b);
}
});
}
expect_stdout: "PASS"
}
issue_3146_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect_stdout: "PASS"
}
issue_3146_4: {
options = {
reduce_vars: true,
unused: true,
}
input: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect: {
var g = "PASS";
(function(f) {
var g = "FAIL";
f("console.log(g)", g[g]);
})(function(a) {
eval(a);
});
}
expect_stdout: "PASS"
}

View File

@@ -1533,7 +1533,7 @@ issue_2663_3: {
unused: true,
}
input: {
(function () {
(function() {
var outputs = [
{ type: 0, target: null, eventName: "ngSubmit", propName: null },
{ type: 0, target: null, eventName: "submit", propName: null },
@@ -1550,11 +1550,11 @@ issue_2663_3: {
return handlers;
}
function renderEventHandlerClosure(eventName) {
return function () {
return function() {
return console.log(eventName);
};
}
listenToElementOutputs(outputs).forEach(function (handler) {
listenToElementOutputs(outputs).forEach(function(handler) {
return handler()
});
})();
@@ -1634,7 +1634,7 @@ loop_init_arg: {
}
input: {
var a = "PASS";
for (var k in "12") (function (b) {
for (var k in "12") (function(b) {
(b >>= 1) && (a = "FAIL"), b = 2;
})();
console.log(a);
@@ -2051,3 +2051,271 @@ drop_lone_use_strict: {
}
}
}
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

@@ -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

@@ -464,3 +464,77 @@ issue_2976_2: {
}
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

@@ -399,7 +399,7 @@ wrap_iife_in_expression: {
wrap_iife: true,
}
input: {
foo = (function () {
foo = (function() {
return bar();
})();
}

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

@@ -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

@@ -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,164 @@ 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"
}
issue_3188_1: {
options = {
collapse_vars: true,
inline: true,
properties: true,
reduce_vars: true,
side_effects: true,
}
input: {
(function() {
function f() {
console.log(this.p);
}
(function() {
var o = {
p: "PASS",
f: f
};
o.f();
})();
})();
}
expect: {
(function() {
function f() {
console.log(this.p);
}
({
p: "PASS",
f: f
}).f();
var o;
})();
}
expect_stdout: "PASS"
}
issue_3188_2: {
options = {
collapse_vars: true,
inline: true,
properties: true,
reduce_vars: true,
side_effects: true,
unused: true,
}
input: {
(function() {
var f = function() {
console.log(this.p);
};
function g() {
var o = {
p: "PASS",
f: f
};
o.f();
}
g();
})();
}
expect: {
({
p: "PASS",
f: function() {
console.log(this.p);
}
}).f();
}
expect_stdout: "PASS"
}
issue_3188_3: {
options = {
collapse_vars: true,
inline: true,
properties: true,
reduce_vars: true,
side_effects: true,
}
input: {
(function() {
function f() {
console.log(this[0]);
}
(function() {
var o = ["PASS", f];
o[1]();
})();
})();
}
expect: {
(function() {
function f() {
console.log(this[0]);
}
["PASS", f][1]();
var 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

@@ -1476,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: {
@@ -1527,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: {
@@ -4873,7 +4887,7 @@ inverted_var: {
}(), function(c) {
c = 4;
return c;
}(), function (c) {
}(), function(c) {
c = 5;
return c;
var c;
@@ -5054,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"
}
@@ -5076,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"
}
@@ -5582,3 +5592,814 @@ issue_2992: {
}
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"
}
issue_3140_5: {
options = {
evaluate: true,
reduce_vars: true,
}
input: {
var n = 1, c = 0;
(function(a) {
var b = function() {
this;
n-- && h();
}();
function h() {
b && c++;
}
h(b = 1);
})();
console.log(c);
}
expect: {
var n = 1, c = 0;
(function(a) {
var b = function() {
this;
n-- && h();
}();
function h() {
b && c++;
}
h(b = 1);
})();
console.log(c);
}
expect_stdout: "1"
}

37
test/compress/regexp.js Normal file
View File

@@ -0,0 +1,37 @@
regexp_simple: {
input: {
/rx/ig
}
expect_exact: "/rx/gi;"
}
regexp_slashes: {
input: {
/\\\/rx\/\\/ig
}
expect_exact: "/\\\\\\/rx\\/\\\\/gi;"
}
regexp_1: {
input: {
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/ig)));
}
expect: {
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/gi)));
}
expect_stdout: '["PASS","pass"]'
}
regexp_2: {
options = {
evaluate: true,
unsafe: true,
}
input: {
console.log(JSON.stringify("COMPASS? Overpass.".match(new RegExp("([Sap]+)", "ig"))));
}
expect: {
console.log(JSON.stringify("COMPASS? Overpass.".match(/([Sap]+)/gi)));
}
expect_stdout: '["PASS","pass"]'
}

View File

@@ -876,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

@@ -14,6 +14,13 @@ issue_1929: {
function f(s) {
return s.split(/[\\/]/);
}
console.log(JSON.stringify(f("A/B\\C\\D/E\\F")));
}
expect_exact: "function f(s){return s.split(/[\\\\/]/)}"
expect: {
function f(s) {
return s.split(/[\\/]/);
}
console.log(JSON.stringify(f("A/B\\C\\D/E\\F")));
}
expect_stdout: '["A","B","C","D","E","F"]'
}

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

@@ -23,7 +23,7 @@ wrap_iife_in_expression: {
wrap_iife: true,
}
input: {
foo = (function () {
foo = (function() {
return bar();
})();
}

View File

@@ -1,4 +1,5 @@
var fs = require("fs");
var parse = require("url").parse;
var path = require("path");
try {
@@ -19,7 +20,9 @@ module.exports = function(url, callback) {
var result = read(url);
result.on("error", function(e) {
if (e.code != "ENOENT") return callback(e);
require(url.slice(0, url.indexOf(":"))).get(url, function(res) {
var options = parse(url);
options.rejectUnauthorized = false;
require(options.protocol.slice(0, -1)).get(options, function(res) {
if (res.statusCode !== 200) return callback(res);
res.pipe(fs.createWriteStream(local(url)).on("close", function() {
callback(null, read(url));

View File

@@ -0,0 +1,4 @@
function enclose() {
console.log("test enclose");
}
enclose();

View File

@@ -1,4 +1,4 @@
var bar = (function () {
var bar = (function() {
function foo (bar) {
return bar;
}

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

@@ -3,7 +3,7 @@
"use strict";
var site = "http://browserbench.org/JetStream";
var site = "https://browserbench.org/JetStream";
if (typeof phantom == "undefined") {
require("../tools/exit");
var args = process.argv.slice(2);

View File

@@ -1,24 +1,114 @@
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() {
reset();
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);
process.on("uncaughtException", raise);
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) {
reset();
task.titles.error = err;
errors.push(task.titles);
log_titles(console.log, task.titles, red('\u00D7 '));
process.nextTick(run);
}
function reset() {
clearTimeout(timer);
done = function() {};
process.removeListener("uncaughtException", raise);
}
});

View File

@@ -1,217 +1,241 @@
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 () {
describe("bin/uglifyjs", function() {
var uglifyjscmd = '"' + process.argv[0] + '" bin/uglifyjs';
it("should produce a functional build when using --self", function (done) {
it("should produce a functional build when using --self", function(done) {
this.timeout(30000);
var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
eval(stdout);
assert.strictEqual(typeof WrappedUglifyJS, 'object');
assert.strictEqual(typeof WrappedUglifyJS, "object");
var result = WrappedUglifyJS.minify("foo([true,,2+3]);");
assert.strictEqual(result.error, undefined);
assert.strictEqual(result.code, "foo([!0,,5]);");
done();
});
});
it("Should be able to filter comments correctly with `--comments all`", function (done) {
it("Should be able to filter comments correctly with `--comments all`", function(done) {
var command = uglifyjscmd + ' test/input/comments/filter.js --comments all';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "// foo\n/*@preserve*/\n// bar\n\n");
done();
});
});
it("Should be able to filter comments correctly with `--comment <RegExp>`", function (done) {
it("Should be able to filter comments correctly with `--comment <RegExp>`", function(done) {
var command = uglifyjscmd + ' test/input/comments/filter.js --comments /r/';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "/*@preserve*/\n// bar\n\n");
done();
});
});
it("Should be able to filter comments correctly with just `--comment`", function (done) {
it("Should be able to filter comments correctly with just `--comment`", function(done) {
var command = uglifyjscmd + ' test/input/comments/filter.js --comments';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "/*@preserve*/\n\n");
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";
exec(command, function (err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n" +
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==\n");
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 not append source map to output when not using --source-map url=inline", function (done) {
var command = uglifyjscmd + ' test/input/issue-1323/sample.js';
exec(command, function (err, stdout) {
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";
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, [
"var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMTMyMy9zYW1wbGUuanMiXSwibmFtZXMiOlsiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFJQSxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==",
"",
].join("\n"));
done();
});
});
it("should not append source map to output when not using --source-map url=inline", function(done) {
var command = uglifyjscmd + ' test/input/issue-1323/sample.js';
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n");
done();
});
});
it("should not consider source map file content as source map file name (issue #2082)", function (done) {
it("should not consider source map file content as source map file name (issue #2082)", function(done) {
var command = [
uglifyjscmd,
"test/input/issue-2082/sample.js",
"--source-map", "content=test/input/issue-2082/sample.js.map",
"--source-map", "url=inline",
].join(" ");
exec(command, function (err, stdout, stderr) {
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 work with --keep-fnames (mangle only)", function (done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m';
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(" ");
exec(command, function (err, stdout) {
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';
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
done();
});
});
it("Should work with --keep-fnames (mangle & compress)", function (done) {
it("Should work with --keep-fnames (mangle & compress)", function(done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n");
done();
});
});
it("Should work with keep_fnames under mangler options", function (done) {
it("Should work with keep_fnames under mangler options", function(done) {
var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep_fnames=true';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(f(g)()==5);\n");
done();
});
});
it("Should work with --define (simple)", function (done) {
it("Should work with --define (simple)", function(done) {
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define D=5 -c';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "console.log(5);\n");
done();
});
});
it("Should work with --define (nested)", function (done) {
it("Should work with --define (nested)", function(done) {
var command = uglifyjscmd + ' test/input/global_defs/nested.js --define C.D=5,C.V=3 -c';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "console.log(3,5);\n");
done();
});
});
it("Should work with --define (AST_Node)", function (done) {
it("Should work with --define (AST_Node)", function(done) {
var command = uglifyjscmd + ' test/input/global_defs/simple.js --define console.log=stdout.println -c';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, "stdout.println(D);\n");
done();
});
});
it("Should work with `--beautify`", function (done) {
it("Should work with `--beautify`", function(done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, read("test/input/issue-1482/default.js"));
done();
});
});
it("Should work with `--beautify braces`", function (done) {
it("Should work with `--beautify braces`", function(done) {
var command = uglifyjscmd + ' test/input/issue-1482/input.js -b braces';
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
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";
exec(command, function (err, stdout) {
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;
assert.strictEqual(stdout, read("test/input/issue-520/output.js"));
done();
});
});
it("Should warn for missing inline source map", function(done) {
var command = uglifyjscmd + " test/input/issue-1323/sample.js --source-map content=inline,url=inline";
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, [
"var bar=function(){function foo(bar){return bar}return foo}();",
"//# 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";
exec(command, function (err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr.split(/\n/)[0], "ERROR: inline source map only works with singular input");
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) {
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();
});
});
it("Should fail with acorn and inline source map", function(done) {
var command = uglifyjscmd + " test/input/issue-520/input.js --source-map content=inline,url=inline -p acorn";
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr, "ERROR: inline source map only works with built-in parser\n");
done();
@@ -219,8 +243,7 @@ describe("bin/uglifyjs", function () {
});
it("Should fail with SpiderMonkey and inline source map", function(done) {
var command = uglifyjscmd + " test/input/issue-520/input.js --source-map content=inline,url=inline -p spidermonkey";
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stderr, "ERROR: inline source map only works with built-in parser\n");
done();
@@ -228,8 +251,7 @@ describe("bin/uglifyjs", function () {
});
it("Should fail with invalid syntax", function(done) {
var command = uglifyjscmd + ' test/input/invalid/simple.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
assert.strictEqual(lines[0], "Parse error at test/input/invalid/simple.js:1,12");
@@ -241,8 +263,7 @@ describe("bin/uglifyjs", function () {
});
it("Should fail with correct marking of tabs", function(done) {
var command = uglifyjscmd + ' test/input/invalid/tab.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
assert.strictEqual(lines[0], "Parse error at test/input/invalid/tab.js:1,12");
@@ -254,8 +275,7 @@ describe("bin/uglifyjs", function () {
});
it("Should fail with correct marking at start of line", function(done) {
var command = uglifyjscmd + ' test/input/invalid/eof.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
assert.strictEqual(lines[0], "Parse error at test/input/invalid/eof.js:2,0");
@@ -267,8 +287,7 @@ describe("bin/uglifyjs", function () {
});
it("Should fail with a missing loop body", function(done) {
var command = uglifyjscmd + ' test/input/invalid/loop-no-body.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
var lines = stderr.split(/\n/);
assert.strictEqual(lines[0], "Parse error at test/input/invalid/loop-no-body.js:2,0");
@@ -280,8 +299,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (5--)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_1.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -295,8 +313,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (Math.random() /= 2)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_2.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -310,8 +327,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (++this)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_3.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -325,8 +341,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (++null)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/assign_4.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -340,8 +355,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (a.=)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/dot_1.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -355,8 +369,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (%.a)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/dot_2.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -370,8 +383,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (a./();)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/dot_3.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -385,8 +397,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error ({%: 1})", function(done) {
var command = uglifyjscmd + ' test/input/invalid/object.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -400,8 +411,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (delete x)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/delete.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -415,8 +425,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (function g(arguments))", function(done) {
var command = uglifyjscmd + ' test/input/invalid/function_1.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -430,8 +439,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (function eval())", function(done) {
var command = uglifyjscmd + ' test/input/invalid/function_2.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -445,8 +453,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (iife arguments())", function(done) {
var command = uglifyjscmd + ' test/input/invalid/function_3.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -460,8 +467,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (catch(eval))", function(done) {
var command = uglifyjscmd + ' test/input/invalid/try.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -475,8 +481,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (var eval)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/var.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -490,8 +495,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (else)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/else.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -505,8 +509,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (return)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/return.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -520,8 +523,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (for-in init)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/for-in_1.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -535,8 +537,7 @@ describe("bin/uglifyjs", function () {
});
it("Should throw syntax error (for-in var)", function(done) {
var command = uglifyjscmd + ' test/input/invalid/for-in_2.js';
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
@@ -555,10 +556,8 @@ describe("bin/uglifyjs", function () {
"--source-map",
'content="' + read_map() + '",url=inline'
].join(" ");
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, [
'"use strict";var foo=function foo(x){return"foo "+x};console.log(foo("bar"));',
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmpzIl0sIm5hbWVzIjpbImZvbyIsIngiLCJjb25zb2xlIiwibG9nIl0sIm1hcHBpbmdzIjoiYUFBQSxJQUFJQSxJQUFNLFNBQU5BLElBQU1DLEdBQUEsTUFBSyxPQUFTQSxHQUN4QkMsUUFBUUMsSUFBSUgsSUFBSSJ9",
@@ -580,10 +579,8 @@ describe("bin/uglifyjs", function () {
"-c",
"--source-map", "url=inline",
].join(" ");
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, [
'function foo(){return function(){console.log("PASS")}}foo()();',
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW5wdXQvaXNzdWUtMjMxMC9pbnB1dC5qcyJdLCJuYW1lcyI6WyJmb28iLCJjb25zb2xlIiwibG9nIiwiZiJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsTUFDTCxPQUFPLFdBQ0hDLFFBQVFDLElBQUksU0FLUkYsS0FDUkcifQ==",
@@ -594,9 +591,8 @@ describe("bin/uglifyjs", function () {
});
it("Should dump AST as JSON", function(done) {
var command = uglifyjscmd + " test/input/global_defs/simple.js -mco ast";
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
var ast = JSON.parse(stdout);
assert.strictEqual(ast._class, "AST_Toplevel");
assert.ok(Array.isArray(ast.body));
@@ -605,7 +601,7 @@ describe("bin/uglifyjs", function () {
});
it("Should print supported options on invalid option syntax", function(done) {
var command = uglifyjscmd + " test/input/comments/filter.js -b ascii-only";
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.ok(/^Supported options:\n[\s\S]*?\nERROR: `ascii-only` is not a supported option/.test(stderr), stderr);
@@ -614,27 +610,23 @@ describe("bin/uglifyjs", function () {
});
it("Should work with --mangle reserved=[]", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=[callback]";
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, 'function test(callback){"aaaaaaaaaaaaaaaa";callback(err,data);callback(err,data)}\n');
done();
});
});
it("Should work with --mangle reserved=false", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js -m reserved=false";
exec(command, function (err, stdout) {
exec(command, function(err, stdout) {
if (err) throw err;
assert.strictEqual(stdout, 'function test(a){"aaaaaaaaaaaaaaaa";a(err,data);a(err,data)}\n');
done();
});
});
it("Should fail with --mangle-props reserved=[in]", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js --mangle-props reserved=[in]";
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.ok(/^Supported options:\n[\s\S]*?\nERROR: `reserved=\[in]` is not a supported option/.test(stderr), stderr);
@@ -643,7 +635,7 @@ describe("bin/uglifyjs", function () {
});
it("Should fail with --define a-b", function(done) {
var command = uglifyjscmd + " test/input/issue-505/input.js --define a-b";
exec(command, function (err, stdout, stderr) {
exec(command, function(err, stdout, stderr) {
assert.ok(err);
assert.strictEqual(stdout, "");
assert.strictEqual(stderr, "Error parsing arguments for 'define': a-b\n");
@@ -682,4 +674,36 @@ describe("bin/uglifyjs", function () {
done();
});
});
it("Should work with --enclose", function(done) {
var command = uglifyjscmd + " test/input/enclose/input.js --enclose";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, '(function(){function enclose(){console.log("test enclose")}enclose()})();\n');
done();
});
});
it("Should work with --enclose arg", function(done) {
var command = uglifyjscmd + " test/input/enclose/input.js --enclose undefined";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, '(function(undefined){function enclose(){console.log("test enclose")}enclose()})();\n');
done();
});
});
it("Should work with --enclose arg:value", function(done) {
var command = uglifyjscmd + " test/input/enclose/input.js --enclose window,undefined:window";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, '(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window);\n');
done();
});
});
it("Should work with --enclose & --wrap", function(done) {
var command = uglifyjscmd + " test/input/enclose/input.js --enclose window,undefined:window --wrap exports";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, '(function(window,undefined){(function(exports){function enclose(){console.log("test enclose")}enclose()})(typeof exports=="undefined"?exports={}:exports)})(window);\n');
done();
});
});
});

View File

@@ -61,29 +61,24 @@ describe("Getters and setters", function() {
return results;
};
var testCase = function(data) {
return function() {
UglifyJS.parse(data.code);
};
};
var fail = function(data) {
return function (e) {
return e instanceof UglifyJS.JS_Parse_Error &&
e.message === "Unexpected token: operator (" + data.operator + ")";
return function(e) {
return e instanceof UglifyJS.JS_Parse_Error
&& e.message === "Unexpected token: operator (" + data.operator + ")";
};
};
var errorMessage = function(data) {
return "Expected but didn't get a syntax error while parsing following line:\n" + data.code;
};
var tests = generator();
for (var i = 0; i < tests.length; i++) {
var test = tests[i];
assert.throws(testCase(test), fail(test), errorMessage(test));
}
});
});

21
test/mocha/ie8.js Normal file
View File

@@ -0,0 +1,21 @@
var assert = require("assert");
var uglify = require("../../");
describe("ie8", function() {
it("Should be able to minify() with undefined as catch parameter in a try...catch statement", function() {
assert.strictEqual(
uglify.minify([
"function a(b){",
" try {",
" throw 'Stuff';",
" } catch (undefined) {",
" console.log('caught: ' + undefined);",
" }",
" console.log('undefined is ' + undefined);",
" return b === undefined;",
"};",
].join("\n")).code,
'function a(o){try{throw"Stuff"}catch(o){console.log("caught: "+o)}return console.log("undefined is "+void 0),void 0===o}'
);
});
});

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

@@ -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() {
@@ -387,4 +303,45 @@ describe("minify", function() {
}
});
});
describe("enclose", function() {
var code = read("test/input/enclose/input.js");
it("Should work with true", function() {
var result = Uglify.minify(code, {
compress: false,
enclose: true,
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(){function enclose(){console.log("test enclose")}enclose()})();');
});
it("Should work with arg", function() {
var result = Uglify.minify(code, {
compress: false,
enclose: 'undefined',
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(undefined){function enclose(){console.log("test enclose")}enclose()})();');
});
it("Should work with arg:value", function() {
var result = Uglify.minify(code, {
compress: false,
enclose: 'window,undefined:window',
mangle: false,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(window,undefined){function enclose(){console.log("test enclose")}enclose()})(window);');
});
it("Should work alongside wrap", function() {
var result = Uglify.minify(code, {
compress: false,
enclose: 'window,undefined:window',
mangle: false,
wrap: 'exports',
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(window,undefined){(function(exports){function enclose(){console.log("test enclose")}enclose()})(typeof exports=="undefined"?exports={}:exports)})(window);');
});
});
});

View File

@@ -1,22 +1,21 @@
var assert = require("assert");
var uglify = require("../node");
describe("Number literals", function () {
describe("Number literals", function() {
it("Should not allow legacy octal literals in strict mode", function() {
var inputs = [
'"use strict";00;',
'"use strict"; var foo = 00;'
];
var test = function(input) {
return function() {
uglify.parse(input);
}
}
};
var error = function(e) {
return e instanceof uglify.JS_Parse_Error &&
e.message === "Legacy octal literals are not allowed in strict mode";
}
return e instanceof uglify.JS_Parse_Error
&& e.message === "Legacy octal literals are not allowed in strict mode";
};
for (var i = 0; i < inputs.length; i++) {
assert.throws(test(inputs[i]), error, inputs[i]);
}

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

@@ -1,21 +0,0 @@
var assert = require("assert");
var uglify = require("../../");
describe("screw-ie8", function () {
it("Should be able to minify() with undefined as catch parameter in a try...catch statement", function () {
assert.strictEqual(
uglify.minify(
"function a(b){\
try {\
throw 'Stuff';\
} catch (undefined) {\
console.log('caught: ' + undefined);\
}\
console.log('undefined is ' + undefined);\
return b === undefined;\
};"
).code,
'function a(o){try{throw"Stuff"}catch(o){console.log("caught: "+o)}return console.log("undefined is "+void 0),void 0===o}'
);
});
});

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

@@ -0,0 +1,224 @@
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"}');
});
it("Should give correct sourceRoot", function() {
var code = "console.log(42);";
var result = Uglify.minify(code, {
sourceMap: {
root: "//foo.bar/",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, code);
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI","sourceRoot":"//foo.bar/"}');
});
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
}
});
if (result.error) throw result.error;
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 result = Uglify.minify(read("./test/input/issue-520/input.js"), {
compress: { toplevel: true },
sourceMap: {
content: "inline",
includeSources: true,
url: "inline"
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-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"
}
});
if (result.error) throw result.error;
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; };');
if (result.error) throw result.error;
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"
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code, read("./test/input/issue-505/output.js"));
});
it("Should work with unicode characters", function() {
var code = [
"var tëst = '→unicøde←';",
"alert(tëst);",
].join("\n");
var result = Uglify.minify(code, {
sourceMap: {
includeSources: true,
url: "inline",
}
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
assert.strictEqual(map.sourcesContent.length, 1);
assert.strictEqual(map.sourcesContent[0], code);
var encoded = result.code.slice(result.code.lastIndexOf(",") + 1);
map = JSON.parse(new Buffer(encoded, "base64").toString());
assert.strictEqual(map.sourcesContent.length, 1);
assert.strictEqual(map.sourcesContent[0], code);
result = Uglify.minify(result.code, {
sourceMap: {
content: "inline",
includeSources: true,
}
});
if (result.error) throw result.error;
map = JSON.parse(result.map);
assert.strictEqual(map.names.length, 2);
assert.strictEqual(map.names[0], "tëst");
assert.strictEqual(map.names[1], "alert");
});
});
});

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

@@ -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) {
@@ -182,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, true);
var stdout = run_code(input_code);
if (test.expect_stdout === true) {
test.expect_stdout = stdout;
}
@@ -196,7 +185,7 @@ function run_compress_tests() {
});
return false;
}
stdout = sandbox.run_code(output, true);
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,
@@ -221,7 +210,7 @@ function run_compress_tests() {
}
}
}
files.forEach(function(file){
files.forEach(function(file) {
test_file(file);
});
}
@@ -239,7 +228,7 @@ function parse_test(file) {
throw e;
}
var tests = {};
var tw = new U.TreeWalker(function(node, descend){
var tw = new U.TreeWalker(function(node, descend) {
if (node instanceof U.AST_LabeledStatement
&& tw.parent() instanceof U.AST_Toplevel) {
var name = node.label.name;
@@ -282,7 +271,7 @@ function parse_test(file) {
function get_one_test(name, block) {
var test = { name: name, options: {} };
var tw = new U.TreeWalker(function(node, descend){
var tw = new U.TreeWalker(function(node, descend) {
if (node instanceof U.AST_Assign) {
if (!(node.left instanceof U.AST_SymbolRef)) {
croak(node);
@@ -354,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) {
@@ -377,7 +371,7 @@ function reminify(orig_options, input_code, input_formatted, expect_stdout) {
});
return false;
} else {
var stdout = sandbox.run_code(result.code, true);
var stdout = run_code(result.code);
if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) {
stdout = expect_stdout;
}

View File

@@ -2,24 +2,18 @@ var semver = require("semver");
var vm = require("vm");
function createContext() {
var context = Object.create(null);
Object.defineProperty(context, "console", {
value: function() {
var con = Object.create(null);
Object.defineProperty(con, "log", {
value: 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);
}));
return vm.createContext(Object.defineProperty({}, "console", {
value: {
log: function(msg) {
if (arguments.length == 1 && typeof msg == "string") {
return console.log("%s", msg);
}
});
return con;
}()
});
return vm.createContext(context);
return console.log.apply(console, [].map.call(arguments, function(arg) {
return safe_log(arg, 3);
}));
}
}
}));
}
function safe_log(arg, level) {
@@ -40,7 +34,7 @@ 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;

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

@@ -18,6 +18,13 @@
{
"toplevel": true
},
{
"compress": {
"passes": 1e6,
"unsafe": true
},
"toplevel": true
},
{
"compress": {
"keep_fargs": false,

View File

@@ -14,7 +14,7 @@ var FILES = UglifyJS.FILES = [
"../lib/propmangle.js",
"../lib/minify.js",
"./exports.js",
].map(function(file){
].map(function(file) {
return require.resolve(file);
});
@@ -33,13 +33,13 @@ function describe_ast() {
var out = OutputStream({ beautify: true });
function doitem(ctor) {
out.print("AST_" + ctor.TYPE);
var props = ctor.SELF_PROPS.filter(function(prop){
var props = ctor.SELF_PROPS.filter(function(prop) {
return !/^\$/.test(prop);
});
if (props.length > 0) {
out.space();
out.with_parens(function(){
props.forEach(function(prop, i){
out.with_parens(function() {
props.forEach(function(prop, i) {
if (i) out.space();
out.print(prop);
});
@@ -51,8 +51,8 @@ function describe_ast() {
}
if (ctor.SUBCLASSES.length > 0) {
out.space();
out.with_block(function(){
ctor.SUBCLASSES.forEach(function(ctor, i){
out.with_block(function() {
ctor.SUBCLASSES.forEach(function(ctor, i) {
out.indent();
doitem(ctor);
out.newline();