Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3ca293e6b | ||
|
|
516b67a43b | ||
|
|
eba3a37bb5 | ||
|
|
6d57ca1a59 | ||
|
|
3320251b4b | ||
|
|
33c94d3bd9 | ||
|
|
b18f717b46 | ||
|
|
a0d4b648bb | ||
|
|
6db880e16d | ||
|
|
a82003d6ac | ||
|
|
da9f1622fc | ||
|
|
8a4c7077bb | ||
|
|
0a63f2f2b0 | ||
|
|
931ac66638 | ||
|
|
35338a100f | ||
|
|
d57b606e73 | ||
|
|
00ada04111 | ||
|
|
a31c477fea | ||
|
|
bde7418ce1 |
12
lib/ast.js
12
lib/ast.js
@@ -837,11 +837,10 @@ var AST_String = DEFNODE("String", "value quote", {
|
||||
}
|
||||
}, AST_Constant);
|
||||
|
||||
var AST_Number = DEFNODE("Number", "value literal", {
|
||||
var AST_Number = DEFNODE("Number", "value", {
|
||||
$documentation: "A number literal",
|
||||
$propdoc: {
|
||||
value: "[number] the numeric value",
|
||||
literal: "[string] numeric value as string (optional)"
|
||||
}
|
||||
}, AST_Constant);
|
||||
|
||||
@@ -980,6 +979,15 @@ TreeWalker.prototype = {
|
||||
|| p instanceof AST_Conditional
|
||||
|| p.tail_node() === self) {
|
||||
self = p;
|
||||
} else if (p instanceof AST_Return) {
|
||||
var fn;
|
||||
do {
|
||||
fn = this.parent(++i);
|
||||
if (!fn) return false;
|
||||
} while (!(fn instanceof AST_Lambda));
|
||||
if (fn.name) return false;
|
||||
self = this.parent(++i);
|
||||
if (!self || self.TYPE != "Call" || self.expression !== fn) return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
149
lib/compress.js
149
lib/compress.js
@@ -1293,6 +1293,7 @@ merge(Compressor.prototype, {
|
||||
return lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression);
|
||||
}
|
||||
if (node instanceof AST_Debugger) return true;
|
||||
if (node instanceof AST_Defun) return funarg && lhs.name === node.name.name;
|
||||
if (node instanceof AST_IterationStatement) return !(node instanceof AST_For);
|
||||
if (node instanceof AST_LoopControl) return true;
|
||||
if (node instanceof AST_Try) return true;
|
||||
@@ -3399,16 +3400,28 @@ merge(Compressor.prototype, {
|
||||
def(AST_Lambda, function(scope) {
|
||||
var self = this;
|
||||
var result = true;
|
||||
self.walk(new TreeWalker(function(node) {
|
||||
var inner_scopes = [];
|
||||
self.walk(new TreeWalker(function(node, descend) {
|
||||
if (!result) return true;
|
||||
if (node instanceof AST_Catch) {
|
||||
inner_scopes.push(node.argname.scope);
|
||||
descend();
|
||||
inner_scopes.pop();
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Scope && node !== self) {
|
||||
inner_scopes.push(node);
|
||||
descend();
|
||||
inner_scopes.pop();
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
if (self.inlined) {
|
||||
result = false;
|
||||
return true;
|
||||
}
|
||||
var def = node.definition();
|
||||
if (member(def, self.enclosed)
|
||||
&& !self.variables.has(def.name)) {
|
||||
if (!self.variables.has(def.name) && !member(def.scope, inner_scopes)) {
|
||||
if (scope) {
|
||||
var scope_def = scope.find_variable(node);
|
||||
if (def.undeclared ? !scope_def : scope_def === def) {
|
||||
@@ -4055,10 +4068,11 @@ merge(Compressor.prototype, {
|
||||
var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
|
||||
var defs_by_id = Object.create(null);
|
||||
self.transform(new TreeTransformer(function(node, descend) {
|
||||
if (node instanceof AST_Assign
|
||||
&& node.operator == "="
|
||||
&& node.write_only
|
||||
&& can_hoist(node.left, node.right, 1)) {
|
||||
if (node instanceof AST_Assign) {
|
||||
if (node.operator != "=") return;
|
||||
if (!node.write_only) return;
|
||||
if (node.left.scope !== self) return;
|
||||
if (!can_hoist(node.left, node.right, 1)) return;
|
||||
descend(node, this);
|
||||
var defs = new Dictionary();
|
||||
var assignments = [];
|
||||
@@ -4087,17 +4101,9 @@ merge(Compressor.prototype, {
|
||||
}));
|
||||
return make_sequence(node, assignments);
|
||||
}
|
||||
if (node instanceof AST_Unary
|
||||
&& !unary_side_effects[node.operator]
|
||||
&& node.expression instanceof AST_SymbolRef
|
||||
&& node.expression.definition().id in defs_by_id) {
|
||||
node = node.clone();
|
||||
node.expression = make_node(AST_Object, node, {
|
||||
properties: []
|
||||
});
|
||||
return node;
|
||||
}
|
||||
if (node instanceof AST_VarDef && can_hoist(node.name, node.value, 0)) {
|
||||
if (node instanceof AST_Scope) return node === self ? undefined : node;
|
||||
if (node instanceof AST_VarDef) {
|
||||
if (!can_hoist(node.name, node.value, 0)) return;
|
||||
descend(node, this);
|
||||
var defs = new Dictionary();
|
||||
var var_defs = [];
|
||||
@@ -4110,32 +4116,6 @@ merge(Compressor.prototype, {
|
||||
defs_by_id[node.name.definition().id] = defs;
|
||||
return MAP.splice(var_defs);
|
||||
}
|
||||
if (node instanceof AST_PropAccess && node.expression instanceof AST_SymbolRef) {
|
||||
var defs = defs_by_id[node.expression.definition().id];
|
||||
if (defs) {
|
||||
var def = defs.get(node.getProperty());
|
||||
var sym = make_node(AST_SymbolRef, node, {
|
||||
name: def.name,
|
||||
scope: node.expression.scope,
|
||||
thedef: def
|
||||
});
|
||||
sym.reference({});
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
|
||||
function can_hoist(sym, right, count) {
|
||||
if (sym.scope !== self) return;
|
||||
var def = sym.definition();
|
||||
if (def.assignments != count) return;
|
||||
if (def.direct_access) return;
|
||||
if (def.escaped.depth == 1) return;
|
||||
if (def.references.length == count) return;
|
||||
if (def.single_use) return;
|
||||
if (top_retain(def)) return;
|
||||
if (sym.fixed_value() !== right) return;
|
||||
return right instanceof AST_Object;
|
||||
}
|
||||
|
||||
function make_sym(sym, key) {
|
||||
var new_var = make_node(AST_SymbolVar, sym, {
|
||||
@@ -4148,6 +4128,43 @@ merge(Compressor.prototype, {
|
||||
return new_var;
|
||||
}
|
||||
}));
|
||||
self.transform(new TreeTransformer(function(node, descend) {
|
||||
if (node instanceof AST_PropAccess) {
|
||||
if (!(node.expression instanceof AST_SymbolRef)) return;
|
||||
var defs = defs_by_id[node.expression.definition().id];
|
||||
if (!defs) return;
|
||||
var def = defs.get(node.getProperty());
|
||||
var sym = make_node(AST_SymbolRef, node, {
|
||||
name: def.name,
|
||||
scope: node.expression.scope,
|
||||
thedef: def
|
||||
});
|
||||
sym.reference({});
|
||||
return sym;
|
||||
}
|
||||
if (node instanceof AST_Unary) {
|
||||
if (unary_side_effects[node.operator]) return;
|
||||
if (!(node.expression instanceof AST_SymbolRef)) return;
|
||||
if (!(node.expression.definition().id in defs_by_id)) return;
|
||||
var opt = node.clone();
|
||||
opt.expression = make_node(AST_Object, node, {
|
||||
properties: []
|
||||
});
|
||||
return opt;
|
||||
}
|
||||
}));
|
||||
|
||||
function can_hoist(sym, right, count) {
|
||||
var def = sym.definition();
|
||||
if (def.assignments != count) return;
|
||||
if (def.direct_access) return;
|
||||
if (def.escaped.depth == 1) return;
|
||||
if (def.references.length == count) return;
|
||||
if (def.single_use) return;
|
||||
if (top_retain(def)) return;
|
||||
if (sym.fixed_value() !== right) return;
|
||||
return right instanceof AST_Object;
|
||||
}
|
||||
});
|
||||
|
||||
// drop_side_effect_free()
|
||||
@@ -5220,25 +5237,26 @@ merge(Compressor.prototype, {
|
||||
return return_value(stat);
|
||||
}
|
||||
|
||||
function var_exists(catches, name) {
|
||||
return catches[name] || identifier_atom[name] || scope.var_names()[name];
|
||||
function var_exists(defined, name) {
|
||||
return defined[name] || identifier_atom[name] || scope.var_names()[name];
|
||||
}
|
||||
|
||||
function can_inject_args(catches, safe_to_inject) {
|
||||
function can_inject_args(catches, used, safe_to_inject) {
|
||||
for (var i = 0; i < fn.argnames.length; i++) {
|
||||
var arg = fn.argnames[i];
|
||||
if (arg.__unused) continue;
|
||||
if (!safe_to_inject || var_exists(catches, arg.name)) return false;
|
||||
used[arg.name] = true;
|
||||
if (in_loop) in_loop.push(arg.definition());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function can_inject_vars(catches, safe_to_inject) {
|
||||
function can_inject_vars(catches, used, safe_to_inject) {
|
||||
for (var i = 0; i < fn.body.length; i++) {
|
||||
var stat = fn.body[i];
|
||||
if (stat instanceof AST_Defun) {
|
||||
if (!safe_to_inject || var_exists(catches, stat.name.name)) return false;
|
||||
if (!safe_to_inject || var_exists(used, stat.name.name)) return false;
|
||||
continue;
|
||||
}
|
||||
if (!(stat instanceof AST_Var)) continue;
|
||||
@@ -5267,8 +5285,9 @@ merge(Compressor.prototype, {
|
||||
var safe_to_inject = (!(scope instanceof AST_Toplevel) || compressor.toplevel.vars)
|
||||
&& (exp !== fn || fn.parent_scope === compressor.find_parent(AST_Scope));
|
||||
var inline = compressor.option("inline");
|
||||
if (!can_inject_vars(catches, inline >= 3 && safe_to_inject)) return false;
|
||||
if (!can_inject_args(catches, inline >= 2 && safe_to_inject)) return false;
|
||||
var used = Object.create(catches);
|
||||
if (!can_inject_args(catches, used, inline >= 2 && safe_to_inject)) return false;
|
||||
if (!can_inject_vars(catches, used, inline >= 3 && safe_to_inject)) return false;
|
||||
return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop);
|
||||
}
|
||||
|
||||
@@ -5677,7 +5696,8 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
|
||||
var in_bool = compressor.option("booleans") && compressor.in_boolean_context();
|
||||
if (in_bool) switch (self.operator) {
|
||||
case "+":
|
||||
var ll = self.left.evaluate(compressor);
|
||||
var rr = self.right.evaluate(compressor);
|
||||
@@ -5710,9 +5730,9 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
break;
|
||||
}
|
||||
var parent = compressor.parent();
|
||||
if (compressor.option("comparisons") && self.is_boolean(compressor)) {
|
||||
if (!(compressor.parent() instanceof AST_Binary)
|
||||
|| compressor.parent() instanceof AST_Assign) {
|
||||
if (!(parent instanceof AST_Binary) || parent instanceof AST_Assign) {
|
||||
var negated = make_node(AST_UnaryPrefix, self, {
|
||||
operator: "!",
|
||||
expression: self.negate(compressor, first_in_statement(compressor))
|
||||
@@ -5750,14 +5770,14 @@ merge(Compressor.prototype, {
|
||||
var ll = fuzzy_eval(self.left);
|
||||
if (!ll) {
|
||||
AST_Node.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
|
||||
return maintain_this_binding(compressor, compressor.parent(), compressor.self(), self.left).optimize(compressor);
|
||||
return maintain_this_binding(compressor, parent, compressor.self(), self.left).optimize(compressor);
|
||||
} else if (!(ll instanceof AST_Node)) {
|
||||
AST_Node.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
|
||||
return make_sequence(self, [ self.left, self.right ]).optimize(compressor);
|
||||
}
|
||||
var rr = self.right.evaluate(compressor);
|
||||
if (!rr) {
|
||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||
if (in_bool) {
|
||||
AST_Node.warn("Boolean && always false [{file}:{line},{col}]", self.start);
|
||||
return make_sequence(self, [
|
||||
self.left,
|
||||
@@ -5765,9 +5785,7 @@ merge(Compressor.prototype, {
|
||||
]).optimize(compressor);
|
||||
} else self.falsy = true;
|
||||
} else if (!(rr instanceof AST_Node)) {
|
||||
var parent = compressor.parent();
|
||||
if (parent.operator == "&&" && parent.left === compressor.self()
|
||||
|| compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||
if (in_bool || parent.operator == "&&" && parent.left === compressor.self()) {
|
||||
AST_Node.warn("Dropping side-effect-free && [{file}:{line},{col}]", self.start);
|
||||
return self.left.optimize(compressor);
|
||||
}
|
||||
@@ -5789,18 +5807,16 @@ merge(Compressor.prototype, {
|
||||
return make_sequence(self, [ self.left, self.right ]).optimize(compressor);
|
||||
} else if (!(ll instanceof AST_Node)) {
|
||||
AST_Node.warn("Condition left of || always true [{file}:{line},{col}]", self.start);
|
||||
return maintain_this_binding(compressor, compressor.parent(), compressor.self(), self.left).optimize(compressor);
|
||||
return maintain_this_binding(compressor, parent, compressor.self(), self.left).optimize(compressor);
|
||||
}
|
||||
var rr = self.right.evaluate(compressor);
|
||||
if (!rr) {
|
||||
var parent = compressor.parent();
|
||||
if (parent.operator == "||" && parent.left === compressor.self()
|
||||
|| compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||
if (in_bool || parent.operator == "||" && parent.left === compressor.self()) {
|
||||
AST_Node.warn("Dropping side-effect-free || [{file}:{line},{col}]", self.start);
|
||||
return self.left.optimize(compressor);
|
||||
}
|
||||
} else if (!(rr instanceof AST_Node)) {
|
||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||
if (in_bool) {
|
||||
AST_Node.warn("Boolean || always true [{file}:{line},{col}]", self.start);
|
||||
return make_sequence(self, [
|
||||
self.left,
|
||||
@@ -5998,12 +6014,11 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (compressor.option("unsafe")) {
|
||||
var indexRight = is_indexFn(self.right);
|
||||
if (compressor.option("booleans")
|
||||
if (in_bool
|
||||
&& indexRight
|
||||
&& (self.operator == "==" || self.operator == "!=")
|
||||
&& self.left instanceof AST_Number
|
||||
&& self.left.getValue() == 0
|
||||
&& compressor.in_boolean_context()) {
|
||||
&& self.left.getValue() == 0) {
|
||||
return (self.operator == "==" ? make_node(AST_UnaryPrefix, self, {
|
||||
operator: "!",
|
||||
expression: self.right
|
||||
|
||||
@@ -1,19 +1,39 @@
|
||||
"use strict";
|
||||
|
||||
var to_ascii = typeof atob == "undefined" ? function(b64) {
|
||||
return new Buffer(b64, "base64").toString();
|
||||
} : atob;
|
||||
var to_base64 = typeof btoa == "undefined" ? function(str) {
|
||||
return new Buffer(str).toString("base64");
|
||||
} : btoa;
|
||||
var to_ascii, to_base64;
|
||||
if (typeof Buffer == "undefined") {
|
||||
to_ascii = atob;
|
||||
to_base64 = btoa;
|
||||
} else if (typeof Buffer.alloc == "undefined") {
|
||||
to_ascii = function(b64) {
|
||||
return new Buffer(b64, "base64").toString();
|
||||
};
|
||||
to_base64 = function(str) {
|
||||
return new Buffer(str).toString("base64");
|
||||
};
|
||||
} else {
|
||||
to_ascii = function(b64) {
|
||||
return Buffer.from(b64, "base64").toString();
|
||||
};
|
||||
to_base64 = function(str) {
|
||||
return Buffer.from(str).toString("base64");
|
||||
};
|
||||
}
|
||||
|
||||
function read_source_map(name, code) {
|
||||
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(\S+)\s*$/.exec(code);
|
||||
if (!match) {
|
||||
AST_Node.warn("inline source map not found: " + name);
|
||||
return null;
|
||||
function read_source_map(name, toplevel) {
|
||||
var comments = toplevel.end.comments_after;
|
||||
for (var i = comments.length; --i >= 0;) {
|
||||
var comment = comments[i];
|
||||
if (comment.type != "comment1") break;
|
||||
var match = /^# ([^\s=]+)=(\S+)\s*$/.exec(comment.value);
|
||||
if (!match) break;
|
||||
if (match[1] == "sourceMappingURL") {
|
||||
match = /^data:application\/json(;.*?)?;base64,(\S+)$/.exec(match[2]);
|
||||
if (!match) break;
|
||||
return to_ascii(match[2]);
|
||||
}
|
||||
}
|
||||
return to_ascii(match[2]);
|
||||
AST_Node.warn("inline source map not found: " + name);
|
||||
}
|
||||
|
||||
function parse_source_map(content) {
|
||||
@@ -134,10 +154,10 @@ function minify(files, options) {
|
||||
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);
|
||||
options.parse.toplevel = toplevel = parse(files[name], options.parse);
|
||||
if (source_maps) {
|
||||
if (source_map_content == "inline") {
|
||||
var inlined_content = read_source_map(name, files[name]);
|
||||
var inlined_content = read_source_map(name, toplevel);
|
||||
if (inlined_content) {
|
||||
source_maps[name] = parse_source_map(inlined_content);
|
||||
}
|
||||
@@ -146,7 +166,6 @@ function minify(files, options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
toplevel = options.parse.toplevel;
|
||||
}
|
||||
if (quoted_props) {
|
||||
reserve_quoted_keys(toplevel, quoted_props);
|
||||
|
||||
@@ -136,8 +136,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) {
|
||||
str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s, i) {
|
||||
switch (s) {
|
||||
case '"': ++dq; return '"';
|
||||
case "'": ++sq; return "'";
|
||||
@@ -599,7 +598,6 @@ function OutputStream(options) {
|
||||
}
|
||||
print(encoded);
|
||||
},
|
||||
encode_string : encode_string,
|
||||
next_indent : next_indent,
|
||||
with_indent : with_indent,
|
||||
with_block : with_block,
|
||||
@@ -1383,8 +1381,27 @@ function OutputStream(options) {
|
||||
if (regexp.raw_source) {
|
||||
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
|
||||
}
|
||||
str = output.to_utf8(str);
|
||||
output.print(str);
|
||||
output.print(output.to_utf8(str).replace(/\\(?:\0(?![0-9])|[^\0])/g, function(seq) {
|
||||
switch (seq[1]) {
|
||||
case "\n": return "\\n";
|
||||
case "\r": return "\\r";
|
||||
case "\t": return "\t";
|
||||
case "\b": return "\b";
|
||||
case "\f": return "\f";
|
||||
case "\0": return "\0";
|
||||
case "\x0B": return "\v";
|
||||
case "\u2028": return "\\u2028";
|
||||
case "\u2029": return "\\u2029";
|
||||
default: return seq;
|
||||
}
|
||||
}).replace(/[\n\r\u2028\u2029]/g, function(c) {
|
||||
switch (c) {
|
||||
case "\n": return "\\n";
|
||||
case "\r": return "\\r";
|
||||
case "\u2028": return "\\u2028";
|
||||
case "\u2029": return "\\u2029";
|
||||
}
|
||||
}));
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
||||
output.print(" ");
|
||||
|
||||
@@ -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.6.0",
|
||||
"version": "3.6.2",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
@@ -23,12 +23,12 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "~2.20.0",
|
||||
"commander": "2.20.0",
|
||||
"source-map": "~0.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"acorn": "~6.1.1",
|
||||
"semver": "~6.0.0"
|
||||
"acorn": "~7.1.0",
|
||||
"semver": "~6.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node test/compress.js && node test/mocha.js"
|
||||
|
||||
@@ -13,15 +13,15 @@ if (!args.length) {
|
||||
}
|
||||
args.push("--timings");
|
||||
var urls = [
|
||||
"https://code.jquery.com/jquery-3.2.1.js",
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.js",
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js",
|
||||
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js",
|
||||
"https://code.jquery.com/jquery-3.4.1.js",
|
||||
"https://code.angularjs.org/1.7.8/angular.js",
|
||||
"https://unpkg.com/mathjs@6.2.3/dist/math.js",
|
||||
"https://unpkg.com/react@15.3.2/dist/react.js",
|
||||
"http://builds.emberjs.com/tags/v2.11.0/ember.prod.js",
|
||||
"https://cdn.jsdelivr.net/lodash/4.17.4/lodash.js",
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.js",
|
||||
"https://raw.githubusercontent.com/kangax/html-minifier/v3.5.7/dist/htmlminifier.js",
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.js",
|
||||
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js",
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js",
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.12.2/ember.prod.js",
|
||||
"https://raw.githubusercontent.com/kangax/html-minifier/v4.0.0/dist/htmlminifier.js",
|
||||
];
|
||||
var results = {};
|
||||
var remaining = 2 * urls.length;
|
||||
@@ -94,3 +94,6 @@ urls.forEach(function(url) {
|
||||
});
|
||||
});
|
||||
});
|
||||
setInterval(function() {
|
||||
process.stderr.write("\0");
|
||||
}, 5 * 60 * 1000).unref();
|
||||
|
||||
88
test/compress/booleans.js
Normal file
88
test/compress/booleans.js
Normal file
@@ -0,0 +1,88 @@
|
||||
iife_boolean_context: {
|
||||
options = {
|
||||
booleans: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function() {
|
||||
return Object(1) || false;
|
||||
}() ? "PASS" : "FAIL");
|
||||
console.log(function() {
|
||||
return [].length || true;
|
||||
}() ? "PASS" : "FAIL");
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
return Object(1);
|
||||
}() ? "PASS" : "FAIL");
|
||||
console.log(function() {
|
||||
return [].length, 1;
|
||||
}() ? "PASS" : "FAIL");
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
expect_warnings: [
|
||||
"WARN: Dropping side-effect-free || [test/compress/booleans.js:2,19]",
|
||||
"WARN: Boolean || always true [test/compress/booleans.js:5,19]",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3465_1: {
|
||||
options = {
|
||||
booleans: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
return typeof a;
|
||||
}() ? "PASS" : "FAIL");
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return 1;
|
||||
}() ? "PASS" : "FAIL");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3465_2: {
|
||||
options = {
|
||||
booleans: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f(a) {
|
||||
if (!a) console.log(f(42));
|
||||
return typeof a;
|
||||
}() ? "PASS" : "FAIL");
|
||||
}
|
||||
expect: {
|
||||
console.log(function f(a) {
|
||||
if (!a) console.log(f(42));
|
||||
return typeof a;
|
||||
}() ? "PASS" : "FAIL");
|
||||
}
|
||||
expect_stdout: [
|
||||
"number",
|
||||
"PASS",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3465_3: {
|
||||
options = {
|
||||
booleans: true,
|
||||
passes: 2,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f(a) {
|
||||
return typeof a;
|
||||
}() ? "PASS" : "FAIL");
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
return 1;
|
||||
}() ? "PASS" : "FAIL");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
@@ -6197,3 +6197,43 @@ Infinity_assignment: {
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_3439_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function(a) {
|
||||
function a() {}
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function(a) {
|
||||
function a() {}
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_3439_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function() {
|
||||
var a = 42;
|
||||
function a() {}
|
||||
return a;
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function() {
|
||||
return 42;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "number"
|
||||
}
|
||||
|
||||
@@ -3148,3 +3148,51 @@ issue_3402: {
|
||||
"function",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3439: {
|
||||
options = {
|
||||
inline: true,
|
||||
}
|
||||
input: {
|
||||
console.log(typeof function() {
|
||||
return function(a) {
|
||||
function a() {}
|
||||
return a;
|
||||
}(42);
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
console.log(typeof function(a) {
|
||||
function a() {}
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_3444: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(h) {
|
||||
return f;
|
||||
function f() {
|
||||
g();
|
||||
}
|
||||
function g() {
|
||||
h("PASS");
|
||||
}
|
||||
})(console.log)();
|
||||
}
|
||||
expect: {
|
||||
(function(h) {
|
||||
return function() {
|
||||
void h("PASS");
|
||||
};
|
||||
})(console.log)();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -886,3 +886,31 @@ issue_3411: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3440: {
|
||||
options = {
|
||||
hoist_props: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
function f() {
|
||||
console.log(o.p);
|
||||
}
|
||||
var o = {
|
||||
p: "PASS",
|
||||
};
|
||||
return f;
|
||||
})()();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var o_p = "PASS";
|
||||
return function() {
|
||||
console.log(o_p);
|
||||
};
|
||||
})()();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -35,3 +35,140 @@ regexp_2: {
|
||||
}
|
||||
expect_stdout: '["PASS","pass"]'
|
||||
}
|
||||
|
||||
issue_3434_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
"\n": RegExp("\n"),
|
||||
"\r": RegExp("\r"),
|
||||
"\t": RegExp("\t"),
|
||||
"\b": RegExp("\b"),
|
||||
"\f": RegExp("\f"),
|
||||
"\0": RegExp("\0"),
|
||||
"\x0B": RegExp("\x0B"),
|
||||
"\u2028": RegExp("\u2028"),
|
||||
"\u2029": RegExp("\u2029"),
|
||||
};
|
||||
for (var c in o)
|
||||
console.log(o[c].test("\\"), o[c].test(c));
|
||||
}
|
||||
expect_exact: [
|
||||
"var o = {",
|
||||
' "\\n": /\\n/,',
|
||||
' "\\r": /\\r/,',
|
||||
' "\\t": /\t/,',
|
||||
' "\\b": /\b/,',
|
||||
' "\\f": /\f/,',
|
||||
' "\\0": /\0/,',
|
||||
' "\\v": /\v/,',
|
||||
' "\\u2028": /\\u2028/,',
|
||||
' "\\u2029": /\\u2029/',
|
||||
"};",
|
||||
"",
|
||||
'for (var c in o) console.log(o[c].test("\\\\"), o[c].test(c));',
|
||||
]
|
||||
expect_stdout: [
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3434_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
beautify = {
|
||||
beautify: true,
|
||||
}
|
||||
input: {
|
||||
var o = {
|
||||
"\n": RegExp("\\\n"),
|
||||
"\r": RegExp("\\\r"),
|
||||
"\t": RegExp("\\\t"),
|
||||
"\b": RegExp("\\\b"),
|
||||
"\f": RegExp("\\\f"),
|
||||
"\0": RegExp("\\\0"),
|
||||
"\x0B": RegExp("\\\x0B"),
|
||||
"\u2028": RegExp("\\\u2028"),
|
||||
"\u2029": RegExp("\\\u2029"),
|
||||
};
|
||||
for (var c in o)
|
||||
console.log(o[c].test("\\"), o[c].test(c));
|
||||
}
|
||||
expect_exact: [
|
||||
"var o = {",
|
||||
' "\\n": /\\n/,',
|
||||
' "\\r": /\\r/,',
|
||||
' "\\t": /\t/,',
|
||||
' "\\b": /\b/,',
|
||||
' "\\f": /\f/,',
|
||||
' "\\0": /\0/,',
|
||||
' "\\v": /\v/,',
|
||||
' "\\u2028": /\\u2028/,',
|
||||
' "\\u2029": /\\u2029/',
|
||||
"};",
|
||||
"",
|
||||
'for (var c in o) console.log(o[c].test("\\\\"), o[c].test(c));',
|
||||
]
|
||||
expect_stdout: [
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
"false true",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3434_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
RegExp("\n");
|
||||
RegExp("\r");
|
||||
RegExp("\\n");
|
||||
RegExp("\\\n");
|
||||
RegExp("\\\\n");
|
||||
RegExp("\\\\\n");
|
||||
RegExp("\\\\\\n");
|
||||
RegExp("\\\\\\\n");
|
||||
RegExp("\u2028");
|
||||
RegExp("\u2029");
|
||||
RegExp("\n\r\u2028\u2029");
|
||||
RegExp("\\\nfo\n[\n]o\\bbb");
|
||||
}
|
||||
expect: {
|
||||
/\n/;
|
||||
/\r/;
|
||||
/\n/;
|
||||
/\n/;
|
||||
/\\n/;
|
||||
/\\\n/;
|
||||
/\\\n/;
|
||||
/\\\n/;
|
||||
/\u2028/;
|
||||
/\u2029/;
|
||||
/\n\r\u2028\u2029/;
|
||||
/\nfo\n[\n]o\bbb/;
|
||||
}
|
||||
}
|
||||
|
||||
8
test/input/issue-3441/input.js
Normal file
8
test/input/issue-3441/input.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Generated by CoffeeScript 2.4.1
|
||||
(function() {
|
||||
console.log('hello');
|
||||
|
||||
}).call(this);
|
||||
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm1haW4uY29mZmVlIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTtFQUFBLE9BQU8sQ0FBQyxHQUFSLENBQVksT0FBWjtBQUFBIiwic291cmNlc0NvbnRlbnQiOlsiY29uc29sZS5sb2cgJ2hlbGxvJ1xuIl19
|
||||
//# sourceURL=/Users/mohamed/Downloads/main.coffee
|
||||
@@ -181,6 +181,18 @@ describe("sourcemaps", function() {
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-3294/output.js", "utf8"));
|
||||
});
|
||||
it("Should work in presence of unrecognised annotations", function() {
|
||||
var result = UglifyJS.minify(read("./test/input/issue-3441/input.js"), {
|
||||
compress: false,
|
||||
mangle: false,
|
||||
sourceMap: {
|
||||
content: "inline",
|
||||
},
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, '(function(){console.log("hello")}).call(this);');
|
||||
assert.strictEqual(result.map, '{"version":3,"sources":["main.coffee"],"names":["console","log"],"mappings":"CAAA,WAAAA,QAAQC,IAAI"}');
|
||||
});
|
||||
});
|
||||
|
||||
describe("sourceMapInline", function() {
|
||||
|
||||
@@ -15,7 +15,7 @@ if (process.argv[2] == "run") {
|
||||
var branch = process.argv[3] || "v" + require("../package.json").version;
|
||||
var repository = encodeURIComponent(process.argv[4] || "mishoo/UglifyJS2");
|
||||
var concurrency = process.argv[5] || 1;
|
||||
var platform = process.argv[6] || "node/latest";
|
||||
var platform = process.argv[6] || "latest";
|
||||
(function request() {
|
||||
setTimeout(request, (period + wait) / concurrency);
|
||||
var options = url.parse("https://api.travis-ci.org/repo/" + repository + "/requests");
|
||||
@@ -37,7 +37,7 @@ if (process.argv[2] == "run") {
|
||||
branch: branch,
|
||||
config: {
|
||||
cache: false,
|
||||
env: "NODEJS_VER=" + platform,
|
||||
env: "NODE=" + platform,
|
||||
script: "node test/travis-ufuzz run"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,12 +960,12 @@ if (require.main !== module) {
|
||||
}
|
||||
|
||||
function println(msg) {
|
||||
if (typeof msg != "undefined") process.stdout.write(msg);
|
||||
if (typeof msg != "undefined") process.stdout.write(typeof msg == "string" ? msg : msg.stack);
|
||||
process.stdout.write("\n");
|
||||
}
|
||||
|
||||
function errorln(msg) {
|
||||
if (typeof msg != "undefined") process.stderr.write(msg);
|
||||
if (typeof msg != "undefined") process.stderr.write(typeof msg == "string" ? msg : msg.stack);
|
||||
process.stderr.write("\n");
|
||||
}
|
||||
|
||||
@@ -980,7 +980,7 @@ function try_beautify(code, toplevel, result, printfn) {
|
||||
});
|
||||
if (beautified.error) {
|
||||
printfn("// !!! beautify failed !!!");
|
||||
printfn(beautified.error.stack);
|
||||
printfn(beautified.error);
|
||||
} else if (sandbox.same_stdout(sandbox.run_code(beautified.code, toplevel), result)) {
|
||||
printfn("// (beautified)");
|
||||
printfn(beautified.code);
|
||||
@@ -1007,7 +1007,7 @@ function log_suspects(minify_options, component) {
|
||||
var result = UglifyJS.minify(original_code, m);
|
||||
if (result.error) {
|
||||
errorln("Error testing options." + component + "." + name);
|
||||
errorln(result.error.stack);
|
||||
errorln(result.error);
|
||||
} else {
|
||||
var r = sandbox.run_code(result.code, m.toplevel);
|
||||
return sandbox.same_stdout(original_result, r);
|
||||
@@ -1029,7 +1029,7 @@ function log_rename(options) {
|
||||
var result = UglifyJS.minify(original_code, m);
|
||||
if (result.error) {
|
||||
errorln("Error testing options.rename");
|
||||
errorln(result.error.stack);
|
||||
errorln(result.error);
|
||||
} else {
|
||||
var r = sandbox.run_code(result.code, m.toplevel);
|
||||
if (sandbox.same_stdout(original_result, r)) {
|
||||
@@ -1056,17 +1056,17 @@ function log(options) {
|
||||
errorln();
|
||||
errorln();
|
||||
errorln("original result:");
|
||||
errorln(errored ? original_result.stack : original_result);
|
||||
errorln(original_result);
|
||||
errorln("uglified result:");
|
||||
errorln(typeof uglify_result == "string" ? uglify_result : uglify_result.stack);
|
||||
errorln(uglify_result);
|
||||
} else {
|
||||
errorln("// !!! uglify failed !!!");
|
||||
errorln(uglify_code.stack);
|
||||
errorln(uglify_code);
|
||||
if (errored) {
|
||||
errorln();
|
||||
errorln();
|
||||
errorln("original stacktrace:");
|
||||
errorln(original_result.stack);
|
||||
errorln(original_result);
|
||||
}
|
||||
}
|
||||
errorln("minify(options):");
|
||||
@@ -1115,7 +1115,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
println();
|
||||
println();
|
||||
println("original result:");
|
||||
println(original_result.stack);
|
||||
println(original_result);
|
||||
println();
|
||||
}
|
||||
if (!ok && isFinite(num_iterations)) {
|
||||
|
||||
@@ -2993,6 +2993,7 @@
|
||||
"caption",
|
||||
"caption-side",
|
||||
"captionSide",
|
||||
"capture",
|
||||
"captureEvents",
|
||||
"captureStackTrace",
|
||||
"captureStream",
|
||||
@@ -4957,6 +4958,7 @@
|
||||
"oncandidatewindowupdate",
|
||||
"oncanplay",
|
||||
"oncanplaythrough",
|
||||
"once",
|
||||
"oncellchange",
|
||||
"onchange",
|
||||
"onchargingchange",
|
||||
@@ -5343,6 +5345,7 @@
|
||||
"parseInt",
|
||||
"part",
|
||||
"participants",
|
||||
"passive",
|
||||
"password",
|
||||
"pasteHTML",
|
||||
"path",
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
var fs = require("fs");
|
||||
|
||||
exports.FILES = [
|
||||
"../lib/utils.js",
|
||||
"../lib/ast.js",
|
||||
"../lib/parse.js",
|
||||
"../lib/transform.js",
|
||||
"../lib/scope.js",
|
||||
"../lib/output.js",
|
||||
"../lib/compress.js",
|
||||
"../lib/sourcemap.js",
|
||||
"../lib/mozilla-ast.js",
|
||||
"../lib/propmangle.js",
|
||||
"../lib/minify.js",
|
||||
"./exports.js",
|
||||
].map(function(file) {
|
||||
return require.resolve(file);
|
||||
});
|
||||
require.resolve("../lib/utils.js"),
|
||||
require.resolve("../lib/ast.js"),
|
||||
require.resolve("../lib/parse.js"),
|
||||
require.resolve("../lib/transform.js"),
|
||||
require.resolve("../lib/scope.js"),
|
||||
require.resolve("../lib/output.js"),
|
||||
require.resolve("../lib/compress.js"),
|
||||
require.resolve("../lib/sourcemap.js"),
|
||||
require.resolve("../lib/mozilla-ast.js"),
|
||||
require.resolve("../lib/propmangle.js"),
|
||||
require.resolve("../lib/minify.js"),
|
||||
require.resolve("./exports.js"),
|
||||
];
|
||||
|
||||
new Function("MOZ_SourceMap", "exports", function() {
|
||||
var code = exports.FILES.map(function(file) {
|
||||
@@ -48,7 +46,9 @@ function describe_ast() {
|
||||
if (ctor.SUBCLASSES.length > 0) {
|
||||
out.space();
|
||||
out.with_block(function() {
|
||||
ctor.SUBCLASSES.forEach(function(ctor, i) {
|
||||
ctor.SUBCLASSES.sort(function(a, b) {
|
||||
return a.TYPE < b.TYPE ? -1 : 1;
|
||||
}).forEach(function(ctor, i) {
|
||||
out.indent();
|
||||
doitem(ctor);
|
||||
out.newline();
|
||||
|
||||
Reference in New Issue
Block a user