@@ -572,6 +572,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.
|
||||||
|
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ function run() {
|
|||||||
col = line.length;
|
col = line.length;
|
||||||
}
|
}
|
||||||
if (line) {
|
if (line) {
|
||||||
var limit = 78;
|
var limit = 70;
|
||||||
if (col > limit) {
|
if (col > limit) {
|
||||||
line = line.slice(col - limit);
|
line = line.slice(col - limit);
|
||||||
col = limit;
|
col = limit;
|
||||||
|
|||||||
115
lib/compress.js
115
lib/compress.js
@@ -81,6 +81,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,
|
||||||
@@ -2973,63 +2974,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()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
|
else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) {
|
||||||
@@ -3112,6 +3056,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) {
|
if (exp instanceof AST_Function) {
|
||||||
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;
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user