Compare commits

..

3 Commits

Author SHA1 Message Date
Alex Lam S.L
5c1ae3662d v3.4.7 2018-08-09 14:47:24 +00:00
Alex Lam S.L
cfebeb2f63 fix corner case in mangle workaround for Safari (#3230)
fixes #3227
2018-08-09 17:34:28 +08:00
Alex Lam S.L
fc78423f1d clean up webkit quirks (#3229) 2018-08-08 16:15:45 +08:00
9 changed files with 222 additions and 153 deletions

View File

@@ -48,51 +48,51 @@ function Compressor(options, false_by_default) {
return new Compressor(options, false_by_default); return new Compressor(options, false_by_default);
TreeTransformer.call(this, this.before, this.after); TreeTransformer.call(this, this.before, this.after);
this.options = defaults(options, { this.options = defaults(options, {
arguments : !false_by_default, arguments : !false_by_default,
booleans : !false_by_default, booleans : !false_by_default,
collapse_vars : !false_by_default, collapse_vars : !false_by_default,
comparisons : !false_by_default, comparisons : !false_by_default,
conditionals : !false_by_default, conditionals : !false_by_default,
dead_code : !false_by_default, dead_code : !false_by_default,
directives : !false_by_default, directives : !false_by_default,
drop_console : false, drop_console : false,
drop_debugger : !false_by_default, drop_debugger : !false_by_default,
evaluate : !false_by_default, evaluate : !false_by_default,
expression : false, expression : false,
global_defs : false, global_defs : false,
hoist_funs : false, hoist_funs : false,
hoist_props : !false_by_default, hoist_props : !false_by_default,
hoist_vars : false, hoist_vars : false,
ie8 : false, ie8 : false,
if_return : !false_by_default, if_return : !false_by_default,
inline : !false_by_default, inline : !false_by_default,
join_vars : !false_by_default, join_vars : !false_by_default,
keep_fargs : true, keep_fargs : true,
keep_fnames : false, keep_fnames : false,
keep_infinity : false, keep_infinity : false,
loops : !false_by_default, loops : !false_by_default,
negate_iife : !false_by_default, negate_iife : !false_by_default,
passes : 1, passes : 1,
properties : !false_by_default, properties : !false_by_default,
pure_getters : !false_by_default && "strict", pure_getters : !false_by_default && "strict",
pure_funcs : null, pure_funcs : null,
reduce_funcs : !false_by_default, reduce_funcs : !false_by_default,
reduce_vars : !false_by_default, reduce_vars : !false_by_default,
sequences : !false_by_default, sequences : !false_by_default,
side_effects : !false_by_default, side_effects : !false_by_default,
switches : !false_by_default, switches : !false_by_default,
top_retain : null, top_retain : null,
toplevel : !!(options && options["top_retain"]), toplevel : !!(options && options["top_retain"]),
typeofs : !false_by_default, typeofs : !false_by_default,
unsafe : false, unsafe : false,
unsafe_comps : false, unsafe_comps : false,
unsafe_Function: false, unsafe_Function : false,
unsafe_math : false, unsafe_math : false,
unsafe_proto : false, unsafe_proto : false,
unsafe_regexp : false, unsafe_regexp : false,
unsafe_undefined: false, unsafe_undefined: false,
unused : !false_by_default, unused : !false_by_default,
warnings : false, warnings : false,
}, true); }, true);
var global_defs = this.options["global_defs"]; var global_defs = this.options["global_defs"];
if (typeof global_defs == "object") for (var key in global_defs) { if (typeof global_defs == "object") for (var key in global_defs) {
@@ -5758,9 +5758,10 @@ merge(Compressor.prototype, {
if (fixed instanceof AST_Defun) { if (fixed instanceof AST_Defun) {
fixed._squeezed = true; fixed._squeezed = true;
fixed = make_node(AST_Function, fixed, fixed); fixed = make_node(AST_Function, fixed, fixed);
fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
} }
var value; var value;
if (d.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) { if (d.recursive_refs > 0) {
value = fixed.clone(true); value = fixed.clone(true);
var defun_def = value.name.definition(); var defun_def = value.name.definition();
var lambda_def = value.variables.get(value.name.name); var lambda_def = value.variables.get(value.name.name);

View File

@@ -694,23 +694,15 @@ function OutputStream(options) {
// a function expression needs parens around it when it's provably // a function expression needs parens around it when it's provably
// the first token to appear in a statement. // 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)) { if (!output.has_parens() && first_in_statement(output)) return true;
return true;
}
if (output.option('webkit')) { if (output.option('webkit')) {
var p = output.parent(); var p = output.parent();
if (p instanceof AST_PropAccess && p.expression === this) { if (p instanceof AST_PropAccess && p.expression === this) return true;
return true;
}
} }
if (output.option('wrap_iife')) { if (output.option('wrap_iife')) {
var p = output.parent(); var p = output.parent();
return p instanceof AST_Call && p.expression === this; if (p instanceof AST_Call && p.expression === this) return true;
} }
return false;
}); });
// same goes for an object literal, because otherwise it would be // same goes for an object literal, because otherwise it would be
@@ -784,17 +776,17 @@ function OutputStream(options) {
}); });
PARENS(AST_Call, function(output) { PARENS(AST_Call, function(output) {
var p = output.parent(), p1; var p = output.parent();
if (p instanceof AST_New && p.expression === this) if (p instanceof AST_New && p.expression === this) return true;
return true;
// workaround for Safari bug.
// https://bugs.webkit.org/show_bug.cgi?id=123506 // https://bugs.webkit.org/show_bug.cgi?id=123506
return this.expression instanceof AST_Function if (output.option('webkit')) {
&& p instanceof AST_PropAccess var g = output.parent(1);
&& p.expression === this return this.expression instanceof AST_Function
&& (p1 = output.parent(1)) instanceof AST_Assign && p instanceof AST_PropAccess
&& p1.left === p; && p.expression === this
&& g instanceof AST_Assign
&& g.left === p;
}
}); });
PARENS(AST_New, function(output) { PARENS(AST_New, function(output) {

View File

@@ -320,14 +320,6 @@ function next_mangled_name(scope, options, def) {
var in_use = names_in_use(scope, options); var in_use = names_in_use(scope, options);
var holes = scope.cname_holes; var holes = scope.cname_holes;
var names = Object.create(null); var names = Object.create(null);
// #179, #326
// in Safari strict mode, something like (function x(x){...}) is a syntax error;
// a function expression's argument cannot shadow the function expression's name
if (scope instanceof AST_Function && scope.name && def.orig[0] instanceof AST_SymbolFunarg) {
var tricky_def = scope.name.definition();
// the function's mangled_name is null when keep_fnames is true
names[tricky_def.mangled_name || tricky_def.name] = true;
}
var scopes = [ scope ]; var scopes = [ scope ];
def.references.forEach(function(sym) { def.references.forEach(function(sym) {
var scope = sym.scope; var scope = sym.scope;

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit", "description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)", "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"version": "3.4.6", "version": "3.4.7",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },

View File

@@ -236,32 +236,6 @@ issue_203: {
expect_stdout: "42" expect_stdout: "42"
} }
no_webkit: {
beautify = {
webkit: false,
}
input: {
console.log(function() {
1 + 1;
}.a = 1);
}
expect_exact: "console.log(function(){1+1}.a=1);"
expect_stdout: "1"
}
webkit: {
beautify = {
webkit: true,
}
input: {
console.log(function() {
1 + 1;
}.a = 1);
}
expect_exact: "console.log((function(){1+1}).a=1);"
expect_stdout: "1"
}
issue_2084: { issue_2084: {
options = { options = {
collapse_vars: true, collapse_vars: true,

109
test/compress/webkit.js Normal file
View File

@@ -0,0 +1,109 @@
lambda_call_dot_assign: {
beautify = {
webkit: false,
}
input: {
console.log(function() {
return {};
}().a = 1);
}
expect_exact: "console.log(function(){return{}}().a=1);"
expect_stdout: "1"
}
lambda_call_dot_assign_webkit: {
beautify = {
webkit: true,
}
input: {
console.log(function() {
return {};
}().a = 1);
}
expect_exact: "console.log((function(){return{}}()).a=1);"
expect_stdout: "1"
}
lambda_dot_assign: {
beautify = {
webkit: false,
}
input: {
console.log(function() {
1 + 1;
}.a = 1);
}
expect_exact: "console.log(function(){1+1}.a=1);"
expect_stdout: "1"
}
lambda_dot_assign_webkit: {
beautify = {
webkit: true,
}
input: {
console.log(function() {
1 + 1;
}.a = 1);
}
expect_exact: "console.log((function(){1+1}).a=1);"
expect_stdout: "1"
}
lambda_name_mangle: {
mangle = {}
input: {
console.log(typeof function foo(bar) {});
}
expect_exact: "console.log(typeof function o(n){});"
expect_stdout: "function"
}
lambda_name_mangle_ie8: {
mangle = {
ie8: true,
toplevel: true,
}
input: {
console.log(typeof function foo(bar) {});
}
expect_exact: "console.log(typeof function n(o){});"
expect_stdout: "function"
}
function_name_mangle: {
options = {
keep_fnames: true,
reduce_vars: true,
unused: true,
}
mangle = {}
input: {
(function() {
function foo(bar) {}
console.log(typeof foo);
})();
}
expect_exact: "(function(){console.log(typeof function o(n){})})();"
expect_stdout: "function"
}
function_name_mangle_ie8: {
options = {
keep_fnames: true,
reduce_vars: true,
unused: true,
}
mangle = {
ie8: true,
toplevel: true,
}
input: {
(function() {
function foo(bar) {}
console.log(typeof foo);
})();
}
expect_exact: "(function(){console.log(typeof function n(o){})})();"
expect_stdout: "function"
}

View File

@@ -23,10 +23,9 @@ module.exports = function(url, callback) {
var options = parse(url); var options = parse(url);
options.rejectUnauthorized = false; options.rejectUnauthorized = false;
require(options.protocol.slice(0, -1)).get(options, function(res) { require(options.protocol.slice(0, -1)).get(options, function(res) {
if (res.statusCode !== 200) return callback(res); if (res.statusCode !== 200) return callback(res.statusCode);
res.pipe(fs.createWriteStream(local(url)).on("close", function() { res.pipe(fs.createWriteStream(local(url)));
callback(null, read(url)); callback(null, res);
}));
}); });
}).on("open", function() { }).on("open", function() {
callback(null, result); callback(null, result);

View File

@@ -25,30 +25,35 @@ if (typeof phantom == "undefined") {
request.resume(); request.resume();
var url = site + request.url; var url = site + request.url;
fetch(url, function(err, res) { fetch(url, function(err, res) {
if (err) throw err; if (err) {
response.writeHead(200, { if (typeof err != "number") throw err;
"Content-Type": { response.writeHead(err);
css: "text/css", response.end();
js: "application/javascript",
png: "image/png"
}[url.slice(url.lastIndexOf(".") + 1)] || "text/html; charset=utf-8"
});
if (/\.js$/.test(url)) {
var stderr = "";
var uglifyjs = child_process.fork("bin/uglifyjs", args, {
silent: true
}).on("exit", function(code) {
console.log("uglifyjs", url.slice(site.length + 1), args.join(" "));
console.log(stderr);
if (code) throw new Error("uglifyjs failed with code " + code);
});
uglifyjs.stderr.on("data", function(data) {
stderr += data;
}).setEncoding("utf8");
uglifyjs.stdout.pipe(response);
res.pipe(uglifyjs.stdin);
} else { } else {
res.pipe(response); response.writeHead(200, {
"Content-Type": {
css: "text/css",
js: "application/javascript",
png: "image/png"
}[url.slice(url.lastIndexOf(".") + 1)] || "text/html; charset=utf-8"
});
if (/\.js$/.test(url)) {
var stderr = "";
var uglifyjs = child_process.fork("bin/uglifyjs", args, {
silent: true
}).on("exit", function(code) {
console.log("uglifyjs", url.slice(site.length + 1), args.join(" "));
console.log(stderr);
if (code) throw new Error("uglifyjs failed with code " + code);
});
uglifyjs.stderr.on("data", function(data) {
stderr += data;
}).setEncoding("utf8");
uglifyjs.stdout.pipe(response);
res.pipe(uglifyjs.stdin);
} else {
res.pipe(response);
}
} }
}); });
}).listen(); }).listen();

View File

@@ -1,21 +1,6 @@
var semver = require("semver"); var semver = require("semver");
var vm = require("vm"); var vm = require("vm");
function createContext() {
return vm.createContext(Object.defineProperty({}, "console", {
value: {
log: function(msg) {
if (arguments.length == 1 && typeof msg == "string") {
return console.log("%s", msg);
}
return console.log.apply(console, [].map.call(arguments, function(arg) {
return safe_log(arg, 3);
}));
}
}
}));
}
function safe_log(arg, level) { function safe_log(arg, level) {
if (arg) switch (typeof arg) { if (arg) switch (typeof arg) {
case "function": case "function":
@@ -25,21 +10,21 @@ function safe_log(arg, level) {
arg.constructor.toString(); arg.constructor.toString();
if (level--) for (var key in arg) { if (level--) for (var key in arg) {
var desc = Object.getOwnPropertyDescriptor(arg, key); var desc = Object.getOwnPropertyDescriptor(arg, key);
if (!desc || !desc.get) { if (!desc || !desc.get) arg[key] = safe_log(arg[key], level);
arg[key] = safe_log(arg[key], level);
}
} }
} }
return arg; return arg;
} }
function strip_func_ids(text) { function log(msg) {
return ("" + text).replace(/F[0-9]{6}N/g, "<F<>N>"); 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);
}));
} }
var context; var func_toString = new vm.Script([
var FUNC_TOSTRING = [ "[ Array, Boolean, Error, Function, Number, Object, RegExp, String ].forEach(function(f) {",
"[ Array, Boolean, Error, Function, Number, Object, RegExp, String].forEach(function(f) {",
" f.toString = Function.prototype.toString;", " f.toString = Function.prototype.toString;",
"});", "});",
"Function.prototype.toString = function() {", "Function.prototype.toString = function() {",
@@ -59,7 +44,15 @@ var FUNC_TOSTRING = [
' return "function(){}";', ' return "function(){}";',
" };", " };",
"}();", "}();",
]).join("\n"); ]).join("\n"));
function createContext() {
var ctx = vm.createContext(Object.defineProperty({}, "console", { value: { log: log } }));
func_toString.runInContext(ctx);
return ctx;
}
var context;
exports.run_code = function(code, reuse) { exports.run_code = function(code, reuse) {
var stdout = ""; var stdout = "";
var original_write = process.stdout.write; var original_write = process.stdout.write;
@@ -69,7 +62,6 @@ exports.run_code = function(code, reuse) {
try { try {
if (!reuse || !context) context = createContext(); if (!reuse || !context) context = createContext();
vm.runInContext([ vm.runInContext([
FUNC_TOSTRING,
"!function() {", "!function() {",
code, code,
"}();", "}();",
@@ -86,6 +78,11 @@ exports.run_code = function(code, reuse) {
} }
} }
}; };
function strip_func_ids(text) {
return ("" + text).replace(/F[0-9]{6}N/g, "<F<>N>");
}
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) { exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
if (typeof expected != typeof actual) return false; if (typeof expected != typeof actual) return false;
if (typeof expected != "string") { if (typeof expected != "string") {