Compare commits
18 Commits
harmony-v3
...
harmony-v3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1647ee0c5 | ||
|
|
c814060b4a | ||
|
|
3e62faa64f | ||
|
|
e9645e017f | ||
|
|
55b5f2a8aa | ||
|
|
303293e4aa | ||
|
|
23265ac253 | ||
|
|
0cc6dedccc | ||
|
|
ec63588496 | ||
|
|
c2e471e3ad | ||
|
|
ee23a84e14 | ||
|
|
520da57fdc | ||
|
|
4e0a22e5c8 | ||
|
|
1aa38051fb | ||
|
|
e62b879b48 | ||
|
|
c6c9f4f5a8 | ||
|
|
fec14379f6 | ||
|
|
79131cd647 |
@@ -42,6 +42,7 @@ a double dash to prevent input files being used as option arguments:
|
|||||||
|
|
||||||
```
|
```
|
||||||
-h, --help Print usage information.
|
-h, --help Print usage information.
|
||||||
|
`--help options` for details on available options.
|
||||||
-V, --version Print version number.
|
-V, --version Print version number.
|
||||||
-p, --parse <options> Specify parser options:
|
-p, --parse <options> Specify parser options:
|
||||||
`acorn` Use Acorn for parsing.
|
`acorn` Use Acorn for parsing.
|
||||||
@@ -568,6 +569,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
comparison are switching. Compression only works if both `comparisons` and
|
comparison are switching. Compression only works if both `comparisons` and
|
||||||
`unsafe_comps` are both set to true.
|
`unsafe_comps` are both set to true.
|
||||||
|
|
||||||
|
- `unsafe_Func` (default: false) -- compress and mangle `Function(args, code)`.
|
||||||
|
|
||||||
- `unsafe_math` (default: false) -- optimize numerical expressions like
|
- `unsafe_math` (default: false) -- optimize numerical expressions like
|
||||||
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
|
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
|
||||||
|
|
||||||
|
|||||||
28
bin/uglifyjs
28
bin/uglifyjs
@@ -21,10 +21,27 @@ var options = {
|
|||||||
compress: false,
|
compress: false,
|
||||||
mangle: false
|
mangle: false
|
||||||
};
|
};
|
||||||
program.version(info.name + ' ' + info.version);
|
program.version(info.name + " " + info.version);
|
||||||
program.parseArgv = program.parse;
|
program.parseArgv = program.parse;
|
||||||
program.parse = undefined;
|
program.parse = undefined;
|
||||||
if (process.argv.indexOf("ast") >= 0) program.helpInformation = UglifyJS.describe_ast;
|
if (process.argv.indexOf("ast") >= 0) program.helpInformation = UglifyJS.describe_ast;
|
||||||
|
else if (process.argv.indexOf("options") >= 0) program.helpInformation = function() {
|
||||||
|
var text = [];
|
||||||
|
var options = UglifyJS.default_options();
|
||||||
|
for (var option in options) {
|
||||||
|
text.push("--" + (option == "output" ? "beautify" : option == "sourceMap" ? "source-map" : option) + " options:");
|
||||||
|
var defs = options[option];
|
||||||
|
var padding = "";
|
||||||
|
Object.keys(defs).map(function(name) {
|
||||||
|
if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
|
||||||
|
return [ name, JSON.stringify(defs[name]) ];
|
||||||
|
}).forEach(function(tokens) {
|
||||||
|
text.push(" " + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
|
||||||
|
});
|
||||||
|
text.push("");
|
||||||
|
}
|
||||||
|
return text.join("\n");
|
||||||
|
};
|
||||||
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true));
|
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true));
|
||||||
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js("compress", true));
|
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js("compress", true));
|
||||||
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js("mangle", true));
|
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js("mangle", true));
|
||||||
@@ -208,9 +225,10 @@ function run() {
|
|||||||
col = line.length;
|
col = line.length;
|
||||||
}
|
}
|
||||||
if (line) {
|
if (line) {
|
||||||
if (col > 40) {
|
var limit = 70;
|
||||||
line = line.slice(col - 40);
|
if (col > limit) {
|
||||||
col = 40;
|
line = line.slice(col - limit);
|
||||||
|
col = limit;
|
||||||
}
|
}
|
||||||
console.error(line.slice(0, 80));
|
console.error(line.slice(0, 80));
|
||||||
console.error(line.slice(0, col).replace(/\S/g, " ") + "^");
|
console.error(line.slice(0, col).replace(/\S/g, " ") + "^");
|
||||||
@@ -351,7 +369,7 @@ function parse_js(flag, constants) {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
fatal("Error parsing arguments for '" + flag + "': " + value);
|
options[value] = null;
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|||||||
261
lib/compress.js
261
lib/compress.js
@@ -82,6 +82,7 @@ function Compressor(options, false_by_default) {
|
|||||||
toplevel : !!(options && options["top_retain"]),
|
toplevel : !!(options && options["top_retain"]),
|
||||||
unsafe : false,
|
unsafe : false,
|
||||||
unsafe_comps : false,
|
unsafe_comps : false,
|
||||||
|
unsafe_Func : false,
|
||||||
unsafe_math : false,
|
unsafe_math : false,
|
||||||
unsafe_proto : false,
|
unsafe_proto : false,
|
||||||
unsafe_regexp : false,
|
unsafe_regexp : false,
|
||||||
@@ -251,7 +252,7 @@ merge(Compressor.prototype, {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Lambda && node !== self) {
|
if (node instanceof AST_Class || node instanceof AST_Lambda && node !== self) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Block) {
|
if (node instanceof AST_Block) {
|
||||||
@@ -372,14 +373,16 @@ merge(Compressor.prototype, {
|
|||||||
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
|
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
|
||||||
// So existing transformation rules can work on them.
|
// So existing transformation rules can work on them.
|
||||||
node.argnames.forEach(function(arg, i) {
|
node.argnames.forEach(function(arg, i) {
|
||||||
var d = arg.definition();
|
if (arg.definition) {
|
||||||
if (!node.uses_arguments && d.fixed === undefined) {
|
var d = arg.definition();
|
||||||
d.fixed = function() {
|
if (!node.uses_arguments && d.fixed === undefined) {
|
||||||
return iife.args[i] || make_node(AST_Undefined, iife);
|
d.fixed = function() {
|
||||||
};
|
return iife.args[i] || make_node(AST_Undefined, iife);
|
||||||
mark(d, true);
|
};
|
||||||
} else {
|
mark(d, true);
|
||||||
d.fixed = false;
|
} else {
|
||||||
|
d.fixed = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -666,6 +669,7 @@ merge(Compressor.prototype, {
|
|||||||
function can_be_evicted_from_block(node) {
|
function can_be_evicted_from_block(node) {
|
||||||
return !(
|
return !(
|
||||||
node instanceof AST_DefClass ||
|
node instanceof AST_DefClass ||
|
||||||
|
node instanceof AST_Defun ||
|
||||||
node instanceof AST_Let ||
|
node instanceof AST_Let ||
|
||||||
node instanceof AST_Const
|
node instanceof AST_Const
|
||||||
);
|
);
|
||||||
@@ -950,6 +954,45 @@ merge(Compressor.prototype, {
|
|||||||
// step. nevertheless, it's good to check.
|
// step. nevertheless, it's good to check.
|
||||||
continue loop;
|
continue loop;
|
||||||
case stat instanceof AST_If:
|
case stat instanceof AST_If:
|
||||||
|
var ab = aborts(stat.body);
|
||||||
|
if (can_merge_flow(ab)) {
|
||||||
|
if (ab.label) {
|
||||||
|
remove(ab.label.thedef.references, ab);
|
||||||
|
}
|
||||||
|
CHANGED = true;
|
||||||
|
var funs = extract_functions_from_statement_array(ret);
|
||||||
|
var body = as_statement_array_with_return(stat.body, ab);
|
||||||
|
stat = stat.clone();
|
||||||
|
stat.condition = stat.condition.negate(compressor);
|
||||||
|
stat.body = make_node(AST_BlockStatement, stat, {
|
||||||
|
body: as_statement_array(stat.alternative).concat(ret)
|
||||||
|
});
|
||||||
|
stat.alternative = make_node(AST_BlockStatement, stat, {
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
ret = [ stat.transform(compressor) ].concat(funs);
|
||||||
|
continue loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ab = aborts(stat.alternative);
|
||||||
|
if (can_merge_flow(ab)) {
|
||||||
|
if (ab.label) {
|
||||||
|
remove(ab.label.thedef.references, ab);
|
||||||
|
}
|
||||||
|
CHANGED = true;
|
||||||
|
var funs = extract_functions_from_statement_array(ret);
|
||||||
|
stat = stat.clone();
|
||||||
|
stat.body = make_node(AST_BlockStatement, stat.body, {
|
||||||
|
body: as_statement_array(stat.body).concat(ret)
|
||||||
|
});
|
||||||
|
var body = as_statement_array_with_return(stat.alternative, ab);
|
||||||
|
stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
|
||||||
|
body: body
|
||||||
|
});
|
||||||
|
ret = [ stat.transform(compressor) ].concat(funs);
|
||||||
|
continue loop;
|
||||||
|
}
|
||||||
|
|
||||||
if (stat.body instanceof AST_Return) {
|
if (stat.body instanceof AST_Return) {
|
||||||
var value = stat.body.value;
|
var value = stat.body.value;
|
||||||
//---
|
//---
|
||||||
@@ -986,23 +1029,6 @@ merge(Compressor.prototype, {
|
|||||||
continue loop;
|
continue loop;
|
||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (foo()) return [ void bar() ]; [ else x...; ] y... ==> if (!foo()) { x...; y... } else bar();
|
|
||||||
if (in_lambda && (!value || value instanceof AST_UnaryPrefix && value.operator == "void")) {
|
|
||||||
CHANGED = true;
|
|
||||||
stat = stat.clone();
|
|
||||||
stat.condition = stat.condition.negate(compressor);
|
|
||||||
var funs = extract_functions_from_statement_array(ret);
|
|
||||||
var body = as_statement_array(stat.alternative).concat(ret);
|
|
||||||
stat.body = make_node(AST_BlockStatement, stat, {
|
|
||||||
body: body
|
|
||||||
});
|
|
||||||
stat.alternative = value ? make_node(AST_SimpleStatement, value, {
|
|
||||||
body: value.expression
|
|
||||||
}) : null;
|
|
||||||
ret = [ stat.transform(compressor) ].concat(funs);
|
|
||||||
continue loop;
|
|
||||||
}
|
|
||||||
//---
|
|
||||||
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
||||||
//
|
//
|
||||||
// if sequences is not enabled, this can lead to an endless loop (issue #866).
|
// if sequences is not enabled, this can lead to an endless loop (issue #866).
|
||||||
@@ -1021,48 +1047,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ab = aborts(stat.body);
|
|
||||||
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null;
|
|
||||||
if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
|
|
||||||
|| (ab instanceof AST_Continue && self === loop_body(lct))
|
|
||||||
|| (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
|
|
||||||
if (ab.label) {
|
|
||||||
remove(ab.label.thedef.references, ab);
|
|
||||||
}
|
|
||||||
CHANGED = true;
|
|
||||||
var body = as_statement_array(stat.body).slice(0, -1);
|
|
||||||
stat = stat.clone();
|
|
||||||
stat.condition = stat.condition.negate(compressor);
|
|
||||||
stat.body = make_node(AST_BlockStatement, stat, {
|
|
||||||
body: as_statement_array(stat.alternative).concat(ret)
|
|
||||||
});
|
|
||||||
stat.alternative = make_node(AST_BlockStatement, stat, {
|
|
||||||
body: body
|
|
||||||
});
|
|
||||||
ret = [ stat.transform(compressor) ];
|
|
||||||
continue loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
var ab = aborts(stat.alternative);
|
|
||||||
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null;
|
|
||||||
if (ab && ((ab instanceof AST_Return && !ab.value && in_lambda)
|
|
||||||
|| (ab instanceof AST_Continue && self === loop_body(lct))
|
|
||||||
|| (ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct))) {
|
|
||||||
if (ab.label) {
|
|
||||||
remove(ab.label.thedef.references, ab);
|
|
||||||
}
|
|
||||||
CHANGED = true;
|
|
||||||
stat = stat.clone();
|
|
||||||
stat.body = make_node(AST_BlockStatement, stat.body, {
|
|
||||||
body: as_statement_array(stat.body).concat(ret)
|
|
||||||
});
|
|
||||||
stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
|
|
||||||
body: as_statement_array(stat.alternative).slice(0, -1)
|
|
||||||
});
|
|
||||||
ret = [ stat.transform(compressor) ];
|
|
||||||
continue loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.unshift(stat);
|
ret.unshift(stat);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1082,6 +1066,30 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_return_void(value) {
|
||||||
|
return !value || value instanceof AST_UnaryPrefix && value.operator == "void";
|
||||||
|
}
|
||||||
|
|
||||||
|
function can_merge_flow(ab) {
|
||||||
|
if (!ab || !all(ret, function(stat) {
|
||||||
|
return !(stat instanceof AST_Const || stat instanceof AST_Let);
|
||||||
|
})) return false;
|
||||||
|
var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null;
|
||||||
|
return ab instanceof AST_Return && in_lambda && is_return_void(ab.value)
|
||||||
|
|| ab instanceof AST_Continue && self === loop_body(lct)
|
||||||
|
|| ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct;
|
||||||
|
}
|
||||||
|
|
||||||
|
function as_statement_array_with_return(node, ab) {
|
||||||
|
var body = as_statement_array(node).slice(0, -1);
|
||||||
|
if (ab.value) {
|
||||||
|
body.push(make_node(AST_SimpleStatement, ab.value, {
|
||||||
|
body: ab.value.expression
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return body;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function eliminate_dead_code(statements, compressor) {
|
function eliminate_dead_code(statements, compressor) {
|
||||||
@@ -1991,7 +1999,8 @@ merge(Compressor.prototype, {
|
|||||||
self.body = tighten_body(self.body, compressor);
|
self.body = tighten_body(self.body, compressor);
|
||||||
switch (self.body.length) {
|
switch (self.body.length) {
|
||||||
case 1:
|
case 1:
|
||||||
if (can_be_evicted_from_block(self.body[0])) {
|
if (!compressor.has_directive("use strict") && compressor.parent() instanceof AST_If
|
||||||
|
|| can_be_evicted_from_block(self.body[0])) {
|
||||||
return self.body[0];
|
return self.body[0];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -3129,63 +3138,6 @@ merge(Compressor.prototype, {
|
|||||||
operator: "!"
|
operator: "!"
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
break;
|
break;
|
||||||
case "Function":
|
|
||||||
// new Function() => function(){}
|
|
||||||
if (self.args.length == 0) return make_node(AST_Function, self, {
|
|
||||||
argnames: [],
|
|
||||||
body: []
|
|
||||||
});
|
|
||||||
if (all(self.args, function(x){ return x instanceof AST_String })) {
|
|
||||||
// quite a corner-case, but we can handle it:
|
|
||||||
// https://github.com/mishoo/UglifyJS2/issues/203
|
|
||||||
// if the code argument is a constant, then we can minify it.
|
|
||||||
try {
|
|
||||||
var code = "(function(" + self.args.slice(0, -1).map(function(arg){
|
|
||||||
return arg.value;
|
|
||||||
}).join(",") + "){" + self.args[self.args.length - 1].value + "})()";
|
|
||||||
var ast = parse(code);
|
|
||||||
var mangle = { ie8: compressor.option("ie8") };
|
|
||||||
ast.figure_out_scope(mangle);
|
|
||||||
var comp = new Compressor(compressor.options);
|
|
||||||
ast = ast.transform(comp);
|
|
||||||
ast.figure_out_scope(mangle);
|
|
||||||
ast.mangle_names();
|
|
||||||
var fun;
|
|
||||||
try {
|
|
||||||
ast.walk(new TreeWalker(function(node){
|
|
||||||
if (node instanceof AST_Lambda) {
|
|
||||||
fun = node;
|
|
||||||
throw ast;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
} catch(ex) {
|
|
||||||
if (ex !== ast) throw ex;
|
|
||||||
};
|
|
||||||
if (!fun) return self;
|
|
||||||
var args = fun.argnames.map(function(arg, i){
|
|
||||||
return make_node(AST_String, self.args[i], {
|
|
||||||
value: arg.print_to_string({ecma: compressor.option("ecma")})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
var code = OutputStream();
|
|
||||||
AST_BlockStatement.prototype._codegen.call(fun, fun, code);
|
|
||||||
code = code.toString().replace(/^\{|\}$/g, "");
|
|
||||||
args.push(make_node(AST_String, self.args[self.args.length - 1], {
|
|
||||||
value: code
|
|
||||||
}));
|
|
||||||
self.args = args;
|
|
||||||
return self;
|
|
||||||
} catch(ex) {
|
|
||||||
if (ex instanceof JS_Parse_Error) {
|
|
||||||
compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start);
|
|
||||||
compressor.warn(ex.toString());
|
|
||||||
} else {
|
|
||||||
console.log(ex);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "Symbol":
|
case "Symbol":
|
||||||
// Symbol's argument is only used for debugging.
|
// Symbol's argument is only used for debugging.
|
||||||
self.args = [];
|
self.args = [];
|
||||||
@@ -3272,6 +3224,63 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (compressor.option("unsafe_Func")
|
||||||
|
&& exp instanceof AST_SymbolRef
|
||||||
|
&& exp.undeclared()
|
||||||
|
&& exp.name == "Function") {
|
||||||
|
// new Function() => function(){}
|
||||||
|
if (self.args.length == 0) return make_node(AST_Function, self, {
|
||||||
|
argnames: [],
|
||||||
|
body: []
|
||||||
|
});
|
||||||
|
if (all(self.args, function(x) {
|
||||||
|
return x instanceof AST_String;
|
||||||
|
})) {
|
||||||
|
// quite a corner-case, but we can handle it:
|
||||||
|
// https://github.com/mishoo/UglifyJS2/issues/203
|
||||||
|
// if the code argument is a constant, then we can minify it.
|
||||||
|
try {
|
||||||
|
var code = "NaN(function(" + self.args.slice(0, -1).map(function(arg) {
|
||||||
|
return arg.value;
|
||||||
|
}).join(",") + "){" + self.args[self.args.length - 1].value + "})";
|
||||||
|
var ast = parse(code);
|
||||||
|
var mangle = { ie8: compressor.option("ie8") };
|
||||||
|
ast.figure_out_scope(mangle);
|
||||||
|
var comp = new Compressor(compressor.options);
|
||||||
|
ast = ast.transform(comp);
|
||||||
|
ast.figure_out_scope(mangle);
|
||||||
|
ast.mangle_names();
|
||||||
|
var fun;
|
||||||
|
ast.walk(new TreeWalker(function(node) {
|
||||||
|
if (fun) return true;
|
||||||
|
if (node instanceof AST_Lambda) {
|
||||||
|
fun = node;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
var args = fun.argnames.map(function(arg, i) {
|
||||||
|
return make_node(AST_String, self.args[i], {
|
||||||
|
value: arg.print_to_string()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
var code = OutputStream();
|
||||||
|
AST_BlockStatement.prototype._codegen.call(fun, fun, code);
|
||||||
|
code = code.toString().replace(/^\{|\}$/g, "");
|
||||||
|
args.push(make_node(AST_String, self.args[self.args.length - 1], {
|
||||||
|
value: code
|
||||||
|
}));
|
||||||
|
self.args = args;
|
||||||
|
return self;
|
||||||
|
} catch (ex) {
|
||||||
|
if (ex instanceof JS_Parse_Error) {
|
||||||
|
compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start);
|
||||||
|
compressor.warn(ex.toString());
|
||||||
|
} else {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (exp instanceof AST_Function && !self.expression.is_generator) {
|
if (exp instanceof AST_Function && !self.expression.is_generator) {
|
||||||
if (exp.body[0] instanceof AST_Return) {
|
if (exp.body[0] instanceof AST_Return) {
|
||||||
var value = exp.body[0].value;
|
var value = exp.body[0].value;
|
||||||
|
|||||||
@@ -866,7 +866,7 @@ function parse($TEXT, options) {
|
|||||||
shebang : true,
|
shebang : true,
|
||||||
strict : false,
|
strict : false,
|
||||||
toplevel : null,
|
toplevel : null,
|
||||||
});
|
}, true);
|
||||||
|
|
||||||
var S = {
|
var S = {
|
||||||
input : (typeof $TEXT == "string"
|
input : (typeof $TEXT == "string"
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ function SymbolDef(scope, index, orig) {
|
|||||||
this.global = false;
|
this.global = false;
|
||||||
this.export = false;
|
this.export = false;
|
||||||
this.mangled_name = null;
|
this.mangled_name = null;
|
||||||
this.object_destructuring_arg = false;
|
|
||||||
this.undeclared = false;
|
this.undeclared = false;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.id = SymbolDef.next_id++;
|
this.id = SymbolDef.next_id++;
|
||||||
@@ -65,7 +64,6 @@ SymbolDef.prototype = {
|
|||||||
|
|
||||||
return (this.global && !options.toplevel)
|
return (this.global && !options.toplevel)
|
||||||
|| this.export
|
|| this.export
|
||||||
|| this.object_destructuring_arg
|
|
||||||
|| this.undeclared
|
|| this.undeclared
|
||||||
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|
||||||
|| (options.keep_fnames
|
|| (options.keep_fnames
|
||||||
@@ -168,9 +166,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
if (node instanceof AST_Symbol) {
|
if (node instanceof AST_Symbol) {
|
||||||
node.scope = scope;
|
node.scope = scope;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolFunarg) {
|
|
||||||
node.object_destructuring_arg = !!in_destructuring;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Label) {
|
if (node instanceof AST_Label) {
|
||||||
node.thedef = node;
|
node.thedef = node;
|
||||||
node.references = [];
|
node.references = [];
|
||||||
@@ -378,7 +373,6 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
|||||||
if (!this.variables.has(symbol.name)) {
|
if (!this.variables.has(symbol.name)) {
|
||||||
def = new SymbolDef(this, this.variables.size(), symbol);
|
def = new SymbolDef(this, this.variables.size(), symbol);
|
||||||
this.variables.set(symbol.name, def);
|
this.variables.set(symbol.name, def);
|
||||||
def.object_destructuring_arg = symbol.object_destructuring_arg;
|
|
||||||
def.global = !this.parent_scope;
|
def.global = !this.parent_scope;
|
||||||
} else {
|
} else {
|
||||||
def = this.variables.get(symbol.name);
|
def = this.variables.get(symbol.name);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
|
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.0.12",
|
"version": "3.0.14",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -47,3 +47,142 @@ keep_some_blocks: {
|
|||||||
} else stuff();
|
} else stuff();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_1664: {
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
function f() {
|
||||||
|
if (undefined) a = 2;
|
||||||
|
{
|
||||||
|
function undefined() {}
|
||||||
|
undefined();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
function f() {
|
||||||
|
if (undefined) a = 2;
|
||||||
|
{
|
||||||
|
function undefined() {}
|
||||||
|
undefined();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1672_for: {
|
||||||
|
input: {
|
||||||
|
switch (function() {
|
||||||
|
return xxx;
|
||||||
|
}) {
|
||||||
|
case xxx:
|
||||||
|
for (; console.log("FAIL");) {
|
||||||
|
function xxx() {}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
switch (function() {
|
||||||
|
return xxx;
|
||||||
|
}) {
|
||||||
|
case xxx:
|
||||||
|
for (; console.log("FAIL");) {
|
||||||
|
function xxx() {}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1672_for_strict: {
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
switch (function() {
|
||||||
|
return xxx;
|
||||||
|
}) {
|
||||||
|
case xxx:
|
||||||
|
for (; console.log("FAIL");) {
|
||||||
|
function xxx() {}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
switch (function() {
|
||||||
|
return xxx;
|
||||||
|
}) {
|
||||||
|
case xxx:
|
||||||
|
for (; console.log("FAIL");) {
|
||||||
|
function xxx() {}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1672_if: {
|
||||||
|
input: {
|
||||||
|
switch (function() {
|
||||||
|
return xxx;
|
||||||
|
}) {
|
||||||
|
case xxx:
|
||||||
|
if (console.log("FAIL")) {
|
||||||
|
function xxx() {}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
switch (function() {
|
||||||
|
return xxx;
|
||||||
|
}) {
|
||||||
|
case xxx:
|
||||||
|
if (console.log("FAIL")) function xxx() {}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1672_if_strict: {
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
switch (function() {
|
||||||
|
return xxx;
|
||||||
|
}) {
|
||||||
|
case xxx:
|
||||||
|
if (console.log("FAIL")) {
|
||||||
|
function xxx() {}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
switch (function() {
|
||||||
|
return xxx;
|
||||||
|
}) {
|
||||||
|
case xxx:
|
||||||
|
if (console.log("FAIL")) {
|
||||||
|
function xxx() {}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|||||||
@@ -543,3 +543,55 @@ mangle_destructuring_decl_array: {
|
|||||||
expect_stdout: "8 7 6 undefined 2 [ 3 ]"
|
expect_stdout: "8 7 6 undefined 2 [ 3 ]"
|
||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
anon_func_with_destructuring_args: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unused: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
ecma: 5,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function({foo = 1 + 0, bar = 2}, [car = 3, far = 4]) {
|
||||||
|
console.log(foo, bar, car, far);
|
||||||
|
})({bar: 5 - 0}, [, 6]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function({foo: o = 1, bar: n = 2}, [a = 3, b = 4]) {
|
||||||
|
console.log(o, n, a, b);
|
||||||
|
})({bar: 5}, [, 6]);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 5 3 6"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
arrow_func_with_destructuring_args: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unused: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
ecma: 5,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(({foo = 1 + 0, bar = 2}, [car = 3, far = 4]) => {
|
||||||
|
console.log(foo, bar, car, far);
|
||||||
|
})({bar: 5 - 0}, [, 6]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(({foo: o = 1, bar: n = 2}, [a = 3, b = 4]) => {
|
||||||
|
console.log(o, n, a, b);
|
||||||
|
})({bar: 5}, [, 6]);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 5 3 6"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|||||||
@@ -245,3 +245,25 @@ hoist_funs_strict: {
|
|||||||
]
|
]
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_203: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: false,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe_Func: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var m = {};
|
||||||
|
var fn = Function("require", "module", "exports", "module.exports = 42;");
|
||||||
|
fn(null, m, m.exports);
|
||||||
|
console.log(m.exports);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var m = {};
|
||||||
|
var fn = Function("a", "b", "b.exports=42");
|
||||||
|
fn(null, m, m.exports);
|
||||||
|
console.log(m.exports);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|||||||
@@ -583,3 +583,39 @@ class_extends_regex: {
|
|||||||
}
|
}
|
||||||
expect_exact: "function f(){class rx1 extends(/rx/){}}"
|
expect_exact: "function f(){class rx1 extends(/rx/){}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2028: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = {};
|
||||||
|
(function(x) {
|
||||||
|
x.X = function() {
|
||||||
|
return X;
|
||||||
|
};
|
||||||
|
class X {
|
||||||
|
static hello() {
|
||||||
|
console.log("hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(a));
|
||||||
|
a.X().hello();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = {};
|
||||||
|
(function(x) {
|
||||||
|
x.X = function() {
|
||||||
|
return X;
|
||||||
|
};
|
||||||
|
class X {
|
||||||
|
static hello() {
|
||||||
|
console.log("hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(a));
|
||||||
|
a.X().hello();
|
||||||
|
}
|
||||||
|
expect_stdout: "hello"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|||||||
@@ -307,6 +307,8 @@ issue_512: {
|
|||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function a() {
|
function a() {
|
||||||
@@ -324,3 +326,61 @@ issue_512: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_1317: {
|
||||||
|
options = {
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function(a) {
|
||||||
|
if (a) return;
|
||||||
|
let b = 1;
|
||||||
|
function g() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function(a) {
|
||||||
|
if (a) return;
|
||||||
|
let b = 1;
|
||||||
|
function g() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1317_strict: {
|
||||||
|
options = {
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
!function(a) {
|
||||||
|
if (a) return;
|
||||||
|
let b = 1;
|
||||||
|
function g() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
!function(a) {
|
||||||
|
if (a) return;
|
||||||
|
let b = 1;
|
||||||
|
function g() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
console.log(g());
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|||||||
@@ -139,3 +139,25 @@ defun_hoist_funs: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defun_else_if_return: {
|
||||||
|
options = {
|
||||||
|
hoist_funs: false,
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function e() {
|
||||||
|
function f() {}
|
||||||
|
if (window) function g() {}
|
||||||
|
else return;
|
||||||
|
function h() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function e() {
|
||||||
|
function f() {}
|
||||||
|
if (window) function g() {}
|
||||||
|
function h() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
compress_new_function: {
|
compress_new_function: {
|
||||||
options = {
|
options = {
|
||||||
unsafe: true
|
unsafe: true,
|
||||||
|
unsafe_Func: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
new Function("aa, bb", 'return aa;');
|
new Function("aa, bb", 'return aa;');
|
||||||
@@ -14,6 +15,7 @@ compress_new_function: {
|
|||||||
compress_new_function_with_destruct: {
|
compress_new_function_with_destruct: {
|
||||||
options = {
|
options = {
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
|
unsafe_Func: true,
|
||||||
ecma: 6
|
ecma: 6
|
||||||
}
|
}
|
||||||
beautify = {
|
beautify = {
|
||||||
@@ -26,9 +28,7 @@ compress_new_function_with_destruct: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
Function("a", "[b]", "return a");
|
Function("a", "[b]", "return a");
|
||||||
Function("a", "{bb}", "return a");
|
Function("a", "{bb:b}", "return a");
|
||||||
Function("[[a]]", "[{bb}]", 'return a');
|
Function("[[a]]", "[{bb:b}]", 'return a');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -552,4 +552,13 @@ describe("bin/uglifyjs", function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
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) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.ok(/^Supported options:\n\{[^}]+}\nERROR: `ascii-only` is not a supported option/.test(stderr), stderr);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
stream._handle.setBlocking(true);
|
stream._handle.setBlocking(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
var UglifyJS = require("./node");
|
var UglifyJS = require("..");
|
||||||
var randomBytes = require("crypto").randomBytes;
|
var randomBytes = require("crypto").randomBytes;
|
||||||
var sandbox = require("./sandbox");
|
var sandbox = require("./sandbox");
|
||||||
|
|
||||||
@@ -962,32 +962,15 @@ function try_beautify(code, result) {
|
|||||||
console.log(code);
|
console.log(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
function infer_options(ctor) {
|
var default_options = UglifyJS.default_options();
|
||||||
try {
|
|
||||||
ctor({ 0: 0 });
|
|
||||||
} catch (e) {
|
|
||||||
return e.defs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var default_options = {
|
|
||||||
compress: infer_options(UglifyJS.Compressor),
|
|
||||||
mangle: {
|
|
||||||
"cache": null,
|
|
||||||
"eval": false,
|
|
||||||
"ie8": false,
|
|
||||||
"keep_fnames": false,
|
|
||||||
"toplevel": false,
|
|
||||||
},
|
|
||||||
output: infer_options(UglifyJS.OutputStream),
|
|
||||||
};
|
|
||||||
|
|
||||||
function log_suspects(minify_options, component) {
|
function log_suspects(minify_options, component) {
|
||||||
var options = component in minify_options ? minify_options[component] : true;
|
var options = component in minify_options ? minify_options[component] : true;
|
||||||
if (!options) return;
|
if (!options) return;
|
||||||
options = UglifyJS.defaults(options, default_options[component]);
|
if (typeof options != "object") options = {};
|
||||||
var suspects = Object.keys(default_options[component]).filter(function(name) {
|
var defs = default_options[component];
|
||||||
if (options[name]) {
|
var suspects = Object.keys(defs).filter(function(name) {
|
||||||
|
if ((name in options ? options : defs)[name]) {
|
||||||
var m = JSON.parse(JSON.stringify(minify_options));
|
var m = JSON.parse(JSON.stringify(minify_options));
|
||||||
var o = JSON.parse(JSON.stringify(options));
|
var o = JSON.parse(JSON.stringify(options));
|
||||||
o[name] = false;
|
o[name] = false;
|
||||||
|
|||||||
@@ -63,3 +63,20 @@ function describe_ast() {
|
|||||||
doitem(AST_Node);
|
doitem(AST_Node);
|
||||||
return out + "\n";
|
return out + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function infer_options(options) {
|
||||||
|
var result = UglifyJS.minify("", options);
|
||||||
|
return result.error && result.error.defs;
|
||||||
|
}
|
||||||
|
|
||||||
|
UglifyJS.default_options = function() {
|
||||||
|
var defs = {};
|
||||||
|
Object.keys(infer_options({ 0: 0 })).forEach(function(component) {
|
||||||
|
var options = {};
|
||||||
|
options[component] = { 0: 0 };
|
||||||
|
if (options = infer_options(options)) {
|
||||||
|
defs[component] = options;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return defs;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user