Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a57b069409 | ||
|
|
4454656c3b | ||
|
|
fa43768ce0 | ||
|
|
a74e600fa0 | ||
|
|
4b21526310 | ||
|
|
a7a7b1daed | ||
|
|
7436977aa5 | ||
|
|
e3c565b46f | ||
|
|
54b0b49b68 | ||
|
|
65648d84a5 | ||
|
|
fd788590f6 | ||
|
|
143f9054da | ||
|
|
f2286c33f1 | ||
|
|
b9615f7a62 | ||
|
|
c520e99eda | ||
|
|
615ae37ca3 | ||
|
|
7aa7f21872 | ||
|
|
4430a436eb | ||
|
|
9707ccdc9f | ||
|
|
cb8f3a2a31 | ||
|
|
8b3259e0c2 | ||
|
|
b66f47b8dd | ||
|
|
8d2e6f333e | ||
|
|
b3ef5e514d | ||
|
|
627f5fb41e | ||
|
|
d90777b724 | ||
|
|
e49297e5eb | ||
|
|
ebd82b3fb6 | ||
|
|
d074aa6e27 | ||
|
|
b052f62710 | ||
|
|
d4ac84b255 | ||
|
|
e250396d7e | ||
|
|
c6fa39b482 | ||
|
|
9aae4f2424 | ||
|
|
008c236137 | ||
|
|
b1c0664066 |
@@ -19,6 +19,7 @@ env:
|
||||
- NODEJS_VER=node/4
|
||||
- NODEJS_VER=node/6
|
||||
- NODEJS_VER=node/8
|
||||
- NODEJS_VER=node/10
|
||||
- NODEJS_VER=node/latest
|
||||
before_install:
|
||||
- git clone --branch v1.4.2 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs
|
||||
|
||||
@@ -605,6 +605,8 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
- `arguments` (default: `true`) -- replace `arguments[index]` with function
|
||||
parameter name whenever possible.
|
||||
|
||||
- `assignments` (default: `true`) -- apply optimizations to assignment expressions.
|
||||
|
||||
- `booleans` (default: `true`) -- various optimizations for boolean context,
|
||||
for example `!!a ? b : c → a ? b : c`
|
||||
|
||||
@@ -664,7 +666,7 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
|
||||
- `keep_fnames` (default: `false`) -- Pass `true` to prevent the
|
||||
compressor from discarding function names. Useful for code relying on
|
||||
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
|
||||
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle-options).
|
||||
|
||||
- `keep_infinity` (default: `false`) -- Pass `true` to prevent `Infinity` from
|
||||
being compressed into `1/0`, which may cause performance issues on Chrome.
|
||||
|
||||
@@ -6,6 +6,7 @@ environment:
|
||||
- NODEJS_VER: node/4
|
||||
- NODEJS_VER: node/6
|
||||
- NODEJS_VER: node/8
|
||||
- NODEJS_VER: node/10
|
||||
- NODEJS_VER: node/latest
|
||||
install:
|
||||
- git clone --branch v1.4.2 --depth 1 https://github.com/jasongin/nvs.git %LOCALAPPDATA%\nvs
|
||||
|
||||
19
bin/uglifyjs
19
bin/uglifyjs
@@ -56,6 +56,11 @@ program.option("--wrap <name>", "Embed everything as a function with “exports
|
||||
program.arguments("[files...]").parseArgv(process.argv);
|
||||
if (program.configFile) {
|
||||
options = JSON.parse(read_file(program.configFile));
|
||||
if (options.mangle && options.mangle.properties && options.mangle.properties.regex) {
|
||||
options.mangle.properties.regex = UglifyJS.parse(options.mangle.properties.regex, {
|
||||
expression: true
|
||||
}).getValue();
|
||||
}
|
||||
}
|
||||
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
|
||||
fatal("ERROR: cannot write source map to STDOUT");
|
||||
@@ -337,17 +342,9 @@ function parse_js(flag) {
|
||||
return function(value, options) {
|
||||
options = options || {};
|
||||
try {
|
||||
UglifyJS.minify(value, {
|
||||
parse: {
|
||||
expression: true
|
||||
},
|
||||
compress: false,
|
||||
mangle: false,
|
||||
output: {
|
||||
ast: true,
|
||||
code: false
|
||||
}
|
||||
}).ast.walk(new UglifyJS.TreeWalker(function(node) {
|
||||
UglifyJS.parse(value, {
|
||||
expression: true
|
||||
}).walk(new UglifyJS.TreeWalker(function(node) {
|
||||
if (node instanceof UglifyJS.AST_Assign) {
|
||||
var name = node.left.print_to_string();
|
||||
var value = node.right;
|
||||
|
||||
358
lib/compress.js
358
lib/compress.js
@@ -49,6 +49,7 @@ function Compressor(options, false_by_default) {
|
||||
TreeTransformer.call(this, this.before, this.after);
|
||||
this.options = defaults(options, {
|
||||
arguments : !false_by_default,
|
||||
assignments : !false_by_default,
|
||||
booleans : !false_by_default,
|
||||
collapse_vars : !false_by_default,
|
||||
comparisons : !false_by_default,
|
||||
@@ -106,10 +107,16 @@ function Compressor(options, false_by_default) {
|
||||
var pure_funcs = this.options["pure_funcs"];
|
||||
if (typeof pure_funcs == "function") {
|
||||
this.pure_funcs = pure_funcs;
|
||||
} else {
|
||||
this.pure_funcs = pure_funcs ? function(node) {
|
||||
} else if (typeof pure_funcs == "string") {
|
||||
this.pure_funcs = function(node) {
|
||||
return pure_funcs !== node.expression.print_to_string();
|
||||
};
|
||||
} else if (Array.isArray(pure_funcs)) {
|
||||
this.pure_funcs = function(node) {
|
||||
return pure_funcs.indexOf(node.expression.print_to_string()) < 0;
|
||||
} : return_true;
|
||||
};
|
||||
} else {
|
||||
this.pure_funcs = return_true;
|
||||
}
|
||||
var top_retain = this.options["top_retain"];
|
||||
if (top_retain instanceof RegExp) {
|
||||
@@ -497,6 +504,15 @@ merge(Compressor.prototype, {
|
||||
d.direct_access = true;
|
||||
}
|
||||
|
||||
function mark_assignment_to_arguments(node) {
|
||||
if (!(node instanceof AST_Sub)) return;
|
||||
var expr = node.expression;
|
||||
var prop = node.property;
|
||||
if (expr instanceof AST_SymbolRef && expr.name == "arguments" && prop instanceof AST_Number) {
|
||||
expr.definition().reassigned = true;
|
||||
}
|
||||
}
|
||||
|
||||
var suppressor = new TreeWalker(function(node) {
|
||||
if (!(node instanceof AST_Symbol)) return;
|
||||
var d = node.definition();
|
||||
@@ -515,17 +531,18 @@ merge(Compressor.prototype, {
|
||||
def(AST_Assign, function(tw, descend, compressor) {
|
||||
var node = this;
|
||||
var sym = node.left;
|
||||
if (!(sym instanceof AST_SymbolRef)) return;
|
||||
if (!(sym instanceof AST_SymbolRef)) {
|
||||
mark_assignment_to_arguments(sym);
|
||||
return;
|
||||
}
|
||||
var d = sym.definition();
|
||||
var safe = safe_to_assign(tw, d, sym.scope, node.right);
|
||||
d.assignments++;
|
||||
if (!safe) return;
|
||||
var fixed = d.fixed;
|
||||
if (!fixed && node.operator != "=") return;
|
||||
var eq = node.operator == "=";
|
||||
var value = eq ? node.right : node;
|
||||
if (is_modified(compressor, tw, node, value, 0)) return;
|
||||
d.references.push(sym);
|
||||
if (!eq) d.chained = true;
|
||||
d.fixed = eq ? function() {
|
||||
return node.right;
|
||||
@@ -536,6 +553,8 @@ merge(Compressor.prototype, {
|
||||
right: node.right
|
||||
});
|
||||
};
|
||||
if (!safe) return;
|
||||
d.references.push(sym);
|
||||
mark(tw, d, false);
|
||||
node.right.walk(tw);
|
||||
mark(tw, d, true);
|
||||
@@ -758,14 +777,15 @@ merge(Compressor.prototype, {
|
||||
var node = this;
|
||||
if (node.operator != "++" && node.operator != "--") return;
|
||||
var exp = node.expression;
|
||||
if (!(exp instanceof AST_SymbolRef)) return;
|
||||
if (!(exp instanceof AST_SymbolRef)) {
|
||||
mark_assignment_to_arguments(exp);
|
||||
return;
|
||||
}
|
||||
var d = exp.definition();
|
||||
var safe = safe_to_assign(tw, d, exp.scope, true);
|
||||
d.assignments++;
|
||||
if (!safe) return;
|
||||
var fixed = d.fixed;
|
||||
if (!fixed) return;
|
||||
d.references.push(exp);
|
||||
d.chained = true;
|
||||
d.fixed = function() {
|
||||
return make_node(AST_Binary, node, {
|
||||
@@ -779,6 +799,8 @@ merge(Compressor.prototype, {
|
||||
})
|
||||
});
|
||||
};
|
||||
if (!safe) return;
|
||||
d.references.push(exp);
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
});
|
||||
@@ -1079,10 +1101,10 @@ merge(Compressor.prototype, {
|
||||
stop_if_hit = parent;
|
||||
}
|
||||
// Replace variable with assignment when found
|
||||
var hit_lhs, hit_rhs;
|
||||
var hit_rhs;
|
||||
if (can_replace
|
||||
&& !(node instanceof AST_SymbolDeclaration)
|
||||
&& (scan_lhs && (hit_lhs = lhs.equivalent_to(node))
|
||||
&& (scan_lhs && lhs.equivalent_to(node)
|
||||
|| scan_rhs && (hit_rhs = scan_rhs(node, this)))) {
|
||||
if (stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
|
||||
abort = true;
|
||||
@@ -1172,10 +1194,9 @@ merge(Compressor.prototype, {
|
||||
var stop_after = null;
|
||||
var stop_if_hit = null;
|
||||
var lhs = get_lhs(candidate);
|
||||
var rhs = get_rhs(candidate);
|
||||
var side_effects = lhs && lhs.has_side_effects(compressor);
|
||||
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs);
|
||||
var scan_rhs = rhs && foldable(rhs);
|
||||
var scan_rhs = foldable(get_rhs(candidate));
|
||||
if (!scan_lhs && !scan_rhs) continue;
|
||||
// Locate symbols which may execute code outside of scanning range
|
||||
var lvalues = get_lvalues(candidate);
|
||||
@@ -1340,6 +1361,7 @@ merge(Compressor.prototype, {
|
||||
hit_stack.push(expr);
|
||||
if (expr instanceof AST_Assign) {
|
||||
candidates.push(hit_stack.slice());
|
||||
extract_candidates(expr.left);
|
||||
extract_candidates(expr.right);
|
||||
} else if (expr instanceof AST_Binary) {
|
||||
extract_candidates(expr.left);
|
||||
@@ -1355,6 +1377,8 @@ merge(Compressor.prototype, {
|
||||
extract_candidates(expr.alternative);
|
||||
} else if (expr instanceof AST_Definitions) {
|
||||
expr.definitions.forEach(extract_candidates);
|
||||
} else if (expr instanceof AST_Dot) {
|
||||
extract_candidates(expr.expression);
|
||||
} else if (expr instanceof AST_DWLoop) {
|
||||
extract_candidates(expr.condition);
|
||||
if (!(expr.body instanceof AST_Block)) {
|
||||
@@ -1386,6 +1410,9 @@ merge(Compressor.prototype, {
|
||||
expr.expressions.forEach(extract_candidates);
|
||||
} else if (expr instanceof AST_SimpleStatement) {
|
||||
extract_candidates(expr.body);
|
||||
} else if (expr instanceof AST_Sub) {
|
||||
extract_candidates(expr.expression);
|
||||
extract_candidates(expr.property);
|
||||
} else if (expr instanceof AST_Switch) {
|
||||
extract_candidates(expr.expression);
|
||||
expr.body.forEach(extract_candidates);
|
||||
@@ -1444,6 +1471,7 @@ merge(Compressor.prototype, {
|
||||
return node;
|
||||
}
|
||||
if (parent instanceof AST_IterationStatement) return node;
|
||||
if (parent instanceof AST_PropAccess) return node;
|
||||
if (parent instanceof AST_Sequence) {
|
||||
return find_stop(parent, level + 1, parent.tail_node() !== node);
|
||||
}
|
||||
@@ -1502,6 +1530,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function foldable(expr) {
|
||||
if (!expr) return false;
|
||||
if (expr instanceof AST_SymbolRef) {
|
||||
var value = expr.evaluate(compressor);
|
||||
if (value === expr) return rhs_exact_match;
|
||||
@@ -1523,10 +1552,10 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}));
|
||||
return !circular && rhs_exact_match;
|
||||
}
|
||||
|
||||
function rhs_exact_match(node) {
|
||||
return rhs.equivalent_to(node);
|
||||
function rhs_exact_match(node) {
|
||||
return expr.equivalent_to(node);
|
||||
}
|
||||
}
|
||||
|
||||
function rhs_fuzzy_match(value, fallback) {
|
||||
@@ -1570,13 +1599,19 @@ merge(Compressor.prototype, {
|
||||
var found = false;
|
||||
return statements[stat_index].transform(new TreeTransformer(function(node, descend, in_list) {
|
||||
if (found) return node;
|
||||
if (node === expr || node.body === expr) {
|
||||
if (node !== expr && node.body !== expr) return;
|
||||
if (node instanceof AST_VarDef) {
|
||||
found = true;
|
||||
if (node instanceof AST_VarDef) {
|
||||
node.value = null;
|
||||
return node;
|
||||
}
|
||||
return in_list ? MAP.skip : null;
|
||||
node.value = null;
|
||||
return node;
|
||||
}
|
||||
if (in_list) {
|
||||
found = true;
|
||||
return MAP.skip;
|
||||
}
|
||||
if (!this.parent()) {
|
||||
found = true;
|
||||
return null;
|
||||
}
|
||||
}, function(node) {
|
||||
if (node instanceof AST_Sequence) switch (node.expressions.length) {
|
||||
@@ -1616,7 +1651,7 @@ merge(Compressor.prototype, {
|
||||
function symbol_in_lvalues(sym, parent) {
|
||||
var lvalue = lvalues[sym.name];
|
||||
if (!lvalue) return;
|
||||
if (lvalue !== lhs) return !(parent instanceof AST_Call);
|
||||
if (lvalue !== lhs) return !(parent instanceof AST_Call && parent.expression === sym);
|
||||
scan_rhs = false;
|
||||
}
|
||||
|
||||
@@ -2211,7 +2246,11 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
def(AST_SymbolRef, function() {
|
||||
var fixed = this.fixed_value();
|
||||
return fixed && fixed.is_truthy();
|
||||
if (!fixed) return false;
|
||||
this.is_truthy = return_false;
|
||||
var result = fixed.is_truthy();
|
||||
delete this.is_truthy;
|
||||
return result;
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("is_truthy", func);
|
||||
@@ -2224,45 +2263,38 @@ merge(Compressor.prototype, {
|
||||
return !compressor.option("pure_getters")
|
||||
|| this._dot_throw(compressor);
|
||||
});
|
||||
|
||||
function is_strict(compressor) {
|
||||
return /strict/.test(compressor.option("pure_getters"));
|
||||
}
|
||||
|
||||
def(AST_Node, is_strict);
|
||||
def(AST_Null, return_true);
|
||||
def(AST_Undefined, return_true);
|
||||
def(AST_Constant, return_false);
|
||||
def(AST_Array, return_false);
|
||||
def(AST_Object, function(compressor) {
|
||||
if (!is_strict(compressor)) return false;
|
||||
for (var i = this.properties.length; --i >=0;)
|
||||
if (this.properties[i].value instanceof AST_Accessor) return true;
|
||||
return false;
|
||||
});
|
||||
def(AST_Lambda, return_false);
|
||||
def(AST_UnaryPostfix, return_false);
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "void";
|
||||
});
|
||||
def(AST_Binary, function(compressor) {
|
||||
return (this.operator == "&&" || this.operator == "||")
|
||||
&& (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
|
||||
})
|
||||
def(AST_Assign, function(compressor) {
|
||||
return this.operator == "="
|
||||
&& this.right._dot_throw(compressor);
|
||||
})
|
||||
def(AST_Binary, function(compressor) {
|
||||
return (this.operator == "&&" || this.operator == "||")
|
||||
&& (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
|
||||
})
|
||||
def(AST_Conditional, function(compressor) {
|
||||
return this.consequent._dot_throw(compressor)
|
||||
|| this.alternative._dot_throw(compressor);
|
||||
})
|
||||
def(AST_Constant, return_false);
|
||||
def(AST_Dot, function(compressor) {
|
||||
if (!is_strict(compressor)) return false;
|
||||
var exp = this.expression;
|
||||
if (exp instanceof AST_SymbolRef) exp = exp.fixed_value();
|
||||
return !(exp instanceof AST_Lambda && this.property == "prototype");
|
||||
});
|
||||
def(AST_Lambda, return_false);
|
||||
def(AST_Null, return_true);
|
||||
def(AST_Object, function(compressor) {
|
||||
if (!is_strict(compressor)) return false;
|
||||
for (var i = this.properties.length; --i >=0;)
|
||||
if (this.properties[i].value instanceof AST_Accessor) return true;
|
||||
return false;
|
||||
});
|
||||
def(AST_Sequence, function(compressor) {
|
||||
return this.tail_node()._dot_throw(compressor);
|
||||
});
|
||||
@@ -2272,8 +2304,17 @@ merge(Compressor.prototype, {
|
||||
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
||||
if (this.is_immutable()) return false;
|
||||
var fixed = this.fixed_value();
|
||||
return !fixed || fixed._dot_throw(compressor);
|
||||
if (!fixed) return true;
|
||||
this._dot_throw = return_true;
|
||||
var result = fixed._dot_throw(compressor);
|
||||
delete this._dot_throw;
|
||||
return result;
|
||||
});
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "void";
|
||||
});
|
||||
def(AST_UnaryPostfix, return_false);
|
||||
def(AST_Undefined, return_true);
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("_dot_throw", func);
|
||||
});
|
||||
@@ -2307,6 +2348,14 @@ merge(Compressor.prototype, {
|
||||
def(AST_Sequence, function(compressor) {
|
||||
return this.tail_node().is_boolean(compressor);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor) {
|
||||
var fixed = this.fixed_value();
|
||||
if (!fixed) return false;
|
||||
this.is_boolean = return_false;
|
||||
var result = fixed.is_boolean(compressor);
|
||||
delete this.is_boolean;
|
||||
return result;
|
||||
});
|
||||
var unary = makePredicate("! delete");
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return unary[this.operator];
|
||||
@@ -2388,6 +2437,14 @@ merge(Compressor.prototype, {
|
||||
def(AST_Sequence, function(compressor) {
|
||||
return this.tail_node().is_number(compressor);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor) {
|
||||
var fixed = this.fixed_value();
|
||||
if (!fixed) return false;
|
||||
this.is_number = return_false;
|
||||
var result = fixed.is_number(compressor);
|
||||
delete this.is_number;
|
||||
return result;
|
||||
});
|
||||
var unary = makePredicate("+ - ~ ++ --");
|
||||
def(AST_Unary, function() {
|
||||
return unary[this.operator];
|
||||
@@ -2399,22 +2456,30 @@ merge(Compressor.prototype, {
|
||||
// methods to determine if an expression has a string result type
|
||||
(function(def) {
|
||||
def(AST_Node, return_false);
|
||||
def(AST_String, return_true);
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "typeof";
|
||||
def(AST_Assign, function(compressor) {
|
||||
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
|
||||
});
|
||||
def(AST_Binary, function(compressor) {
|
||||
return this.operator == "+" &&
|
||||
(this.left.is_string(compressor) || this.right.is_string(compressor));
|
||||
});
|
||||
def(AST_Assign, function(compressor) {
|
||||
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
|
||||
def(AST_Conditional, function(compressor) {
|
||||
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
||||
});
|
||||
def(AST_Sequence, function(compressor) {
|
||||
return this.tail_node().is_string(compressor);
|
||||
});
|
||||
def(AST_Conditional, function(compressor) {
|
||||
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
||||
def(AST_String, return_true);
|
||||
def(AST_SymbolRef, function(compressor) {
|
||||
var fixed = this.fixed_value();
|
||||
if (!fixed) return false;
|
||||
this.is_string = return_false;
|
||||
var result = fixed.is_string(compressor);
|
||||
delete this.is_string;
|
||||
return result;
|
||||
});
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "typeof";
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("is_string", func);
|
||||
@@ -2700,19 +2765,25 @@ merge(Compressor.prototype, {
|
||||
return typeof function(){};
|
||||
}
|
||||
if (!non_converting_unary[this.operator]) depth++;
|
||||
e = e._eval(compressor, cached, depth);
|
||||
if (e === this.expression) return this;
|
||||
var v = e._eval(compressor, cached, depth);
|
||||
if (v === this.expression) return this;
|
||||
switch (this.operator) {
|
||||
case "!": return !e;
|
||||
case "!": return !v;
|
||||
case "typeof":
|
||||
// typeof <RegExp> returns "object" or "function" on different platforms
|
||||
// so cannot evaluate reliably
|
||||
if (e instanceof RegExp) return this;
|
||||
return typeof e;
|
||||
case "void": return void e;
|
||||
case "~": return ~e;
|
||||
case "-": return -e;
|
||||
case "+": return +e;
|
||||
if (v instanceof RegExp) return this;
|
||||
return typeof v;
|
||||
case "void": return void v;
|
||||
case "~": return ~v;
|
||||
case "-": return -v;
|
||||
case "+": return +v;
|
||||
case "++":
|
||||
case "--":
|
||||
if (e instanceof AST_SymbolRef) {
|
||||
var refs = e.definition().references;
|
||||
if (refs[refs.length - 1] === e) return v;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
});
|
||||
@@ -3207,6 +3278,12 @@ merge(Compressor.prototype, {
|
||||
return true;
|
||||
}
|
||||
def(AST_Node, return_false);
|
||||
def(AST_Array, function() {
|
||||
return all(this.elements);
|
||||
});
|
||||
def(AST_Binary, function() {
|
||||
return this.left.is_constant_expression() && this.right.is_constant_expression();
|
||||
});
|
||||
def(AST_Constant, return_true);
|
||||
def(AST_Lambda, function(scope) {
|
||||
var self = this;
|
||||
@@ -3235,21 +3312,15 @@ merge(Compressor.prototype, {
|
||||
}));
|
||||
return result;
|
||||
});
|
||||
def(AST_Unary, function() {
|
||||
return this.expression.is_constant_expression();
|
||||
});
|
||||
def(AST_Binary, function() {
|
||||
return this.left.is_constant_expression() && this.right.is_constant_expression();
|
||||
});
|
||||
def(AST_Array, function() {
|
||||
return all(this.elements);
|
||||
});
|
||||
def(AST_Object, function() {
|
||||
return all(this.properties);
|
||||
});
|
||||
def(AST_ObjectProperty, function() {
|
||||
return this.value.is_constant_expression();
|
||||
});
|
||||
def(AST_Unary, function() {
|
||||
return this.expression.is_constant_expression();
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("is_constant_expression", func);
|
||||
});
|
||||
@@ -3959,17 +4030,17 @@ merge(Compressor.prototype, {
|
||||
return this;
|
||||
});
|
||||
def(AST_Binary, function(compressor, first_in_statement) {
|
||||
var right = this.right.drop_side_effect_free(compressor);
|
||||
var right = this.right.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (!right) return this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (lazy_op[this.operator]) {
|
||||
if (right === this.right) return this;
|
||||
var node = this.clone();
|
||||
node.right = right;
|
||||
node.right = right.drop_side_effect_free(compressor);
|
||||
return node;
|
||||
} else {
|
||||
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (!left) return this.right.drop_side_effect_free(compressor, first_in_statement);
|
||||
return make_sequence(this, [ left, right ]);
|
||||
if (!left) return right;
|
||||
return make_sequence(this, [ left, right.drop_side_effect_free(compressor) ]);
|
||||
}
|
||||
});
|
||||
def(AST_Call, function(compressor, first_in_statement) {
|
||||
@@ -4029,19 +4100,6 @@ merge(Compressor.prototype, {
|
||||
def(AST_Function, function(compressor) {
|
||||
return this.name && compressor.option("ie8") ? this : null;
|
||||
});
|
||||
def(AST_Unary, function(compressor, first_in_statement) {
|
||||
if (unary_side_effects[this.operator]) {
|
||||
this.write_only = !this.expression.has_side_effects(compressor);
|
||||
return this;
|
||||
}
|
||||
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) return null;
|
||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (first_in_statement && expression && is_iife_call(expression)) {
|
||||
if (expression === this.expression && this.operator == "!") return this;
|
||||
return expression.negate(compressor, first_in_statement);
|
||||
}
|
||||
return expression;
|
||||
});
|
||||
def(AST_Object, function(compressor, first_in_statement) {
|
||||
var values = trim(this.properties, compressor, first_in_statement);
|
||||
return values && make_sequence(this, values);
|
||||
@@ -4049,12 +4107,10 @@ merge(Compressor.prototype, {
|
||||
def(AST_ObjectProperty, function(compressor, first_in_statement) {
|
||||
return this.value.drop_side_effect_free(compressor, first_in_statement);
|
||||
});
|
||||
def(AST_Sequence, function(compressor) {
|
||||
var last = this.tail_node();
|
||||
var expr = last.drop_side_effect_free(compressor);
|
||||
if (expr === last) return this;
|
||||
var expressions = this.expressions.slice(0, -1);
|
||||
if (expr) expressions.push(expr);
|
||||
def(AST_Sequence, function(compressor, first_in_statement) {
|
||||
var expressions = trim(this.expressions, compressor, first_in_statement);
|
||||
if (expressions === this.expressions) return this;
|
||||
if (!expressions) return null;
|
||||
return make_sequence(this, expressions);
|
||||
});
|
||||
def(AST_Sub, function(compressor, first_in_statement) {
|
||||
@@ -4066,9 +4122,27 @@ merge(Compressor.prototype, {
|
||||
return make_sequence(this, [ expression, property ]);
|
||||
});
|
||||
def(AST_SymbolRef, function(compressor) {
|
||||
return this.is_declared(compressor) ? null : this;
|
||||
if (!this.is_declared(compressor)) return this;
|
||||
this.definition().replaced++;
|
||||
return null;
|
||||
});
|
||||
def(AST_This, return_null);
|
||||
def(AST_Unary, function(compressor, first_in_statement) {
|
||||
if (unary_side_effects[this.operator]) {
|
||||
this.write_only = !this.expression.has_side_effects(compressor);
|
||||
return this;
|
||||
}
|
||||
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) {
|
||||
this.expression.definition().replaced++;
|
||||
return null;
|
||||
}
|
||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (first_in_statement && expression && is_iife_call(expression)) {
|
||||
if (expression === this.expression && this.operator == "!") return this;
|
||||
return expression.negate(compressor, first_in_statement);
|
||||
}
|
||||
return expression;
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("drop_side_effect_free", func);
|
||||
});
|
||||
@@ -4563,9 +4637,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
|
||||
OPT(AST_Definitions, function(self, compressor) {
|
||||
if (self.definitions.length == 0)
|
||||
return make_node(AST_EmptyStatement, self);
|
||||
return self;
|
||||
return self.definitions.length ? self : make_node(AST_EmptyStatement, self);
|
||||
});
|
||||
|
||||
AST_Call.DEFMETHOD("lift_sequences", function(compressor) {
|
||||
@@ -4619,12 +4691,30 @@ merge(Compressor.prototype, {
|
||||
if (compressor.option("unsafe")) {
|
||||
if (is_undeclared_ref(exp)) switch (exp.name) {
|
||||
case "Array":
|
||||
if (self.args.length != 1) {
|
||||
return make_node(AST_Array, self, {
|
||||
elements: self.args
|
||||
}).optimize(compressor);
|
||||
if (self.args.length == 1) {
|
||||
var first = self.args[0];
|
||||
if (first instanceof AST_Number) try {
|
||||
var length = first.getValue();
|
||||
if (length > 6) break;
|
||||
var elements = Array(length);
|
||||
for (var i = 0; i < length; i++) elements[i] = make_node(AST_Hole, self);
|
||||
return make_node(AST_Array, self, {
|
||||
elements: elements
|
||||
});
|
||||
} catch (ex) {
|
||||
compressor.warn("Invalid array length: {length} [{file}:{line},{col}]", {
|
||||
length: length,
|
||||
file: self.start.file,
|
||||
line: self.start.line,
|
||||
col: self.start.col
|
||||
});
|
||||
break;
|
||||
}
|
||||
if (!first.is_boolean(compressor) && !first.is_string(compressor)) break;
|
||||
}
|
||||
break;
|
||||
return make_node(AST_Array, self, {
|
||||
elements: self.args
|
||||
});
|
||||
case "Object":
|
||||
if (self.args.length == 0) {
|
||||
return make_node(AST_Object, self, {
|
||||
@@ -4972,8 +5062,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function can_inject_vars(catches, safe_to_inject) {
|
||||
var len = fn.body.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
for (var i = 0, len = fn.body.length; i < len; i++) {
|
||||
var stat = fn.body[i];
|
||||
if (!(stat instanceof AST_Var)) continue;
|
||||
if (!safe_to_inject) return false;
|
||||
@@ -5002,7 +5091,8 @@ merge(Compressor.prototype, {
|
||||
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||
}
|
||||
} while (!(scope instanceof AST_Scope));
|
||||
var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars;
|
||||
var safe_to_inject = (!(scope instanceof AST_Toplevel) || compressor.toplevel.vars)
|
||||
&& (exp !== fn || fn.parent_scope === compressor.find_parent(AST_Scope));
|
||||
var inline = compressor.option("inline");
|
||||
if (!can_inject_vars(catches, inline >= 3 && safe_to_inject)) return false;
|
||||
if (!can_inject_args(catches, inline >= 2 && safe_to_inject)) return false;
|
||||
@@ -5772,8 +5862,8 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (single_use && fixed) {
|
||||
def.single_use = false;
|
||||
fixed._squeezed = true;
|
||||
if (fixed instanceof AST_Defun) {
|
||||
fixed._squeezed = true;
|
||||
fixed = make_node(AST_Function, fixed, fixed);
|
||||
fixed.name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
|
||||
}
|
||||
@@ -5797,12 +5887,21 @@ merge(Compressor.prototype, {
|
||||
lambda_def.references.push(node);
|
||||
} else {
|
||||
def.single_use = false;
|
||||
var fn = node.fixed_value();
|
||||
if (!(fn instanceof AST_Lambda)) return;
|
||||
if (!fn.name) return;
|
||||
if (fixed.variables.get(fn.name.name) !== fn.name.definition()) return;
|
||||
fn.name = fn.name.clone();
|
||||
var value_def = value.variables.get(fn.name.name) || value.def_function(fn.name);
|
||||
node.thedef = value_def;
|
||||
value_def.references.push(node);
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
value = fixed.optimize(compressor);
|
||||
if (value === fixed) value = fixed.clone(true);
|
||||
}
|
||||
def.replaced++;
|
||||
return value;
|
||||
}
|
||||
if (fixed && def.should_replace === undefined) {
|
||||
@@ -5845,7 +5944,9 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
if (def.should_replace) {
|
||||
return def.should_replace();
|
||||
var value = def.should_replace();
|
||||
def.replaced++;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
@@ -5969,6 +6070,7 @@ merge(Compressor.prototype, {
|
||||
|| parent instanceof AST_Sequence && parent.tail_node() === node);
|
||||
}
|
||||
self = self.lift_sequences(compressor);
|
||||
if (!compressor.option("assignments")) return self;
|
||||
if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
|
||||
// x = expr1 OP expr2
|
||||
if (self.right.left instanceof AST_SymbolRef
|
||||
@@ -5987,6 +6089,16 @@ merge(Compressor.prototype, {
|
||||
self.right = self.right.left;
|
||||
}
|
||||
}
|
||||
if ((self.operator == "+=" || self.operator == "-=")
|
||||
&& self.left.is_number(compressor)
|
||||
&& self.right instanceof AST_Number
|
||||
&& self.right.getValue() === 1) {
|
||||
var op = self.operator.slice(0, -1);
|
||||
return make_node(AST_UnaryPrefix, self, {
|
||||
operator: op + op,
|
||||
expression: self.left
|
||||
});
|
||||
}
|
||||
return self;
|
||||
|
||||
function in_try(level, node) {
|
||||
@@ -6051,12 +6163,14 @@ merge(Compressor.prototype, {
|
||||
if (seq_tail instanceof AST_Assign) {
|
||||
var is_eq = seq_tail.operator == "=";
|
||||
var alt_tail = is_eq ? alternative.tail_node() : alternative;
|
||||
if ((is_eq || consequent instanceof AST_Assign)
|
||||
if ((is_eq || consequent === seq_tail)
|
||||
&& alt_tail instanceof AST_Assign
|
||||
&& seq_tail.operator == alt_tail.operator
|
||||
&& seq_tail.left.equivalent_to(alt_tail.left)
|
||||
&& (!condition.has_side_effects(compressor)
|
||||
|| is_eq && !seq_tail.left.has_side_effects(compressor))) {
|
||||
&& (is_eq && !seq_tail.left.has_side_effects(compressor)
|
||||
|| !condition.has_side_effects(compressor)
|
||||
&& can_shift_lhs_of_tail(consequent)
|
||||
&& can_shift_lhs_of_tail(alternative))) {
|
||||
return make_node(AST_Assign, self, {
|
||||
operator: seq_tail.operator,
|
||||
left: seq_tail.left,
|
||||
@@ -6221,6 +6335,19 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
function can_shift_lhs_of_tail(node) {
|
||||
if (node === node.tail_node()) return true;
|
||||
var exprs = node.expressions;
|
||||
for (var i = exprs.length - 1; --i >= 0;) {
|
||||
var expr = exprs[i];
|
||||
if (!(expr instanceof AST_Assign) && expr.has_side_effects(compressor)
|
||||
|| expr.operator != "="
|
||||
|| expr.left.has_side_effects(compressor)
|
||||
|| expr.right.has_side_effects(compressor)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function pop_lhs(node) {
|
||||
if (!(node instanceof AST_Sequence)) return node.right;
|
||||
var exprs = node.expressions.slice();
|
||||
@@ -6304,13 +6431,16 @@ merge(Compressor.prototype, {
|
||||
&& expr instanceof AST_SymbolRef
|
||||
&& expr.name == "arguments"
|
||||
&& expr.definition().orig.length == 1
|
||||
&& (fn = expr.scope) instanceof AST_Lambda
|
||||
&& prop instanceof AST_Number) {
|
||||
&& prop instanceof AST_Number
|
||||
&& (fn = expr.scope) === compressor.find_parent(AST_Lambda)) {
|
||||
var index = prop.getValue();
|
||||
var argname = fn.argnames[index];
|
||||
if (argname && compressor.has_directive("use strict")) {
|
||||
var def = argname.definition();
|
||||
if (!compressor.option("reduce_vars") || def.assignments || def.orig.length > 1) {
|
||||
if (!compressor.option("reduce_vars")
|
||||
|| expr.definition().reassigned
|
||||
|| def.assignments
|
||||
|| def.orig.length > 1) {
|
||||
argname = null;
|
||||
}
|
||||
} else if (!argname && !compressor.option("keep_fargs") && index < fn.argnames.length + 5) {
|
||||
@@ -6423,7 +6553,7 @@ merge(Compressor.prototype, {
|
||||
|
||||
OPT(AST_Dot, function(self, compressor) {
|
||||
if (self.property == "arguments" || self.property == "caller") {
|
||||
compressor.warn("Function.protoype.{prop} not supported [{file}:{line},{col}]", {
|
||||
compressor.warn("Function.prototype.{prop} not supported [{file}:{line},{col}]", {
|
||||
prop: self.property,
|
||||
file: self.start.file,
|
||||
line: self.start.line,
|
||||
|
||||
29
lib/parse.js
29
lib/parse.js
@@ -758,17 +758,21 @@ function parse($TEXT, options) {
|
||||
croak(msg, token.line, token.col);
|
||||
}
|
||||
|
||||
function token_to_string(type, value) {
|
||||
return type + (value === undefined ? "" : " «" + value + "»");
|
||||
}
|
||||
|
||||
function unexpected(token) {
|
||||
if (token == null)
|
||||
token = S.token;
|
||||
token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
|
||||
token_error(token, "Unexpected token: " + token_to_string(token.type, token.value));
|
||||
}
|
||||
|
||||
function expect_token(type, val) {
|
||||
if (is(type, val)) {
|
||||
return next();
|
||||
}
|
||||
token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
|
||||
token_error(S.token, "Unexpected token: " + token_to_string(S.token.type, S.token.value) + ", expected: " + token_to_string(type, val));
|
||||
}
|
||||
|
||||
function expect(punc) {
|
||||
@@ -788,7 +792,7 @@ function parse($TEXT, options) {
|
||||
|
||||
function semicolon(optional) {
|
||||
if (is("punc", ";")) next();
|
||||
else if (!optional && !can_insert_semicolon()) unexpected();
|
||||
else if (!optional && !can_insert_semicolon()) expect_token("punc", ";");
|
||||
}
|
||||
|
||||
function parenthesised() {
|
||||
@@ -1069,7 +1073,7 @@ function parse($TEXT, options) {
|
||||
var in_statement = ctor === AST_Defun;
|
||||
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
|
||||
if (in_statement && !name)
|
||||
unexpected();
|
||||
expect_token("name");
|
||||
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
||||
unexpected(prev());
|
||||
expect("(");
|
||||
@@ -1119,7 +1123,7 @@ function parse($TEXT, options) {
|
||||
expect("{");
|
||||
var a = [];
|
||||
while (!is("punc", "}")) {
|
||||
if (is("eof")) unexpected();
|
||||
if (is("eof")) expect_token("punc", "}");
|
||||
a.push(statement(strict_defun));
|
||||
}
|
||||
next();
|
||||
@@ -1130,7 +1134,7 @@ function parse($TEXT, options) {
|
||||
expect("{");
|
||||
var a = [], cur = null, branch = null, tmp;
|
||||
while (!is("punc", "}")) {
|
||||
if (is("eof")) unexpected();
|
||||
if (is("eof")) expect_token("punc", "}");
|
||||
if (is("keyword", "case")) {
|
||||
if (branch) branch.end = prev();
|
||||
cur = [];
|
||||
@@ -1141,8 +1145,7 @@ function parse($TEXT, options) {
|
||||
});
|
||||
a.push(branch);
|
||||
expect(":");
|
||||
}
|
||||
else if (is("keyword", "default")) {
|
||||
} else if (is("keyword", "default")) {
|
||||
if (branch) branch.end = prev();
|
||||
cur = [];
|
||||
branch = new AST_Default({
|
||||
@@ -1150,8 +1153,7 @@ function parse($TEXT, options) {
|
||||
body : cur
|
||||
});
|
||||
a.push(branch);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (!cur) unexpected();
|
||||
cur.push(statement());
|
||||
}
|
||||
@@ -1420,10 +1422,10 @@ function parse($TEXT, options) {
|
||||
}
|
||||
|
||||
function as_name() {
|
||||
var tmp = S.token;
|
||||
if (tmp.type != "name") unexpected();
|
||||
if (!is("name")) expect_token("name");
|
||||
var name = S.token.value;
|
||||
next();
|
||||
return tmp.value;
|
||||
return name;
|
||||
}
|
||||
|
||||
function _make_symbol(type) {
|
||||
@@ -1625,6 +1627,7 @@ function parse($TEXT, options) {
|
||||
}
|
||||
|
||||
if (options.expression) {
|
||||
handle_regexp();
|
||||
return expression(true);
|
||||
}
|
||||
|
||||
|
||||
22
lib/scope.js
22
lib/scope.js
@@ -198,24 +198,20 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
}
|
||||
if (node instanceof AST_SymbolLambda) {
|
||||
var def = node.thedef;
|
||||
if (def.orig.length == 1) {
|
||||
redefine(node, node.scope.parent_scope);
|
||||
node.thedef.init = def.init;
|
||||
}
|
||||
redefine(node, node.scope.parent_scope);
|
||||
node.thedef.init = def.init;
|
||||
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);
|
||||
var old_def = node.thedef;
|
||||
var new_def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node);
|
||||
old_def.orig.concat(old_def.references).forEach(function(node) {
|
||||
node.thedef = new_def;
|
||||
node.reference(options);
|
||||
});
|
||||
node.thedef = def;
|
||||
node.reference(options);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -309,8 +305,12 @@ function names_in_use(scope, options) {
|
||||
if (!names) {
|
||||
scope.names_in_use = names = Object.create(scope.mangled_names || null);
|
||||
scope.cname_holes = [];
|
||||
var cache = options.cache && options.cache.props;
|
||||
scope.enclosed.forEach(function(def) {
|
||||
if (def.unmangleable(options)) names[def.name] = true;
|
||||
if (def.global && cache && cache.has(def.name)) {
|
||||
names[cache.get(def.name)] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
return names;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.4.9",
|
||||
"version": "3.5.4",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
@@ -23,12 +23,12 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "~2.17.1",
|
||||
"commander": "~2.20.0",
|
||||
"source-map": "~0.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"acorn": "~5.7.1",
|
||||
"semver": "~5.5.0"
|
||||
"acorn": "~6.1.1",
|
||||
"semver": "~6.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node test/run-tests.js"
|
||||
|
||||
@@ -237,3 +237,342 @@ duplicate_argname: {
|
||||
}
|
||||
expect_stdout: "bar 42 foo 42 bar"
|
||||
}
|
||||
|
||||
issue_3273: {
|
||||
options = {
|
||||
arguments: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
console.log(a, a);
|
||||
a++;
|
||||
console.log(a, a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
"1 1",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3273_reduce_vars: {
|
||||
options = {
|
||||
arguments: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
console.log(a, a);
|
||||
a++;
|
||||
console.log(a, a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
"1 1",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3273_local_strict: {
|
||||
options = {
|
||||
arguments: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
"use strict";
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
"use strict";
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
"1 0",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3273_local_strict_reduce_vars: {
|
||||
options = {
|
||||
arguments: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
"use strict";
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
"use strict";
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
"1 0",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3273_global_strict: {
|
||||
options = {
|
||||
arguments: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
"1 0",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3273_global_strict_reduce_vars: {
|
||||
options = {
|
||||
arguments: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
function f(a) {
|
||||
console.log(arguments[0], a);
|
||||
arguments[0]++;
|
||||
console.log(arguments[0], a);
|
||||
}
|
||||
f(0);
|
||||
}
|
||||
expect_stdout: [
|
||||
"0 0",
|
||||
"1 0",
|
||||
]
|
||||
}
|
||||
|
||||
issue_3282_1: {
|
||||
options = {
|
||||
arguments: true,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(t) {
|
||||
return function() {
|
||||
t();
|
||||
};
|
||||
})(function() {
|
||||
'use strict';
|
||||
function e() {
|
||||
return arguments[0];
|
||||
}
|
||||
e();
|
||||
e();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
return function() {
|
||||
(function() {
|
||||
"use strict";
|
||||
function e() {
|
||||
return arguments[0];
|
||||
}
|
||||
e();
|
||||
e();
|
||||
})();
|
||||
};
|
||||
})()();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_3282_1_passes: {
|
||||
options = {
|
||||
arguments: true,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(t) {
|
||||
return function() {
|
||||
t();
|
||||
};
|
||||
})(function() {
|
||||
'use strict';
|
||||
function e() {
|
||||
return arguments[0];
|
||||
}
|
||||
e();
|
||||
e();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
return function() {
|
||||
(function() {
|
||||
"use strict";
|
||||
function e(argument_0) {
|
||||
return argument_0;
|
||||
}
|
||||
e();
|
||||
e();
|
||||
})();
|
||||
};
|
||||
})()();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_3282_2: {
|
||||
options = {
|
||||
arguments: true,
|
||||
reduce_vars: true,
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(f) {
|
||||
f();
|
||||
})(function() {
|
||||
return (function(t) {
|
||||
return function() {
|
||||
t();
|
||||
};
|
||||
})(function() {
|
||||
'use strict';
|
||||
function e() {
|
||||
return arguments[0];
|
||||
}
|
||||
e();
|
||||
e();
|
||||
})();
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function() {
|
||||
return function(t) {
|
||||
return function() {
|
||||
t();
|
||||
};
|
||||
}(function() {
|
||||
"use strict";
|
||||
function e() {
|
||||
return arguments[0];
|
||||
}
|
||||
e();
|
||||
e();
|
||||
})();
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_3282_2_passes: {
|
||||
options = {
|
||||
arguments: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
keep_fargs: false,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(f) {
|
||||
f();
|
||||
})(function() {
|
||||
return (function(t) {
|
||||
return function() {
|
||||
t();
|
||||
};
|
||||
})(function() {
|
||||
'use strict';
|
||||
function e() {
|
||||
return arguments[0];
|
||||
}
|
||||
e();
|
||||
e();
|
||||
})();
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function() {
|
||||
return function(t) {
|
||||
return function() {
|
||||
t();
|
||||
};
|
||||
}(function() {
|
||||
"use strict";
|
||||
function e(argument_0) {
|
||||
return argument_0;
|
||||
}
|
||||
e();
|
||||
e();
|
||||
})();
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -239,3 +239,113 @@ index_length: {
|
||||
}
|
||||
expect_stdout: "1 2"
|
||||
}
|
||||
|
||||
constructor_bad: {
|
||||
options = {
|
||||
unsafe: true
|
||||
}
|
||||
input: {
|
||||
try {
|
||||
Array(NaN);
|
||||
console.log("FAIL1");
|
||||
} catch (ex) {
|
||||
try {
|
||||
new Array(NaN);
|
||||
console.log("FAIL2");
|
||||
} catch (ex) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
try {
|
||||
Array(3.14);
|
||||
console.log("FAIL1");
|
||||
} catch (ex) {
|
||||
try {
|
||||
new Array(3.14);
|
||||
console.log("FAIL2");
|
||||
} catch (ex) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
try {
|
||||
Array(NaN);
|
||||
console.log("FAIL1");
|
||||
} catch (ex) {
|
||||
try {
|
||||
Array(NaN);
|
||||
console.log("FAIL2");
|
||||
} catch (ex) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
try {
|
||||
Array(3.14);
|
||||
console.log("FAIL1");
|
||||
} catch (ex) {
|
||||
try {
|
||||
Array(3.14);
|
||||
console.log("FAIL2");
|
||||
} catch (ex) {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
}
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"PASS",
|
||||
]
|
||||
expect_warnings: [
|
||||
"WARN: Invalid array length: 3.14 [test/compress/arrays.js:13,12]",
|
||||
"WARN: Invalid array length: 3.14 [test/compress/arrays.js:17,16]",
|
||||
]
|
||||
}
|
||||
|
||||
constructor_good: {
|
||||
options = {
|
||||
unsafe: true
|
||||
}
|
||||
input: {
|
||||
console.log(Array());
|
||||
console.log(Array(0));
|
||||
console.log(Array(1));
|
||||
console.log(Array(6));
|
||||
console.log(Array(7));
|
||||
console.log(Array(1, 2));
|
||||
console.log(Array(false));
|
||||
console.log(Array("foo"));
|
||||
console.log(Array(Array));
|
||||
console.log(new Array());
|
||||
console.log(new Array(0));
|
||||
console.log(new Array(1));
|
||||
console.log(new Array(6));
|
||||
console.log(new Array(7));
|
||||
console.log(new Array(1, 2));
|
||||
console.log(new Array(false));
|
||||
console.log(new Array("foo"));
|
||||
console.log(new Array(Array));
|
||||
}
|
||||
expect: {
|
||||
console.log([]);
|
||||
console.log([]);
|
||||
console.log([,]);
|
||||
console.log([,,,,,,]);
|
||||
console.log(Array(7));
|
||||
console.log([ 1, 2 ]);
|
||||
console.log([ false ]);
|
||||
console.log([ "foo" ]);
|
||||
console.log(Array(Array));
|
||||
console.log([]);
|
||||
console.log([]);
|
||||
console.log([,]);
|
||||
console.log([,,,,,,]);
|
||||
console.log(Array(7));
|
||||
console.log([ 1, 2 ]);
|
||||
console.log([ false ]);
|
||||
console.log([ "foo" ]);
|
||||
console.log(Array(Array));
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_warnings: []
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
asm_mixed: {
|
||||
options = {
|
||||
assignments: true,
|
||||
booleans: true,
|
||||
comparisons: true,
|
||||
conditionals: true,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
op_equals_left_local_var: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
@@ -60,6 +61,7 @@ op_equals_left_local_var: {
|
||||
|
||||
op_equals_right_local_var: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
@@ -123,6 +125,7 @@ op_equals_right_local_var: {
|
||||
}
|
||||
op_equals_left_global_var: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
@@ -179,6 +182,7 @@ op_equals_left_global_var: {
|
||||
|
||||
op_equals_right_global_var: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
@@ -236,3 +240,52 @@ op_equals_right_global_var: {
|
||||
x = g() & x;
|
||||
}
|
||||
}
|
||||
|
||||
increment_decrement_1: {
|
||||
options = {
|
||||
assignments: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
a += 1;
|
||||
a -= 1;
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a){
|
||||
++a;
|
||||
--a;
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
increment_decrement_2: {
|
||||
options = {
|
||||
assignments: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
a = a + 1;
|
||||
a = a - 1;
|
||||
a += 1;
|
||||
a -= 1;
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a){
|
||||
++a;
|
||||
--a;
|
||||
++a;
|
||||
--a;
|
||||
return a;
|
||||
}(42));
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
@@ -944,10 +944,10 @@ collapse_vars_misc1: {
|
||||
function f5(x) { var z = foo(); return (5 - window.x) / z }
|
||||
function f6() { return window.a * window.z && zap() }
|
||||
function f7() { var b = window.a * window.z; return b + b }
|
||||
function f8() { var b = window.a * window.z; return b + (b + 5) }
|
||||
function f8() { var b = window.a * window.z; return b + (5 + b) }
|
||||
function f9() { var b = window.a * window.z; return bar() || b }
|
||||
function f10(x) { var a = 5; return a += 3; }
|
||||
function f11(x) { var a = 5, b = 3; return a += --b; }
|
||||
function f11(x) { var a = 5; return a += 2; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3895,11 +3895,11 @@ issue_2436_10: {
|
||||
o = { b: 3 };
|
||||
return n;
|
||||
}
|
||||
console.log((c = o, [
|
||||
c.a,
|
||||
console.log([
|
||||
(c = o).a,
|
||||
f(c.b),
|
||||
c.b,
|
||||
]).join(" "));
|
||||
].join(" "));
|
||||
var c;
|
||||
}
|
||||
expect_stdout: "1 2 2"
|
||||
@@ -6007,3 +6007,153 @@ issue_3238_6: {
|
||||
}
|
||||
expect_stdout: "true false"
|
||||
}
|
||||
|
||||
issue_3247: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function f(o) {
|
||||
console.log(o.p);
|
||||
}
|
||||
var a;
|
||||
a = Object({ p: "PASS" });
|
||||
a.q = true;
|
||||
f(a, true);
|
||||
}
|
||||
expect: {
|
||||
function f(o) {
|
||||
console.log(o.p);
|
||||
}
|
||||
var a;
|
||||
(a = Object({ p: "PASS" })).q = true;
|
||||
f(a, true);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3305: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
function calc(a) {
|
||||
var x, w;
|
||||
if (a) {
|
||||
x = a;
|
||||
w = 1;
|
||||
} else {
|
||||
x = 1;
|
||||
w = 0;
|
||||
}
|
||||
return add(x, w);
|
||||
}
|
||||
function add(x, w) {
|
||||
return x + w;
|
||||
}
|
||||
console.log(calc(41));
|
||||
}
|
||||
expect: {
|
||||
function calc(a) {
|
||||
var x, w;
|
||||
return w = a ? (x = a, 1) : (x = 1, 0), add(x, w);
|
||||
}
|
||||
function add(x, w) {
|
||||
return x + w;
|
||||
}
|
||||
console.log(calc(41));
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_3314: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
function test(a, b) {
|
||||
console.log(a, b);
|
||||
}
|
||||
var a = "FAIL", b;
|
||||
b = a = "PASS";
|
||||
test(a, b);
|
||||
}
|
||||
expect: {
|
||||
function test(a, b) {
|
||||
console.log(a, b);
|
||||
}
|
||||
var a = "FAIL", b;
|
||||
b = a = "PASS";
|
||||
test(a, b);
|
||||
}
|
||||
expect_stdout: "PASS PASS"
|
||||
}
|
||||
|
||||
issue_3327: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
var a, b, l = ["PASS", 42];
|
||||
if (l.length === 1) {
|
||||
a = l[0].a;
|
||||
b = l[0].b;
|
||||
} else {
|
||||
a = l[0];
|
||||
b = l[1];
|
||||
}
|
||||
function echo(a, b) {
|
||||
console.log(a, b);
|
||||
}
|
||||
echo(a, b);
|
||||
}
|
||||
expect: {
|
||||
var a, b, l = ["PASS", 42];
|
||||
function echo(a, b) {
|
||||
console.log(a, b);
|
||||
}
|
||||
b = 1 === l.length ? (a = l[0].a, l[0].b) : (a = l[0], l[1]),
|
||||
echo(a,b);
|
||||
}
|
||||
expect_stdout: "PASS 42"
|
||||
}
|
||||
|
||||
assign_left: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, b) {
|
||||
(b = a, b.p).q = "PASS";
|
||||
return a.p.q;
|
||||
}({p: {}}));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
(b = a).p.q = "PASS";
|
||||
return a.p.q;
|
||||
}({p: {}}));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
sub_property: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, b) {
|
||||
return a[(b = a, b.length - 1)];
|
||||
}([ "FAIL", "PASS" ]));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
return a[(b = a).length - 1];
|
||||
}([ "FAIL", "PASS" ]));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -323,3 +323,25 @@ is_number_unsafe: {
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
is_boolean_var: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a, b) {
|
||||
for (var i = 0, c = !b; i < a.length; i++)
|
||||
if (!a[i] === c)
|
||||
return i;
|
||||
}([ false, true ], 42));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
for (var i = 0, c = !b; i < a.length; i++)
|
||||
if (!a[i] == c)
|
||||
return i;
|
||||
}([ false, true ], 42));
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
@@ -1367,6 +1367,7 @@ cond_seq_assign_2: {
|
||||
|
||||
cond_seq_assign_3: {
|
||||
options = {
|
||||
assignments: true,
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
@@ -1384,3 +1385,34 @@ cond_seq_assign_3: {
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
issue_3271: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
}
|
||||
input: {
|
||||
function f(a) {
|
||||
var i = 0, b = [];
|
||||
if (a) {
|
||||
b[i++] = 4,
|
||||
b[i++] = 1;
|
||||
} else {
|
||||
b[i++] = 3,
|
||||
b[i++] = 2,
|
||||
b[i++] = 1;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
console.log(f(0).pop(), f(1).pop());
|
||||
}
|
||||
expect: {
|
||||
function f(a) {
|
||||
var i = 0, b = [];
|
||||
a ? b[i++] = 4 : (b[i++] = 3, b[i++] = 2),
|
||||
b[i++] = 1;
|
||||
return b;
|
||||
}
|
||||
console.log(f(0).pop(), f(1).pop());
|
||||
}
|
||||
expect_stdout: "1 1"
|
||||
}
|
||||
|
||||
@@ -1124,14 +1124,14 @@ issue_2207_1: {
|
||||
console.log(Math.max(3, 6, 2, 7, 3, 4));
|
||||
console.log(Math.cos(1.2345));
|
||||
console.log(Math.cos(1.2345) - Math.sin(4.321));
|
||||
console.log(Math.pow(Math.PI, Math.E - Math.LN10));
|
||||
console.log(Math.pow(Math.PI, Math.E - Math.LN10).toFixed(15));
|
||||
}
|
||||
expect: {
|
||||
console.log("A");
|
||||
console.log(7);
|
||||
console.log(Math.cos(1.2345));
|
||||
console.log(1.2543732512566947);
|
||||
console.log(1.6093984514472044);
|
||||
console.log("1.609398451447204");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
@@ -1245,12 +1245,12 @@ self_comparison_1: {
|
||||
}
|
||||
input: {
|
||||
var o = { n: NaN };
|
||||
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
|
||||
console.log(typeof o.n, o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n);
|
||||
}
|
||||
expect: {
|
||||
console.log(false, false, true, true, "number");
|
||||
console.log("number", false, false, true, true);
|
||||
}
|
||||
expect_stdout: "false false true true 'number'"
|
||||
expect_stdout: "number false false true true"
|
||||
}
|
||||
|
||||
self_comparison_2: {
|
||||
@@ -1265,12 +1265,12 @@ self_comparison_2: {
|
||||
}
|
||||
input: {
|
||||
var o = { n: NaN };
|
||||
console.log(o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n, typeof o.n);
|
||||
console.log(typeof o.n, o.n == o.n, o.n === o.n, o.n != o.n, o.n !== o.n);
|
||||
}
|
||||
expect: {
|
||||
console.log(false, false, true, true, "number");
|
||||
console.log("number", false, false, true, true);
|
||||
}
|
||||
expect_stdout: "false false true true 'number'"
|
||||
expect_stdout: "number false false true true"
|
||||
}
|
||||
|
||||
issue_2535_1: {
|
||||
@@ -1540,7 +1540,7 @@ issue_2926_2: {
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_2968: {
|
||||
issue_2968_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
@@ -1571,6 +1571,39 @@ issue_2968: {
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2968_2: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = "FAIL";
|
||||
(function() {
|
||||
(function(a, b) {
|
||||
a <<= 0;
|
||||
a && (a[(c = "PASS", 0 >>> (b += 1))] = 0);
|
||||
})(42, -42);
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = "FAIL";
|
||||
(function() {
|
||||
a = 42,
|
||||
((a <<= 0) && (a[(c = "PASS", 0)] = 0));
|
||||
var a;
|
||||
})();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
truthy_conditionals: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
@@ -1610,3 +1643,47 @@ truthy_loops: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if_increment: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
if (console)
|
||||
return ++a;
|
||||
}(0));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
if (console)
|
||||
return 1;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
try_increment: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(a) {
|
||||
try {
|
||||
return ++a;
|
||||
} catch (e) {}
|
||||
}(0));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a) {
|
||||
try {
|
||||
return 1;
|
||||
} catch (e) {}
|
||||
}());
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -358,6 +358,7 @@ inner_ref: {
|
||||
|
||||
issue_2107: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
@@ -387,6 +388,7 @@ issue_2107: {
|
||||
|
||||
issue_2114_1: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
if_return: true,
|
||||
inline: true,
|
||||
@@ -419,6 +421,7 @@ issue_2114_1: {
|
||||
|
||||
issue_2114_2: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
if_return: true,
|
||||
inline: true,
|
||||
@@ -1223,6 +1226,7 @@ issue_2630_1: {
|
||||
|
||||
issue_2630_2: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
passes: 2,
|
||||
@@ -1320,6 +1324,7 @@ issue_2630_4: {
|
||||
|
||||
issue_2630_5: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
@@ -1398,6 +1403,8 @@ recursive_inline_2: {
|
||||
issue_2657: {
|
||||
options = {
|
||||
inline: true,
|
||||
passes: 2,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
unused: true,
|
||||
@@ -2315,3 +2322,384 @@ issue_3125: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3274: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
join_vars: true,
|
||||
loops: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var g = function(a) {
|
||||
var c = a.p, b = c;
|
||||
return b != c;
|
||||
};
|
||||
while (g(1))
|
||||
console.log("FAIL");
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
for (var c; void 0, (c = 1..p) != c;)
|
||||
console.log("FAIL");
|
||||
console.log("PASS");
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3297_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {}
|
||||
input: {
|
||||
function function1() {
|
||||
var r = {
|
||||
function2: function2
|
||||
};
|
||||
function function2() {
|
||||
alert(1234);
|
||||
function function3() {
|
||||
function2();
|
||||
};
|
||||
function3();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function function1() {
|
||||
return {
|
||||
function2: function n() {
|
||||
alert(1234);
|
||||
function t() {
|
||||
n();
|
||||
}
|
||||
t();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_3297_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {}
|
||||
input: {
|
||||
function function1(session) {
|
||||
var public = {
|
||||
processBulk: processBulk
|
||||
};
|
||||
return public;
|
||||
function processBulk(bulk) {
|
||||
var subparam1 = session();
|
||||
function processOne(param1) {
|
||||
var param2 = {
|
||||
subparam1: subparam1
|
||||
};
|
||||
doProcessOne({
|
||||
param1: param1,
|
||||
param2: param2,
|
||||
}, function () {
|
||||
processBulk(bulk);
|
||||
});
|
||||
};
|
||||
if (bulk && bulk.length > 0)
|
||||
processOne(bulk.shift());
|
||||
}
|
||||
function doProcessOne(config, callback) {
|
||||
console.log(JSON.stringify(config));
|
||||
callback();
|
||||
}
|
||||
}
|
||||
function1(function session() {
|
||||
return 42;
|
||||
}).processBulk([1, 2, 3]);
|
||||
}
|
||||
expect: {
|
||||
function function1(o) {
|
||||
return {
|
||||
processBulk: function t(u) {
|
||||
var r = o();
|
||||
function n(n) {
|
||||
var o = {
|
||||
subparam1: r
|
||||
};
|
||||
c({
|
||||
param1: n,
|
||||
param2: o
|
||||
}, function() {
|
||||
t(u);
|
||||
});
|
||||
}
|
||||
u && u.length > 0 && n(u.shift());
|
||||
}
|
||||
};
|
||||
function c(n, o) {
|
||||
console.log(JSON.stringify(n));
|
||||
o();
|
||||
}
|
||||
}
|
||||
function1(function() {
|
||||
return 42;
|
||||
}).processBulk([ 1, 2, 3 ]);
|
||||
}
|
||||
expect_stdout: [
|
||||
'{"param1":1,"param2":{"subparam1":42}}',
|
||||
'{"param1":2,"param2":{"subparam1":42}}',
|
||||
'{"param1":3,"param2":{"subparam1":42}}',
|
||||
]
|
||||
}
|
||||
|
||||
issue_3297_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
comparisons: true,
|
||||
conditionals: true,
|
||||
inline: true,
|
||||
join_vars: true,
|
||||
passes: 3,
|
||||
reduce_funcs: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
mangle = {}
|
||||
input: {
|
||||
function function1(session) {
|
||||
var public = {
|
||||
processBulk: processBulk
|
||||
};
|
||||
return public;
|
||||
function processBulk(bulk) {
|
||||
var subparam1 = session();
|
||||
function processOne(param1) {
|
||||
var param2 = {
|
||||
subparam1: subparam1
|
||||
};
|
||||
doProcessOne({
|
||||
param1: param1,
|
||||
param2: param2,
|
||||
}, function () {
|
||||
processBulk(bulk);
|
||||
});
|
||||
};
|
||||
if (bulk && bulk.length > 0)
|
||||
processOne(bulk.shift());
|
||||
}
|
||||
function doProcessOne(config, callback) {
|
||||
console.log(JSON.stringify(config));
|
||||
callback();
|
||||
}
|
||||
}
|
||||
function1(function session() {
|
||||
return 42;
|
||||
}).processBulk([1, 2, 3]);
|
||||
}
|
||||
expect: {
|
||||
function function1(u) {
|
||||
return {
|
||||
processBulk: function n(r) {
|
||||
var o, t = u();
|
||||
r && 0 < r.length && (o = {
|
||||
param1: r.shift(),
|
||||
param2: {
|
||||
subparam1: t
|
||||
}
|
||||
},
|
||||
console.log(JSON.stringify(o)),
|
||||
n(r));
|
||||
}
|
||||
};
|
||||
}
|
||||
function1(function() {
|
||||
return 42;
|
||||
}).processBulk([ 1, 2, 3 ]);
|
||||
}
|
||||
expect_stdout: [
|
||||
'{"param1":1,"param2":{"subparam1":42}}',
|
||||
'{"param1":2,"param2":{"subparam1":42}}',
|
||||
'{"param1":3,"param2":{"subparam1":42}}',
|
||||
]
|
||||
}
|
||||
|
||||
cross_references_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var Math = {
|
||||
square: function(n) {
|
||||
return n * n;
|
||||
}
|
||||
};
|
||||
console.log((function(factory) {
|
||||
return factory();
|
||||
})(function() {
|
||||
return function(Math) {
|
||||
return function(n) {
|
||||
return Math.square(n);
|
||||
};
|
||||
}(Math);
|
||||
})(3));
|
||||
}
|
||||
expect: {
|
||||
var Math = {
|
||||
square: function(n) {
|
||||
return n * n;
|
||||
}
|
||||
};
|
||||
console.log(function(Math) {
|
||||
return function(n) {
|
||||
return Math.square(n);
|
||||
};
|
||||
}(Math)(3));
|
||||
}
|
||||
expect_stdout: "9"
|
||||
}
|
||||
|
||||
cross_references_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
hoist_props: true,
|
||||
inline: true,
|
||||
passes: 4,
|
||||
pure_getters: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var Math = {
|
||||
square: function(n) {
|
||||
return n * n;
|
||||
}
|
||||
};
|
||||
console.log((function(factory) {
|
||||
return factory();
|
||||
})(function() {
|
||||
return function(Math) {
|
||||
return function(n) {
|
||||
return Math.square(n);
|
||||
};
|
||||
}(Math);
|
||||
})(3));
|
||||
}
|
||||
expect: {
|
||||
console.log(9);
|
||||
}
|
||||
expect_stdout: "9"
|
||||
}
|
||||
|
||||
cross_references_3: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var Math = {
|
||||
square: function(n) {
|
||||
return n * n;
|
||||
},
|
||||
cube: function(n) {
|
||||
return n * n * n;
|
||||
}
|
||||
};
|
||||
console.log(function(factory) {
|
||||
return factory();
|
||||
}(function() {
|
||||
return function(Math) {
|
||||
return function(n) {
|
||||
Math = {
|
||||
square: function(x) {
|
||||
return "(SQUARE" + x + ")";
|
||||
},
|
||||
cube: function(x) {
|
||||
return "(CUBE" + x + ")";
|
||||
}
|
||||
};
|
||||
return Math.square(n) + Math.cube(n);
|
||||
};
|
||||
}(Math);
|
||||
})(2));
|
||||
console.log(Math.square(3), Math.cube(3));
|
||||
}
|
||||
expect: {
|
||||
var Math = {
|
||||
square: function(n) {
|
||||
return n * n;
|
||||
},
|
||||
cube: function(n) {
|
||||
return n * n * n;
|
||||
}
|
||||
};
|
||||
console.log(function(Math) {
|
||||
return function(n) {
|
||||
Math = {
|
||||
square: function(x) {
|
||||
return "(SQUARE" + x + ")";
|
||||
},
|
||||
cube: function(x) {
|
||||
return "(CUBE" + x + ")";
|
||||
}
|
||||
};
|
||||
return Math.square(n) + Math.cube(n);
|
||||
};
|
||||
}(Math)(2));
|
||||
console.log(Math.square(3), Math.cube(3));
|
||||
}
|
||||
expect_stdout: [
|
||||
"(SQUARE2)(CUBE2)",
|
||||
"9 27",
|
||||
]
|
||||
}
|
||||
|
||||
loop_inline: {
|
||||
options = {
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(o) {
|
||||
function g(p) {
|
||||
return o[p];
|
||||
}
|
||||
function h(q) {
|
||||
while (g(q));
|
||||
}
|
||||
return h;
|
||||
}([ 1, "foo", 0 ])(2));
|
||||
}
|
||||
expect: {
|
||||
console.log(function(o) {
|
||||
return function(q) {
|
||||
while (p = q, o[p]);
|
||||
var p;
|
||||
};
|
||||
}([ 1, "foo", 0 ])(2));
|
||||
}
|
||||
expect_stdout: "undefined"
|
||||
}
|
||||
|
||||
@@ -861,3 +861,111 @@ issue_3215_4: {
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3355_1: {
|
||||
mangle = {
|
||||
ie8: false,
|
||||
}
|
||||
input: {
|
||||
(function f() {
|
||||
var f;
|
||||
})();
|
||||
(function g() {
|
||||
})();
|
||||
console.log(typeof f === typeof g);
|
||||
}
|
||||
expect: {
|
||||
(function o() {
|
||||
var o;
|
||||
})();
|
||||
(function o() {
|
||||
})();
|
||||
console.log(typeof f === typeof g);
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
issue_3355_2: {
|
||||
mangle = {
|
||||
ie8: true,
|
||||
}
|
||||
input: {
|
||||
(function f() {
|
||||
var f;
|
||||
})();
|
||||
(function g() {
|
||||
})();
|
||||
console.log(typeof f === typeof g);
|
||||
}
|
||||
expect: {
|
||||
(function f() {
|
||||
var f;
|
||||
})();
|
||||
(function g() {
|
||||
})();
|
||||
console.log(typeof f === typeof g);
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
issue_3355_3: {
|
||||
mangle = {
|
||||
ie8: false,
|
||||
}
|
||||
input: {
|
||||
!function(a) {
|
||||
"aaaaaaaaaa";
|
||||
a();
|
||||
var b = function c() {
|
||||
var c = 42;
|
||||
console.log("FAIL");
|
||||
};
|
||||
}(function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
!function(a) {
|
||||
"aaaaaaaaaa";
|
||||
a();
|
||||
var o = function a() {
|
||||
var a = 42;
|
||||
console.log("FAIL");
|
||||
};
|
||||
}(function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3355_4: {
|
||||
mangle = {
|
||||
ie8: true,
|
||||
}
|
||||
input: {
|
||||
!function(a) {
|
||||
"aaaaaaaaaa";
|
||||
a();
|
||||
var b = function c() {
|
||||
var c = 42;
|
||||
console.log("FAIL");
|
||||
};
|
||||
}(function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
!function(a) {
|
||||
"aaaaaaaaaa";
|
||||
a();
|
||||
var o = function n() {
|
||||
var n = 42;
|
||||
console.log("FAIL");
|
||||
};
|
||||
}(function() {
|
||||
console.log("PASS");
|
||||
});
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ warn: {
|
||||
}().length);
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Function.protoype.caller not supported [test/compress/issue-2719.js:5,19]",
|
||||
"WARN: Function.protoype.arguments not supported [test/compress/issue-2719.js:5,19]",
|
||||
"WARN: Function.prototype.caller not supported [test/compress/issue-2719.js:5,19]",
|
||||
"WARN: Function.prototype.arguments not supported [test/compress/issue-2719.js:5,19]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -642,3 +642,41 @@ issue_3065_4: {
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
issue_3325_1: {
|
||||
options = {
|
||||
pure_funcs: "cb",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
function cb() {
|
||||
console.log("PASS");
|
||||
}
|
||||
cb();
|
||||
}
|
||||
expect: {
|
||||
function cb() {
|
||||
console.log("PASS");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_3325_2: {
|
||||
options = {
|
||||
pure_funcs: "xxxcbxxx",
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
function cb() {
|
||||
console.log("PASS");
|
||||
}
|
||||
cb();
|
||||
}
|
||||
expect: {
|
||||
function cb() {
|
||||
console.log("PASS");
|
||||
}
|
||||
cb();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -2740,18 +2740,18 @@ issue_1814_2: {
|
||||
!function() {
|
||||
var b = a + 1;
|
||||
!function(a) {
|
||||
console.log(a++, b);
|
||||
console.log(b, a++);
|
||||
}(0);
|
||||
}();
|
||||
}
|
||||
expect: {
|
||||
!function() {
|
||||
!function(a) {
|
||||
console.log(a++, "321");
|
||||
console.log("321", a++);
|
||||
}(0);
|
||||
}();
|
||||
}
|
||||
expect_stdout: "0 '321'"
|
||||
expect_stdout: "321 0"
|
||||
}
|
||||
|
||||
try_abort: {
|
||||
@@ -6586,3 +6586,154 @@ issue_3240_4: {
|
||||
"1",
|
||||
]
|
||||
}
|
||||
|
||||
issues_3267_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(x) {
|
||||
x();
|
||||
})(function() {
|
||||
(function(i) {
|
||||
if (i)
|
||||
return console.log("PASS");
|
||||
throw "FAIL";
|
||||
})(Object());
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
!function(i) {
|
||||
if (i)
|
||||
return console.log("PASS");
|
||||
throw "FAIL";
|
||||
}(Object());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issues_3267_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(x) {
|
||||
x();
|
||||
})(function() {
|
||||
(function(i) {
|
||||
if (i)
|
||||
return console.log("PASS");
|
||||
throw "FAIL";
|
||||
})(Object());
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
!function() {
|
||||
if (Object())
|
||||
return console.log("PASS");
|
||||
throw "FAIL";
|
||||
}();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issues_3267_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
inline: true,
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(x) {
|
||||
x();
|
||||
})(function() {
|
||||
(function(i) {
|
||||
if (i)
|
||||
return console.log("PASS");
|
||||
throw "FAIL";
|
||||
})(Object());
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_3297: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
function f() {
|
||||
var a;
|
||||
var b = function a() {
|
||||
console.log(a === b) && f();
|
||||
};
|
||||
b();
|
||||
}
|
||||
f();
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
(function f() {
|
||||
var b = function a() {
|
||||
console.log(a === b) && f();
|
||||
};
|
||||
b();
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
drop_side_effect_free: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 123;
|
||||
"" + (a && (a.b = 0) || a);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 123;
|
||||
a.b = 0;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "123"
|
||||
}
|
||||
|
||||
@@ -924,14 +924,14 @@ call: {
|
||||
b.c = function() {
|
||||
console.log(this === b ? "bar" : "baz");
|
||||
},
|
||||
a, b(),
|
||||
b(),
|
||||
(a, b.c)(),
|
||||
a, function() {
|
||||
function() {
|
||||
console.log(this === a);
|
||||
}(),
|
||||
a, new b(),
|
||||
a, new b.c(),
|
||||
a, new function() {
|
||||
new b(),
|
||||
new b.c(),
|
||||
new function() {
|
||||
console.log(this === a);
|
||||
}();
|
||||
}
|
||||
@@ -944,3 +944,23 @@ call: {
|
||||
"false",
|
||||
]
|
||||
}
|
||||
|
||||
missing_link: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
evaluate: true,
|
||||
sequences: true,
|
||||
}
|
||||
input: {
|
||||
var a = 100;
|
||||
a;
|
||||
a++ + (0 ? 2 : 1);
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 100;
|
||||
a,
|
||||
a++,
|
||||
console.log(a);
|
||||
}
|
||||
}
|
||||
|
||||
8
test/input/issue-3315/config.json
Normal file
8
test/input/issue-3315/config.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"compress": false,
|
||||
"mangle": {
|
||||
"properties": {
|
||||
"regex": "/^_/"
|
||||
}
|
||||
}
|
||||
}
|
||||
8
test/input/issue-3315/input.js
Normal file
8
test/input/issue-3315/input.js
Normal file
@@ -0,0 +1,8 @@
|
||||
function f() {
|
||||
"aaaaaaaaaa";
|
||||
var o = {
|
||||
prop: 1,
|
||||
_int: 2,
|
||||
};
|
||||
return o.prop + o._int;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
var assert = require("assert");
|
||||
var exec = require("child_process").exec;
|
||||
var fs = require("fs");
|
||||
var run_code = require("../sandbox").run_code;
|
||||
|
||||
function read(path) {
|
||||
return fs.readFileSync(path, "utf8");
|
||||
@@ -257,7 +258,7 @@ describe("bin/uglifyjs", function() {
|
||||
assert.strictEqual(lines[0], "Parse error at test/input/invalid/simple.js:1,12");
|
||||
assert.strictEqual(lines[1], "function f(a{}");
|
||||
assert.strictEqual(lines[2], " ^");
|
||||
assert.strictEqual(lines[3], "ERROR: Unexpected token punc «{», expected punc «,»");
|
||||
assert.strictEqual(lines[3], "ERROR: Unexpected token: punc «{», expected: punc «,»");
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -281,7 +282,7 @@ describe("bin/uglifyjs", function() {
|
||||
assert.strictEqual(lines[0], "Parse error at test/input/invalid/eof.js:2,0");
|
||||
assert.strictEqual(lines[1], "foo, bar(");
|
||||
assert.strictEqual(lines[2], " ^");
|
||||
assert.strictEqual(lines[3], "ERROR: Unexpected token: eof (undefined)");
|
||||
assert.strictEqual(lines[3], "ERROR: Unexpected token: eof");
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -293,7 +294,7 @@ describe("bin/uglifyjs", function() {
|
||||
assert.strictEqual(lines[0], "Parse error at test/input/invalid/loop-no-body.js:2,0");
|
||||
assert.strictEqual(lines[1], "for (var i = 0; i < 1; i++) ");
|
||||
assert.strictEqual(lines[2], " ^");
|
||||
assert.strictEqual(lines[3], "ERROR: Unexpected token: eof (undefined)");
|
||||
assert.strictEqual(lines[3], "ERROR: Unexpected token: eof");
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -362,7 +363,7 @@ describe("bin/uglifyjs", function() {
|
||||
"Parse error at test/input/invalid/dot_1.js:1,2",
|
||||
"a.=",
|
||||
" ^",
|
||||
"ERROR: Unexpected token: operator (=)"
|
||||
"ERROR: Unexpected token: operator «=», expected: name"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
@@ -376,7 +377,7 @@ describe("bin/uglifyjs", function() {
|
||||
"Parse error at test/input/invalid/dot_2.js:1,0",
|
||||
"%.a;",
|
||||
"^",
|
||||
"ERROR: Unexpected token: operator (%)"
|
||||
"ERROR: Unexpected token: operator «%»"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
@@ -390,7 +391,7 @@ describe("bin/uglifyjs", function() {
|
||||
"Parse error at test/input/invalid/dot_3.js:1,2",
|
||||
"a./();",
|
||||
" ^",
|
||||
"ERROR: Unexpected token: operator (/)"
|
||||
"ERROR: Unexpected token: operator «/», expected: name"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
@@ -404,7 +405,7 @@ describe("bin/uglifyjs", function() {
|
||||
"Parse error at test/input/invalid/object.js:1,13",
|
||||
"console.log({%: 1});",
|
||||
" ^",
|
||||
"ERROR: Unexpected token: operator (%)"
|
||||
"ERROR: Unexpected token: operator «%»"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
@@ -502,7 +503,7 @@ describe("bin/uglifyjs", function() {
|
||||
"Parse error at test/input/invalid/else.js:1,7",
|
||||
"if (0) else 1;",
|
||||
" ^",
|
||||
"ERROR: Unexpected token: keyword (else)"
|
||||
"ERROR: Unexpected token: keyword «else»"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
@@ -633,6 +634,14 @@ describe("bin/uglifyjs", function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should work with mangle.properties.regex from --config-file", function(done) {
|
||||
var command = uglifyjscmd + " test/input/issue-3315/input.js --config-file test/input/issue-3315/config.json";
|
||||
exec(command, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, 'function f(){"aaaaaaaaaa";var a={prop:1,a:2};return a.prop+a.a}\n');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should fail with --define a-b", function(done) {
|
||||
var command = uglifyjscmd + " test/input/issue-505/input.js --define a-b";
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
@@ -706,4 +715,32 @@ describe("bin/uglifyjs", function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should compress swarm of unused variables with reasonable performance", function(done) {
|
||||
var code = [
|
||||
"console.log(function() {",
|
||||
];
|
||||
for (var i = 0; i < 10000; i++) {
|
||||
code.push("var obj" + i + " = {p: " + i + "};");
|
||||
}
|
||||
code.push("var map = {");
|
||||
for (var i = 0; i < 10000; i++) {
|
||||
code.push("obj" + i + ": obj" + i + ",");
|
||||
}
|
||||
code = code.concat([
|
||||
"};",
|
||||
"return obj25.p + obj121.p + obj1024.p;",
|
||||
"}());",
|
||||
]).join("\n");
|
||||
exec(uglifyjscmd + " -mc", function(err, stdout) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(stdout, [
|
||||
"console.log(function(){",
|
||||
"var p={p:25},n={p:121},o={p:1024};",
|
||||
"return p.p+n.p+o.p",
|
||||
"}());\n",
|
||||
].join(""));
|
||||
assert.strictEqual(run_code(stdout), run_code(code));
|
||||
done();
|
||||
}).stdin.end(code);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ describe("comments", function() {
|
||||
|
||||
var fail = function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unexpected token: operator (>)"
|
||||
&& e.message === "Unexpected token: operator «>»"
|
||||
&& e.line === 2
|
||||
&& e.col === 0;
|
||||
}
|
||||
@@ -36,7 +36,7 @@ describe("comments", function() {
|
||||
|
||||
var fail = function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unexpected token: operator (>)"
|
||||
&& e.message === "Unexpected token: operator «>»"
|
||||
&& e.line === 5
|
||||
&& e.col === 0;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ describe("Directives", function() {
|
||||
UglifyJS.parse(tokenizer);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unexpected token: punc (])"
|
||||
&& /^Unexpected token: punc «]»/.test(e.message)
|
||||
}, test[0]);
|
||||
test[1].forEach(function(directive) {
|
||||
assert.strictEqual(tokenizer.has_directive(directive), true, directive + " in " + test[0]);
|
||||
|
||||
@@ -69,7 +69,7 @@ describe("Getters and setters", function() {
|
||||
var fail = function(data) {
|
||||
return function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unexpected token: operator (" + data.operator + ")";
|
||||
&& e.message === "Unexpected token: operator «" + data.operator + "»";
|
||||
};
|
||||
};
|
||||
var errorMessage = function(data) {
|
||||
|
||||
@@ -87,7 +87,7 @@ describe("minify", function() {
|
||||
assert.strictEqual(run_code(compressed), run_code(original));
|
||||
});
|
||||
|
||||
it("Should avoid mangled names in cache", function() {
|
||||
it("Should avoid cached names when mangling top-level variables", function() {
|
||||
var cache = {};
|
||||
var original = "";
|
||||
var compressed = "";
|
||||
@@ -116,10 +116,34 @@ describe("minify", function() {
|
||||
assert.strictEqual(run_code(compressed), run_code(original));
|
||||
});
|
||||
|
||||
it("Should avoid cached names when mangling inner-scoped variables", function() {
|
||||
var cache = {};
|
||||
var original = "";
|
||||
var compressed = "";
|
||||
[
|
||||
'var extend = function(a, b) { console.log("extend"); a(); b(); }; function A() { console.log("A"); };',
|
||||
'var B = function(A) { function B() { console.log("B") }; extend(B, A); return B; }(A);',
|
||||
].forEach(function(code) {
|
||||
var result = UglifyJS.minify(code, {
|
||||
compress: false,
|
||||
nameCache: cache,
|
||||
toplevel: true,
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
original += code;
|
||||
compressed += result.code;
|
||||
});
|
||||
assert.strictEqual(compressed, [
|
||||
'var o=function(o,n){console.log("extend");o();n()};function n(){console.log("A")}',
|
||||
'var e=function(n){function e(){console.log("B")}o(e,n);return e}(n);',
|
||||
].join(""));
|
||||
assert.strictEqual(run_code(compressed), run_code(original));
|
||||
});
|
||||
|
||||
it("Should not parse invalid use of reserved words", function() {
|
||||
assert.strictEqual(UglifyJS.minify("function enum(){}").error, undefined);
|
||||
assert.strictEqual(UglifyJS.minify("function static(){}").error, undefined);
|
||||
assert.strictEqual(UglifyJS.minify("function this(){}").error.message, "Unexpected token: name (this)");
|
||||
assert.strictEqual(UglifyJS.minify("function this(){}").error.message, "Unexpected token: name «this»");
|
||||
});
|
||||
|
||||
describe("keep_quoted_props", function() {
|
||||
@@ -214,7 +238,7 @@ describe("minify", function() {
|
||||
var result = UglifyJS.minify("function f(a{}");
|
||||
var err = result.error;
|
||||
assert.ok(err instanceof Error);
|
||||
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token punc «{», expected punc «,»");
|
||||
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token: punc «{», expected: punc «,»");
|
||||
assert.strictEqual(err.filename, "0");
|
||||
assert.strictEqual(err.line, 1);
|
||||
assert.strictEqual(err.col, 12);
|
||||
@@ -241,7 +265,7 @@ describe("minify", function() {
|
||||
});
|
||||
var err = result.error;
|
||||
assert.ok(err instanceof Error);
|
||||
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token: keyword (debugger)");
|
||||
assert.strictEqual(err.stack.split(/\n/)[0], "SyntaxError: Unexpected token: keyword «debugger»");
|
||||
});
|
||||
it("Should skip inherited properties", function() {
|
||||
var foo = Object.create({ skip: this });
|
||||
|
||||
Reference in New Issue
Block a user