Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08514030f4 | ||
|
|
694ca5d045 | ||
|
|
57fb58b263 | ||
|
|
18c1c9b38a | ||
|
|
5c1ae3662d | ||
|
|
cfebeb2f63 | ||
|
|
fc78423f1d | ||
|
|
2a5277b391 | ||
|
|
d47547dc71 | ||
|
|
304db15a20 | ||
|
|
7cf72b8d66 | ||
|
|
cea685f8d9 | ||
|
|
8d4b5344f4 | ||
|
|
34a0ab6f2c | ||
|
|
bcebacbb9e |
@@ -857,8 +857,8 @@ can pass additional arguments that control the code output:
|
|||||||
adjust for this text. Can be used to insert a comment containing
|
adjust for this text. Can be used to insert a comment containing
|
||||||
licensing information, for example.
|
licensing information, for example.
|
||||||
|
|
||||||
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
|
- `preserve_line` (default `false`) -- pass `true` to retain line numbering on
|
||||||
only works if `beautify` is set to `false`.
|
a best effort basis.
|
||||||
|
|
||||||
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
||||||
objects
|
objects
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ if (program.mangleProps) {
|
|||||||
if (typeof program.mangleProps != "object") program.mangleProps = {};
|
if (typeof program.mangleProps != "object") program.mangleProps = {};
|
||||||
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
|
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
|
||||||
require("../tools/domprops").forEach(function(name) {
|
require("../tools/domprops").forEach(function(name) {
|
||||||
UglifyJS._push_uniq(program.mangleProps.reserved, name);
|
UglifyJS.push_uniq(program.mangleProps.reserved, name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (typeof options.mangle != "object") options.mangle = {};
|
if (typeof options.mangle != "object") options.mangle = {};
|
||||||
|
|||||||
@@ -118,10 +118,8 @@ var AST_Node = DEFNODE("Node", "start end", {
|
|||||||
}
|
}
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
AST_Node.warn_function = null;
|
|
||||||
AST_Node.warn = function(txt, props) {
|
AST_Node.warn = function(txt, props) {
|
||||||
if (AST_Node.warn_function)
|
if (AST_Node.warn_function) AST_Node.warn_function(string_template(txt, props));
|
||||||
AST_Node.warn_function(string_template(txt, props));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -----[ statements ]----- */
|
/* -----[ statements ]----- */
|
||||||
@@ -207,8 +205,7 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
|||||||
var label = node.label;
|
var label = node.label;
|
||||||
var def = this.label;
|
var def = this.label;
|
||||||
node.walk(new TreeWalker(function(node) {
|
node.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_LoopControl
|
if (node instanceof AST_LoopControl && node.label && node.label.thedef === def) {
|
||||||
&& node.label && node.label.thedef === def) {
|
|
||||||
node.label.thedef = label;
|
node.label.thedef = label;
|
||||||
label.references.push(node);
|
label.references.push(node);
|
||||||
}
|
}
|
||||||
|
|||||||
324
lib/compress.js
324
lib/compress.js
@@ -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 : {},
|
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) {
|
||||||
@@ -149,6 +149,7 @@ merge(Compressor.prototype, {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
compress: function(node) {
|
compress: function(node) {
|
||||||
|
node = node.resolve_defines(this);
|
||||||
if (this.option("expression")) {
|
if (this.option("expression")) {
|
||||||
node.process_expression(true);
|
node.process_expression(true);
|
||||||
}
|
}
|
||||||
@@ -449,8 +450,7 @@ merge(Compressor.prototype, {
|
|||||||
return value instanceof AST_Node && def.fixed.parent_scope === scope;
|
return value instanceof AST_Node && def.fixed.parent_scope === scope;
|
||||||
}
|
}
|
||||||
return all(def.orig, function(sym) {
|
return all(def.orig, function(sym) {
|
||||||
return !(sym instanceof AST_SymbolDefun
|
return !(sym instanceof AST_SymbolDefun || sym instanceof AST_SymbolLambda);
|
||||||
|| sym instanceof AST_SymbolLambda);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1264,6 +1264,9 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_Exit) {
|
if (node instanceof AST_Exit) {
|
||||||
return side_effects || lhs instanceof AST_PropAccess || may_modify(lhs);
|
return side_effects || lhs instanceof AST_PropAccess || may_modify(lhs);
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Function) {
|
||||||
|
return compressor.option("ie8") && node.name && node.name.name in lvalues;
|
||||||
|
}
|
||||||
if (node instanceof AST_PropAccess) {
|
if (node instanceof AST_PropAccess) {
|
||||||
return side_effects || node.expression.may_throw_on_access(compressor);
|
return side_effects || node.expression.may_throw_on_access(compressor);
|
||||||
}
|
}
|
||||||
@@ -1610,10 +1613,7 @@ merge(Compressor.prototype, {
|
|||||||
if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) return false;
|
if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) return false;
|
||||||
if (def.scope !== scope) return true;
|
if (def.scope !== scope) return true;
|
||||||
return !all(def.references, function(ref) {
|
return !all(def.references, function(ref) {
|
||||||
var s = ref.scope;
|
return ref.scope.resolve() === scope;
|
||||||
// "block" scope within AST_Catch
|
|
||||||
if (s.TYPE == "Scope") s = s.parent_scope;
|
|
||||||
return s === scope;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1698,6 +1698,19 @@ merge(Compressor.prototype, {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ab && !stat.alternative && stat.body instanceof AST_BlockStatement && next instanceof AST_Jump) {
|
||||||
|
var negated = stat.condition.negate(compressor);
|
||||||
|
if (negated.print_to_string().length <= stat.condition.print_to_string().length) {
|
||||||
|
CHANGED = true;
|
||||||
|
stat = stat.clone();
|
||||||
|
stat.condition = negated;
|
||||||
|
statements[j] = stat.body;
|
||||||
|
stat.body = next;
|
||||||
|
statements[i] = stat.transform(compressor);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var ab = aborts(stat.alternative);
|
var ab = aborts(stat.alternative);
|
||||||
if (can_merge_flow(ab)) {
|
if (can_merge_flow(ab)) {
|
||||||
if (ab.label) {
|
if (ab.label) {
|
||||||
@@ -1999,7 +2012,7 @@ merge(Compressor.prototype, {
|
|||||||
statements.length = n;
|
statements.length = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
function join_object_assignments(defn, body) {
|
function join_assigns(defn, body) {
|
||||||
var exprs;
|
var exprs;
|
||||||
if (body instanceof AST_Assign) {
|
if (body instanceof AST_Assign) {
|
||||||
exprs = [ body ];
|
exprs = [ body ];
|
||||||
@@ -2009,7 +2022,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!exprs) return;
|
if (!exprs) return;
|
||||||
if (defn instanceof AST_Definitions) {
|
if (defn instanceof AST_Definitions) {
|
||||||
var def = defn.definitions[defn.definitions.length - 1];
|
var def = defn.definitions[defn.definitions.length - 1];
|
||||||
if (trim_object_assignments(def.name, def.value, exprs)) return exprs;
|
if (trim_assigns(def.name, def.value, exprs)) return exprs;
|
||||||
}
|
}
|
||||||
for (var i = exprs.length - 1; --i >= 0;) {
|
for (var i = exprs.length - 1; --i >= 0;) {
|
||||||
var expr = exprs[i];
|
var expr = exprs[i];
|
||||||
@@ -2017,12 +2030,12 @@ merge(Compressor.prototype, {
|
|||||||
if (expr.operator != "=") continue;
|
if (expr.operator != "=") continue;
|
||||||
if (!(expr.left instanceof AST_SymbolRef)) continue;
|
if (!(expr.left instanceof AST_SymbolRef)) continue;
|
||||||
var tail = exprs.slice(i + 1);
|
var tail = exprs.slice(i + 1);
|
||||||
if (!trim_object_assignments(expr.left, expr.right, tail)) continue;
|
if (!trim_assigns(expr.left, expr.right, tail)) continue;
|
||||||
return exprs.slice(0, i + 1).concat(tail);
|
return exprs.slice(0, i + 1).concat(tail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function trim_object_assignments(name, value, exprs) {
|
function trim_assigns(name, value, exprs) {
|
||||||
if (!(value instanceof AST_Object)) return;
|
if (!(value instanceof AST_Object)) return;
|
||||||
var trimmed = false;
|
var trimmed = false;
|
||||||
do {
|
do {
|
||||||
@@ -2073,9 +2086,9 @@ merge(Compressor.prototype, {
|
|||||||
defs = stat;
|
defs = stat;
|
||||||
}
|
}
|
||||||
} else if (stat instanceof AST_Exit) {
|
} else if (stat instanceof AST_Exit) {
|
||||||
stat.value = extract_object_assignments(stat.value);
|
stat.value = join_assigns_expr(stat.value);
|
||||||
} else if (stat instanceof AST_For) {
|
} else if (stat instanceof AST_For) {
|
||||||
var exprs = join_object_assignments(prev, stat.init);
|
var exprs = join_assigns(prev, stat.init);
|
||||||
if (exprs) {
|
if (exprs) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat.init = exprs.length ? make_sequence(stat.init, exprs) : null;
|
stat.init = exprs.length ? make_sequence(stat.init, exprs) : null;
|
||||||
@@ -2096,11 +2109,11 @@ merge(Compressor.prototype, {
|
|||||||
statements[++j] = stat;
|
statements[++j] = stat;
|
||||||
}
|
}
|
||||||
} else if (stat instanceof AST_ForIn) {
|
} else if (stat instanceof AST_ForIn) {
|
||||||
stat.object = extract_object_assignments(stat.object);
|
stat.object = join_assigns_expr(stat.object);
|
||||||
} else if (stat instanceof AST_If) {
|
} else if (stat instanceof AST_If) {
|
||||||
stat.condition = extract_object_assignments(stat.condition);
|
stat.condition = join_assigns_expr(stat.condition);
|
||||||
} else if (stat instanceof AST_SimpleStatement) {
|
} else if (stat instanceof AST_SimpleStatement) {
|
||||||
var exprs = join_object_assignments(prev, stat.body);
|
var exprs = join_assigns(prev, stat.body);
|
||||||
if (exprs) {
|
if (exprs) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
if (!exprs.length) continue;
|
if (!exprs.length) continue;
|
||||||
@@ -2108,29 +2121,23 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
statements[++j] = stat;
|
statements[++j] = stat;
|
||||||
} else if (stat instanceof AST_Switch) {
|
} else if (stat instanceof AST_Switch) {
|
||||||
stat.expression = extract_object_assignments(stat.expression);
|
stat.expression = join_assigns_expr(stat.expression);
|
||||||
} else if (stat instanceof AST_With) {
|
} else if (stat instanceof AST_With) {
|
||||||
stat.expression = extract_object_assignments(stat.expression);
|
stat.expression = join_assigns_expr(stat.expression);
|
||||||
} else {
|
} else {
|
||||||
statements[++j] = stat;
|
statements[++j] = stat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statements.length = j + 1;
|
statements.length = j + 1;
|
||||||
|
|
||||||
function extract_object_assignments(value) {
|
function join_assigns_expr(value) {
|
||||||
statements[++j] = stat;
|
statements[++j] = stat;
|
||||||
var exprs = join_object_assignments(prev, value);
|
var exprs = join_assigns(prev, value);
|
||||||
if (exprs) {
|
if (!exprs) return value;
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
if (exprs.length) {
|
var tail = value.tail_node();
|
||||||
return make_sequence(value, exprs);
|
if (exprs[exprs.length - 1] !== tail) exprs.push(tail.left);
|
||||||
} else if (value instanceof AST_Sequence) {
|
return make_sequence(value, exprs);
|
||||||
return value.tail_node().left;
|
|
||||||
} else {
|
|
||||||
return value.left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2410,22 +2417,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(function(def) {
|
(function(def) {
|
||||||
AST_Node.DEFMETHOD("resolve_defines", function(compressor) {
|
|
||||||
if (!compressor.option("global_defs")) return;
|
|
||||||
var def = this._find_defs(compressor, "");
|
|
||||||
if (def) {
|
|
||||||
var node, parent = this, level = 0;
|
|
||||||
do {
|
|
||||||
node = parent;
|
|
||||||
parent = compressor.parent(level++);
|
|
||||||
} while (parent instanceof AST_PropAccess && parent.expression === node);
|
|
||||||
if (is_lhs(node, parent)) {
|
|
||||||
compressor.warn('global_defs ' + this.print_to_string() + ' redefined [{file}:{line},{col}]', this.start);
|
|
||||||
} else {
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
function to_node(value, orig) {
|
function to_node(value, orig) {
|
||||||
if (value instanceof AST_Node) return make_node(value.CTOR, orig, value);
|
if (value instanceof AST_Node) return make_node(value.CTOR, orig, value);
|
||||||
if (Array.isArray(value)) return make_node(AST_Array, orig, {
|
if (Array.isArray(value)) return make_node(AST_Array, orig, {
|
||||||
@@ -2447,25 +2438,43 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return make_node_from_constant(value, orig);
|
return make_node_from_constant(value, orig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function warn(compressor, node) {
|
||||||
|
compressor.warn("global_defs " + node.print_to_string() + " redefined [{file}:{line},{col}]", node.start);
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_Toplevel.DEFMETHOD("resolve_defines", function(compressor) {
|
||||||
|
if (!compressor.option("global_defs")) return this;
|
||||||
|
this.figure_out_scope({ ie8: compressor.option("ie8") });
|
||||||
|
return this.transform(new TreeTransformer(function(node) {
|
||||||
|
var def = node._find_defs(compressor, "");
|
||||||
|
if (!def) return;
|
||||||
|
var level = 0, child = node, parent;
|
||||||
|
while (parent = this.parent(level++)) {
|
||||||
|
if (!(parent instanceof AST_PropAccess)) break;
|
||||||
|
if (parent.expression !== child) break;
|
||||||
|
child = parent;
|
||||||
|
}
|
||||||
|
if (is_lhs(child, parent)) {
|
||||||
|
warn(compressor, node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}));
|
||||||
|
});
|
||||||
def(AST_Node, noop);
|
def(AST_Node, noop);
|
||||||
def(AST_Dot, function(compressor, suffix) {
|
def(AST_Dot, function(compressor, suffix) {
|
||||||
return this.expression._find_defs(compressor, "." + this.property + suffix);
|
return this.expression._find_defs(compressor, "." + this.property + suffix);
|
||||||
});
|
});
|
||||||
|
def(AST_SymbolDeclaration, function(compressor) {
|
||||||
|
if (!this.global()) return;
|
||||||
|
if (HOP(compressor.option("global_defs"), this.name)) warn(compressor, this);
|
||||||
|
});
|
||||||
def(AST_SymbolRef, function(compressor, suffix) {
|
def(AST_SymbolRef, function(compressor, suffix) {
|
||||||
if (!this.global()) return;
|
if (!this.global()) return;
|
||||||
var name;
|
|
||||||
var defines = compressor.option("global_defs");
|
var defines = compressor.option("global_defs");
|
||||||
if (defines && HOP(defines, (name = this.name + suffix))) {
|
var name = this.name + suffix;
|
||||||
var node = to_node(defines[name], this);
|
if (HOP(defines, name)) return to_node(defines[name], this);
|
||||||
var top = compressor.find_parent(AST_Toplevel);
|
|
||||||
node.walk(new TreeWalker(function(node) {
|
|
||||||
if (node instanceof AST_SymbolRef) {
|
|
||||||
node.scope = top;
|
|
||||||
node.thedef = top.def_global(node);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
})(function(node, func) {
|
})(function(node, func) {
|
||||||
node.DEFMETHOD("_find_defs", func);
|
node.DEFMETHOD("_find_defs", func);
|
||||||
@@ -2704,35 +2713,30 @@ merge(Compressor.prototype, {
|
|||||||
if (right === this.right) return this;
|
if (right === this.right) return this;
|
||||||
var result;
|
var result;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "&&" : result = left && right; break;
|
case "&&" : result = left && right; break;
|
||||||
case "||" : result = left || right; break;
|
case "||" : result = left || right; break;
|
||||||
case "|" : result = left | right; break;
|
case "|" : result = left | right; break;
|
||||||
case "&" : result = left & right; break;
|
case "&" : result = left & right; break;
|
||||||
case "^" : result = left ^ right; break;
|
case "^" : result = left ^ right; break;
|
||||||
case "+" : result = left + right; break;
|
case "+" : result = left + right; break;
|
||||||
case "*" : result = left * right; break;
|
case "*" : result = left * right; break;
|
||||||
case "/" : result = left / right; break;
|
case "/" : result = left / right; break;
|
||||||
case "%" : result = left % right; break;
|
case "%" : result = left % right; break;
|
||||||
case "-" : result = left - right; break;
|
case "-" : result = left - right; break;
|
||||||
case "<<" : result = left << right; break;
|
case "<<" : result = left << right; break;
|
||||||
case ">>" : result = left >> right; break;
|
case ">>" : result = left >> right; break;
|
||||||
case ">>>" : result = left >>> right; break;
|
case ">>>": result = left >>> right; break;
|
||||||
case "==" : result = left == right; break;
|
case "==" : result = left == right; break;
|
||||||
case "===" : result = left === right; break;
|
case "===": result = left === right; break;
|
||||||
case "!=" : result = left != right; break;
|
case "!=" : result = left != right; break;
|
||||||
case "!==" : result = left !== right; break;
|
case "!==": result = left !== right; break;
|
||||||
case "<" : result = left < right; break;
|
case "<" : result = left < right; break;
|
||||||
case "<=" : result = left <= right; break;
|
case "<=" : result = left <= right; break;
|
||||||
case ">" : result = left > right; break;
|
case ">" : result = left > right; break;
|
||||||
case ">=" : result = left >= right; break;
|
case ">=" : result = left >= right; break;
|
||||||
default:
|
default : return this;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
if (isNaN(result) && compressor.find_parent(AST_With)) {
|
return isNaN(result) && compressor.find_parent(AST_With) ? this : result;
|
||||||
// leave original expression as is
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(compressor, cached, depth) {
|
def(AST_Conditional, function(compressor, cached, depth) {
|
||||||
var condition = this.condition._eval(compressor, cached, depth);
|
var condition = this.condition._eval(compressor, cached, depth);
|
||||||
@@ -3324,13 +3328,14 @@ merge(Compressor.prototype, {
|
|||||||
} else if (node instanceof AST_Unary && node.write_only) {
|
} else if (node instanceof AST_Unary && node.write_only) {
|
||||||
sym = node.expression;
|
sym = node.expression;
|
||||||
}
|
}
|
||||||
if (/strict/.test(compressor.option("pure_getters"))) {
|
if (!/strict/.test(compressor.option("pure_getters"))) return sym instanceof AST_SymbolRef && sym;
|
||||||
while (sym instanceof AST_PropAccess && !sym.expression.may_throw_on_access(compressor)) {
|
while (sym instanceof AST_PropAccess && !sym.expression.may_throw_on_access(compressor)) {
|
||||||
if (sym instanceof AST_Sub) props.unshift(sym.property);
|
if (sym instanceof AST_Sub) props.unshift(sym.property);
|
||||||
sym = sym.expression;
|
sym = sym.expression;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return sym;
|
return sym instanceof AST_SymbolRef && all(sym.definition().orig, function(sym) {
|
||||||
|
return !(sym instanceof AST_SymbolLambda);
|
||||||
|
}) && sym;
|
||||||
};
|
};
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
||||||
@@ -3412,12 +3417,20 @@ merge(Compressor.prototype, {
|
|||||||
init.walk(tw);
|
init.walk(tw);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
var drop_fn_name = compressor.option("keep_fnames") ? return_false : compressor.option("ie8") ? function(def) {
|
||||||
|
return !compressor.exposed(def) && !def.references.length;
|
||||||
|
} : function(def) {
|
||||||
|
// any declarations with same name will overshadow
|
||||||
|
// name of this anonymous function and can therefore
|
||||||
|
// never be used anywhere
|
||||||
|
return !(def.id in in_use_ids) || def.orig.length > 1;
|
||||||
|
};
|
||||||
// pass 3: we should drop declarations not in_use
|
// pass 3: we should drop declarations not in_use
|
||||||
var tt = new TreeTransformer(function(node, descend, in_list) {
|
var tt = new TreeTransformer(function(node, descend, in_list) {
|
||||||
var parent = tt.parent();
|
var parent = tt.parent();
|
||||||
if (drop_vars) {
|
if (drop_vars) {
|
||||||
var props = [], sym = assign_as_unused(node, props);
|
var props = [], sym = assign_as_unused(node, props);
|
||||||
if (sym instanceof AST_SymbolRef) {
|
if (sym) {
|
||||||
var def = sym.definition();
|
var def = sym.definition();
|
||||||
var in_use = def.id in in_use_ids;
|
var in_use = def.id in in_use_ids;
|
||||||
var value = null;
|
var value = null;
|
||||||
@@ -3439,15 +3452,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (scope !== self) return;
|
if (scope !== self) return;
|
||||||
if (node instanceof AST_Function
|
if (node instanceof AST_Function && node.name && drop_fn_name(node.name.definition())) {
|
||||||
&& node.name
|
node.name = null;
|
||||||
&& !compressor.option("ie8")
|
|
||||||
&& !compressor.option("keep_fnames")) {
|
|
||||||
var def = node.name.definition();
|
|
||||||
// any declarations with same name will overshadow
|
|
||||||
// name of this anonymous function and can therefore
|
|
||||||
// never be used anywhere
|
|
||||||
if (!(def.id in in_use_ids) || def.orig.length > 1) node.name = null;
|
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
|
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
|
||||||
var trim = !compressor.option("keep_fargs");
|
var trim = !compressor.option("keep_fargs");
|
||||||
@@ -3623,8 +3629,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function scan_ref_scoped(node, descend) {
|
function scan_ref_scoped(node, descend) {
|
||||||
var node_def, props = [], sym = assign_as_unused(node, props);
|
var node_def, props = [], sym = assign_as_unused(node, props);
|
||||||
if (sym instanceof AST_SymbolRef
|
if (sym && self.variables.get(sym.name) === (node_def = sym.definition())) {
|
||||||
&& self.variables.get(sym.name) === (node_def = sym.definition())) {
|
|
||||||
props.forEach(function(prop) {
|
props.forEach(function(prop) {
|
||||||
prop.walk(tw);
|
prop.walk(tw);
|
||||||
});
|
});
|
||||||
@@ -5722,14 +5727,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OPT(AST_SymbolRef, function(self, compressor) {
|
OPT(AST_SymbolRef, function(self, compressor) {
|
||||||
var def = self.resolve_defines(compressor);
|
|
||||||
if (def) {
|
|
||||||
return def.optimize(compressor);
|
|
||||||
}
|
|
||||||
// testing against !self.scope.uses_with first is an optimization
|
|
||||||
if (!compressor.option("ie8")
|
if (!compressor.option("ie8")
|
||||||
&& is_undeclared_ref(self)
|
&& is_undeclared_ref(self)
|
||||||
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
// testing against `self.scope.uses_with` is an optimization
|
||||||
|
&& !(self.scope.uses_with && compressor.find_parent(AST_With))) {
|
||||||
switch (self.name) {
|
switch (self.name) {
|
||||||
case "undefined":
|
case "undefined":
|
||||||
return make_node(AST_Undefined, self).optimize(compressor);
|
return make_node(AST_Undefined, self).optimize(compressor);
|
||||||
@@ -5769,9 +5770,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);
|
||||||
@@ -6409,10 +6411,6 @@ merge(Compressor.prototype, {
|
|||||||
col: self.start.col
|
col: self.start.col
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var def = self.resolve_defines(compressor);
|
|
||||||
if (def) {
|
|
||||||
return def.optimize(compressor);
|
|
||||||
}
|
|
||||||
if (is_lhs(self, compressor.parent())) return self;
|
if (is_lhs(self, compressor.parent())) return self;
|
||||||
if (compressor.option("unsafe_proto")
|
if (compressor.option("unsafe_proto")
|
||||||
&& self.expression instanceof AST_Dot
|
&& self.expression instanceof AST_Dot
|
||||||
@@ -6468,14 +6466,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_VarDef, function(self, compressor) {
|
|
||||||
var defines = compressor.option("global_defs");
|
|
||||||
if (defines && HOP(defines, self.name.name)) {
|
|
||||||
compressor.warn('global_defs ' + self.name.name + ' redefined [{file}:{line},{col}]', self.start);
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
});
|
|
||||||
})(function(node, optimizer) {
|
})(function(node, optimizer) {
|
||||||
node.DEFMETHOD("optimize", function(compressor) {
|
node.DEFMETHOD("optimize", function(compressor) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|||||||
127
lib/output.js
127
lib/output.js
@@ -198,16 +198,24 @@ function OutputStream(options) {
|
|||||||
/* -----[ beautification/minification ]----- */
|
/* -----[ beautification/minification ]----- */
|
||||||
|
|
||||||
var has_parens = false;
|
var has_parens = false;
|
||||||
|
var line_end = 0;
|
||||||
|
var line_fixed = true;
|
||||||
var might_need_space = false;
|
var might_need_space = false;
|
||||||
var might_need_semicolon = false;
|
var might_need_semicolon = false;
|
||||||
var might_add_newline = 0;
|
|
||||||
var need_newline_indented = false;
|
var need_newline_indented = false;
|
||||||
var need_space = false;
|
var need_space = false;
|
||||||
var newline_insert = -1;
|
var newline_insert = -1;
|
||||||
var last = "";
|
var last = "";
|
||||||
var mapping_token, mapping_name, mappings = options.source_map && [];
|
var mapping_token, mapping_name, mappings = options.source_map && [];
|
||||||
|
|
||||||
var do_add_mapping = mappings ? function() {
|
var adjust_mappings = mappings ? function(line, col) {
|
||||||
|
mappings.forEach(function(mapping) {
|
||||||
|
mapping.line += line;
|
||||||
|
mapping.col += col;
|
||||||
|
});
|
||||||
|
} : noop;
|
||||||
|
|
||||||
|
var flush_mappings = mappings ? function() {
|
||||||
mappings.forEach(function(mapping) {
|
mappings.forEach(function(mapping) {
|
||||||
try {
|
try {
|
||||||
options.source_map.add(
|
options.source_map.add(
|
||||||
@@ -230,31 +238,30 @@ function OutputStream(options) {
|
|||||||
mappings = [];
|
mappings = [];
|
||||||
} : noop;
|
} : noop;
|
||||||
|
|
||||||
var ensure_line_len = options.max_line_len ? function() {
|
function insert_newlines(count) {
|
||||||
if (current_col > options.max_line_len) {
|
var index = OUTPUT.lastIndexOf("\n");
|
||||||
if (might_add_newline) {
|
if (line_end < index) line_end = index;
|
||||||
var left = OUTPUT.slice(0, might_add_newline);
|
var left = OUTPUT.slice(0, line_end);
|
||||||
var right = OUTPUT.slice(might_add_newline);
|
var right = OUTPUT.slice(line_end);
|
||||||
if (mappings) {
|
adjust_mappings(count, right.length - current_col);
|
||||||
var delta = right.length - current_col;
|
current_line += count;
|
||||||
mappings.forEach(function(mapping) {
|
current_pos += count;
|
||||||
mapping.line++;
|
current_col = right.length;
|
||||||
mapping.col += delta;
|
OUTPUT = left;
|
||||||
});
|
while (count--) OUTPUT += "\n";
|
||||||
}
|
OUTPUT += right;
|
||||||
OUTPUT = left + "\n" + right;
|
}
|
||||||
current_line++;
|
|
||||||
current_pos++;
|
var fix_line = options.max_line_len ? function() {
|
||||||
current_col = right.length;
|
if (line_fixed) {
|
||||||
}
|
|
||||||
if (current_col > options.max_line_len) {
|
if (current_col > options.max_line_len) {
|
||||||
AST_Node.warn("Output exceeds {max_line_len} characters", options);
|
AST_Node.warn("Output exceeds {max_line_len} characters", options);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (might_add_newline) {
|
if (current_col > options.max_line_len) insert_newlines(1);
|
||||||
might_add_newline = 0;
|
line_fixed = true;
|
||||||
do_add_mapping();
|
flush_mappings();
|
||||||
}
|
|
||||||
} : noop;
|
} : noop;
|
||||||
|
|
||||||
var requireSemicolonChars = makePredicate("( [ + * / - , .");
|
var requireSemicolonChars = makePredicate("( [ + * / - , .");
|
||||||
@@ -286,7 +293,7 @@ function OutputStream(options) {
|
|||||||
current_col++;
|
current_col++;
|
||||||
current_pos++;
|
current_pos++;
|
||||||
} else {
|
} else {
|
||||||
ensure_line_len();
|
fix_line();
|
||||||
OUTPUT += "\n";
|
OUTPUT += "\n";
|
||||||
current_pos++;
|
current_pos++;
|
||||||
current_line++;
|
current_line++;
|
||||||
@@ -304,18 +311,6 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
|
|
||||||
var target_line = stack[stack.length - 1].start.line;
|
|
||||||
while (current_line < target_line) {
|
|
||||||
ensure_line_len();
|
|
||||||
OUTPUT += "\n";
|
|
||||||
current_pos++;
|
|
||||||
current_line++;
|
|
||||||
current_col = 0;
|
|
||||||
might_need_space = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (might_need_space) {
|
if (might_need_space) {
|
||||||
if ((is_identifier_char(prev)
|
if ((is_identifier_char(prev)
|
||||||
&& (is_identifier_char(ch) || ch == "\\"))
|
&& (is_identifier_char(ch) || ch == "\\"))
|
||||||
@@ -337,7 +332,7 @@ function OutputStream(options) {
|
|||||||
col: current_col
|
col: current_col
|
||||||
});
|
});
|
||||||
mapping_token = false;
|
mapping_token = false;
|
||||||
if (!might_add_newline) do_add_mapping();
|
if (line_fixed) flush_mappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
OUTPUT += str;
|
OUTPUT += str;
|
||||||
@@ -347,7 +342,7 @@ function OutputStream(options) {
|
|||||||
current_line += n;
|
current_line += n;
|
||||||
current_col += a[0].length;
|
current_col += a[0].length;
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
ensure_line_len();
|
fix_line();
|
||||||
current_col = a[n].length;
|
current_col = a[n].length;
|
||||||
}
|
}
|
||||||
last = str;
|
last = str;
|
||||||
@@ -374,9 +369,10 @@ function OutputStream(options) {
|
|||||||
return ret;
|
return ret;
|
||||||
} : function(col, cont) { return cont() };
|
} : function(col, cont) { return cont() };
|
||||||
|
|
||||||
var may_add_newline = options.max_line_len ? function() {
|
var may_add_newline = options.max_line_len || options.preserve_line ? function() {
|
||||||
ensure_line_len();
|
fix_line();
|
||||||
might_add_newline = OUTPUT.length;
|
line_end = OUTPUT.length;
|
||||||
|
line_fixed = false;
|
||||||
} : noop;
|
} : noop;
|
||||||
|
|
||||||
var newline = options.beautify ? function() {
|
var newline = options.beautify ? function() {
|
||||||
@@ -455,9 +451,7 @@ function OutputStream(options) {
|
|||||||
} : noop;
|
} : noop;
|
||||||
|
|
||||||
function get() {
|
function get() {
|
||||||
if (might_add_newline) {
|
if (!line_fixed) fix_line();
|
||||||
ensure_line_len();
|
|
||||||
}
|
|
||||||
return OUTPUT;
|
return OUTPUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,7 +616,14 @@ function OutputStream(options) {
|
|||||||
col : function() { return current_col },
|
col : function() { return current_col },
|
||||||
pos : function() { return current_pos },
|
pos : function() { return current_pos },
|
||||||
push_node : function(node) { stack.push(node) },
|
push_node : function(node) { stack.push(node) },
|
||||||
pop_node : function() { return stack.pop() },
|
pop_node : options.preserve_line ? function() {
|
||||||
|
var node = stack.pop();
|
||||||
|
if (node.start && node.start.line > current_line) {
|
||||||
|
insert_newlines(node.start.line - current_line);
|
||||||
|
}
|
||||||
|
} : function() {
|
||||||
|
stack.pop();
|
||||||
|
},
|
||||||
parent : function(n) {
|
parent : function(n) {
|
||||||
return stack[stack.length - 2 - (n || 0)];
|
return stack[stack.length - 2 - (n || 0)];
|
||||||
}
|
}
|
||||||
@@ -693,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
|
||||||
@@ -783,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) {
|
||||||
@@ -1160,7 +1153,7 @@ function OutputStream(options) {
|
|||||||
def.print(output);
|
def.print(output);
|
||||||
});
|
});
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon();
|
if (p && p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon();
|
||||||
});
|
});
|
||||||
|
|
||||||
function parenthesize_for_noin(node, output, noin) {
|
function parenthesize_for_noin(node, output, noin) {
|
||||||
|
|||||||
@@ -53,25 +53,30 @@ function find_builtins(reserved) {
|
|||||||
"-Infinity",
|
"-Infinity",
|
||||||
"undefined",
|
"undefined",
|
||||||
].forEach(add);
|
].forEach(add);
|
||||||
[ Object, Array, Function, Number,
|
[
|
||||||
String, Boolean, Error, Math,
|
Array,
|
||||||
Date, RegExp
|
Boolean,
|
||||||
|
Date,
|
||||||
|
Error,
|
||||||
|
Function,
|
||||||
|
Math,
|
||||||
|
Number,
|
||||||
|
Object,
|
||||||
|
RegExp,
|
||||||
|
String,
|
||||||
].forEach(function(ctor) {
|
].forEach(function(ctor) {
|
||||||
Object.getOwnPropertyNames(ctor).map(add);
|
Object.getOwnPropertyNames(ctor).map(add);
|
||||||
if (ctor.prototype) {
|
if (ctor.prototype) {
|
||||||
Object.getOwnPropertyNames(ctor.prototype).map(add);
|
Object.getOwnPropertyNames(ctor.prototype).map(add);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function add(name) {
|
function add(name) {
|
||||||
push_uniq(reserved, name);
|
push_uniq(reserved, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reserve_quoted_keys(ast, reserved) {
|
function reserve_quoted_keys(ast, reserved) {
|
||||||
function add(name) {
|
|
||||||
push_uniq(reserved, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
ast.walk(new TreeWalker(function(node) {
|
ast.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_ObjectKeyVal && node.quote) {
|
if (node instanceof AST_ObjectKeyVal && node.quote) {
|
||||||
add(node.key);
|
add(node.key);
|
||||||
@@ -79,6 +84,10 @@ function reserve_quoted_keys(ast, reserved) {
|
|||||||
addStrings(node.property, add);
|
addStrings(node.property, add);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
function add(name) {
|
||||||
|
push_uniq(reserved, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addStrings(node, add) {
|
function addStrings(node, add) {
|
||||||
@@ -127,10 +136,8 @@ function mangle_properties(ast, options) {
|
|||||||
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
|
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
|
||||||
// the same as passing an empty string.
|
// the same as passing an empty string.
|
||||||
var debug = options.debug !== false;
|
var debug = options.debug !== false;
|
||||||
var debug_name_suffix;
|
var debug_suffix;
|
||||||
if (debug) {
|
if (debug) debug_suffix = options.debug === true ? "" : options.debug;
|
||||||
debug_name_suffix = (options.debug === true ? "" : options.debug);
|
|
||||||
}
|
|
||||||
|
|
||||||
var names_to_mangle = [];
|
var names_to_mangle = [];
|
||||||
var unmangleable = [];
|
var unmangleable = [];
|
||||||
@@ -139,18 +146,14 @@ function mangle_properties(ast, options) {
|
|||||||
ast.walk(new TreeWalker(function(node) {
|
ast.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
add(node.key);
|
add(node.key);
|
||||||
}
|
} else if (node instanceof AST_ObjectProperty) {
|
||||||
else if (node instanceof AST_ObjectProperty) {
|
|
||||||
// setter or getter, since KeyVal is handled above
|
// setter or getter, since KeyVal is handled above
|
||||||
add(node.key.name);
|
add(node.key.name);
|
||||||
}
|
} else if (node instanceof AST_Dot) {
|
||||||
else if (node instanceof AST_Dot) {
|
|
||||||
add(node.property);
|
add(node.property);
|
||||||
}
|
} else if (node instanceof AST_Sub) {
|
||||||
else if (node instanceof AST_Sub) {
|
|
||||||
addStrings(node.property, add);
|
addStrings(node.property, add);
|
||||||
}
|
} else if (node instanceof AST_Call
|
||||||
else if (node instanceof AST_Call
|
|
||||||
&& node.expression.print_to_string() == "Object.defineProperty") {
|
&& node.expression.print_to_string() == "Object.defineProperty") {
|
||||||
addStrings(node.args[1], add);
|
addStrings(node.args[1], add);
|
||||||
}
|
}
|
||||||
@@ -160,18 +163,14 @@ function mangle_properties(ast, options) {
|
|||||||
return ast.transform(new TreeTransformer(function(node) {
|
return ast.transform(new TreeTransformer(function(node) {
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
node.key = mangle(node.key);
|
node.key = mangle(node.key);
|
||||||
}
|
} else if (node instanceof AST_ObjectProperty) {
|
||||||
else if (node instanceof AST_ObjectProperty) {
|
|
||||||
// setter or getter
|
// setter or getter
|
||||||
node.key.name = mangle(node.key.name);
|
node.key.name = mangle(node.key.name);
|
||||||
}
|
} else if (node instanceof AST_Dot) {
|
||||||
else if (node instanceof AST_Dot) {
|
|
||||||
node.property = mangle(node.property);
|
node.property = mangle(node.property);
|
||||||
}
|
} else if (!options.keep_quoted && node instanceof AST_Sub) {
|
||||||
else if (!options.keep_quoted && node instanceof AST_Sub) {
|
|
||||||
node.property = mangleStrings(node.property);
|
node.property = mangleStrings(node.property);
|
||||||
}
|
} else if (node instanceof AST_Call
|
||||||
else if (node instanceof AST_Call
|
|
||||||
&& node.expression.print_to_string() == "Object.defineProperty") {
|
&& node.expression.print_to_string() == "Object.defineProperty") {
|
||||||
node.args[1] = mangleStrings(node.args[1]);
|
node.args[1] = mangleStrings(node.args[1]);
|
||||||
}
|
}
|
||||||
@@ -182,9 +181,7 @@ function mangle_properties(ast, options) {
|
|||||||
function can_mangle(name) {
|
function can_mangle(name) {
|
||||||
if (unmangleable.indexOf(name) >= 0) return false;
|
if (unmangleable.indexOf(name) >= 0) return false;
|
||||||
if (reserved.indexOf(name) >= 0) return false;
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
if (options.only_cache) {
|
if (options.only_cache) return cache.has(name);
|
||||||
return cache.has(name);
|
|
||||||
}
|
|
||||||
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -192,42 +189,29 @@ function mangle_properties(ast, options) {
|
|||||||
function should_mangle(name) {
|
function should_mangle(name) {
|
||||||
if (regex && !regex.test(name)) return false;
|
if (regex && !regex.test(name)) return false;
|
||||||
if (reserved.indexOf(name) >= 0) return false;
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
return cache.has(name)
|
return cache.has(name) || names_to_mangle.indexOf(name) >= 0;
|
||||||
|| names_to_mangle.indexOf(name) >= 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(name) {
|
function add(name) {
|
||||||
if (can_mangle(name))
|
if (can_mangle(name)) push_uniq(names_to_mangle, name);
|
||||||
push_uniq(names_to_mangle, name);
|
if (!should_mangle(name)) push_uniq(unmangleable, name);
|
||||||
|
|
||||||
if (!should_mangle(name)) {
|
|
||||||
push_uniq(unmangleable, name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mangle(name) {
|
function mangle(name) {
|
||||||
if (!should_mangle(name)) {
|
if (!should_mangle(name)) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mangled = cache.get(name);
|
var mangled = cache.get(name);
|
||||||
if (!mangled) {
|
if (!mangled) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
||||||
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
|
var debug_mangled = "_$" + name + "$" + debug_suffix + "_";
|
||||||
|
if (can_mangle(debug_mangled)) mangled = debug_mangled;
|
||||||
if (can_mangle(debug_mangled)) {
|
|
||||||
mangled = debug_mangled;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// either debug mode is off, or it is on and we could not use the mangled name
|
// either debug mode is off, or it is on and we could not use the mangled name
|
||||||
if (!mangled) {
|
if (!mangled) do {
|
||||||
do {
|
mangled = base54(++cname);
|
||||||
mangled = base54(++cname);
|
} while (!can_mangle(mangled));
|
||||||
} while (!can_mangle(mangled));
|
|
||||||
}
|
|
||||||
|
|
||||||
cache.set(name, mangled);
|
cache.set(name, mangled);
|
||||||
}
|
}
|
||||||
return mangled;
|
return mangled;
|
||||||
@@ -238,11 +222,9 @@ function mangle_properties(ast, options) {
|
|||||||
if (node instanceof AST_Sequence) {
|
if (node instanceof AST_Sequence) {
|
||||||
var last = node.expressions.length - 1;
|
var last = node.expressions.length - 1;
|
||||||
node.expressions[last] = mangleStrings(node.expressions[last]);
|
node.expressions[last] = mangleStrings(node.expressions[last]);
|
||||||
}
|
} else if (node instanceof AST_String) {
|
||||||
else if (node instanceof AST_String) {
|
|
||||||
node.value = mangle(node.value);
|
node.value = mangle(node.value);
|
||||||
}
|
} else if (node instanceof AST_Conditional) {
|
||||||
else if (node instanceof AST_Conditional) {
|
|
||||||
node.consequent = mangleStrings(node.consequent);
|
node.consequent = mangleStrings(node.consequent);
|
||||||
node.alternative = mangleStrings(node.alternative);
|
node.alternative = mangleStrings(node.alternative);
|
||||||
}
|
}
|
||||||
|
|||||||
106
lib/scope.js
106
lib/scope.js
@@ -118,11 +118,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
descend();
|
descend();
|
||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
defun = save_defun;
|
defun = save_defun;
|
||||||
return true; // don't descend again in TreeWalker
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_With) {
|
if (node instanceof AST_With) {
|
||||||
for (var s = scope; s; s = s.parent_scope)
|
for (var s = scope; s; s = s.parent_scope) s.uses_with = true;
|
||||||
s.uses_with = true;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Symbol) {
|
if (node instanceof AST_Symbol) {
|
||||||
@@ -132,18 +131,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
node.thedef = node;
|
node.thedef = node;
|
||||||
node.references = [];
|
node.references = [];
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolDefun || options.ie8 && node instanceof AST_SymbolLambda) {
|
if (node instanceof AST_SymbolDefun) {
|
||||||
// Careful here, the scope where this should be defined is
|
// This should be defined in the parent scope, as we encounter the
|
||||||
// the parent scope. The reason is that we enter a new
|
// AST_Defun node before getting to its AST_Symbol.
|
||||||
// scope when we encounter the AST_Defun node (which is
|
(node.scope = defun.parent_scope.resolve()).def_function(node, defun);
|
||||||
// instanceof AST_Scope) but we get to the symbol a bit
|
} else if (node instanceof AST_SymbolLambda) {
|
||||||
// later.
|
var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
||||||
(node.scope = defun.parent_scope).def_function(node, defun);
|
if (options.ie8) def.defun = defun.parent_scope.resolve();
|
||||||
}
|
} else if (node instanceof AST_SymbolVar) {
|
||||||
else if (node instanceof AST_SymbolLambda) {
|
|
||||||
defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
|
||||||
}
|
|
||||||
else if (node instanceof AST_SymbolVar) {
|
|
||||||
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
|
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
|
||||||
if (defun !== scope) {
|
if (defun !== scope) {
|
||||||
node.mark_enclosed(options);
|
node.mark_enclosed(options);
|
||||||
@@ -153,8 +148,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
}
|
}
|
||||||
node.reference(options);
|
node.reference(options);
|
||||||
}
|
}
|
||||||
}
|
} else if (node instanceof AST_SymbolCatch) {
|
||||||
else if (node instanceof AST_SymbolCatch) {
|
|
||||||
scope.def_variable(node).defun = defun;
|
scope.def_variable(node).defun = defun;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -162,9 +156,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
|
|
||||||
// pass 2: find back references and eval
|
// pass 2: find back references and eval
|
||||||
self.globals = new Dictionary();
|
self.globals = new Dictionary();
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_LoopControl && node.label) {
|
if (node instanceof AST_LoopControl) {
|
||||||
node.label.thedef.references.push(node);
|
if (node.label) node.label.thedef.references.push(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
@@ -185,35 +179,43 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// ensure mangling works if catch reuses a scope variable
|
// ensure mangling works if catch reuses a scope variable
|
||||||
var def;
|
if (node instanceof AST_SymbolCatch) {
|
||||||
if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) {
|
var def = node.definition().redefined();
|
||||||
var s = node.scope;
|
if (def) for (var s = node.scope; s; s = s.parent_scope) {
|
||||||
while (s) {
|
|
||||||
push_uniq(s.enclosed, def);
|
push_uniq(s.enclosed, def);
|
||||||
if (s === def.scope) break;
|
if (s === def.scope) break;
|
||||||
s = s.parent_scope;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
|
||||||
// pass 3: fix up any scoping issue with IE8
|
// pass 3: fix up any scoping issue with IE8
|
||||||
if (options.ie8) {
|
if (options.ie8) self.walk(new TreeWalker(function(node) {
|
||||||
self.walk(new TreeWalker(function(node, descend) {
|
if (node instanceof AST_SymbolCatch) {
|
||||||
if (node instanceof AST_SymbolCatch) {
|
redefine(node, node.thedef.defun);
|
||||||
var name = node.name;
|
return true;
|
||||||
var refs = node.thedef.references;
|
}
|
||||||
var scope = node.thedef.defun;
|
if (node instanceof AST_SymbolLambda) {
|
||||||
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
|
var def = node.thedef;
|
||||||
refs.forEach(function(ref) {
|
if (def.orig.length == 1) {
|
||||||
ref.thedef = def;
|
redefine(node, node.scope.parent_scope);
|
||||||
ref.reference(options);
|
node.thedef.init = def.init;
|
||||||
});
|
|
||||||
node.thedef = def;
|
|
||||||
node.reference(options);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}));
|
return true;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
function redefine(node, scope) {
|
||||||
|
var name = node.name;
|
||||||
|
var refs = node.thedef.references;
|
||||||
|
var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
|
||||||
|
refs.forEach(function(ref) {
|
||||||
|
ref.thedef = def;
|
||||||
|
ref.reference(options);
|
||||||
|
});
|
||||||
|
node.thedef = def;
|
||||||
|
node.reference(options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -252,8 +254,7 @@ AST_Lambda.DEFMETHOD("init_scope_vars", function() {
|
|||||||
|
|
||||||
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
||||||
var def = this.definition();
|
var def = this.definition();
|
||||||
var s = this.scope;
|
for (var s = this.scope; s; s = s.parent_scope) {
|
||||||
while (s) {
|
|
||||||
push_uniq(s.enclosed, def);
|
push_uniq(s.enclosed, def);
|
||||||
if (options.keep_fnames) {
|
if (options.keep_fnames) {
|
||||||
s.functions.each(function(d) {
|
s.functions.each(function(d) {
|
||||||
@@ -261,7 +262,6 @@ AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (s === def.scope) break;
|
if (s === def.scope) break;
|
||||||
s = s.parent_scope;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -298,6 +298,12 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
|||||||
return symbol.thedef = def;
|
return symbol.thedef = def;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Lambda.DEFMETHOD("resolve", return_this);
|
||||||
|
AST_Scope.DEFMETHOD("resolve", function() {
|
||||||
|
return this.parent_scope;
|
||||||
|
});
|
||||||
|
AST_Toplevel.DEFMETHOD("resolve", return_this);
|
||||||
|
|
||||||
function names_in_use(scope, options) {
|
function names_in_use(scope, options) {
|
||||||
var names = scope.names_in_use;
|
var names = scope.names_in_use;
|
||||||
if (!names) {
|
if (!names) {
|
||||||
@@ -314,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;
|
||||||
@@ -410,7 +408,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
var save_nesting = lname;
|
var save_nesting = lname;
|
||||||
descend();
|
descend();
|
||||||
lname = save_nesting;
|
lname = save_nesting;
|
||||||
return true; // don't descend again in TreeWalker
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
descend();
|
descend();
|
||||||
@@ -422,7 +420,9 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Label) {
|
if (node instanceof AST_Label) {
|
||||||
var name;
|
var name;
|
||||||
do name = base54(++lname); while (!is_identifier(name));
|
do {
|
||||||
|
name = base54(++lname);
|
||||||
|
} while (!is_identifier(name));
|
||||||
node.mangled_name = name;
|
node.mangled_name = name;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,8 +162,7 @@ var MAP = (function() {
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
function push_uniq(array, el) {
|
function push_uniq(array, el) {
|
||||||
if (array.indexOf(el) < 0)
|
if (array.indexOf(el) < 0) return array.push(el);
|
||||||
array.push(el);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function string_template(text, props) {
|
function string_template(text, props) {
|
||||||
@@ -173,9 +172,8 @@ function string_template(text, props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function remove(array, el) {
|
function remove(array, el) {
|
||||||
for (var i = array.length; --i >= 0;) {
|
var index = array.indexOf(el);
|
||||||
if (array[i] === el) array.splice(i, 1);
|
if (index >= 0) array.splice(index, 1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makePredicate(words) {
|
function makePredicate(words) {
|
||||||
|
|||||||
@@ -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.4",
|
"version": "3.4.8",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "~2.16.0",
|
"commander": "~2.17.1",
|
||||||
"source-map": "~0.6.1"
|
"source-map": "~0.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -5730,3 +5730,100 @@ issue_3096: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "ab"
|
expect_stdout: "ab"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3215_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
ie8: false,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function a() {
|
||||||
|
var a = 42;
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("number");
|
||||||
|
}
|
||||||
|
expect_stdout: "number"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3215_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
ie8: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function a() {
|
||||||
|
var a = 42;
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function a() {
|
||||||
|
var a = 42;
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "number"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3215_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
ie8: false,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = 42;
|
||||||
|
(function a() {});
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("number");
|
||||||
|
}
|
||||||
|
expect_stdout: "number"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3215_4: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
ie8: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = 42;
|
||||||
|
(function a() {});
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = 42;
|
||||||
|
(function a() {});
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "number"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1982,3 +1982,26 @@ issue_3192: {
|
|||||||
"foo bar",
|
"foo bar",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3233: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = function b() {
|
||||||
|
b.c = "PASS";
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
console.log(a.c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = function b() {
|
||||||
|
b.c = "PASS";
|
||||||
|
};
|
||||||
|
a();
|
||||||
|
console.log(a.c);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1199,7 +1199,7 @@ issue_2231_1: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Error evaluating Object.keys(void 0) [test/compress/evaluate.js:1195,20]",
|
"WARN: Error evaluating Object.keys(void 0) [test/compress/evaluate.js:1,20]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1216,7 +1216,7 @@ issue_2231_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Error evaluating Object.getOwnPropertyNames(null) [test/compress/evaluate.js:1212,20]",
|
"WARN: Error evaluating Object.getOwnPropertyNames(null) [test/compress/evaluate.js:1,20]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1354,14 +1354,14 @@ issue_2535_3: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1340,20]",
|
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1,20]",
|
||||||
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1341,20]",
|
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:2,20]",
|
||||||
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1342,20]",
|
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:3,20]",
|
||||||
"WARN: Condition left of && always false [test/compress/evaluate.js:1342,20]",
|
"WARN: Condition left of && always false [test/compress/evaluate.js:3,20]",
|
||||||
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1343,20]",
|
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:4,20]",
|
||||||
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1344,20]",
|
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:5,20]",
|
||||||
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1345,20]",
|
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:6,20]",
|
||||||
"WARN: Condition left of || always true [test/compress/evaluate.js:1345,20]",
|
"WARN: Condition left of || always true [test/compress/evaluate.js:6,20]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -141,9 +141,8 @@ mixed: {
|
|||||||
console.log(CONFIG);
|
console.log(CONFIG);
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]",
|
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:4,22]",
|
||||||
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:128,22]",
|
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:7,8]",
|
||||||
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:130,8]",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,3 +196,23 @@ issue_2167: {
|
|||||||
doWork();
|
doWork();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3217: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
global_defs: {
|
||||||
|
"@o": "{fn:function(){var a=42;console.log(a)}}",
|
||||||
|
},
|
||||||
|
inline: true,
|
||||||
|
properties: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
o.fn();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(42);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -678,6 +678,7 @@ issue_3206_1: {
|
|||||||
input: {
|
input: {
|
||||||
console.log(function() {
|
console.log(function() {
|
||||||
var foo = function bar() {};
|
var foo = function bar() {};
|
||||||
|
var baz = function moo() {};
|
||||||
return "function" == typeof bar;
|
return "function" == typeof bar;
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
@@ -700,6 +701,7 @@ issue_3206_2: {
|
|||||||
input: {
|
input: {
|
||||||
console.log(function() {
|
console.log(function() {
|
||||||
var foo = function bar() {};
|
var foo = function bar() {};
|
||||||
|
var baz = function moo() {};
|
||||||
return "function" == typeof bar;
|
return "function" == typeof bar;
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
@@ -711,3 +713,151 @@ issue_3206_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "false"
|
expect_stdout: "false"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_3215_1: {
|
||||||
|
mangle = {
|
||||||
|
ie8: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function foo() {
|
||||||
|
var bar = function bar(name) {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
"moo";
|
||||||
|
} catch (e) {
|
||||||
|
bar = function bar(name) {
|
||||||
|
return "FAIL";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return bar;
|
||||||
|
}()());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function n() {
|
||||||
|
var o = function n(o) {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
"moo";
|
||||||
|
} catch (n) {
|
||||||
|
o = function n(o) {
|
||||||
|
return "FAIL";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}()());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3215_2: {
|
||||||
|
mangle = {
|
||||||
|
ie8: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function foo() {
|
||||||
|
var bar = function bar(name) {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
"moo";
|
||||||
|
} catch (e) {
|
||||||
|
bar = function bar(name) {
|
||||||
|
return "FAIL";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return bar;
|
||||||
|
}()());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function foo() {
|
||||||
|
var o = function o(n) {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
"moo";
|
||||||
|
} catch (n) {
|
||||||
|
o = function o(n) {
|
||||||
|
return "FAIL";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}()());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3215_3: {
|
||||||
|
mangle = {
|
||||||
|
ie8: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function foo() {
|
||||||
|
var bar = function bar(name) {
|
||||||
|
return "FAIL";
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
moo;
|
||||||
|
} catch (e) {
|
||||||
|
bar = function bar(name) {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return bar;
|
||||||
|
}()());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function n() {
|
||||||
|
var o = function n(o) {
|
||||||
|
return "FAIL";
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
moo;
|
||||||
|
} catch (n) {
|
||||||
|
o = function n(o) {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}()());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_3215_4: {
|
||||||
|
mangle = {
|
||||||
|
ie8: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function foo() {
|
||||||
|
var bar = function bar(name) {
|
||||||
|
return "FAIL";
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
moo;
|
||||||
|
} catch (e) {
|
||||||
|
bar = function bar(name) {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return bar;
|
||||||
|
}()());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function foo() {
|
||||||
|
var o = function o(n) {
|
||||||
|
return "FAIL";
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
moo;
|
||||||
|
} catch (n) {
|
||||||
|
o = function o(n) {
|
||||||
|
return "PASS";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}()());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -396,3 +396,151 @@ if_if_return_return: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if_body_return_1: {
|
||||||
|
options = {
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = "PASS";
|
||||||
|
function f(a, b) {
|
||||||
|
if (a) {
|
||||||
|
if (b) throw new Error(c);
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
console.log(f(0, 0));
|
||||||
|
console.log(f(0, 1));
|
||||||
|
console.log(f(1, 0));
|
||||||
|
try {
|
||||||
|
f(1, 1);
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = "PASS";
|
||||||
|
function f(a, b) {
|
||||||
|
if (a) {
|
||||||
|
if (b) throw new Error(c);
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
console.log(f(0, 0));
|
||||||
|
console.log(f(0, 1));
|
||||||
|
console.log(f(1, 0));
|
||||||
|
try {
|
||||||
|
f(1, 1);
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"true",
|
||||||
|
"true",
|
||||||
|
"42",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
if_body_return_2: {
|
||||||
|
options = {
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = "PASS";
|
||||||
|
function f(a, b) {
|
||||||
|
if (0 + a) {
|
||||||
|
if (b) throw new Error(c);
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
console.log(f(0, 0));
|
||||||
|
console.log(f(0, 1));
|
||||||
|
console.log(f(1, 0));
|
||||||
|
try {
|
||||||
|
f(1, 1);
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = "PASS";
|
||||||
|
function f(a, b) {
|
||||||
|
if (0 + a) {
|
||||||
|
if (b) throw new Error(c);
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
console.log(f(0, 0));
|
||||||
|
console.log(f(0, 1));
|
||||||
|
console.log(f(1, 0));
|
||||||
|
try {
|
||||||
|
f(1, 1);
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"true",
|
||||||
|
"true",
|
||||||
|
"42",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
if_body_return_3: {
|
||||||
|
options = {
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = "PASS";
|
||||||
|
function f(a, b) {
|
||||||
|
if (1 == a) {
|
||||||
|
if (b) throw new Error(c);
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
console.log(f(0, 0));
|
||||||
|
console.log(f(0, 1));
|
||||||
|
console.log(f(1, 0));
|
||||||
|
try {
|
||||||
|
f(1, 1);
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = "PASS";
|
||||||
|
function f(a, b) {
|
||||||
|
if (1 != a) return true;
|
||||||
|
if (b) throw new Error(c);
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
console.log(f(0, 0));
|
||||||
|
console.log(f(0, 1));
|
||||||
|
console.log(f(1, 0));
|
||||||
|
try {
|
||||||
|
f(1, 1);
|
||||||
|
console.log("FAIL");
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"true",
|
||||||
|
"true",
|
||||||
|
"42",
|
||||||
|
"PASS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,10 +36,10 @@ non_hoisted_function_after_return: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:20,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:23,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:26,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:27,21]"
|
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,18 +85,18 @@ non_hoisted_function_after_return_2a: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:68,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:68,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:71,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:71,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
||||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:68,20]",
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
|
||||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:75,21]",
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
||||||
"WARN: pass 0: last_count: Infinity, count: 37",
|
"WARN: pass 0: last_count: Infinity, count: 37",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:73,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:73,12]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:76,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:71,20]",
|
"WARN: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
|
||||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:73,16]",
|
"WARN: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
|
||||||
"WARN: pass 1: last_count: 37, count: 18",
|
"WARN: pass 1: last_count: 37, count: 18",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -139,12 +139,11 @@ non_hoisted_function_after_return_2b: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
// duplicate warnings no longer emitted
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:126,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:6,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:126,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:128,12]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:128,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:132,12]",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,10 +190,10 @@ non_hoisted_function_after_return_strict: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "8 7"
|
expect_stdout: "8 7"
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:171,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:174,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:177,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:11,12]",
|
||||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:178,21]",
|
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:12,21]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,18 +244,18 @@ non_hoisted_function_after_return_2a_strict: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "5 6"
|
expect_stdout: "5 6"
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:224,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:224,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:227,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:227,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
|
||||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:224,20]",
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
|
||||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:231,21]",
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
||||||
"WARN: pass 0: last_count: Infinity, count: 48",
|
"WARN: pass 0: last_count: Infinity, count: 48",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:229,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:229,12]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:232,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:227,20]",
|
"WARN: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
|
||||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:229,16]",
|
"WARN: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
|
||||||
"WARN: pass 1: last_count: 48, count: 29",
|
"WARN: pass 1: last_count: 48, count: 29",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -304,11 +303,10 @@ non_hoisted_function_after_return_2b_strict: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "5 6"
|
expect_stdout: "5 6"
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
// duplicate warnings no longer emitted
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:287,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:287,16]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:289,12]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:289,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:293,12]",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,13 +48,13 @@ pure_function_calls: {
|
|||||||
a.b(), f.g();
|
a.b(), f.g();
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,8]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:3,8]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:16,8]",
|
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:3,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:29,37]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,37]",
|
||||||
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:29,16]",
|
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:16,16]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:27,8]",
|
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:14,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:37,8]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:24,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:38,31]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:25,31]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,17 +110,17 @@ pure_function_calls_toplevel: {
|
|||||||
a.b(), f.g();
|
a.b(), f.g();
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:77,8]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:3,8]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:77,8]",
|
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:3,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:90,37]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,37]",
|
||||||
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:90,16]",
|
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:16,16]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:88,8]",
|
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:14,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:105,8]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:31,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:106,31]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:32,31]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:82,33]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:8,33]",
|
||||||
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:82,12]",
|
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:8,12]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:98,45]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:24,45]",
|
||||||
"WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:98,12]",
|
"WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:24,12]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,29 +155,29 @@ should_warn: {
|
|||||||
baz();
|
baz();
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,61]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:1,61]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:1,23]",
|
||||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:135,23]",
|
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:1,23]",
|
||||||
"WARN: Boolean || always true [test/compress/issue-1261.js:136,23]",
|
"WARN: Boolean || always true [test/compress/issue-1261.js:2,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:2,23]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:136,23]",
|
"WARN: Condition always true [test/compress/issue-1261.js:2,23]",
|
||||||
"WARN: Condition left of || always true [test/compress/issue-1261.js:137,8]",
|
"WARN: Condition left of || always true [test/compress/issue-1261.js:3,8]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:137,8]",
|
"WARN: Condition always true [test/compress/issue-1261.js:3,8]",
|
||||||
"WARN: Boolean && always false [test/compress/issue-1261.js:138,23]",
|
"WARN: Boolean && always false [test/compress/issue-1261.js:4,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:138,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:4,23]",
|
||||||
"WARN: Condition always false [test/compress/issue-1261.js:138,23]",
|
"WARN: Condition always false [test/compress/issue-1261.js:4,23]",
|
||||||
"WARN: Condition left of && always false [test/compress/issue-1261.js:139,8]",
|
"WARN: Condition left of && always false [test/compress/issue-1261.js:5,8]",
|
||||||
"WARN: Condition always false [test/compress/issue-1261.js:139,8]",
|
"WARN: Condition always false [test/compress/issue-1261.js:5,8]",
|
||||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:140,23]",
|
"WARN: + in boolean context always true [test/compress/issue-1261.js:6,23]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:140,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:6,23]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:140,23]",
|
"WARN: Condition always true [test/compress/issue-1261.js:6,23]",
|
||||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:141,8]",
|
"WARN: + in boolean context always true [test/compress/issue-1261.js:7,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:141,31]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:7,31]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:141,8]",
|
"WARN: Condition always true [test/compress/issue-1261.js:7,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:142,23]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:8,23]",
|
||||||
"WARN: Condition always true [test/compress/issue-1261.js:143,8]",
|
"WARN: Condition always true [test/compress/issue-1261.js:9,8]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:143,24]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:9,24]",
|
||||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:144,31]",
|
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:10,31]",
|
||||||
"WARN: Condition always false [test/compress/issue-1261.js:144,8]",
|
"WARN: Condition always false [test/compress/issue-1261.js:10,8]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,11 +64,11 @@ mixed: {
|
|||||||
x = 0;
|
x = 0;
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: global_defs ENV redefined [test/compress/issue-208.js:45,12]",
|
"WARN: global_defs ENV redefined [test/compress/issue-208.js:1,12]",
|
||||||
"WARN: global_defs FOO redefined [test/compress/issue-208.js:46,12]",
|
"WARN: global_defs FOO redefined [test/compress/issue-208.js:2,12]",
|
||||||
"WARN: global_defs FOO redefined [test/compress/issue-208.js:48,10]",
|
"WARN: global_defs FOO redefined [test/compress/issue-208.js:4,10]",
|
||||||
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:49,8]",
|
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:5,8]",
|
||||||
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:50,8]",
|
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:6,8]",
|
||||||
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:51,8]",
|
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:7,8]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,6 @@ regexp: {
|
|||||||
RegExp("should", "fail");
|
RegExp("should", "fail");
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:86,2]',
|
'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:5,2]',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ warn: {
|
|||||||
}().length);
|
}().length);
|
||||||
}
|
}
|
||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Function.protoype.caller not supported [test/compress/issue-2719.js:17,19]",
|
"WARN: Function.protoype.caller not supported [test/compress/issue-2719.js:5,19]",
|
||||||
"WARN: Function.protoype.arguments not supported [test/compress/issue-2719.js:17,19]",
|
"WARN: Function.protoype.arguments not supported [test/compress/issue-2719.js:5,19]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
181
test/compress/preserve_line.js
Normal file
181
test/compress/preserve_line.js
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
return_1: {
|
||||||
|
beautify = {
|
||||||
|
beautify: false,
|
||||||
|
preserve_line: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {
|
||||||
|
return (
|
||||||
|
f.toString() != 42
|
||||||
|
);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"console.log(function f(){",
|
||||||
|
"",
|
||||||
|
"return 42!=f.toString()}());",
|
||||||
|
]
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
return_2: {
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
preserve_line: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {
|
||||||
|
return (
|
||||||
|
f.toString() != 42
|
||||||
|
);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"console.log(function f() {",
|
||||||
|
"",
|
||||||
|
" return 42 != f.toString();",
|
||||||
|
"}());",
|
||||||
|
]
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
return_3: {
|
||||||
|
options = {}
|
||||||
|
beautify = {
|
||||||
|
beautify: false,
|
||||||
|
preserve_line: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {
|
||||||
|
return (
|
||||||
|
f.toString() != 42
|
||||||
|
);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"console.log(function f(){",
|
||||||
|
"",
|
||||||
|
"return 42!=f.toString()}());",
|
||||||
|
]
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
return_4: {
|
||||||
|
options = {}
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
preserve_line: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {
|
||||||
|
return (
|
||||||
|
f.toString() != 42
|
||||||
|
);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"console.log(function f() {",
|
||||||
|
"",
|
||||||
|
" return 42 != f.toString();",
|
||||||
|
"}());",
|
||||||
|
]
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
return_5: {
|
||||||
|
beautify = {
|
||||||
|
beautify: false,
|
||||||
|
preserve_line: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
_is_selected = function(tags, slug) {
|
||||||
|
var ref;
|
||||||
|
return (ref = _.find(tags, {
|
||||||
|
slug: slug
|
||||||
|
})) != null ? ref.selected : void 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"_is_selected=function(tags,slug){",
|
||||||
|
"var ref",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
";return null!=(ref=_.find(tags,{slug:slug}))?ref.selected:void 0};",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return_6: {
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
preserve_line: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
_is_selected = function(tags, slug) {
|
||||||
|
var ref;
|
||||||
|
return (ref = _.find(tags, {
|
||||||
|
slug: slug
|
||||||
|
})) != null ? ref.selected : void 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"_is_selected = function(tags, slug) {",
|
||||||
|
" var ref;",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
" return null != (ref = _.find(tags, {",
|
||||||
|
" slug: slug",
|
||||||
|
" })) ? ref.selected : void 0;",
|
||||||
|
"};",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return_7: {
|
||||||
|
options = {}
|
||||||
|
mangle = {}
|
||||||
|
beautify = {
|
||||||
|
beautify: false,
|
||||||
|
preserve_line: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
_is_selected = function(tags, slug) {
|
||||||
|
var ref;
|
||||||
|
return (ref = _.find(tags, {
|
||||||
|
slug: slug
|
||||||
|
})) != null ? ref.selected : void 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"_is_selected=function(e,l){",
|
||||||
|
"var n",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
";return null!=(n=_.find(e,{slug:l}))?n.selected:void 0};",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return_8: {
|
||||||
|
options = {}
|
||||||
|
mangle = {}
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
preserve_line: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
_is_selected = function(tags, slug) {
|
||||||
|
var ref;
|
||||||
|
return (ref = _.find(tags, {
|
||||||
|
slug: slug
|
||||||
|
})) != null ? ref.selected : void 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"_is_selected = function(e, l) {",
|
||||||
|
" var n;",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
" return null != (n = _.find(e, {",
|
||||||
|
" slug: l",
|
||||||
|
" })) ? n.selected : void 0;",
|
||||||
|
"};",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1832,3 +1832,33 @@ issue_3188_3: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
join_expr: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
join_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var c = "FAIL";
|
||||||
|
(function() {
|
||||||
|
var a = 0;
|
||||||
|
switch ((a = {}) && (a.b = 0)) {
|
||||||
|
case 0:
|
||||||
|
c = "PASS";
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var c = "FAIL";
|
||||||
|
(function() {
|
||||||
|
var a = 0;
|
||||||
|
switch (a = { b: 0 }, a.b) {
|
||||||
|
case 0:
|
||||||
|
c = "PASS";
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -5231,11 +5231,11 @@ defun_catch_4: {
|
|||||||
try {
|
try {
|
||||||
throw 42;
|
throw 42;
|
||||||
} catch (a) {
|
} catch (a) {
|
||||||
function a() {}
|
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: "42"
|
||||||
|
node_version: "<=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
defun_catch_5: {
|
defun_catch_5: {
|
||||||
@@ -5257,10 +5257,10 @@ defun_catch_5: {
|
|||||||
throw 42;
|
throw 42;
|
||||||
} catch (a) {
|
} catch (a) {
|
||||||
console.log(a);
|
console.log(a);
|
||||||
function a() {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: "42"
|
||||||
|
node_version: "<=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
defun_catch_6: {
|
defun_catch_6: {
|
||||||
|
|||||||
@@ -534,3 +534,80 @@ function_catch_catch_ie8: {
|
|||||||
"undefined",
|
"undefined",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function_do_catch_ie8: {
|
||||||
|
rename = true
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
ie8: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1, b = 1, c = 0;
|
||||||
|
function d(e) {
|
||||||
|
var f, g, h, i;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
var j = function q(){}();
|
||||||
|
} catch (r) {
|
||||||
|
--a && w("ddddddddeeeeeeegggggggggiiiiilllllllnnnnntuuuuuuuuyyyyyyy");
|
||||||
|
var k, l, m, n, o;
|
||||||
|
--m;
|
||||||
|
--n;
|
||||||
|
--o;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
i[1];
|
||||||
|
} catch (s) {
|
||||||
|
var p;
|
||||||
|
switch (function t() {
|
||||||
|
c++;
|
||||||
|
}()) {
|
||||||
|
case j + --p:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (u) {}
|
||||||
|
} while (--i);
|
||||||
|
b--;
|
||||||
|
}
|
||||||
|
d();
|
||||||
|
console.log(b, c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var t = 1, u = 1, y = 0;
|
||||||
|
function c(c) {
|
||||||
|
var d;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
var e = void 0;
|
||||||
|
} catch (i) {
|
||||||
|
--t && w("ddddddddeeeeeeegggggggggiiiiilllllllnnnnntuuuuuuuuyyyyyyy");
|
||||||
|
0;
|
||||||
|
0;
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
d[1];
|
||||||
|
} catch (l) {
|
||||||
|
var g;
|
||||||
|
switch(function x() {
|
||||||
|
y++;
|
||||||
|
}()) {
|
||||||
|
case e + --g:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (n) {}
|
||||||
|
} while (--d);
|
||||||
|
u--;
|
||||||
|
}
|
||||||
|
c();
|
||||||
|
console.log(u, y);
|
||||||
|
}
|
||||||
|
expect_stdout: "0 1"
|
||||||
|
}
|
||||||
|
|||||||
109
test/compress/webkit.js
Normal file
109
test/compress/webkit.js
Normal 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"
|
||||||
|
}
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
exports["Compressor"] = Compressor;
|
|
||||||
exports["JS_Parse_Error"] = JS_Parse_Error;
|
|
||||||
exports["OutputStream"] = OutputStream;
|
|
||||||
exports["SourceMap"] = SourceMap;
|
|
||||||
exports["TreeWalker"] = TreeWalker;
|
|
||||||
exports["base54"] = base54;
|
exports["base54"] = base54;
|
||||||
|
exports["Compressor"] = Compressor;
|
||||||
exports["defaults"] = defaults;
|
exports["defaults"] = defaults;
|
||||||
|
exports["is_identifier"] = is_identifier;
|
||||||
|
exports["JS_Parse_Error"] = JS_Parse_Error;
|
||||||
exports["mangle_properties"] = mangle_properties;
|
exports["mangle_properties"] = mangle_properties;
|
||||||
exports["minify"] = minify;
|
exports["minify"] = minify;
|
||||||
|
exports["OutputStream"] = OutputStream;
|
||||||
exports["parse"] = parse;
|
exports["parse"] = parse;
|
||||||
|
exports["push_uniq"] = push_uniq;
|
||||||
exports["reserve_quoted_keys"] = reserve_quoted_keys;
|
exports["reserve_quoted_keys"] = reserve_quoted_keys;
|
||||||
|
exports["SourceMap"] = SourceMap;
|
||||||
exports["string_template"] = string_template;
|
exports["string_template"] = string_template;
|
||||||
exports["tokenizer"] = tokenizer;
|
exports["tokenizer"] = tokenizer;
|
||||||
exports["is_identifier"] = is_identifier;
|
exports["TreeTransformer"] = TreeTransformer;
|
||||||
|
exports["TreeWalker"] = TreeWalker;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -651,7 +651,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with explicit --no-rename", function(done) {
|
it("Should work with explicit --no-rename", function(done) {
|
||||||
var command = uglifyjscmd + " test/input/rename/input.js -mc --no-rename";
|
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2 --no-rename";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(stdout, "function f(n){return function(n){return n}(n)}\n");
|
assert.strictEqual(stdout, "function f(n){return function(n){return n}(n)}\n");
|
||||||
@@ -659,7 +659,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with implicit --rename", function(done) {
|
it("Should work with implicit --rename", function(done) {
|
||||||
var command = uglifyjscmd + " test/input/rename/input.js -mc";
|
var command = uglifyjscmd + " test/input/rename/input.js -mc passes=2";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(stdout, "function f(n){return n}\n");
|
assert.strictEqual(stdout, "function f(n){return n}\n");
|
||||||
@@ -667,7 +667,7 @@ describe("bin/uglifyjs", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
it("Should work with implicit --no-rename", function(done) {
|
it("Should work with implicit --no-rename", function(done) {
|
||||||
var command = uglifyjscmd + " test/input/rename/input.js -c";
|
var command = uglifyjscmd + " test/input/rename/input.js -c passes=2";
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, function(err, stdout, stderr) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
assert.strictEqual(stdout, "function f(x){return function(x){return x}(x)}\n");
|
assert.strictEqual(stdout, "function f(x){return function(x){return x}(x)}\n");
|
||||||
|
|||||||
@@ -23,68 +23,200 @@ require("./mocha.js");
|
|||||||
|
|
||||||
/* -----[ utils ]----- */
|
/* -----[ utils ]----- */
|
||||||
|
|
||||||
function tmpl() {
|
function evaluate(code) {
|
||||||
return U.string_template.apply(this, arguments);
|
if (code instanceof U.AST_Node) code = make_code(code, { beautify: true });
|
||||||
|
return new Function("return(" + code + ")")();
|
||||||
}
|
}
|
||||||
|
|
||||||
function log() {
|
function log() {
|
||||||
var txt = tmpl.apply(this, arguments);
|
console.log("%s", tmpl.apply(null, arguments));
|
||||||
console.log("%s", txt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function log_directory(dir) {
|
function make_code(ast, options) {
|
||||||
log("*** Entering [{dir}]", { dir: dir });
|
var stream = U.OutputStream(options);
|
||||||
|
ast.print(stream);
|
||||||
|
return stream.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
function log_start_file(file) {
|
function parse_test(file) {
|
||||||
log("--- {file}", { file: file });
|
var script = fs.readFileSync(file, "utf8");
|
||||||
}
|
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS2/issues/348
|
||||||
|
try {
|
||||||
function log_test(name) {
|
var ast = U.parse(script, {
|
||||||
log(" Running test [{name}]", { name: name });
|
filename: file
|
||||||
}
|
});
|
||||||
|
} catch (e) {
|
||||||
function find_test_files(dir) {
|
console.log("Caught error while parsing tests in " + file + "\n");
|
||||||
return fs.readdirSync(dir).filter(function(name) {
|
console.log(e);
|
||||||
return /\.js$/i.test(name);
|
throw e;
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function test_directory(dir) {
|
|
||||||
return path.resolve(tests_dir, dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
function as_toplevel(input, mangle_options) {
|
|
||||||
if (!(input instanceof U.AST_BlockStatement))
|
|
||||||
throw new Error("Unsupported input syntax");
|
|
||||||
for (var i = 0; i < input.body.length; i++) {
|
|
||||||
var stat = input.body[i];
|
|
||||||
if (stat instanceof U.AST_SimpleStatement && stat.body instanceof U.AST_String)
|
|
||||||
input.body[i] = new U.AST_Directive(stat.body);
|
|
||||||
else break;
|
|
||||||
}
|
}
|
||||||
var toplevel = new U.AST_Toplevel(input);
|
var tests = {};
|
||||||
toplevel.figure_out_scope(mangle_options);
|
var tw = new U.TreeWalker(function(node, descend) {
|
||||||
return toplevel;
|
if (node instanceof U.AST_LabeledStatement
|
||||||
|
&& tw.parent() instanceof U.AST_Toplevel) {
|
||||||
|
var name = node.label.name;
|
||||||
|
if (name in tests) {
|
||||||
|
throw new Error('Duplicated test name "' + name + '" in ' + file);
|
||||||
|
}
|
||||||
|
tests[name] = get_one_test(name, node.body);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(node instanceof U.AST_Toplevel)) croak(node);
|
||||||
|
});
|
||||||
|
ast.walk(tw);
|
||||||
|
return tests;
|
||||||
|
|
||||||
|
function croak(node) {
|
||||||
|
throw new Error(tmpl("Can't understand test file {file} [{line},{col}]\n{code}", {
|
||||||
|
file: file,
|
||||||
|
line: node.start.line,
|
||||||
|
col: node.start.col,
|
||||||
|
code: make_code(node, { beautify: false })
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_string(stat) {
|
||||||
|
if (stat.TYPE == "SimpleStatement") {
|
||||||
|
var body = stat.body;
|
||||||
|
switch(body.TYPE) {
|
||||||
|
case "String":
|
||||||
|
return body.value;
|
||||||
|
case "Array":
|
||||||
|
return body.elements.map(function(element) {
|
||||||
|
if (element.TYPE !== "String")
|
||||||
|
throw new Error("Should be array of strings");
|
||||||
|
return element.value;
|
||||||
|
}).join("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error("Should be string or array of strings");
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_one_test(name, block) {
|
||||||
|
var test = { name: name, options: {} };
|
||||||
|
var tw = new U.TreeWalker(function(node, descend) {
|
||||||
|
if (node instanceof U.AST_Assign) {
|
||||||
|
if (!(node.left instanceof U.AST_SymbolRef)) {
|
||||||
|
croak(node);
|
||||||
|
}
|
||||||
|
var name = node.left.name;
|
||||||
|
test[name] = evaluate(node.right);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof U.AST_LabeledStatement) {
|
||||||
|
var label = node.label;
|
||||||
|
assert.ok([
|
||||||
|
"input",
|
||||||
|
"expect",
|
||||||
|
"expect_exact",
|
||||||
|
"expect_warnings",
|
||||||
|
"expect_stdout",
|
||||||
|
"node_version",
|
||||||
|
].indexOf(label.name) >= 0, tmpl("Unsupported label {name} [{line},{col}]", {
|
||||||
|
name: label.name,
|
||||||
|
line: label.start.line,
|
||||||
|
col: label.start.col
|
||||||
|
}));
|
||||||
|
var stat = node.body;
|
||||||
|
if (label.name == "expect_exact" || label.name == "node_version") {
|
||||||
|
test[label.name] = read_string(stat);
|
||||||
|
} else if (label.name == "expect_stdout") {
|
||||||
|
var body = stat.body;
|
||||||
|
if (body instanceof U.AST_Boolean) {
|
||||||
|
test[label.name] = body.value;
|
||||||
|
} else if (body instanceof U.AST_Call) {
|
||||||
|
var ctor = global[body.expression.name];
|
||||||
|
assert.ok(ctor === Error || ctor.prototype instanceof Error, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
||||||
|
line: label.start.line,
|
||||||
|
col: label.start.col
|
||||||
|
}));
|
||||||
|
test[label.name] = ctor.apply(null, body.args.map(function(node) {
|
||||||
|
assert.ok(node instanceof U.AST_Constant, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
||||||
|
line: label.start.line,
|
||||||
|
col: label.start.col
|
||||||
|
}));
|
||||||
|
return node.value;
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
test[label.name] = read_string(stat) + "\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
test[label.name] = stat;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
block.walk(tw);
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to reminify original input with standard options
|
||||||
|
// to see if it matches expect_stdout.
|
||||||
|
function reminify(orig_options, input_code, input_formatted, expect_stdout) {
|
||||||
|
for (var i = 0; i < minify_options.length; i++) {
|
||||||
|
var options = JSON.parse(minify_options[i]);
|
||||||
|
if (options.compress) [
|
||||||
|
"keep_fargs",
|
||||||
|
"keep_fnames",
|
||||||
|
].forEach(function(name) {
|
||||||
|
if (name in orig_options) {
|
||||||
|
options.compress[name] = orig_options[name];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var options_formatted = JSON.stringify(options, null, 4);
|
||||||
|
var result = U.minify(input_code, options);
|
||||||
|
if (result.error) {
|
||||||
|
log("!!! failed input reminify\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n--ERROR---\n{error}\n\n", {
|
||||||
|
input: input_formatted,
|
||||||
|
options: options_formatted,
|
||||||
|
error: result.error,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
var stdout = run_code(result.code);
|
||||||
|
if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) {
|
||||||
|
stdout = expect_stdout;
|
||||||
|
}
|
||||||
|
if (!sandbox.same_stdout(expect_stdout, stdout)) {
|
||||||
|
log("!!! failed running reminified input\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n---OUTPUT---\n{output}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||||
|
input: input_formatted,
|
||||||
|
options: options_formatted,
|
||||||
|
output: result.code,
|
||||||
|
expected_type: typeof expect_stdout == "string" ? "STDOUT" : "ERROR",
|
||||||
|
expected: expect_stdout,
|
||||||
|
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
||||||
|
actual: stdout,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_code(code) {
|
||||||
|
var result = sandbox.run_code(code, true);
|
||||||
|
return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function run_compress_tests() {
|
function run_compress_tests() {
|
||||||
var dir = test_directory("compress");
|
var dir = path.resolve(tests_dir, "compress");
|
||||||
log_directory("compress");
|
fs.readdirSync(dir).filter(function(name) {
|
||||||
var files = find_test_files(dir);
|
return /\.js$/i.test(name);
|
||||||
function test_file(file) {
|
}).forEach(function(file) {
|
||||||
log_start_file(file);
|
log("--- {file}", { file: file });
|
||||||
function test_case(test) {
|
function test_case(test) {
|
||||||
log_test(test.name);
|
log(" Running test [{name}]", { name: test.name });
|
||||||
var output_options = test.beautify || {};
|
var output_options = test.beautify || {};
|
||||||
var expect;
|
var expect;
|
||||||
if (test.expect) {
|
if (test.expect) {
|
||||||
expect = make_code(as_toplevel(test.expect, test.mangle), output_options);
|
expect = make_code(to_toplevel(test.expect, test.mangle), output_options);
|
||||||
} else {
|
} else {
|
||||||
expect = test.expect_exact;
|
expect = test.expect_exact;
|
||||||
}
|
}
|
||||||
var input = as_toplevel(test.input, test.mangle);
|
var input = to_toplevel(test.input, test.mangle);
|
||||||
var input_code = make_code(input, output_options);
|
var input_code = make_code(input);
|
||||||
var input_formatted = make_code(test.input, {
|
var input_formatted = make_code(test.input, {
|
||||||
beautify: true,
|
beautify: true,
|
||||||
quote_style: 3,
|
quote_style: 3,
|
||||||
@@ -209,185 +341,27 @@ function run_compress_tests() {
|
|||||||
failed_files[file] = 1;
|
failed_files[file] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
files.forEach(function(file) {
|
|
||||||
test_file(file);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function parse_test(file) {
|
function tmpl() {
|
||||||
var script = fs.readFileSync(file, "utf8");
|
return U.string_template.apply(null, arguments);
|
||||||
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS2/issues/348
|
|
||||||
try {
|
|
||||||
var ast = U.parse(script, {
|
|
||||||
filename: file
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Caught error while parsing tests in " + file + "\n");
|
|
||||||
console.log(e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
var tests = {};
|
|
||||||
var tw = new U.TreeWalker(function(node, descend) {
|
|
||||||
if (node instanceof U.AST_LabeledStatement
|
|
||||||
&& tw.parent() instanceof U.AST_Toplevel) {
|
|
||||||
var name = node.label.name;
|
|
||||||
if (name in tests) {
|
|
||||||
throw new Error('Duplicated test name "' + name + '" in ' + file);
|
|
||||||
}
|
|
||||||
tests[name] = get_one_test(name, node.body);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(node instanceof U.AST_Toplevel)) croak(node);
|
|
||||||
});
|
|
||||||
ast.walk(tw);
|
|
||||||
return tests;
|
|
||||||
|
|
||||||
function croak(node) {
|
|
||||||
throw new Error(tmpl("Can't understand test file {file} [{line},{col}]\n{code}", {
|
|
||||||
file: file,
|
|
||||||
line: node.start.line,
|
|
||||||
col: node.start.col,
|
|
||||||
code: make_code(node, { beautify: false })
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function read_string(stat) {
|
|
||||||
if (stat.TYPE == "SimpleStatement") {
|
|
||||||
var body = stat.body;
|
|
||||||
switch(body.TYPE) {
|
|
||||||
case "String":
|
|
||||||
return body.value;
|
|
||||||
case "Array":
|
|
||||||
return body.elements.map(function(element) {
|
|
||||||
if (element.TYPE !== "String")
|
|
||||||
throw new Error("Should be array of strings");
|
|
||||||
return element.value;
|
|
||||||
}).join("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Error("Should be string or array of strings");
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_one_test(name, block) {
|
|
||||||
var test = { name: name, options: {} };
|
|
||||||
var tw = new U.TreeWalker(function(node, descend) {
|
|
||||||
if (node instanceof U.AST_Assign) {
|
|
||||||
if (!(node.left instanceof U.AST_SymbolRef)) {
|
|
||||||
croak(node);
|
|
||||||
}
|
|
||||||
var name = node.left.name;
|
|
||||||
test[name] = evaluate(node.right);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof U.AST_LabeledStatement) {
|
|
||||||
var label = node.label;
|
|
||||||
assert.ok(
|
|
||||||
[
|
|
||||||
"input",
|
|
||||||
"expect",
|
|
||||||
"expect_exact",
|
|
||||||
"expect_warnings",
|
|
||||||
"expect_stdout",
|
|
||||||
"node_version",
|
|
||||||
].indexOf(label.name) >= 0,
|
|
||||||
tmpl("Unsupported label {name} [{line},{col}]", {
|
|
||||||
name: label.name,
|
|
||||||
line: label.start.line,
|
|
||||||
col: label.start.col
|
|
||||||
})
|
|
||||||
);
|
|
||||||
var stat = node.body;
|
|
||||||
if (label.name == "expect_exact" || label.name == "node_version") {
|
|
||||||
test[label.name] = read_string(stat);
|
|
||||||
} else if (label.name == "expect_stdout") {
|
|
||||||
var body = stat.body;
|
|
||||||
if (body instanceof U.AST_Boolean) {
|
|
||||||
test[label.name] = body.value;
|
|
||||||
} else if (body instanceof U.AST_Call) {
|
|
||||||
var ctor = global[body.expression.name];
|
|
||||||
assert.ok(ctor === Error || ctor.prototype instanceof Error, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
|
||||||
line: label.start.line,
|
|
||||||
col: label.start.col
|
|
||||||
}));
|
|
||||||
test[label.name] = ctor.apply(null, body.args.map(function(node) {
|
|
||||||
assert.ok(node instanceof U.AST_Constant, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
|
||||||
line: label.start.line,
|
|
||||||
col: label.start.col
|
|
||||||
}));
|
|
||||||
return node.value;
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
test[label.name] = read_string(stat) + "\n";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
test[label.name] = stat;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
block.walk(tw);
|
|
||||||
return test;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function make_code(ast, options) {
|
function to_toplevel(input, mangle_options) {
|
||||||
var stream = U.OutputStream(options);
|
if (!(input instanceof U.AST_BlockStatement)) throw new Error("Unsupported input syntax");
|
||||||
ast.print(stream);
|
var directive = true;
|
||||||
return stream.get();
|
var offset = input.start.line;
|
||||||
}
|
var tokens = [];
|
||||||
|
var toplevel = new U.AST_Toplevel(input.transform(new U.TreeTransformer(function(node) {
|
||||||
function evaluate(code) {
|
if (U.push_uniq(tokens, node.start)) node.start.line -= offset;
|
||||||
if (code instanceof U.AST_Node)
|
if (!directive || node === input) return;
|
||||||
code = make_code(code, { beautify: true });
|
if (node instanceof U.AST_SimpleStatement && node.body instanceof U.AST_String) {
|
||||||
return new Function("return(" + code + ")")();
|
return new U.AST_Directive(node.body);
|
||||||
}
|
|
||||||
|
|
||||||
function run_code(code) {
|
|
||||||
var result = sandbox.run_code(code, true);
|
|
||||||
return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to reminify original input with standard options
|
|
||||||
// to see if it matches expect_stdout.
|
|
||||||
function reminify(orig_options, input_code, input_formatted, expect_stdout) {
|
|
||||||
for (var i = 0; i < minify_options.length; i++) {
|
|
||||||
var options = JSON.parse(minify_options[i]);
|
|
||||||
if (options.compress) [
|
|
||||||
"keep_fargs",
|
|
||||||
"keep_fnames",
|
|
||||||
].forEach(function(name) {
|
|
||||||
if (name in orig_options) {
|
|
||||||
options.compress[name] = orig_options[name];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var options_formatted = JSON.stringify(options, null, 4);
|
|
||||||
var result = U.minify(input_code, options);
|
|
||||||
if (result.error) {
|
|
||||||
log("!!! failed input reminify\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n--ERROR---\n{error}\n\n", {
|
|
||||||
input: input_formatted,
|
|
||||||
options: options_formatted,
|
|
||||||
error: result.error,
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
var stdout = run_code(result.code);
|
directive = false;
|
||||||
if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) {
|
|
||||||
stdout = expect_stdout;
|
|
||||||
}
|
|
||||||
if (!sandbox.same_stdout(expect_stdout, stdout)) {
|
|
||||||
log("!!! failed running reminified input\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n---OUTPUT---\n{output}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
|
||||||
input: input_formatted,
|
|
||||||
options: options_formatted,
|
|
||||||
output: result.code,
|
|
||||||
expected_type: typeof expect_stdout == "string" ? "STDOUT" : "ERROR",
|
|
||||||
expected: expect_stdout,
|
|
||||||
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
|
||||||
actual: stdout,
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
})));
|
||||||
return true;
|
toplevel.figure_out_scope(mangle_options);
|
||||||
|
return toplevel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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") {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ if (process.argv[2] == "run") {
|
|||||||
var branch = process.argv[3] || "v" + require("../package.json").version;
|
var branch = process.argv[3] || "v" + require("../package.json").version;
|
||||||
var repository = encodeURIComponent(process.argv[4] || "mishoo/UglifyJS2");
|
var repository = encodeURIComponent(process.argv[4] || "mishoo/UglifyJS2");
|
||||||
var concurrency = process.argv[5] || 1;
|
var concurrency = process.argv[5] || 1;
|
||||||
|
var platform = process.argv[6] || "node/latest";
|
||||||
(function request() {
|
(function request() {
|
||||||
setTimeout(request, (period + wait) / concurrency);
|
setTimeout(request, (period + wait) / concurrency);
|
||||||
var options = url.parse("https://api.travis-ci.org/repo/" + repository + "/requests");
|
var options = url.parse("https://api.travis-ci.org/repo/" + repository + "/requests");
|
||||||
@@ -32,20 +33,18 @@ if (process.argv[2] == "run") {
|
|||||||
res.on("data", console.log);
|
res.on("data", console.log);
|
||||||
}).on("error", console.error).end(JSON.stringify({
|
}).on("error", console.error).end(JSON.stringify({
|
||||||
request: {
|
request: {
|
||||||
message: "ufuzz testing (when idle)",
|
message: "ufuzz testing",
|
||||||
branch: branch,
|
branch: branch,
|
||||||
config: {
|
config: {
|
||||||
merge_mode: "replace",
|
cache: false,
|
||||||
language: "node_js",
|
env: "NODEJS_VER=" + platform,
|
||||||
node_js: "9",
|
|
||||||
sudo: false,
|
|
||||||
script: "node test/travis-ufuzz run"
|
script: "node test/travis-ufuzz run"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
})();
|
})();
|
||||||
} else {
|
} else {
|
||||||
console.log("Usage: test/travis-ufuzz.js <token> [branch] [repository] [concurrency]");
|
console.log("Usage: test/travis-ufuzz.js <token> [branch] [repository] [concurrency] [platform]");
|
||||||
}
|
}
|
||||||
|
|
||||||
function spawn(endTime) {
|
function spawn(endTime) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
|
"ie8": true,
|
||||||
"toplevel": true
|
"toplevel": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
exports["Dictionary"] = Dictionary;
|
exports["Dictionary"] = Dictionary;
|
||||||
exports["TreeWalker"] = TreeWalker;
|
|
||||||
exports["TreeTransformer"] = TreeTransformer;
|
|
||||||
exports["minify"] = minify;
|
exports["minify"] = minify;
|
||||||
exports["parse"] = parse;
|
exports["parse"] = parse;
|
||||||
exports["_push_uniq"] = push_uniq;
|
exports["push_uniq"] = push_uniq;
|
||||||
|
exports["TreeTransformer"] = TreeTransformer;
|
||||||
|
exports["TreeWalker"] = TreeWalker;
|
||||||
|
|||||||
Reference in New Issue
Block a user