Compare commits

...

13 Commits

Author SHA1 Message Date
Alex Lam S.L
33ad0d258c harmony-v3.0.23 2017-07-02 19:04:15 +08:00
alexlamsl
5ea1da2d42 handle AST_Expansion in collapse_vars & inline 2017-07-02 18:15:16 +08:00
alexlamsl
e77b6d525c Merge branch 'master' into harmony-v3.0.23 2017-07-02 17:47:21 +08:00
Alex Lam S.L
2dde41615a v3.0.23 2017-07-02 17:24:22 +08:00
Alex Lam S.L
8b69a3d18e drop argument value after collapse_vars (#2190) 2017-07-02 04:28:11 +08:00
Alex Lam S.L
d40950b741 improve inline efficiency (#2188)
... by teaching `collapse_vars` some new tricks.

fixes #2187
2017-07-02 01:05:14 +08:00
Alex Lam S.L
a9eecd844f harmony-v3.0.22 2017-06-30 12:56:56 +08:00
alexlamsl
ed3032e52a Merge branch 'master' into harmony-v3.0.22 2017-06-30 11:24:07 +08:00
Alex Lam S.L
7659ea1d2e v3.0.22 2017-06-30 11:18:34 +08:00
Alex Lam S.L
52cc21d999 remove extraneous ! before AST_Arrow (#2185) 2017-06-30 11:17:58 +08:00
kzc
a938fe5e1f async arrow function IIFE fix (#2184)
fixes #2183
2017-06-30 10:12:42 +08:00
kzc
07a5a57336 fix await parens for property access and calls (#2181)
fixes #2179
2017-06-30 09:14:24 +08:00
Alex Lam S.L
bdeadffbf5 improve usability of name cache under minify() (#2176)
fixes #2174
2017-06-29 12:48:34 +08:00
14 changed files with 395 additions and 126 deletions

View File

@@ -109,7 +109,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.
@@ -381,7 +381,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:
@@ -462,6 +502,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
@@ -488,6 +535,7 @@ if (result.error) throw result.error;
// source map options
},
ecma: 5, // specify one of: 5, 6, 7 or 8
nameCache: null, // or specify a name cache object
toplevel: false,
ie8: false,
warnings: false,
@@ -689,7 +737,7 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
functions marked as "pure". A function call is marked as "pure" if a comment
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
example: `/*@__PURE__*/foo();`
- `ecma` -- default `5`. Pass `6` or greater to enable `compress` options that
will transform ES5 code into smaller ES6+ equivalent forms.
@@ -768,7 +816,7 @@ can pass additional arguments that control the code output:
(e.g. `/^!/`) or a function.
- `ecma` (default `5`) -- set output printing mode. Set `ecma` to `6` or
greater to emit shorthand object properties - i.e.: `{a}` instead of `{a: a}`.
The `ecma` option will only change the output in direct control of the
The `ecma` option will only change the output in direct control of the
beautifier. Non-compatible features in the abstract syntax tree will still
be output as is. For example: an `ecma` setting of `5` will **not** convert
ES6+ code to ES5.

View File

@@ -111,17 +111,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 = {
@@ -271,9 +262,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");
@@ -386,18 +375,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;
}

View File

@@ -708,7 +708,7 @@ merge(Compressor.prototype, {
function is_iife_call(node) {
if (node instanceof AST_Call && !(node instanceof AST_New)) {
return is_func_expr(node.expression) || is_iife_call(node.expression);
return node.expression instanceof AST_Function || is_iife_call(node.expression);
}
return false;
}
@@ -749,15 +749,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
@@ -840,6 +848,58 @@ merge(Compressor.prototype, {
}
}
function has_overlapping_symbol(fn, arg) {
var found = false;
arg.walk(new TreeWalker(function(node) {
if (found) 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;
}
found = true;
}
}));
return found;
}
function extract_args() {
var iife, fn = compressor.self();
if (is_func_expr(fn)
&& !fn.name
&& !fn.uses_arguments
&& !fn.uses_eval
&& (iife = compressor.parent()) instanceof AST_Call
&& iife.expression === fn
&& all(iife.args, function(arg) {
return !(arg instanceof AST_Expansion);
})) {
fn.argnames.forEach(function(sym, i) {
if (sym instanceof AST_Expansion) {
var elements = iife.args.slice(i);
if (all(elements, function(arg) {
return !has_overlapping_symbol(fn, arg);
})) {
candidates.push(make_node(AST_VarDef, sym, {
name: sym.expression,
value: make_node(AST_Array, iife, {
elements: elements
})
}));
}
} else {
var arg = iife.args[i];
if (!arg) arg = make_node(AST_Undefined, sym);
else if (has_overlapping_symbol(fn, arg)) 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 == "--")) {
@@ -860,7 +920,7 @@ merge(Compressor.prototype, {
function get_lhs(expr) {
if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) {
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);
}
@@ -903,6 +963,19 @@ merge(Compressor.prototype, {
}
function remove_candidate(expr) {
if (expr.name instanceof AST_SymbolFunarg) {
var iife = compressor.parent(), argnames = compressor.self().argnames;
var index = argnames.indexOf(expr.name);
if (index < 0) {
iife.args.length = Math.min(iife.args.length, argnames.length - 1);
} else {
var args = iife.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;
@@ -3105,7 +3178,7 @@ merge(Compressor.prototype, {
var pos = 0, last = 0;
for (var i = 0, len = self.args.length; i < len; i++) {
if (fn.argnames[i] instanceof AST_Expansion) {
if (fn.argnames[i].__unused) while (i < len) {
if (fn.argnames[i].expression.__unused) while (i < len) {
var node = self.args[i++].drop_side_effect_free(compressor);
if (node) {
self.args[pos++] = node;
@@ -3343,98 +3416,55 @@ 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 (is_func_expr(exp) && !exp.is_generator && !exp.async) {
if (compressor.option("inline")
&& simple_args
&& !exp.name
&& (exp.body instanceof AST_Node || exp.body.length == 1)
&& !exp.uses_arguments
&& !exp.uses_eval
&& simple_args
&& (exp.body instanceof AST_Node || exp.body.length == 1)
&& all(exp.argnames, function(arg) {
if (arg instanceof AST_Expansion) return arg.expression.__unused;
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) {
if (sym instanceof AST_Expansion) {
return make_node(AST_VarDef, sym, {
name: sym.expression,
value: make_node(AST_Array, self, {
elements: self.args.slice(i).map(function(arg) {
return arg.clone(true);
})
})
});
}
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 && !(exp.argnames[exp.argnames.length - 1] instanceof AST_Expansion)) {
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 instanceof AST_Node) {
body = [
make_node(AST_Return, body, {
value: 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") && !(exp.body instanceof AST_Node) && 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")) {

View File

@@ -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 {
@@ -36,6 +53,7 @@ function minify(files, options) {
ie8: false,
keep_fnames: false,
mangle: {},
nameCache: null,
output: {},
parse: {},
sourceMap: false,
@@ -54,7 +72,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_classnames: false,
@@ -64,6 +82,16 @@ function minify(files, options) {
safari10: false,
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, {
@@ -157,6 +185,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 = {

View File

@@ -673,6 +673,12 @@ function OutputStream(options) {
&& this.operator !== "--";
});
PARENS(AST_Await, function(output){
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_Call && p.expression === this;
});
PARENS(AST_Sequence, function(output){
var p = output.parent();
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
@@ -1039,11 +1045,11 @@ function OutputStream(options) {
var needs_parens = parent instanceof AST_Binary ||
parent instanceof AST_Unary ||
(parent instanceof AST_Call && self === parent.expression);
if (needs_parens) { output.print("(") }
if (self.async) {
output.print("async");
output.space();
}
if (needs_parens) { output.print("(") }
if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) {
self.argnames[0].print(output);
} else {

View File

@@ -4,7 +4,7 @@
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.0.21",
"version": "3.0.23",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -287,6 +287,7 @@ issue_2105_1: {
collapse_vars: true,
ecma: 6,
inline: true,
passes: 3,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -312,7 +313,7 @@ issue_2105_1: {
});
}
expect: {
!void (() => {
(() => {
var quux = () => {
console.log("PASS");
};
@@ -332,6 +333,7 @@ issue_2105_2: {
options = {
collapse_vars: true,
inline: true,
passes: 2,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -357,7 +359,7 @@ issue_2105_2: {
});
}
expect: {
!void (() => {
(() => {
var quux = () => {
console.log("PASS");
};
@@ -528,7 +530,7 @@ issue_2084: {
}
expect: {
var c = 0;
!((c) => {
((c) => {
c = 1 + c,
c = 1 + (c = 0),
0 !== 23..toString() && (c = 1 + c);

View File

@@ -6,6 +6,22 @@ await_precedence: {
expect_exact: "async function f1(){await x+y}async function f2(){await(x+y)}"
}
await_precedence_prop: {
input: {
async function f1(){ return (await foo()).bar; }
async function f2(){ return (await foo().bar); }
}
expect_exact: "async function f1(){return(await foo()).bar}async function f2(){return await foo().bar}"
}
await_precedence_call: {
input: {
async function f3(){ return (await foo())(); }
async function f4(){ return await (foo()()); }
}
expect_exact: "async function f3(){return(await foo())()}async function f4(){return await foo()()}"
}
async_function_declaration: {
options = {
side_effects: true,
@@ -252,3 +268,27 @@ async_arrow_wait: {
}
expect_exact: "var a=async(x,y)=>await x(y);"
}
async_arrow_iife: {
input: {
(async () => {
await fetch({});
})();
}
expect_exact: "(async()=>{await fetch({})})();"
}
async_arrow_iife_negate_iife: {
options = {
negate_iife: true,
}
input: {
(async () => {
await fetch();
})();
(() => {
plain();
})();
}
expect_exact: "(async()=>{await fetch()})();(()=>{plain()})();"
}

View File

@@ -2077,10 +2077,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"
}
@@ -2330,3 +2330,73 @@ reassign_const_2: {
}
expect_stdout: true
}
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"
}

View File

@@ -1299,6 +1299,7 @@ issue_2105: {
options = {
collapse_vars: true,
inline: true,
passes: 3,
reduce_vars: true,
side_effects: true,
unused: true,
@@ -1324,7 +1325,7 @@ issue_2105: {
});
}
expect: {
!void function() {
(function() {
var quux = function() {
console.log("PASS");
};
@@ -1334,7 +1335,7 @@ issue_2105: {
quux();
}
};
}().prop();
})().prop();
}
expect_stdout: "PASS"
}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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();
});
});

View File

@@ -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};';