Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dde41615a | ||
|
|
8b69a3d18e | ||
|
|
d40950b741 | ||
|
|
7659ea1d2e | ||
|
|
bdeadffbf5 | ||
|
|
5e6f26445f | ||
|
|
f0a99125ee | ||
|
|
1e4de2e6d3 |
52
README.md
52
README.md
@@ -111,7 +111,7 @@ a double dash to prevent input files being used as option arguments:
|
||||
By default UglifyJS will not try to be IE-proof.
|
||||
--keep-fnames Do not mangle/drop function names. Useful for
|
||||
code relying on Function.prototype.name.
|
||||
--name-cache File to hold mangled name mappings.
|
||||
--name-cache <file> File to hold mangled name mappings.
|
||||
--self Build UglifyJS as a library (implies --wrap UglifyJS)
|
||||
--source-map [options] Enable source map/specify source map options:
|
||||
`base` Path to compute relative paths from input files.
|
||||
@@ -383,7 +383,47 @@ var code = {
|
||||
var options = { toplevel: true };
|
||||
var result = UglifyJS.minify(code, options);
|
||||
console.log(result.code);
|
||||
// console.log(function(n,o){return n+o}(3,7));
|
||||
// console.log(3+7);
|
||||
```
|
||||
|
||||
The `nameCache` option:
|
||||
```javascript
|
||||
var options = {
|
||||
mangle: {
|
||||
toplevel: true,
|
||||
},
|
||||
nameCache: {}
|
||||
};
|
||||
var result1 = UglifyJS.minify({
|
||||
"file1.js": "function add(first, second) { return first + second; }"
|
||||
}, options);
|
||||
var result2 = UglifyJS.minify({
|
||||
"file2.js": "console.log(add(1 + 2, 3 + 4));"
|
||||
}, options);
|
||||
console.log(result1.code);
|
||||
// function n(n,r){return n+r}
|
||||
console.log(result2.code);
|
||||
// console.log(n(3,7));
|
||||
```
|
||||
|
||||
You may persist the name cache to the file system in the following way:
|
||||
```javascript
|
||||
var cacheFileName = "/tmp/cache.json";
|
||||
var options = {
|
||||
mangle: {
|
||||
properties: true,
|
||||
},
|
||||
nameCache: JSON.parse(fs.readFileSync(cacheFileName, "utf8"))
|
||||
};
|
||||
fs.writeFileSync("part1.js", UglifyJS.minify({
|
||||
"file1.js": fs.readFileSync("file1.js", "utf8"),
|
||||
"file2.js": fs.readFileSync("file2.js", "utf8")
|
||||
}, options).code, "utf8");
|
||||
fs.writeFileSync("part2.js", UglifyJS.minify({
|
||||
"file3.js": fs.readFileSync("file3.js", "utf8"),
|
||||
"file4.js": fs.readFileSync("file4.js", "utf8")
|
||||
}, options).code, "utf8");
|
||||
fs.writeFileSync(cacheFileName, JSON.stringify(options.nameCache), "utf8");
|
||||
```
|
||||
|
||||
An example of a combination of `minify()` options:
|
||||
@@ -461,6 +501,13 @@ if (result.error) throw result.error;
|
||||
- `toplevel` (default `false`) - set to `true` if you wish to enable top level
|
||||
variable and function name mangling and to drop unused variables and functions.
|
||||
|
||||
- `nameCache` (default `null`) - pass an empty object `{}` or a previously
|
||||
used `nameCache` object if you wish to cache mangled variable and
|
||||
property names across multiple invocations of `minify()`. Note: this is
|
||||
a read/write property. `minify()` will read the name cache state of this
|
||||
object and update it during minification so that it may be
|
||||
reused or externally persisted by the user.
|
||||
|
||||
- `ie8` (default `false`) - set to `true` to support IE8.
|
||||
|
||||
## Minify options structure
|
||||
@@ -487,6 +534,7 @@ if (result.error) throw result.error;
|
||||
sourceMap: {
|
||||
// source map options
|
||||
},
|
||||
nameCache: null, // or specify a name cache object
|
||||
toplevel: false,
|
||||
ie8: false,
|
||||
}
|
||||
|
||||
27
bin/uglifyjs
27
bin/uglifyjs
@@ -106,17 +106,8 @@ if (program.mangleProps) {
|
||||
if (typeof options.mangle != "object") options.mangle = {};
|
||||
options.mangle.properties = program.mangleProps;
|
||||
}
|
||||
var cache;
|
||||
if (program.nameCache) {
|
||||
cache = JSON.parse(read_file(program.nameCache, "{}"));
|
||||
if (options.mangle) {
|
||||
if (typeof options.mangle != "object") options.mangle = {};
|
||||
options.mangle.cache = to_cache("vars");
|
||||
if (options.mangle.properties) {
|
||||
if (typeof options.mangle.properties != "object") options.mangle.properties = {};
|
||||
options.mangle.properties.cache = to_cache("props");
|
||||
}
|
||||
}
|
||||
options.nameCache = JSON.parse(read_file(program.nameCache, "{}"));
|
||||
}
|
||||
if (program.output == "ast") {
|
||||
options.output = {
|
||||
@@ -266,9 +257,7 @@ function run() {
|
||||
print(result.code);
|
||||
}
|
||||
if (program.nameCache) {
|
||||
fs.writeFileSync(program.nameCache, JSON.stringify(cache, function(key, value) {
|
||||
return value instanceof UglifyJS.Dictionary ? value.toObject() : value;
|
||||
}));
|
||||
fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache));
|
||||
}
|
||||
if (result.timings) for (var phase in result.timings) {
|
||||
print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
|
||||
@@ -381,18 +370,6 @@ function parse_source_map() {
|
||||
}
|
||||
}
|
||||
|
||||
function to_cache(key) {
|
||||
if (cache[key]) {
|
||||
cache[key].props = UglifyJS.Dictionary.fromObject(cache[key].props);
|
||||
} else {
|
||||
cache[key] = {
|
||||
cname: -1,
|
||||
props: new UglifyJS.Dictionary()
|
||||
};
|
||||
}
|
||||
return cache[key];
|
||||
}
|
||||
|
||||
function skip_key(key) {
|
||||
return skip_keys.indexOf(key) >= 0;
|
||||
}
|
||||
|
||||
157
lib/compress.js
157
lib/compress.js
@@ -92,12 +92,9 @@ function Compressor(options, false_by_default) {
|
||||
var global_defs = this.options["global_defs"];
|
||||
if (typeof global_defs == "object") for (var key in global_defs) {
|
||||
if (/^@/.test(key) && HOP(global_defs, key)) {
|
||||
var ast = parse(global_defs[key]);
|
||||
if (ast.body.length == 1 && ast.body[0] instanceof AST_SimpleStatement) {
|
||||
global_defs[key.slice(1)] = ast.body[0].body;
|
||||
} else throw new Error(string_template("Can't handle expression: {value}", {
|
||||
value: global_defs[key]
|
||||
}));
|
||||
global_defs[key.slice(1)] = parse(global_defs[key], {
|
||||
expression: true
|
||||
});
|
||||
}
|
||||
}
|
||||
var pure_funcs = this.options["pure_funcs"];
|
||||
@@ -717,15 +714,23 @@ merge(Compressor.prototype, {
|
||||
var candidates = [];
|
||||
var stat_index = statements.length;
|
||||
while (--stat_index >= 0) {
|
||||
// Treat parameters as collapsible in IIFE, i.e.
|
||||
// function(a, b){ ... }(x());
|
||||
// would be translated into equivalent assignments:
|
||||
// var a = x(), b = undefined;
|
||||
if (stat_index == 0 && compressor.option("unused")) extract_args();
|
||||
// Find collapsible assignments
|
||||
extract_candidates(statements[stat_index]);
|
||||
while (candidates.length > 0) {
|
||||
var candidate = candidates.pop();
|
||||
var lhs = get_lhs(candidate);
|
||||
if (!lhs || is_lhs_read_only(lhs)) continue;
|
||||
// Locate symbols which may execute code outside of scanning range
|
||||
var lvalues = get_lvalues(candidate);
|
||||
if (lhs instanceof AST_SymbolRef) lvalues[lhs.name] = false;
|
||||
var side_effects = value_has_side_effects(candidate);
|
||||
var hit = false, abort = false, replaced = false;
|
||||
var hit = candidate.name instanceof AST_SymbolFunarg;
|
||||
var abort = false, replaced = false;
|
||||
var tt = new TreeTransformer(function(node, descend) {
|
||||
if (abort) return node;
|
||||
// Skip nodes before `candidate` as quickly as possible
|
||||
@@ -806,6 +811,35 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
function extract_args() {
|
||||
var iife, fn = compressor.self();
|
||||
if (fn instanceof AST_Function
|
||||
&& !fn.name
|
||||
&& !fn.uses_arguments
|
||||
&& !fn.uses_eval
|
||||
&& (iife = compressor.parent()) instanceof AST_Call
|
||||
&& iife.expression === fn) {
|
||||
fn.argnames.forEach(function(sym, i) {
|
||||
var arg = iife.args[i];
|
||||
if (!arg) arg = make_node(AST_Undefined, sym);
|
||||
else arg.walk(new TreeWalker(function(node) {
|
||||
if (!arg) return true;
|
||||
if (node instanceof AST_SymbolRef && fn.variables.has(node.name)) {
|
||||
var s = node.definition().scope;
|
||||
if (s !== scope) while (s = s.parent_scope) {
|
||||
if (s === scope) return true;
|
||||
}
|
||||
arg = null;
|
||||
}
|
||||
}));
|
||||
if (arg) candidates.push(make_node(AST_VarDef, sym, {
|
||||
name: sym,
|
||||
value: arg
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function extract_candidates(expr) {
|
||||
if (expr instanceof AST_Assign && !expr.left.has_side_effects(compressor)
|
||||
|| expr instanceof AST_Unary && (expr.operator == "++" || expr.operator == "--")) {
|
||||
@@ -826,7 +860,7 @@ merge(Compressor.prototype, {
|
||||
function get_lhs(expr) {
|
||||
if (expr instanceof AST_VarDef) {
|
||||
var def = expr.name.definition();
|
||||
if (def.orig.length > 1
|
||||
if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg)
|
||||
|| def.references.length == 1 && !compressor.exposed(def)) {
|
||||
return make_node(AST_SymbolRef, expr.name, expr.name);
|
||||
}
|
||||
@@ -868,6 +902,14 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function remove_candidate(expr) {
|
||||
if (expr.name instanceof AST_SymbolFunarg) {
|
||||
var index = compressor.self().argnames.indexOf(expr.name);
|
||||
var args = compressor.parent().args;
|
||||
if (args[index]) args[index] = make_node(AST_Number, args[index], {
|
||||
value: 0
|
||||
});
|
||||
return true;
|
||||
}
|
||||
var found = false;
|
||||
return statements[stat_index].transform(new TreeTransformer(function(node, descend, in_list) {
|
||||
if (found) return node;
|
||||
@@ -3123,7 +3165,7 @@ merge(Compressor.prototype, {
|
||||
// https://github.com/mishoo/UglifyJS2/issues/203
|
||||
// if the code argument is a constant, then we can minify it.
|
||||
try {
|
||||
var code = "NaN(function(" + self.args.slice(0, -1).map(function(arg) {
|
||||
var code = "n(function(" + self.args.slice(0, -1).map(function(arg) {
|
||||
return arg.value;
|
||||
}).join(",") + "){" + self.args[self.args.length - 1].value + "})";
|
||||
var ast = parse(code);
|
||||
@@ -3143,18 +3185,18 @@ merge(Compressor.prototype, {
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
var args = fun.argnames.map(function(arg, i) {
|
||||
return make_node(AST_String, self.args[i], {
|
||||
value: arg.print_to_string()
|
||||
});
|
||||
});
|
||||
var code = OutputStream();
|
||||
AST_BlockStatement.prototype._codegen.call(fun, fun, code);
|
||||
code = code.toString().replace(/^\{|\}$/g, "");
|
||||
args.push(make_node(AST_String, self.args[self.args.length - 1], {
|
||||
value: code
|
||||
}));
|
||||
self.args = args;
|
||||
self.args = [
|
||||
make_node(AST_String, self, {
|
||||
value: fun.argnames.map(function(arg) {
|
||||
return arg.print_to_string();
|
||||
}).join(",")
|
||||
}),
|
||||
make_node(AST_String, self.args[self.args.length - 1], {
|
||||
value: code.get().replace(/^\{|\}$/g, "")
|
||||
})
|
||||
];
|
||||
return self;
|
||||
} catch (ex) {
|
||||
if (ex instanceof JS_Parse_Error) {
|
||||
@@ -3171,80 +3213,53 @@ merge(Compressor.prototype, {
|
||||
var value = stat.value;
|
||||
if (!value || value.is_constant_expression()) {
|
||||
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
||||
return make_sequence(self, args).transform(compressor);
|
||||
return make_sequence(self, args).optimize(compressor);
|
||||
}
|
||||
}
|
||||
if (exp instanceof AST_Function) {
|
||||
if (compressor.option("inline")
|
||||
&& !exp.name
|
||||
&& exp.body.length == 1
|
||||
&& !exp.uses_arguments
|
||||
&& !exp.uses_eval
|
||||
&& exp.body.length == 1
|
||||
&& all(exp.argnames, function(arg) {
|
||||
return arg.__unused;
|
||||
})
|
||||
&& !self.has_pure_annotation(compressor)) {
|
||||
var value;
|
||||
if (stat instanceof AST_Return) {
|
||||
value = stat.value.clone(true);
|
||||
value = stat.value;
|
||||
} else if (stat instanceof AST_SimpleStatement) {
|
||||
value = make_node(AST_UnaryPrefix, stat, {
|
||||
operator: "void",
|
||||
expression: stat.body.clone(true)
|
||||
expression: stat.body
|
||||
});
|
||||
}
|
||||
if (value) {
|
||||
var fn = exp.clone();
|
||||
fn.argnames = [];
|
||||
fn.body = [];
|
||||
if (exp.argnames.length > 0) {
|
||||
fn.body.push(make_node(AST_Var, self, {
|
||||
definitions: exp.argnames.map(function(sym, i) {
|
||||
var arg = self.args[i];
|
||||
return make_node(AST_VarDef, sym, {
|
||||
name: sym,
|
||||
value: arg ? arg.clone(true) : make_node(AST_Undefined, self)
|
||||
});
|
||||
})
|
||||
}));
|
||||
}
|
||||
if (self.args.length > exp.argnames.length) {
|
||||
fn.body.push(make_node(AST_SimpleStatement, self, {
|
||||
body: make_sequence(self, self.args.slice(exp.argnames.length).map(function(node) {
|
||||
return node.clone(true);
|
||||
}))
|
||||
}));
|
||||
}
|
||||
fn.body.push(make_node(AST_Return, self, {
|
||||
value: value
|
||||
}));
|
||||
var body = fn.transform(compressor).body;
|
||||
if (body.length == 0) return make_node(AST_Undefined, self);
|
||||
if (body.length == 1 && body[0] instanceof AST_Return) {
|
||||
value = body[0].value;
|
||||
if (!value) return make_node(AST_Undefined, self);
|
||||
var tw = new TreeWalker(function(node) {
|
||||
if (value === self) return true;
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var ref = node.scope.find_variable(node);
|
||||
if (ref && ref.scope.parent_scope === fn.parent_scope) {
|
||||
value = self;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
|
||||
value = self;
|
||||
var tw = new TreeWalker(function(node) {
|
||||
if (!value) return true;
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var ref = node.scope.find_variable(node);
|
||||
if (ref && ref.scope.parent_scope === fn.parent_scope) {
|
||||
value = null;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
value.walk(tw);
|
||||
if (value !== self) value = best_of(compressor, value, self);
|
||||
} else {
|
||||
value = self;
|
||||
}
|
||||
if (value !== self) return value;
|
||||
}
|
||||
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
|
||||
value = null;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
value.walk(tw);
|
||||
}
|
||||
if (value) {
|
||||
var args = self.args.concat(value);
|
||||
return make_sequence(self, args).optimize(compressor);
|
||||
}
|
||||
}
|
||||
if (compressor.option("side_effects") && all(exp.body, is_empty)) {
|
||||
var args = self.args.concat(make_node(AST_Undefined, self));
|
||||
return make_sequence(self, args).transform(compressor);
|
||||
return make_sequence(self, args).optimize(compressor);
|
||||
}
|
||||
}
|
||||
if (compressor.option("drop_console")) {
|
||||
|
||||
@@ -27,6 +27,23 @@ function set_shorthand(name, options, keys) {
|
||||
}
|
||||
}
|
||||
|
||||
function init_cache(cache) {
|
||||
if (!cache) return;
|
||||
if (!("cname" in cache)) cache.cname = -1;
|
||||
if (!("props" in cache)) {
|
||||
cache.props = new Dictionary();
|
||||
} else if (!(cache.props instanceof Dictionary)) {
|
||||
cache.props = Dictionary.fromObject(cache.props);
|
||||
}
|
||||
}
|
||||
|
||||
function to_json(cache) {
|
||||
return {
|
||||
cname: cache.cname,
|
||||
props: cache.props.toObject()
|
||||
};
|
||||
}
|
||||
|
||||
function minify(files, options) {
|
||||
var warn_function = AST_Node.warn_function;
|
||||
try {
|
||||
@@ -35,6 +52,7 @@ function minify(files, options) {
|
||||
ie8: false,
|
||||
keep_fnames: false,
|
||||
mangle: {},
|
||||
nameCache: null,
|
||||
output: {},
|
||||
parse: {},
|
||||
sourceMap: false,
|
||||
@@ -52,7 +70,7 @@ function minify(files, options) {
|
||||
set_shorthand("warnings", options, [ "compress" ]);
|
||||
if (options.mangle) {
|
||||
options.mangle = defaults(options.mangle, {
|
||||
cache: null,
|
||||
cache: options.nameCache && (options.nameCache.vars || {}),
|
||||
eval: false,
|
||||
ie8: false,
|
||||
keep_fnames: false,
|
||||
@@ -60,6 +78,16 @@ function minify(files, options) {
|
||||
reserved: [],
|
||||
toplevel: false,
|
||||
}, true);
|
||||
if (options.nameCache && options.mangle.properties) {
|
||||
if (typeof options.mangle.properties != "object") {
|
||||
options.mangle.properties = {};
|
||||
}
|
||||
if (!("cache" in options.mangle.properties)) {
|
||||
options.mangle.properties.cache = options.nameCache.props || {};
|
||||
}
|
||||
}
|
||||
init_cache(options.mangle.cache);
|
||||
init_cache(options.mangle.properties.cache);
|
||||
}
|
||||
if (options.sourceMap) {
|
||||
options.sourceMap = defaults(options.sourceMap, {
|
||||
@@ -153,6 +181,12 @@ function minify(files, options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (options.nameCache && options.mangle) {
|
||||
if (options.mangle.cache) options.nameCache.vars = to_json(options.mangle.cache);
|
||||
if (options.mangle.properties && options.mangle.properties.cache) {
|
||||
options.nameCache.props = to_json(options.mangle.properties.cache);
|
||||
}
|
||||
}
|
||||
if (timings) {
|
||||
timings.end = Date.now();
|
||||
result.timings = {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": "http://lisperator.net/uglifyjs",
|
||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||
"license": "BSD-2-Clause",
|
||||
"version": "3.0.20",
|
||||
"version": "3.0.23",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
|
||||
@@ -1978,10 +1978,10 @@ chained_3: {
|
||||
}
|
||||
expect: {
|
||||
console.log(function(a, b) {
|
||||
var c = a, c = b;
|
||||
var c = 1, c = b;
|
||||
b++;
|
||||
return c;
|
||||
}(1, 2));
|
||||
}(0, 2));
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
@@ -2186,3 +2186,73 @@ compound_assignment: {
|
||||
}
|
||||
expect_stdout: "4"
|
||||
}
|
||||
|
||||
issue_2187_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
!function(foo) {
|
||||
foo();
|
||||
var a = 2;
|
||||
console.log(a);
|
||||
}(function() {
|
||||
console.log(a);
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
!function(foo) {
|
||||
foo();
|
||||
var a = 2;
|
||||
console.log(a);
|
||||
}(function() {
|
||||
console.log(a);
|
||||
});
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
"2",
|
||||
]
|
||||
}
|
||||
|
||||
issue_2187_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
console.log(function(a) {
|
||||
return a && ++b;
|
||||
}(b--));
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
console.log(function(a) {
|
||||
return b-- && ++b;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
issue_2187_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var b = 1;
|
||||
console.log(function(a) {
|
||||
return a && ++b;
|
||||
}(b--));
|
||||
}
|
||||
expect: {
|
||||
var b = 1;
|
||||
console.log(b-- && ++b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -1113,6 +1113,7 @@ issue_2105: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
@@ -1138,7 +1139,7 @@ issue_2105: {
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
!void function() {
|
||||
(function() {
|
||||
var quux = function() {
|
||||
console.log("PASS");
|
||||
};
|
||||
@@ -1148,7 +1149,7 @@ issue_2105: {
|
||||
quux();
|
||||
}
|
||||
};
|
||||
}().prop();
|
||||
})().prop();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ issue_203: {
|
||||
}
|
||||
expect: {
|
||||
var m = {};
|
||||
var fn = Function("n", "o", "o.exports=42");
|
||||
var fn = Function("n,o", "o.exports=42");
|
||||
fn(null, m, m.exports);
|
||||
console.log(m.exports);
|
||||
}
|
||||
@@ -468,11 +468,9 @@ issue_2114_1: {
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
!function() {
|
||||
0;
|
||||
}((c += 1, c = 1 + c, function() {
|
||||
c = 1 + (c += 1), function() {
|
||||
var b = void (b && (b.b += (c += 1, 0)));
|
||||
}()));
|
||||
}();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
|
||||
@@ -174,3 +174,24 @@ issue_1986: {
|
||||
console.log(42);
|
||||
}
|
||||
}
|
||||
|
||||
issue_2167: {
|
||||
options = {
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true,
|
||||
global_defs: {
|
||||
"@isDevMode": "function(){}",
|
||||
},
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
if (isDevMode()) {
|
||||
greetOverlord();
|
||||
}
|
||||
doWork();
|
||||
}
|
||||
expect: {
|
||||
doWork();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,7 +419,7 @@ wrap_iife_in_return_call: {
|
||||
expect_exact: '(void console.log("test"))();'
|
||||
}
|
||||
|
||||
pure_annotation: {
|
||||
pure_annotation_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
@@ -432,6 +432,20 @@ pure_annotation: {
|
||||
expect_exact: ""
|
||||
}
|
||||
|
||||
pure_annotation_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
/*@__PURE__*/(function(n) {
|
||||
console.log("hello", n);
|
||||
}(42));
|
||||
}
|
||||
expect_exact: ""
|
||||
}
|
||||
|
||||
drop_fargs: {
|
||||
options = {
|
||||
cascade: true,
|
||||
@@ -449,9 +463,7 @@ drop_fargs: {
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
!function() {
|
||||
a++;
|
||||
}(++a && a.var);
|
||||
++a && a.var, a++;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "3"
|
||||
@@ -474,9 +486,7 @@ keep_fargs: {
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
!function(a_1) {
|
||||
a++;
|
||||
}(++a && a.var);
|
||||
++a && a.var, a++;
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "3"
|
||||
|
||||
@@ -26,12 +26,12 @@ describe("bin/uglifyjs with input file globs", function() {
|
||||
});
|
||||
});
|
||||
it("bin/uglifyjs with multiple input file globs.", function(done) {
|
||||
var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel';
|
||||
var command = uglifyjscmd + ' "test/input/issue-1242/???.es5" "test/input/issue-1242/*.js" -mc toplevel,passes=2';
|
||||
|
||||
exec(command, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
|
||||
assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",2*11);\n');
|
||||
assert.strictEqual(stdout, 'var print=console.log.bind(console);print("qux",9,6),print("Foo:",22);\n');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var Uglify = require('../../');
|
||||
var assert = require("assert");
|
||||
var readFileSync = require("fs").readFileSync;
|
||||
var run_code = require("../sandbox").run_code;
|
||||
|
||||
function read(path) {
|
||||
return readFileSync(path, "utf8");
|
||||
@@ -20,6 +21,58 @@ describe("minify", function() {
|
||||
assert.strictEqual(result.code, "alert(2);");
|
||||
});
|
||||
|
||||
it("Should work with mangle.cache", function() {
|
||||
var cache = {};
|
||||
var original = "";
|
||||
var compressed = "";
|
||||
[
|
||||
"bar.es5",
|
||||
"baz.es5",
|
||||
"foo.es5",
|
||||
"qux.js",
|
||||
].forEach(function(file) {
|
||||
var code = read("test/input/issue-1242/" + file);
|
||||
var result = Uglify.minify(code, {
|
||||
mangle: {
|
||||
cache: cache,
|
||||
toplevel: true
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
original += code;
|
||||
compressed += result.code;
|
||||
});
|
||||
assert.strictEqual(JSON.stringify(cache).slice(0, 20), '{"cname":5,"props":{');
|
||||
assert.strictEqual(compressed, 'function n(n){return 3*n}function r(n){return n/2}function c(o){l("Foo:",2*o)}var l=console.log.bind(console);var f=n(3),i=r(12);l("qux",f,i),c(11);');
|
||||
assert.strictEqual(run_code(compressed), run_code(original));
|
||||
});
|
||||
|
||||
it("Should work with nameCache", function() {
|
||||
var cache = {};
|
||||
var original = "";
|
||||
var compressed = "";
|
||||
[
|
||||
"bar.es5",
|
||||
"baz.es5",
|
||||
"foo.es5",
|
||||
"qux.js",
|
||||
].forEach(function(file) {
|
||||
var code = read("test/input/issue-1242/" + file);
|
||||
var result = Uglify.minify(code, {
|
||||
mangle: {
|
||||
toplevel: true
|
||||
},
|
||||
nameCache: cache
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
original += code;
|
||||
compressed += result.code;
|
||||
});
|
||||
assert.strictEqual(JSON.stringify(cache).slice(0, 28), '{"vars":{"cname":5,"props":{');
|
||||
assert.strictEqual(compressed, 'function n(n){return 3*n}function r(n){return n/2}function c(o){l("Foo:",2*o)}var l=console.log.bind(console);var f=n(3),i=r(12);l("qux",f,i),c(11);');
|
||||
assert.strictEqual(run_code(compressed), run_code(original));
|
||||
});
|
||||
|
||||
describe("keep_quoted_props", function() {
|
||||
it("Should preserve quotes in object literals", function() {
|
||||
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||
@@ -212,7 +265,7 @@ describe("minify", function() {
|
||||
});
|
||||
var err = result.error;
|
||||
assert.ok(err instanceof Error);
|
||||
assert.strictEqual(err.stack.split(/\n/)[0], "Error: Can't handle expression: 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