Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd7be07c38 | ||
|
|
71ee91e716 | ||
|
|
4f70d2e28c | ||
|
|
4b6ca5e742 | ||
|
|
9306da3c58 | ||
|
|
1ac25fc032 | ||
|
|
5f046c724b | ||
|
|
af0262b7e5 | ||
|
|
6b3aeff1d8 | ||
|
|
20e4f8277f | ||
|
|
f3a487a368 | ||
|
|
2dde41615a | ||
|
|
8b69a3d18e | ||
|
|
d40950b741 | ||
|
|
7659ea1d2e | ||
|
|
bdeadffbf5 | ||
|
|
5e6f26445f | ||
|
|
f0a99125ee | ||
|
|
1e4de2e6d3 | ||
|
|
8b4dcd8f3e | ||
|
|
285401ced8 | ||
|
|
9db4c42380 | ||
|
|
94e5e00c03 | ||
|
|
dc6bcaa18e | ||
|
|
d58b184835 | ||
|
|
b3a57ff019 | ||
|
|
3d5bc08185 | ||
|
|
0692435f01 | ||
|
|
f67a6b0e43 | ||
|
|
343ea326c2 | ||
|
|
1c150c632f | ||
|
|
0a0f4f5591 | ||
|
|
931daa85bf | ||
|
|
00e4f7b3c1 | ||
|
|
11e63bc335 | ||
|
|
33405bb24b |
83
README.md
83
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,
|
||||
}
|
||||
@@ -596,6 +644,10 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
||||
- `booleans` -- various optimizations for boolean context, for example `!!a
|
||||
? b : c → a ? b : c`
|
||||
|
||||
- `typeofs` -- default `true`. Transforms `typeof foo == "undefined"` into
|
||||
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
|
||||
earlier versions due to known issues.
|
||||
|
||||
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
||||
statically determine the condition
|
||||
|
||||
@@ -825,7 +877,6 @@ when this flag is on:
|
||||
- `new Object()` → `{}`
|
||||
- `String(exp)` or `exp.toString()` → `"" + exp`
|
||||
- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`
|
||||
- `typeof foo == "undefined"` → `foo === void 0`
|
||||
- `void 0` → `undefined` (if there is a variable named "undefined" in
|
||||
scope; we do it because the variable name will be mangled, typically
|
||||
reduced to a single character)
|
||||
@@ -978,3 +1029,29 @@ in total it's a bit more than just using UglifyJS's own parser.
|
||||
|
||||
[acorn]: https://github.com/ternjs/acorn
|
||||
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k
|
||||
|
||||
### Uglify Fast Minify Mode
|
||||
|
||||
It's not well known, but variable and function name mangling accounts for
|
||||
95% of the size reduction in minified code for most javascript - not
|
||||
elaborate code transforms. One can simply disable `compress` to speed up
|
||||
Uglify builds by 3 to 4 times. In this fast `mangle`-only mode Uglify has
|
||||
comparable minify speeds and gzip sizes to
|
||||
[`butternut`](https://www.npmjs.com/package/butternut):
|
||||
|
||||
| d3.js | minify size | gzip size | minify time (seconds) |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| original | 451,131 | 108,733 | - |
|
||||
| uglify-js@3.0.23 mangle=false, compress=false | 316,600 | 85,245 | 0.73 |
|
||||
| uglify-js@3.0.23 mangle=true, compress=false | 220,216 | 72,730 | 1.21 |
|
||||
| Butternut 0.4.6 | 217,568 | 72,738 | 1.81 |
|
||||
| uglify-js@3.0.23 mangle=true, compress=true | 212,511 | 71,560 | 4.64 |
|
||||
|
||||
To enable fast minify mode from the CLI use:
|
||||
```
|
||||
uglifyjs file.js -m
|
||||
```
|
||||
To enable fast minify mode with the API use:
|
||||
```js
|
||||
UglifyJS.minify(code, { compress: false, mangle: true });
|
||||
```
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -859,7 +859,7 @@ TreeWalker.prototype = {
|
||||
if (!ret && descend) {
|
||||
descend.call(node);
|
||||
}
|
||||
this.pop(node);
|
||||
this.pop();
|
||||
return ret;
|
||||
},
|
||||
parent: function(n) {
|
||||
@@ -873,9 +873,8 @@ TreeWalker.prototype = {
|
||||
}
|
||||
this.stack.push(node);
|
||||
},
|
||||
pop: function(node) {
|
||||
this.stack.pop();
|
||||
if (node instanceof AST_Lambda) {
|
||||
pop: function() {
|
||||
if (this.stack.pop() instanceof AST_Lambda) {
|
||||
this.directives = Object.getPrototypeOf(this.directives);
|
||||
}
|
||||
},
|
||||
|
||||
977
lib/compress.js
977
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -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 = {
|
||||
|
||||
@@ -501,6 +501,7 @@ function OutputStream(options) {
|
||||
use_asm = prev_use_asm;
|
||||
}
|
||||
});
|
||||
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||
|
||||
AST_Node.DEFMETHOD("print_to_string", function(options){
|
||||
var s = OutputStream(options);
|
||||
@@ -671,14 +672,15 @@ function OutputStream(options) {
|
||||
// parens around it too, otherwise the call will be
|
||||
// interpreted as passing the arguments to the upper New
|
||||
// expression.
|
||||
try {
|
||||
this.walk(new TreeWalker(function(node){
|
||||
if (node instanceof AST_Call) throw p;
|
||||
}));
|
||||
} catch(ex) {
|
||||
if (ex !== p) throw ex;
|
||||
return true;
|
||||
}
|
||||
var parens = false;
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (parens || node instanceof AST_Scope) return true;
|
||||
if (node instanceof AST_Call) {
|
||||
parens = true;
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
return parens;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1072,19 +1074,17 @@ function OutputStream(options) {
|
||||
});
|
||||
|
||||
function parenthesize_for_noin(node, output, noin) {
|
||||
if (!noin) node.print(output);
|
||||
else try {
|
||||
// need to take some precautions here:
|
||||
// https://github.com/mishoo/UglifyJS2/issues/60
|
||||
node.walk(new TreeWalker(function(node){
|
||||
if (node instanceof AST_Binary && node.operator == "in")
|
||||
throw output;
|
||||
}));
|
||||
node.print(output);
|
||||
} catch(ex) {
|
||||
if (ex !== output) throw ex;
|
||||
node.print(output, true);
|
||||
}
|
||||
var parens = false;
|
||||
// need to take some precautions here:
|
||||
// https://github.com/mishoo/UglifyJS2/issues/60
|
||||
if (noin) node.walk(new TreeWalker(function(node) {
|
||||
if (parens || node instanceof AST_Scope) return true;
|
||||
if (node instanceof AST_Binary && node.operator == "in") {
|
||||
parens = true;
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
node.print(output, parens);
|
||||
};
|
||||
|
||||
DEFPRINT(AST_VarDef, function(self, output){
|
||||
|
||||
@@ -1010,8 +1010,12 @@ function parse($TEXT, options) {
|
||||
? (next(), var_(true))
|
||||
: expression(true, true);
|
||||
if (is("operator", "in")) {
|
||||
if (init instanceof AST_Var && init.definitions.length > 1)
|
||||
croak("Only one variable declaration allowed in for..in loop");
|
||||
if (init instanceof AST_Var) {
|
||||
if (init.definitions.length > 1)
|
||||
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||
} else if (!is_assignable(init)) {
|
||||
croak("Invalid left-hand side in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||
}
|
||||
next();
|
||||
return for_in(init);
|
||||
}
|
||||
|
||||
138
lib/scope.js
138
lib/scope.js
@@ -79,7 +79,7 @@ SymbolDef.prototype = {
|
||||
if (options.ie8 && sym instanceof AST_SymbolLambda)
|
||||
s = s.parent_scope;
|
||||
var def;
|
||||
if (this.defun && (def = this.defun.variables.get(this.name))) {
|
||||
if (def = this.redefined()) {
|
||||
this.mangled_name = def.mangled_name || def.name;
|
||||
} else
|
||||
this.mangled_name = s.next_mangled(options, this);
|
||||
@@ -87,6 +87,9 @@ SymbolDef.prototype = {
|
||||
cache.set(this.name, this.mangled_name);
|
||||
}
|
||||
}
|
||||
},
|
||||
redefined: function() {
|
||||
return this.defun && this.defun.variables.get(this.name);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -206,6 +209,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
node.reference(options);
|
||||
return true;
|
||||
}
|
||||
// ensure mangling works if catch reuses a scope variable
|
||||
var def;
|
||||
if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) {
|
||||
var s = node.scope;
|
||||
while (s) {
|
||||
push_uniq(s.enclosed, def);
|
||||
if (s === def.scope) break;
|
||||
s = s.parent_scope;
|
||||
}
|
||||
}
|
||||
});
|
||||
self.walk(tw);
|
||||
|
||||
@@ -348,7 +361,8 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("unmangleable", function(options){
|
||||
return this.definition().unmangleable(options);
|
||||
var def = this.definition();
|
||||
return !def || def.unmangleable(options);
|
||||
});
|
||||
|
||||
// labels are always mangleable
|
||||
@@ -447,103 +461,69 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
||||
|
||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
||||
options = this._default_mangler_options(options);
|
||||
var tw = new TreeWalker(function(node){
|
||||
if (node instanceof AST_Constant)
|
||||
base54.consider(node.print_to_string());
|
||||
else if (node instanceof AST_Return)
|
||||
base54.consider("return");
|
||||
else if (node instanceof AST_Throw)
|
||||
base54.consider("throw");
|
||||
else if (node instanceof AST_Continue)
|
||||
base54.consider("continue");
|
||||
else if (node instanceof AST_Break)
|
||||
base54.consider("break");
|
||||
else if (node instanceof AST_Debugger)
|
||||
base54.consider("debugger");
|
||||
else if (node instanceof AST_Directive)
|
||||
base54.consider(node.value);
|
||||
else if (node instanceof AST_While)
|
||||
base54.consider("while");
|
||||
else if (node instanceof AST_Do)
|
||||
base54.consider("do while");
|
||||
else if (node instanceof AST_If) {
|
||||
base54.consider("if");
|
||||
if (node.alternative) base54.consider("else");
|
||||
}
|
||||
else if (node instanceof AST_Var)
|
||||
base54.consider("var");
|
||||
else if (node instanceof AST_Lambda)
|
||||
base54.consider("function");
|
||||
else if (node instanceof AST_For)
|
||||
base54.consider("for");
|
||||
else if (node instanceof AST_ForIn)
|
||||
base54.consider("for in");
|
||||
else if (node instanceof AST_Switch)
|
||||
base54.consider("switch");
|
||||
else if (node instanceof AST_Case)
|
||||
base54.consider("case");
|
||||
else if (node instanceof AST_Default)
|
||||
base54.consider("default");
|
||||
else if (node instanceof AST_With)
|
||||
base54.consider("with");
|
||||
else if (node instanceof AST_ObjectSetter)
|
||||
base54.consider("set" + node.key);
|
||||
else if (node instanceof AST_ObjectGetter)
|
||||
base54.consider("get" + node.key);
|
||||
else if (node instanceof AST_ObjectKeyVal)
|
||||
base54.consider(node.key);
|
||||
else if (node instanceof AST_New)
|
||||
base54.consider("new");
|
||||
else if (node instanceof AST_This)
|
||||
base54.consider("this");
|
||||
else if (node instanceof AST_Try)
|
||||
base54.consider("try");
|
||||
else if (node instanceof AST_Catch)
|
||||
base54.consider("catch");
|
||||
else if (node instanceof AST_Finally)
|
||||
base54.consider("finally");
|
||||
else if (node instanceof AST_Symbol && node.unmangleable(options))
|
||||
base54.consider(node.name);
|
||||
else if (node instanceof AST_Unary || node instanceof AST_Binary)
|
||||
base54.consider(node.operator);
|
||||
else if (node instanceof AST_Dot)
|
||||
base54.consider(node.property);
|
||||
});
|
||||
this.walk(tw);
|
||||
try {
|
||||
AST_Node.prototype.print = function(stream, force_parens) {
|
||||
this._print(stream, force_parens);
|
||||
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
|
||||
base54.consider(this.name, -1);
|
||||
} else if (options.properties) {
|
||||
if (this instanceof AST_Dot) {
|
||||
base54.consider(this.property, -1);
|
||||
} else if (this instanceof AST_Sub) {
|
||||
skip_string(this.property);
|
||||
}
|
||||
}
|
||||
};
|
||||
base54.consider(this.print_to_string(), 1);
|
||||
} finally {
|
||||
AST_Node.prototype.print = AST_Node.prototype._print;
|
||||
}
|
||||
base54.sort();
|
||||
|
||||
function skip_string(node) {
|
||||
if (node instanceof AST_String) {
|
||||
base54.consider(node.value, -1);
|
||||
} else if (node instanceof AST_Conditional) {
|
||||
skip_string(node.consequent);
|
||||
skip_string(node.alternative);
|
||||
} else if (node instanceof AST_Sequence) {
|
||||
skip_string(node.expressions[node.expressions.length - 1]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var base54 = (function() {
|
||||
var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
|
||||
var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
|
||||
var digits = "0123456789".split("");
|
||||
var chars, frequency;
|
||||
function reset() {
|
||||
frequency = Object.create(null);
|
||||
chars = string.split("").map(function(ch){ return ch.charCodeAt(0) });
|
||||
chars.forEach(function(ch){ frequency[ch] = 0 });
|
||||
leading.forEach(function(ch) {
|
||||
frequency[ch] = 0;
|
||||
});
|
||||
digits.forEach(function(ch) {
|
||||
frequency[ch] = 0;
|
||||
});
|
||||
}
|
||||
base54.consider = function(str){
|
||||
base54.consider = function(str, delta) {
|
||||
for (var i = str.length; --i >= 0;) {
|
||||
var code = str.charCodeAt(i);
|
||||
if (code in frequency) ++frequency[code];
|
||||
frequency[str[i]] += delta;
|
||||
}
|
||||
};
|
||||
function compare(a, b) {
|
||||
return frequency[b] - frequency[a];
|
||||
}
|
||||
base54.sort = function() {
|
||||
chars = mergeSort(chars, function(a, b){
|
||||
if (is_digit(a) && !is_digit(b)) return 1;
|
||||
if (is_digit(b) && !is_digit(a)) return -1;
|
||||
return frequency[b] - frequency[a];
|
||||
});
|
||||
chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
|
||||
};
|
||||
base54.reset = reset;
|
||||
reset();
|
||||
base54.get = function(){ return chars };
|
||||
base54.freq = function(){ return frequency };
|
||||
function base54(num) {
|
||||
var ret = "", base = 54;
|
||||
num++;
|
||||
do {
|
||||
num--;
|
||||
ret += String.fromCharCode(chars[num % base]);
|
||||
ret += chars[num % base];
|
||||
num = Math.floor(num / base);
|
||||
base = 64;
|
||||
} while (num > 0);
|
||||
|
||||
@@ -70,7 +70,7 @@ TreeTransformer.prototype = new TreeWalker;
|
||||
if (y !== undefined) x = y;
|
||||
}
|
||||
}
|
||||
tw.pop(this);
|
||||
tw.pop();
|
||||
return x;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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.17",
|
||||
"version": "3.0.24",
|
||||
"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,159 @@ 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"
|
||||
}
|
||||
|
||||
issue_2203_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
a = "FAIL";
|
||||
console.log({
|
||||
a: "PASS",
|
||||
b: function() {
|
||||
return function(c) {
|
||||
return c.a;
|
||||
}((String, (Object, this)));
|
||||
}
|
||||
}.b());
|
||||
}
|
||||
expect: {
|
||||
a = "FAIL";
|
||||
console.log({
|
||||
a: "PASS",
|
||||
b: function() {
|
||||
return function(c) {
|
||||
return c.a;
|
||||
}((String, (Object, this)));
|
||||
}
|
||||
}.b());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2203_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
a = "PASS";
|
||||
console.log({
|
||||
a: "FAIL",
|
||||
b: function() {
|
||||
return function(c) {
|
||||
return c.a;
|
||||
}((String, (Object, function() {
|
||||
return this;
|
||||
}())));
|
||||
}
|
||||
}.b());
|
||||
}
|
||||
expect: {
|
||||
a = "PASS";
|
||||
console.log({
|
||||
a: "FAIL",
|
||||
b: function() {
|
||||
return function(c) {
|
||||
return (String, (Object, function() {
|
||||
return this;
|
||||
}())).a;
|
||||
}();
|
||||
}
|
||||
}.b());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
duplicate_argname: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() { return "PASS"; }
|
||||
console.log(function(a, a) {
|
||||
f++;
|
||||
return a;
|
||||
}("FAIL", f()));
|
||||
}
|
||||
expect: {
|
||||
function f() { return "PASS"; }
|
||||
console.log(function(a, a) {
|
||||
f++;
|
||||
return a;
|
||||
}("FAIL", f()));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -1108,3 +1108,48 @@ var_catch_toplevel: {
|
||||
}();
|
||||
}
|
||||
}
|
||||
|
||||
issue_2105: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
passes: 3,
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
!function(factory) {
|
||||
factory();
|
||||
}( function() {
|
||||
return function(fn) {
|
||||
fn()().prop();
|
||||
}( function() {
|
||||
function bar() {
|
||||
var quux = function() {
|
||||
console.log("PASS");
|
||||
}, foo = function() {
|
||||
console.log;
|
||||
quux();
|
||||
};
|
||||
return { prop: foo };
|
||||
}
|
||||
return bar;
|
||||
} );
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var quux = function() {
|
||||
console.log("PASS");
|
||||
};
|
||||
return {
|
||||
prop: function() {
|
||||
console.log;
|
||||
quux();
|
||||
}
|
||||
};
|
||||
})().prop();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -250,22 +250,26 @@ unsafe_constant: {
|
||||
|
||||
unsafe_object: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
unsafe : true
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var o = { a: 1 };
|
||||
console.log(
|
||||
({a:1}) + 1,
|
||||
({a:1}).a + 1,
|
||||
({a:1}).b + 1,
|
||||
({a:1}).a.b + 1
|
||||
o + 1,
|
||||
o.a + 1,
|
||||
o.b + 1,
|
||||
o.a.b + 1
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
var o = { a: 1 };
|
||||
console.log(
|
||||
({a:1}) + 1,
|
||||
o + 1,
|
||||
2,
|
||||
({a:1}).b + 1,
|
||||
o.b + 1,
|
||||
1..b + 1
|
||||
);
|
||||
}
|
||||
@@ -274,22 +278,26 @@ unsafe_object: {
|
||||
|
||||
unsafe_object_nested: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
unsafe : true
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var o = { a: { b: 1 } };
|
||||
console.log(
|
||||
({a:{b:1}}) + 1,
|
||||
({a:{b:1}}).a + 1,
|
||||
({a:{b:1}}).b + 1,
|
||||
({a:{b:1}}).a.b + 1
|
||||
o + 1,
|
||||
o.a + 1,
|
||||
o.b + 1,
|
||||
o.a.b + 1
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
var o = { a: { b: 1 } };
|
||||
console.log(
|
||||
({a:{b:1}}) + 1,
|
||||
({a:{b:1}}).a + 1,
|
||||
({a:{b:1}}).b + 1,
|
||||
o + 1,
|
||||
o.a + 1,
|
||||
o.b + 1,
|
||||
2
|
||||
);
|
||||
}
|
||||
@@ -298,21 +306,25 @@ unsafe_object_nested: {
|
||||
|
||||
unsafe_object_complex: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
unsafe : true
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var o = { a: { b: 1 }, b: 1 };
|
||||
console.log(
|
||||
({a:{b:1},b:1}) + 1,
|
||||
({a:{b:1},b:1}).a + 1,
|
||||
({a:{b:1},b:1}).b + 1,
|
||||
({a:{b:1},b:1}).a.b + 1
|
||||
o + 1,
|
||||
o.a + 1,
|
||||
o.b + 1,
|
||||
o.a.b + 1
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
var o = { a: { b: 1 }, b: 1 };
|
||||
console.log(
|
||||
({a:{b:1},b:1}) + 1,
|
||||
({a:{b:1},b:1}).a + 1,
|
||||
o + 1,
|
||||
o.a + 1,
|
||||
2,
|
||||
2
|
||||
);
|
||||
@@ -322,22 +334,26 @@ unsafe_object_complex: {
|
||||
|
||||
unsafe_object_repeated: {
|
||||
options = {
|
||||
evaluate : true,
|
||||
unsafe : true
|
||||
evaluate: true,
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
var o = { a: { b: 1 }, a: 1 };
|
||||
console.log(
|
||||
({a:{b:1},a:1}) + 1,
|
||||
({a:{b:1},a:1}).a + 1,
|
||||
({a:{b:1},a:1}).b + 1,
|
||||
({a:{b:1},a:1}).a.b + 1
|
||||
o + 1,
|
||||
o.a + 1,
|
||||
o.b + 1,
|
||||
o.a.b + 1
|
||||
);
|
||||
}
|
||||
expect: {
|
||||
var o = { a: { b: 1 }, a: 1 };
|
||||
console.log(
|
||||
({a:{b:1},a:1}) + 1,
|
||||
o + 1,
|
||||
2,
|
||||
({a:{b:1},a:1}).b + 1,
|
||||
o.b + 1,
|
||||
1..b + 1
|
||||
);
|
||||
}
|
||||
@@ -386,9 +402,9 @@ unsafe_function: {
|
||||
expect: {
|
||||
console.log(
|
||||
({a:{b:1},b:function(){}}) + 1,
|
||||
({a:{b:1},b:function(){}}).a + 1,
|
||||
({a:{b:1},b:function(){}}).b + 1,
|
||||
({a:{b:1},b:function(){}}).a.b + 1
|
||||
({b:function(){}}, {b:1}) + 1,
|
||||
({a:{b:1}}, function(){}) + 1,
|
||||
({b:function(){}}, {b:1}).b + 1
|
||||
);
|
||||
}
|
||||
expect_stdout: true
|
||||
@@ -636,8 +652,8 @@ unsafe_prototype_function: {
|
||||
var d = ({toString: 0}) + "";
|
||||
var e = (({valueOf: 0}) + "")[2];
|
||||
var f = (({toString: 0}) + "")[2];
|
||||
var g = ({valueOf: 0}).valueOf();
|
||||
var h = "" + ({toString: 0});
|
||||
var g = ({}, 0)();
|
||||
var h = ({}, 0)();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1069,3 +1085,75 @@ string_charCodeAt: {
|
||||
}
|
||||
expect_stdout: "NaN"
|
||||
}
|
||||
|
||||
issue_2207_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log(String.fromCharCode(65));
|
||||
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));
|
||||
}
|
||||
expect: {
|
||||
console.log("A");
|
||||
console.log(7);
|
||||
console.log(Math.cos(1.2345));
|
||||
console.log(1.2543732512566947);
|
||||
console.log(1.6093984514472044);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2207_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log(Math.E);
|
||||
console.log(Math.LN10);
|
||||
console.log(Math.LN2);
|
||||
console.log(Math.LOG2E);
|
||||
console.log(Math.LOG10E);
|
||||
console.log(Math.PI);
|
||||
console.log(Math.SQRT1_2);
|
||||
console.log(Math.SQRT2);
|
||||
}
|
||||
expect: {
|
||||
console.log(Math.E);
|
||||
console.log(Math.LN10);
|
||||
console.log(Math.LN2);
|
||||
console.log(Math.LOG2E);
|
||||
console.log(Math.LOG10E);
|
||||
console.log(Math.PI);
|
||||
console.log(Math.SQRT1_2);
|
||||
console.log(Math.SQRT2);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
issue_2207_3: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log(Number.MAX_VALUE);
|
||||
console.log(Number.MIN_VALUE);
|
||||
console.log(Number.NaN);
|
||||
console.log(Number.NEGATIVE_INFINITY);
|
||||
console.log(Number.POSITIVE_INFINITY);
|
||||
}
|
||||
expect: {
|
||||
console.log(Number.MAX_VALUE);
|
||||
console.log(5e-324);
|
||||
console.log(NaN);
|
||||
console.log(-1/0);
|
||||
console.log(1/0);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ issue_203: {
|
||||
}
|
||||
expect: {
|
||||
var m = {};
|
||||
var fn = Function("a", "b", "b.exports=42");
|
||||
var fn = Function("n,o", "o.exports=42");
|
||||
fn(null, m, m.exports);
|
||||
console.log(m.exports);
|
||||
}
|
||||
@@ -414,3 +414,97 @@ inner_ref: {
|
||||
}
|
||||
expect_stdout: "1 undefined"
|
||||
}
|
||||
|
||||
issue_2107: {
|
||||
options = {
|
||||
cascade: true,
|
||||
collapse_vars: true,
|
||||
inline: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
!function() {
|
||||
c++;
|
||||
}(c++ + new function() {
|
||||
this.a = 0;
|
||||
var a = (c = c + 1) + (c = 1 + c);
|
||||
return c++ + a;
|
||||
}());
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
c++, new function() {
|
||||
this.a = 0, c = 1 + (c += 1), c++;
|
||||
}(), c++, console.log(c);
|
||||
}
|
||||
expect_stdout: "5"
|
||||
}
|
||||
|
||||
issue_2114_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
if_return: true,
|
||||
inline: true,
|
||||
keep_fargs: false,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
!function(a) {
|
||||
a = 0;
|
||||
}([ {
|
||||
0: c = c + 1,
|
||||
length: c = 1 + c
|
||||
}, typeof void function a() {
|
||||
var b = function f1(a) {
|
||||
}(b && (b.b += (c = c + 1, 0)));
|
||||
}() ]);
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
c = 1 + (c += 1), function() {
|
||||
var b = void (b && (b.b += (c += 1, 0)));
|
||||
}();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
issue_2114_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
if_return: true,
|
||||
inline: true,
|
||||
keep_fargs: false,
|
||||
passes: 2,
|
||||
side_effects: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var c = 0;
|
||||
!function(a) {
|
||||
a = 0;
|
||||
}([ {
|
||||
0: c = c + 1,
|
||||
length: c = 1 + c
|
||||
}, typeof void function a() {
|
||||
var b = function f1(a) {
|
||||
}(b && (b.b += (c = c + 1, 0)));
|
||||
}() ]);
|
||||
console.log(c);
|
||||
}
|
||||
expect: {
|
||||
var c = 0;
|
||||
c = 1 + (c += 1), function() {
|
||||
var b = void (b && (b.b += (c += 1, 0)));
|
||||
}();
|
||||
console.log(c);
|
||||
}
|
||||
expect_stdout: "2"
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ object: {
|
||||
VALUE: 42,
|
||||
},
|
||||
},
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
@@ -140,9 +141,9 @@ mixed: {
|
||||
console.log(CONFIG);
|
||||
}
|
||||
expect_warnings: [
|
||||
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:126,22]',
|
||||
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]',
|
||||
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:129,8]',
|
||||
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:128,22]',
|
||||
'WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:130,8]',
|
||||
]
|
||||
}
|
||||
|
||||
@@ -174,3 +175,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ issue_1321_no_debug: {
|
||||
}
|
||||
expect: {
|
||||
var x = {};
|
||||
x.b = 1;
|
||||
x["a"] = 2 * x.b;
|
||||
console.log(x.b, x["a"]);
|
||||
x.o = 1;
|
||||
x["a"] = 2 * x.o;
|
||||
console.log(x.o, x["a"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
@@ -30,9 +30,9 @@ issue_1321_debug: {
|
||||
}
|
||||
expect: {
|
||||
var x = {};
|
||||
x.a = 1;
|
||||
x["_$foo$_"] = 2 * x.a;
|
||||
console.log(x.a, x["_$foo$_"]);
|
||||
x.o = 1;
|
||||
x["_$foo$_"] = 2 * x.o;
|
||||
console.log(x.o, x["_$foo$_"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
@@ -49,9 +49,9 @@ issue_1321_with_quoted: {
|
||||
}
|
||||
expect: {
|
||||
var x = {};
|
||||
x.a = 1;
|
||||
x["b"] = 2 * x.a;
|
||||
console.log(x.a, x["b"]);
|
||||
x.o = 1;
|
||||
x["x"] = 2 * x.o;
|
||||
console.log(x.o, x["x"]);
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
typeof_eq_undefined: {
|
||||
options = {
|
||||
comparisons: true
|
||||
comparisons: true,
|
||||
typeofs: true,
|
||||
}
|
||||
input: {
|
||||
var a = typeof b != "undefined";
|
||||
@@ -24,6 +25,7 @@ typeof_eq_undefined_ie8: {
|
||||
options = {
|
||||
comparisons: true,
|
||||
ie8: true,
|
||||
typeofs: true,
|
||||
}
|
||||
input: {
|
||||
var a = typeof b != "undefined";
|
||||
@@ -45,7 +47,8 @@ typeof_eq_undefined_ie8: {
|
||||
|
||||
undefined_redefined: {
|
||||
options = {
|
||||
comparisons: true
|
||||
comparisons: true,
|
||||
typeofs: true,
|
||||
}
|
||||
input: {
|
||||
function f(undefined) {
|
||||
@@ -58,7 +61,8 @@ undefined_redefined: {
|
||||
|
||||
undefined_redefined_mangle: {
|
||||
options = {
|
||||
comparisons: true
|
||||
comparisons: true,
|
||||
typeofs: true,
|
||||
}
|
||||
mangle = {}
|
||||
input: {
|
||||
|
||||
@@ -82,7 +82,7 @@ numeric_literal: {
|
||||
' 42: 2,',
|
||||
' "42": 3,',
|
||||
' 37: 4,',
|
||||
' a: 5,',
|
||||
' o: 5,',
|
||||
' 1e42: 6,',
|
||||
' b: 7,',
|
||||
' "1e+42": 8',
|
||||
@@ -92,7 +92,7 @@ numeric_literal: {
|
||||
'',
|
||||
'console.log(obj[42], obj["42"]);',
|
||||
'',
|
||||
'console.log(obj[37], obj["a"], obj[37], obj["37"]);',
|
||||
'console.log(obj[37], obj["o"], obj[37], obj["37"]);',
|
||||
'',
|
||||
'console.log(obj[1e42], obj["b"], obj["1e+42"]);',
|
||||
]
|
||||
@@ -173,32 +173,32 @@ identifier: {
|
||||
}
|
||||
expect: {
|
||||
var obj = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
d: 4,
|
||||
e: 5,
|
||||
f: 6,
|
||||
g: 7,
|
||||
h: 8,
|
||||
i: 9,
|
||||
j: 10,
|
||||
k: 11,
|
||||
l: 12,
|
||||
m: 13,
|
||||
n: 14,
|
||||
o: 15,
|
||||
p: 16,
|
||||
q: 17,
|
||||
r: 18,
|
||||
s: 19,
|
||||
t: 20,
|
||||
u: 21,
|
||||
v: 22,
|
||||
w: 23,
|
||||
x: 24,
|
||||
y: 25,
|
||||
z: 26,
|
||||
e: 1,
|
||||
t: 2,
|
||||
n: 3,
|
||||
a: 4,
|
||||
i: 5,
|
||||
o: 6,
|
||||
r: 7,
|
||||
l: 8,
|
||||
s: 9,
|
||||
c: 10,
|
||||
f: 11,
|
||||
u: 12,
|
||||
d: 13,
|
||||
h: 14,
|
||||
p: 15,
|
||||
b: 16,
|
||||
v: 17,
|
||||
w: 18,
|
||||
y: 19,
|
||||
g: 20,
|
||||
m: 21,
|
||||
k: 22,
|
||||
x: 23,
|
||||
j: 24,
|
||||
z: 25,
|
||||
q: 26,
|
||||
A: 27,
|
||||
B: 28,
|
||||
C: 29,
|
||||
@@ -229,11 +229,11 @@ identifier: {
|
||||
Z: 54,
|
||||
$: 55,
|
||||
_: 56,
|
||||
aa: 57,
|
||||
ba: 58,
|
||||
ca: 59,
|
||||
da: 60,
|
||||
ea: 61,
|
||||
ee: 57,
|
||||
te: 58,
|
||||
ne: 59,
|
||||
ae: 60,
|
||||
ie: 61,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,37 +1,41 @@
|
||||
dont_reuse_prop: {
|
||||
mangle_props = {
|
||||
regex: /asd/
|
||||
};
|
||||
|
||||
}
|
||||
input: {
|
||||
"aaaaaaaaaabbbbb";
|
||||
var obj = {};
|
||||
obj.a = 123;
|
||||
obj.asd = 256;
|
||||
console.log(obj.a);
|
||||
}
|
||||
expect: {
|
||||
"aaaaaaaaaabbbbb";
|
||||
var obj = {};
|
||||
obj.a = 123;
|
||||
obj.b = 256;
|
||||
console.log(obj.a);
|
||||
}
|
||||
expect_stdout: "123"
|
||||
}
|
||||
|
||||
unmangleable_props_should_always_be_reserved: {
|
||||
mangle_props = {
|
||||
regex: /asd/
|
||||
};
|
||||
|
||||
}
|
||||
input: {
|
||||
"aaaaaaaaaabbbbb";
|
||||
var obj = {};
|
||||
obj.asd = 256;
|
||||
obj.a = 123;
|
||||
console.log(obj.a);
|
||||
}
|
||||
expect: {
|
||||
"aaaaaaaaaabbbbb";
|
||||
var obj = {};
|
||||
obj.b = 256;
|
||||
obj.a = 123;
|
||||
console.log(obj.a);
|
||||
}
|
||||
}
|
||||
expect_stdout: "123"
|
||||
}
|
||||
|
||||
@@ -436,3 +436,17 @@ do_switch: {
|
||||
} while (false);
|
||||
}
|
||||
}
|
||||
|
||||
in_parenthesis_1: {
|
||||
input: {
|
||||
for (("foo" in {});0;);
|
||||
}
|
||||
expect_exact: 'for(("foo"in{});0;);'
|
||||
}
|
||||
|
||||
in_parenthesis_2: {
|
||||
input: {
|
||||
for ((function(){ "foo" in {}; });0;);
|
||||
}
|
||||
expect_exact: 'for(function(){"foo"in{}};0;);'
|
||||
}
|
||||
|
||||
@@ -82,3 +82,19 @@ new_with_unary_prefix: {
|
||||
}
|
||||
expect_exact: 'var bar=(+new Date).toString(32);';
|
||||
}
|
||||
|
||||
dot_parenthesis_1: {
|
||||
input: {
|
||||
console.log(new (Math.random().constructor) instanceof Number);
|
||||
}
|
||||
expect_exact: "console.log(new(Math.random().constructor)instanceof Number);"
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
dot_parenthesis_2: {
|
||||
input: {
|
||||
console.log(typeof new function(){Math.random()}.constructor);
|
||||
}
|
||||
expect_exact: "console.log(typeof new function(){Math.random()}.constructor);"
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
@@ -135,11 +135,11 @@ mangle_properties: {
|
||||
a['run']({color: "blue", foo: "baz"});
|
||||
}
|
||||
expect: {
|
||||
a["a"] = "bar";
|
||||
a.b = "red";
|
||||
x = {c: 10};
|
||||
a.d(x.c, a.a);
|
||||
a['d']({b: "blue", a: "baz"});
|
||||
a["o"] = "bar";
|
||||
a.a = "red";
|
||||
x = {r: 10};
|
||||
a.b(x.r, a.o);
|
||||
a['b']({a: "blue", o: "baz"});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,16 +177,16 @@ mangle_unquoted_properties: {
|
||||
function f1() {
|
||||
a["foo"] = "bar";
|
||||
a.color = "red";
|
||||
a.b = 2;
|
||||
x = {"bar": 10, c: 7};
|
||||
a.c = 9;
|
||||
a.o = 2;
|
||||
x = {"bar": 10, f: 7};
|
||||
a.f = 9;
|
||||
}
|
||||
function f2() {
|
||||
a.foo = "bar";
|
||||
a['color'] = "red";
|
||||
x = {bar: 10, c: 7};
|
||||
a.c = 9;
|
||||
a.b = 3;
|
||||
x = {bar: 10, f: 7};
|
||||
a.f = 9;
|
||||
a.o = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -657,3 +657,116 @@ accessor_this: {
|
||||
expect_exact: 'var a=1;var b={get this(){return a},set this(c){a=c}};console.log(b.this,b.this=2,b.this);'
|
||||
expect_stdout: "1 2 2"
|
||||
}
|
||||
|
||||
issue_2208_1: {
|
||||
options = {
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
p: function() {
|
||||
return 42;
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect: {
|
||||
console.log(42);
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_2208_2: {
|
||||
options = {
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
a: 42,
|
||||
p: function() {
|
||||
return this.a;
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect: {
|
||||
console.log({
|
||||
a: 42,
|
||||
p: function() {
|
||||
return this.a;
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_2208_3: {
|
||||
options = {
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
a = 42;
|
||||
console.log({
|
||||
p: function() {
|
||||
return function() {
|
||||
return this.a;
|
||||
}();
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect: {
|
||||
a = 42;
|
||||
console.log(function() {
|
||||
return this.a;
|
||||
}());
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_2208_4: {
|
||||
options = {
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
function foo() {}
|
||||
console.log({
|
||||
a: foo(),
|
||||
p: function() {
|
||||
return 42;
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect: {
|
||||
function foo() {}
|
||||
console.log((foo(), function() {
|
||||
return 42;
|
||||
})());
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
issue_2208_5: {
|
||||
options = {
|
||||
inline: true,
|
||||
side_effects: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
console.log({
|
||||
p: "FAIL",
|
||||
p: function() {
|
||||
return 42;
|
||||
}
|
||||
}.p());
|
||||
}
|
||||
expect: {
|
||||
console.log(42);
|
||||
}
|
||||
expect_stdout: "42"
|
||||
}
|
||||
|
||||
@@ -178,3 +178,210 @@ impure_getter_2: {
|
||||
}
|
||||
expect: {}
|
||||
}
|
||||
|
||||
issue_2110_1: {
|
||||
options = {
|
||||
cascade: true,
|
||||
pure_getters: "strict",
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
function f() {}
|
||||
function g() {
|
||||
return this;
|
||||
}
|
||||
f.g = g;
|
||||
return f.g();
|
||||
}
|
||||
console.log(typeof f());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
function f() {}
|
||||
return f.g = function() {
|
||||
return this;
|
||||
}, f.g();
|
||||
}
|
||||
console.log(typeof f());
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
issue_2110_2: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
function f() {}
|
||||
function g() {
|
||||
return this;
|
||||
}
|
||||
f.g = g;
|
||||
return f.g();
|
||||
}
|
||||
console.log(typeof f());
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
function f() {}
|
||||
f.g = function() {
|
||||
return this;
|
||||
};
|
||||
return f.g();
|
||||
}
|
||||
console.log(typeof f());
|
||||
}
|
||||
expect_stdout: "function"
|
||||
}
|
||||
|
||||
set_immutable_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
1..foo += "";
|
||||
if (1..foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
set_immutable_2: {
|
||||
options = {
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
var a = 1;
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
var a = 1;
|
||||
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
set_immutable_3: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
var a = 1;
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
1..foo += "";
|
||||
if (1..foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
set_immutable_4: {
|
||||
options = {
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
}
|
||||
input: {
|
||||
"use strict";
|
||||
var a = 1;
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("FAIL");
|
||||
else console.log("PASS");
|
||||
}
|
||||
expect: {
|
||||
"use strict";
|
||||
var a = 1;
|
||||
a.foo += "", a.foo ? console.log("FAIL") : console.log("PASS");
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
||||
set_mutable_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
evaluate: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
!function a() {
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("PASS");
|
||||
else console.log("FAIL");
|
||||
}();
|
||||
}
|
||||
expect: {
|
||||
!function a() {
|
||||
if (a.foo += "") console.log("PASS");
|
||||
else console.log("FAIL");
|
||||
}();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
set_mutable_2: {
|
||||
options = {
|
||||
cascade: true,
|
||||
conditionals: true,
|
||||
pure_getters: "strict",
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
}
|
||||
input: {
|
||||
!function a() {
|
||||
a.foo += "";
|
||||
if (a.foo) console.log("PASS");
|
||||
else console.log("FAIL");
|
||||
}();
|
||||
}
|
||||
expect: {
|
||||
!function a() {
|
||||
(a.foo += "") ? console.log("PASS") : console.log("FAIL");
|
||||
}();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -1469,6 +1469,7 @@ issue_1670_1: {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
typeofs: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -1532,6 +1533,7 @@ issue_1670_3: {
|
||||
reduce_vars: true,
|
||||
side_effects: true,
|
||||
switches: true,
|
||||
typeofs: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
@@ -2575,3 +2577,28 @@ accessor: {
|
||||
}
|
||||
expect_stdout: "1 1"
|
||||
}
|
||||
|
||||
for_in_prop: {
|
||||
options = {
|
||||
reduce_vars: true,
|
||||
}
|
||||
input: {
|
||||
var a = {
|
||||
foo: function() {
|
||||
for (this.b in [1, 2]);
|
||||
}
|
||||
};
|
||||
a.foo();
|
||||
console.log(a.b);
|
||||
}
|
||||
expect: {
|
||||
var a = {
|
||||
foo: function() {
|
||||
for (this.b in [1, 2]);
|
||||
}
|
||||
};
|
||||
a.foo();
|
||||
console.log(a.b);
|
||||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
@@ -255,3 +255,73 @@ issue_1586_2: {
|
||||
}
|
||||
expect_exact: "function f(){try{x()}catch(c){console.log(c.message)}}"
|
||||
}
|
||||
|
||||
issue_2120_1: {
|
||||
mangle = {
|
||||
ie8: false,
|
||||
}
|
||||
input: {
|
||||
"aaaaaaaa";
|
||||
var a = 1, b = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (c) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (a) {
|
||||
if (c) b = "PASS";
|
||||
}
|
||||
}
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
"aaaaaaaa";
|
||||
var a = 1, b = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (t) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (a) {
|
||||
if (t) b = "PASS";
|
||||
}
|
||||
}
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
issue_2120_2: {
|
||||
mangle = {
|
||||
ie8: true,
|
||||
}
|
||||
input: {
|
||||
"aaaaaaaa";
|
||||
var a = 1, b = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (c) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (a) {
|
||||
if (c) b = "PASS";
|
||||
}
|
||||
}
|
||||
console.log(b);
|
||||
}
|
||||
expect: {
|
||||
"aaaaaaaa";
|
||||
var a = 1, b = "FAIL";
|
||||
try {
|
||||
throw 1;
|
||||
} catch (c) {
|
||||
try {
|
||||
throw 0;
|
||||
} catch (a) {
|
||||
if (c) b = "PASS";
|
||||
}
|
||||
}
|
||||
console.log(b);
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
@@ -176,6 +176,11 @@ for_sequences: {
|
||||
// 4
|
||||
x = (foo in bar);
|
||||
for (y = 5; false;);
|
||||
// 5
|
||||
x = function() {
|
||||
foo in bar;
|
||||
};
|
||||
for (y = 5; false;);
|
||||
}
|
||||
expect: {
|
||||
// 1
|
||||
@@ -188,6 +193,10 @@ for_sequences: {
|
||||
// 4
|
||||
x = (foo in bar);
|
||||
for (y = 5; false;);
|
||||
// 5
|
||||
for (x = function() {
|
||||
foo in bar;
|
||||
}, y = 5; false;);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
test/input/invalid/for-in_1.js
Normal file
4
test/input/invalid/for-in_1.js
Normal file
@@ -0,0 +1,4 @@
|
||||
var a, b = [1, 2];
|
||||
for (1, 2, a in b) {
|
||||
console.log(a, b[a]);
|
||||
}
|
||||
4
test/input/invalid/for-in_2.js
Normal file
4
test/input/invalid/for-in_2.js
Normal file
@@ -0,0 +1,4 @@
|
||||
var c = [1, 2];
|
||||
for (var a, b in c) {
|
||||
console.log(a, c[a]);
|
||||
}
|
||||
@@ -518,6 +518,36 @@ describe("bin/uglifyjs", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (for-in init)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/for-in_1.js';
|
||||
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||
"Parse error at test/input/invalid/for-in_1.js:2,5",
|
||||
"for (1, 2, a in b) {",
|
||||
" ^",
|
||||
"ERROR: Invalid left-hand side in for..in loop"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should throw syntax error (for-in var)", function(done) {
|
||||
var command = uglifyjscmd + ' test/input/invalid/for-in_2.js';
|
||||
|
||||
exec(command, function (err, stdout, stderr) {
|
||||
assert.ok(err);
|
||||
assert.strictEqual(stdout, "");
|
||||
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||
"Parse error at test/input/invalid/for-in_2.js:2,5",
|
||||
"for (var a, b in c) {",
|
||||
" ^",
|
||||
"ERROR: Only one variable declaration allowed in for..in loop"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Should handle literal string as source map input", function(done) {
|
||||
var command = [
|
||||
uglifyjscmd,
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,29 +2,37 @@ var Uglify = require('../../');
|
||||
var assert = require("assert");
|
||||
|
||||
describe("let", function() {
|
||||
it("Should not produce `let` as a variable name in mangle", function(done) {
|
||||
it("Should not produce reserved keywords as variable name in mangle", function(done) {
|
||||
this.timeout(10000);
|
||||
|
||||
// Produce a lot of variables in a function and run it through mangle.
|
||||
var s = '"use strict"; function foo() {';
|
||||
for (var i = 0; i < 21000; ++i) {
|
||||
var s = '"dddddeeeeelllllooooottttt"; function foo() {';
|
||||
for (var i = 0; i < 18000; i++) {
|
||||
s += "var v" + i + "=0;";
|
||||
}
|
||||
s += '}';
|
||||
var result = Uglify.minify(s, {compress: false});
|
||||
|
||||
// Verify that select keywords and reserved keywords not produced
|
||||
assert.strictEqual(result.code.indexOf("var let="), -1);
|
||||
assert.strictEqual(result.code.indexOf("var do="), -1);
|
||||
assert.strictEqual(result.code.indexOf("var var="), -1);
|
||||
[
|
||||
"do",
|
||||
"let",
|
||||
"var",
|
||||
].forEach(function(name) {
|
||||
assert.strictEqual(result.code.indexOf("var " + name + "="), -1);
|
||||
});
|
||||
|
||||
// Verify that the variable names that appeared immediately before
|
||||
// and after the erroneously generated `let` variable name still exist
|
||||
// and after the erroneously generated variable name still exist
|
||||
// to show the test generated enough symbols.
|
||||
assert(result.code.indexOf("var ket=") >= 0);
|
||||
assert(result.code.indexOf("var met=") >= 0);
|
||||
[
|
||||
"to", "eo",
|
||||
"eet", "fet",
|
||||
"rar", "oar",
|
||||
].forEach(function(name) {
|
||||
assert.ok(result.code.indexOf("var " + name + "=") >= 0);
|
||||
});
|
||||
|
||||
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 });
|
||||
|
||||
@@ -86,7 +86,6 @@ function run_compress_tests() {
|
||||
log_start_file(file);
|
||||
function test_case(test) {
|
||||
log_test(test.name);
|
||||
U.base54.reset();
|
||||
var output_options = test.beautify || {};
|
||||
var expect;
|
||||
if (test.expect) {
|
||||
@@ -101,9 +100,6 @@ function run_compress_tests() {
|
||||
quote_style: 3,
|
||||
keep_quoted_props: true
|
||||
});
|
||||
if (test.mangle_props) {
|
||||
input = U.mangle_properties(input, test.mangle_props);
|
||||
}
|
||||
var options = U.defaults(test.options, {
|
||||
warnings: false
|
||||
});
|
||||
@@ -118,10 +114,16 @@ function run_compress_tests() {
|
||||
var cmp = new U.Compressor(options, true);
|
||||
var output = cmp.compress(input);
|
||||
output.figure_out_scope(test.mangle);
|
||||
if (test.mangle) {
|
||||
if (test.mangle || test.mangle_props) {
|
||||
U.base54.reset();
|
||||
output.compute_char_frequency(test.mangle);
|
||||
}
|
||||
if (test.mangle) {
|
||||
output.mangle_names(test.mangle);
|
||||
}
|
||||
if (test.mangle_props) {
|
||||
output = U.mangle_properties(output, test.mangle_props);
|
||||
}
|
||||
output = make_code(output, output_options);
|
||||
if (expect != output) {
|
||||
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
|
||||
|
||||
Reference in New Issue
Block a user