Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db66eca958 | ||
|
|
916faf0a48 | ||
|
|
f36e4e9a78 | ||
|
|
fdf8b5eb71 | ||
|
|
de7ec7f1b7 | ||
|
|
3c8a0bdff4 | ||
|
|
9e8ba27dcd | ||
|
|
719a8fd102 | ||
|
|
3a22e917de | ||
|
|
a9af2c9e62 | ||
|
|
31e99cebe7 | ||
|
|
a5b209470c | ||
|
|
e9a571b2a1 | ||
|
|
8bf83f42ea | ||
|
|
522566ea80 | ||
|
|
297af47c89 | ||
|
|
faa354f5ca | ||
|
|
1529ab965a | ||
|
|
605f330e69 | ||
|
|
f0909bdc8f | ||
|
|
c13e7e621d | ||
|
|
ad071f8017 | ||
|
|
c058d8b9cd | ||
|
|
1d8871a092 | ||
|
|
16953c2064 | ||
|
|
6b14f7c224 | ||
|
|
130c623be7 | ||
|
|
47c9895d59 | ||
|
|
ba403331c5 | ||
|
|
e82e89d1b0 | ||
|
|
83a4ebfedc | ||
|
|
9916d0e547 | ||
|
|
31c4a37e37 | ||
|
|
08219f0cee | ||
|
|
c4993e1e5c | ||
|
|
6064bea3db | ||
|
|
98978fc827 | ||
|
|
16430acc1f | ||
|
|
320c110b33 | ||
|
|
dbe33bbfc5 | ||
|
|
b5c3253b49 | ||
|
|
5cc90db7d0 | ||
|
|
f427e5efc7 | ||
|
|
e48802ad29 | ||
|
|
13c4dfcabd |
44
README.md
44
README.md
@@ -12,7 +12,14 @@ Chrome and probably Safari).
|
|||||||
Install
|
Install
|
||||||
-------
|
-------
|
||||||
|
|
||||||
From NPM:
|
First make sure you have installed the latest version of [node.js](http://nodejs.org/)
|
||||||
|
(You may need to restart your computer after this step).
|
||||||
|
|
||||||
|
From NPM for use as a command line app:
|
||||||
|
|
||||||
|
npm install uglify-js -g
|
||||||
|
|
||||||
|
From NPM for programmatic use:
|
||||||
|
|
||||||
npm install uglify-js
|
npm install uglify-js
|
||||||
|
|
||||||
@@ -42,6 +49,9 @@ The available options are:
|
|||||||
[string]
|
[string]
|
||||||
--source-map-root The path to the original source to be included in the
|
--source-map-root The path to the original source to be included in the
|
||||||
source map. [string]
|
source map. [string]
|
||||||
|
--source-map-url The path to the source map to be added in //@
|
||||||
|
sourceMappingURL. Defaults to the value passed with
|
||||||
|
--source-map. [string]
|
||||||
--in-source-map Input source map, useful if you're compressing JS that was
|
--in-source-map Input source map, useful if you're compressing JS that was
|
||||||
generated from some other original code.
|
generated from some other original code.
|
||||||
-p, --prefix Skip prefix for original filenames that appear in source
|
-p, --prefix Skip prefix for original filenames that appear in source
|
||||||
@@ -78,7 +88,9 @@ The available options are:
|
|||||||
[string]
|
[string]
|
||||||
--export-all Only used when --wrap, this tells UglifyJS to add code to
|
--export-all Only used when --wrap, this tells UglifyJS to add code to
|
||||||
automatically export all globals. [boolean]
|
automatically export all globals. [boolean]
|
||||||
|
--lint Display some scope warnings [boolean]
|
||||||
-v, --verbose Verbose [boolean]
|
-v, --verbose Verbose [boolean]
|
||||||
|
-V, --version Print version number and exit. [boolean]
|
||||||
|
|
||||||
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
||||||
goes to STDOUT.
|
goes to STDOUT.
|
||||||
@@ -130,7 +142,7 @@ input files from the command line.
|
|||||||
## Mangler options
|
## Mangler options
|
||||||
|
|
||||||
To enable the mangler you need to pass `--mangle` (`-m`). Optionally you
|
To enable the mangler you need to pass `--mangle` (`-m`). Optionally you
|
||||||
can pass `-m sort` (we'll possibly have other flags in the future) in order
|
can pass `-m sort=true` (we'll possibly have other flags in the future) in order
|
||||||
to assign shorter names to most frequently used variables. This saves a few
|
to assign shorter names to most frequently used variables. This saves a few
|
||||||
hundred bytes on jQuery before gzip, but the output is _bigger_ after gzip
|
hundred bytes on jQuery before gzip, but the output is _bigger_ after gzip
|
||||||
(and seems to happen for other libraries I tried it on) therefore it's not
|
(and seems to happen for other libraries I tried it on) therefore it's not
|
||||||
@@ -157,8 +169,8 @@ the available options (all are `true` by default, except `hoist_vars`):
|
|||||||
- `sequences` -- join consecutive simple statements using the comma operator
|
- `sequences` -- join consecutive simple statements using the comma operator
|
||||||
- `properties` -- rewrite property access using the dot notation, for
|
- `properties` -- rewrite property access using the dot notation, for
|
||||||
example `foo["bar"] → foo.bar`
|
example `foo["bar"] → foo.bar`
|
||||||
- `dead-code` -- remove unreachable code
|
- `dead_code` -- remove unreachable code
|
||||||
- `drop-debugger` -- remove `debugger;` statements
|
- `drop_debugger` -- remove `debugger;` statements
|
||||||
- `unsafe` -- apply "unsafe" transformations (discussion below)
|
- `unsafe` -- apply "unsafe" transformations (discussion below)
|
||||||
- `conditionals` -- apply optimizations for `if`-s and conditional
|
- `conditionals` -- apply optimizations for `if`-s and conditional
|
||||||
expressions
|
expressions
|
||||||
@@ -171,11 +183,11 @@ the available options (all are `true` by default, except `hoist_vars`):
|
|||||||
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
||||||
statically determine the condition
|
statically determine the condition
|
||||||
- `unused` -- drop unreferenced functions and variables
|
- `unused` -- drop unreferenced functions and variables
|
||||||
- `hoist-funs` -- hoist function declarations
|
- `hoist_funs` -- hoist function declarations
|
||||||
- `hoist-vars` -- hoist `var` declarations (this is `false` by default
|
- `hoist_vars` -- hoist `var` declarations (this is `false` by default
|
||||||
because it seems to increase the size of the output in general)
|
because it seems to increase the size of the output in general)
|
||||||
- `if-return` -- optimizations for if/return and if/continue
|
- `if_return` -- optimizations for if/return and if/continue
|
||||||
- `join-vars` -- join consecutive `var` statements
|
- `join_vars` -- join consecutive `var` statements
|
||||||
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
|
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
|
||||||
and `x = something(), x` into `x = something()`
|
and `x = something(), x` into `x = something()`
|
||||||
- `warnings` -- display warnings when dropping unreachable code or unused
|
- `warnings` -- display warnings when dropping unreachable code or unused
|
||||||
@@ -213,6 +225,7 @@ will evaluate references to them to the value itself and drop unreachable
|
|||||||
code as usual. The possible downside of this approach is that the build
|
code as usual. The possible downside of this approach is that the build
|
||||||
will contain the `const` declarations.
|
will contain the `const` declarations.
|
||||||
|
|
||||||
|
<a name="codegen-options"></a>
|
||||||
## Beautifier options
|
## Beautifier options
|
||||||
|
|
||||||
The code generator tries to output shortest code possible by default. In
|
The code generator tries to output shortest code possible by default. In
|
||||||
@@ -322,9 +335,10 @@ There's a single toplevel function which combines all the steps. If you
|
|||||||
don't need additional customization, you might want to go with `minify`.
|
don't need additional customization, you might want to go with `minify`.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
// see "fromString" below if you need to pass code instead of file name
|
|
||||||
var result = UglifyJS.minify("/path/to/file.js");
|
var result = UglifyJS.minify("/path/to/file.js");
|
||||||
console.log(result.code); // minified output
|
console.log(result.code); // minified output
|
||||||
|
// if you need to pass code instead of file name
|
||||||
|
var result = UglifyJS.minify("var b = function () {};", {fromString: true});
|
||||||
|
|
||||||
You can also compress multiple files:
|
You can also compress multiple files:
|
||||||
|
|
||||||
@@ -366,9 +380,19 @@ no sense otherwise).
|
|||||||
Other options:
|
Other options:
|
||||||
|
|
||||||
- `warnings` (default `false`) — pass `true` to display compressor warnings.
|
- `warnings` (default `false`) — pass `true` to display compressor warnings.
|
||||||
|
|
||||||
- `fromString` (default `false`) — if you pass `true` then you can pass
|
- `fromString` (default `false`) — if you pass `true` then you can pass
|
||||||
JavaScript source code, rather than file names.
|
JavaScript source code, rather than file names.
|
||||||
|
|
||||||
|
- `mangle` — pass `false` to skip mangling names.
|
||||||
|
|
||||||
|
- `output` (default `null`) — pass an object if you wish to specify
|
||||||
|
additional [output options][codegen]. The defaults are optimized
|
||||||
|
for best compression.
|
||||||
|
|
||||||
|
- `compress` (default `{}`) — pass `false` to skip compressing entirely.
|
||||||
|
Pass an object to specify custom [compressor options][compressor].
|
||||||
|
|
||||||
We could add more options to `UglifyJS.minify` — if you need additional
|
We could add more options to `UglifyJS.minify` — if you need additional
|
||||||
functionality please suggest!
|
functionality please suggest!
|
||||||
|
|
||||||
@@ -516,3 +540,5 @@ The `source_map_options` (optional) can contain the following properties:
|
|||||||
[acorn]: https://github.com/marijnh/acorn
|
[acorn]: https://github.com/marijnh/acorn
|
||||||
[source-map]: https://github.com/mozilla/source-map
|
[source-map]: https://github.com/mozilla/source-map
|
||||||
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
|
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
|
||||||
|
[codegen]: http://lisperator.net/uglifyjs/codegen
|
||||||
|
[compressor]: http://lisperator.net/uglifyjs/compress
|
||||||
|
|||||||
13
bin/uglifyjs
13
bin/uglifyjs
@@ -19,6 +19,7 @@ mangling you need to use `-c` and `-m`.\
|
|||||||
")
|
")
|
||||||
.describe("source-map", "Specify an output file where to generate source map.")
|
.describe("source-map", "Specify an output file where to generate source map.")
|
||||||
.describe("source-map-root", "The path to the original source to be included in the source map.")
|
.describe("source-map-root", "The path to the original source to be included in the source map.")
|
||||||
|
.describe("source-map-url", "The path to the source map to be added in //@ sourceMappingURL. Defaults to the value passed with --source-map.")
|
||||||
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
|
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
|
||||||
.describe("p", "Skip prefix for original filenames that appear in source maps. \
|
.describe("p", "Skip prefix for original filenames that appear in source maps. \
|
||||||
For example -p 3 will drop 3 directories from file names and ensure they are relative paths.")
|
For example -p 3 will drop 3 directories from file names and ensure they are relative paths.")
|
||||||
@@ -49,6 +50,7 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.describe("export-all", "Only used when --wrap, this tells UglifyJS to add code to automatically export all globals.")
|
.describe("export-all", "Only used when --wrap, this tells UglifyJS to add code to automatically export all globals.")
|
||||||
.describe("lint", "Display some scope warnings")
|
.describe("lint", "Display some scope warnings")
|
||||||
.describe("v", "Verbose")
|
.describe("v", "Verbose")
|
||||||
|
.describe("V", "Print version number and exit.")
|
||||||
|
|
||||||
.alias("p", "prefix")
|
.alias("p", "prefix")
|
||||||
.alias("o", "output")
|
.alias("o", "output")
|
||||||
@@ -58,9 +60,11 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.alias("c", "compress")
|
.alias("c", "compress")
|
||||||
.alias("d", "define")
|
.alias("d", "define")
|
||||||
.alias("r", "reserved")
|
.alias("r", "reserved")
|
||||||
|
.alias("V", "version")
|
||||||
|
|
||||||
.string("source-map")
|
.string("source-map")
|
||||||
.string("source-map-root")
|
.string("source-map-root")
|
||||||
|
.string("source-map-url")
|
||||||
.string("b")
|
.string("b")
|
||||||
.string("m")
|
.string("m")
|
||||||
.string("c")
|
.string("c")
|
||||||
@@ -74,6 +78,7 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.boolean("acorn")
|
.boolean("acorn")
|
||||||
.boolean("spidermonkey")
|
.boolean("spidermonkey")
|
||||||
.boolean("lint")
|
.boolean("lint")
|
||||||
|
.boolean("V")
|
||||||
|
|
||||||
.wrap(80)
|
.wrap(80)
|
||||||
|
|
||||||
@@ -82,6 +87,12 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
|
|
||||||
normalize(ARGS);
|
normalize(ARGS);
|
||||||
|
|
||||||
|
if (ARGS.version || ARGS.V) {
|
||||||
|
var json = require("../package.json");
|
||||||
|
sys.puts(json.name + ' ' + json.version);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (ARGS.ast_help) {
|
if (ARGS.ast_help) {
|
||||||
var desc = UglifyJS.describe_ast();
|
var desc = UglifyJS.describe_ast();
|
||||||
sys.puts(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2));
|
sys.puts(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2));
|
||||||
@@ -268,7 +279,7 @@ output = output.get();
|
|||||||
|
|
||||||
if (SOURCE_MAP) {
|
if (SOURCE_MAP) {
|
||||||
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
|
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
|
||||||
output += "\n//@ sourceMappingURL=" + ARGS.source_map;
|
output += "\n/*\n//@ sourceMappingURL=" + (ARGS.source_map_url || ARGS.source_map) + "\n*/";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OUTPUT_FILE) {
|
if (OUTPUT_FILE) {
|
||||||
|
|||||||
@@ -287,9 +287,9 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
|||||||
},
|
},
|
||||||
wrap_commonjs: function(name, export_all) {
|
wrap_commonjs: function(name, export_all) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var to_export = [];
|
||||||
if (export_all) {
|
if (export_all) {
|
||||||
self.figure_out_scope();
|
self.figure_out_scope();
|
||||||
var to_export = [];
|
|
||||||
self.walk(new TreeWalker(function(node){
|
self.walk(new TreeWalker(function(node){
|
||||||
if (node instanceof AST_SymbolDeclaration && node.definition().global) {
|
if (node instanceof AST_SymbolDeclaration && node.definition().global) {
|
||||||
if (!find_if(function(n){ return n.name == node.name }, to_export))
|
if (!find_if(function(n){ return n.name == node.name }, to_export))
|
||||||
@@ -863,6 +863,11 @@ var AST_Undefined = DEFNODE("Undefined", null, {
|
|||||||
value: (function(){}())
|
value: (function(){}())
|
||||||
}, AST_Atom);
|
}, AST_Atom);
|
||||||
|
|
||||||
|
var AST_Hole = DEFNODE("Hole", null, {
|
||||||
|
$documentation: "A hole in an array",
|
||||||
|
value: (function(){}())
|
||||||
|
}, AST_Atom);
|
||||||
|
|
||||||
var AST_Infinity = DEFNODE("Infinity", null, {
|
var AST_Infinity = DEFNODE("Infinity", null, {
|
||||||
$documentation: "The `Infinity` value",
|
$documentation: "The `Infinity` value",
|
||||||
value: 1/0
|
value: 1/0
|
||||||
|
|||||||
120
lib/compress.js
120
lib/compress.js
@@ -628,7 +628,10 @@ merge(Compressor.prototype, {
|
|||||||
case "typeof": return typeof ev(e);
|
case "typeof": return typeof ev(e);
|
||||||
case "void": return void ev(e);
|
case "void": return void ev(e);
|
||||||
case "~": return ~ev(e);
|
case "~": return ~ev(e);
|
||||||
case "-": return -ev(e);
|
case "-":
|
||||||
|
e = ev(e);
|
||||||
|
if (e === 0) throw def;
|
||||||
|
return -e;
|
||||||
case "+": return +ev(e);
|
case "+": return +ev(e);
|
||||||
}
|
}
|
||||||
throw def;
|
throw def;
|
||||||
@@ -669,12 +672,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(){
|
def(AST_SymbolRef, function(){
|
||||||
var d = this.definition();
|
var d = this.definition();
|
||||||
if (d && d.constant) {
|
if (d && d.constant && d.init) return ev(d.init);
|
||||||
var orig = d.orig[0];
|
|
||||||
if (orig) orig = orig.init[0];
|
|
||||||
orig = orig && orig.value;
|
|
||||||
if (orig) return ev(orig);
|
|
||||||
}
|
|
||||||
throw def;
|
throw def;
|
||||||
});
|
});
|
||||||
})(function(node, func){
|
})(function(node, func){
|
||||||
@@ -883,18 +881,23 @@ merge(Compressor.prototype, {
|
|||||||
&& !self.uses_eval
|
&& !self.uses_eval
|
||||||
) {
|
) {
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
|
var initializations = new Dictionary();
|
||||||
// pass 1: find out which symbols are directly used in
|
// pass 1: find out which symbols are directly used in
|
||||||
// this scope (not in nested scopes).
|
// this scope (not in nested scopes).
|
||||||
var scope = this;
|
var scope = this;
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node !== self) {
|
if (node !== self) {
|
||||||
if (node instanceof AST_Defun) {
|
if (node instanceof AST_Defun) {
|
||||||
|
initializations.add(node.name.name, node);
|
||||||
return true; // don't go in nested scopes
|
return true; // don't go in nested scopes
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Definitions && scope === self) {
|
if (node instanceof AST_Definitions && scope === self) {
|
||||||
node.definitions.forEach(function(def){
|
node.definitions.forEach(function(def){
|
||||||
if (def.value && def.value.has_side_effects()) {
|
if (def.value) {
|
||||||
def.value.walk(tw);
|
initializations.add(def.name.name, def.value);
|
||||||
|
if (def.value.has_side_effects()) {
|
||||||
|
def.value.walk(tw);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
@@ -919,16 +922,15 @@ merge(Compressor.prototype, {
|
|||||||
for (var i = 0; i < in_use.length; ++i) {
|
for (var i = 0; i < in_use.length; ++i) {
|
||||||
in_use[i].orig.forEach(function(decl){
|
in_use[i].orig.forEach(function(decl){
|
||||||
// undeclared globals will be instanceof AST_SymbolRef
|
// undeclared globals will be instanceof AST_SymbolRef
|
||||||
if (decl instanceof AST_SymbolDeclaration) {
|
var init = initializations.get(decl.name);
|
||||||
decl.init.forEach(function(init){
|
if (init) init.forEach(function(init){
|
||||||
var tw = new TreeWalker(function(node){
|
var tw = new TreeWalker(function(node){
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
push_uniq(in_use, node.definition());
|
push_uniq(in_use, node.definition());
|
||||||
}
|
}
|
||||||
});
|
|
||||||
init.walk(tw);
|
|
||||||
});
|
});
|
||||||
}
|
init.walk(tw);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// pass 3: we should drop declarations not in_use
|
// pass 3: we should drop declarations not in_use
|
||||||
@@ -1100,13 +1102,71 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
self = self.transform(tt);
|
self = self.transform(tt);
|
||||||
if (vars_found > 0) hoisted.unshift(make_node(AST_Var, self, {
|
if (vars_found > 0) {
|
||||||
definitions: vars.map(function(def){
|
// collect only vars which don't show up in self's arguments list
|
||||||
def = def.clone();
|
var defs = [];
|
||||||
def.value = null;
|
vars.each(function(def, name){
|
||||||
return def;
|
if (self instanceof AST_Lambda
|
||||||
})
|
&& find_if(function(x){ return x.name == def.name.name },
|
||||||
}));
|
self.argnames)) {
|
||||||
|
vars.del(name);
|
||||||
|
} else {
|
||||||
|
def = def.clone();
|
||||||
|
def.value = null;
|
||||||
|
defs.push(def);
|
||||||
|
vars.set(name, def);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (defs.length > 0) {
|
||||||
|
// try to merge in assignments
|
||||||
|
for (var i = 0; i < self.body.length;) {
|
||||||
|
if (self.body[i] instanceof AST_SimpleStatement) {
|
||||||
|
var expr = self.body[i].body, sym, assign;
|
||||||
|
if (expr instanceof AST_Assign
|
||||||
|
&& expr.operator == "="
|
||||||
|
&& (sym = expr.left) instanceof AST_Symbol
|
||||||
|
&& vars.has(sym.name))
|
||||||
|
{
|
||||||
|
var def = vars.get(sym.name);
|
||||||
|
if (def.value) break;
|
||||||
|
def.value = expr.right;
|
||||||
|
remove(defs, def);
|
||||||
|
defs.push(def);
|
||||||
|
self.body.splice(i, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (expr instanceof AST_Seq
|
||||||
|
&& (assign = expr.car) instanceof AST_Assign
|
||||||
|
&& assign.operator == "="
|
||||||
|
&& (sym = assign.left) instanceof AST_Symbol
|
||||||
|
&& vars.has(sym.name))
|
||||||
|
{
|
||||||
|
var def = vars.get(sym.name);
|
||||||
|
if (def.value) break;
|
||||||
|
def.value = assign.right;
|
||||||
|
remove(defs, def);
|
||||||
|
defs.push(def);
|
||||||
|
self.body[i].body = expr.cdr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self.body[i] instanceof AST_EmptyStatement) {
|
||||||
|
self.body.splice(i, 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (self.body[i] instanceof AST_BlockStatement) {
|
||||||
|
var tmp = [ i, 1 ].concat(self.body[i].body);
|
||||||
|
self.body.splice.apply(self.body, tmp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
defs = make_node(AST_Var, self, {
|
||||||
|
definitions: defs
|
||||||
|
});
|
||||||
|
hoisted.push(defs);
|
||||||
|
};
|
||||||
|
}
|
||||||
self.body = dirs.concat(hoisted, self.body);
|
self.body = dirs.concat(hoisted, self.body);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -1430,7 +1490,7 @@ merge(Compressor.prototype, {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
tt.stack = compressor.stack; // so that's able to see parent nodes
|
tt.stack = compressor.stack.slice(); // so that's able to see parent nodes
|
||||||
self = self.transform(tt);
|
self = self.transform(tt);
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex !== self) throw ex;
|
if (ex !== self) throw ex;
|
||||||
@@ -1504,6 +1564,9 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "String":
|
case "String":
|
||||||
|
if (self.args.length == 0) return make_node(AST_String, self, {
|
||||||
|
value: ""
|
||||||
|
});
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
left: self.args[0],
|
left: self.args[0],
|
||||||
operator: "+",
|
operator: "+",
|
||||||
@@ -1539,7 +1602,7 @@ merge(Compressor.prototype, {
|
|||||||
case "Function":
|
case "Function":
|
||||||
case "Error":
|
case "Error":
|
||||||
case "Array":
|
case "Array":
|
||||||
return make_node(AST_Call, self, self);
|
return make_node(AST_Call, self, self).transform(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1674,7 +1737,8 @@ merge(Compressor.prototype, {
|
|||||||
if (self.left instanceof AST_String
|
if (self.left instanceof AST_String
|
||||||
&& self.left.value == "undefined"
|
&& self.left.value == "undefined"
|
||||||
&& self.right instanceof AST_UnaryPrefix
|
&& self.right instanceof AST_UnaryPrefix
|
||||||
&& self.right.operator == "typeof") {
|
&& self.right.operator == "typeof"
|
||||||
|
&& compressor.option("unsafe")) {
|
||||||
if (!(self.right.expression instanceof AST_SymbolRef)
|
if (!(self.right.expression instanceof AST_SymbolRef)
|
||||||
|| !self.right.expression.undeclared()) {
|
|| !self.right.expression.undeclared()) {
|
||||||
self.left = self.right.expression;
|
self.left = self.right.expression;
|
||||||
|
|||||||
108
lib/output.js
108
lib/output.js
@@ -340,23 +340,25 @@ function OutputStream(options) {
|
|||||||
/* -----[ utils ]----- */
|
/* -----[ utils ]----- */
|
||||||
|
|
||||||
function DEFPRINT(nodetype, generator) {
|
function DEFPRINT(nodetype, generator) {
|
||||||
nodetype.DEFMETHOD("print", function(stream){
|
nodetype.DEFMETHOD("_codegen", generator);
|
||||||
var self = this;
|
};
|
||||||
stream.push_node(self);
|
|
||||||
if (self.needs_parens(stream)) {
|
AST_Node.DEFMETHOD("print", function(stream, force_parens){
|
||||||
stream.with_parens(function(){
|
var self = this, generator = self._codegen;
|
||||||
self.add_comments(stream);
|
stream.push_node(self);
|
||||||
self.add_source_map(stream);
|
if (force_parens || self.needs_parens(stream)) {
|
||||||
generator(self, stream);
|
stream.with_parens(function(){
|
||||||
});
|
|
||||||
} else {
|
|
||||||
self.add_comments(stream);
|
self.add_comments(stream);
|
||||||
self.add_source_map(stream);
|
self.add_source_map(stream);
|
||||||
generator(self, stream);
|
generator(self, stream);
|
||||||
}
|
});
|
||||||
stream.pop_node();
|
} else {
|
||||||
});
|
self.add_comments(stream);
|
||||||
};
|
self.add_source_map(stream);
|
||||||
|
generator(self, stream);
|
||||||
|
}
|
||||||
|
stream.pop_node();
|
||||||
|
});
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print_to_string", function(options){
|
AST_Node.DEFMETHOD("print_to_string", function(options){
|
||||||
var s = OutputStream(options);
|
var s = OutputStream(options);
|
||||||
@@ -373,6 +375,16 @@ function OutputStream(options) {
|
|||||||
if (start && !start._comments_dumped) {
|
if (start && !start._comments_dumped) {
|
||||||
start._comments_dumped = true;
|
start._comments_dumped = true;
|
||||||
var comments = start.comments_before;
|
var comments = start.comments_before;
|
||||||
|
|
||||||
|
// XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
|
||||||
|
// if this node is `return` or `throw`, we cannot allow comments before
|
||||||
|
// the returned or thrown value.
|
||||||
|
if (self instanceof AST_Exit &&
|
||||||
|
self.value && self.value.start.comments_before.length > 0) {
|
||||||
|
comments = (comments || []).concat(self.value.start.comments_before);
|
||||||
|
self.value.start.comments_before = [];
|
||||||
|
}
|
||||||
|
|
||||||
if (c.test) {
|
if (c.test) {
|
||||||
comments = comments.filter(function(comment){
|
comments = comments.filter(function(comment){
|
||||||
return c.test(comment.value);
|
return c.test(comment.value);
|
||||||
@@ -467,18 +479,6 @@ function OutputStream(options) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// for (var i = (foo in bar);;); ← perhaps useless, but valid syntax
|
|
||||||
if (this.operator == "in") {
|
|
||||||
// the “NoIn” stuff :-\
|
|
||||||
// UglifyJS 1.3.3 misses this one.
|
|
||||||
if ((p instanceof AST_For || p instanceof AST_ForIn) && p.init === this)
|
|
||||||
return true;
|
|
||||||
if (p instanceof AST_VarDef) {
|
|
||||||
var v = output.parent(1), p2 = output.parent(2);
|
|
||||||
if ((p2 instanceof AST_For || p2 instanceof AST_ForIn) && p2.init === v)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_PropAccess, function(output){
|
PARENS(AST_PropAccess, function(output){
|
||||||
@@ -509,11 +509,23 @@ function OutputStream(options) {
|
|||||||
PARENS(AST_New, function(output){
|
PARENS(AST_New, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (no_constructor_parens(this, output)
|
if (no_constructor_parens(this, output)
|
||||||
&& (p instanceof AST_Dot // (new Date).getTime()
|
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
||||||
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
PARENS(AST_Number, function(output){
|
||||||
|
var p = output.parent();
|
||||||
|
if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this)
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
PARENS(AST_NaN, function(output){
|
||||||
|
var p = output.parent();
|
||||||
|
if (p instanceof AST_PropAccess && p.expression === this)
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
function assign_and_conditional_paren_rules(output) {
|
function assign_and_conditional_paren_rules(output) {
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
// !(a = false) → true
|
// !(a = false) → true
|
||||||
@@ -622,7 +634,11 @@ function OutputStream(options) {
|
|||||||
output.space();
|
output.space();
|
||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
if (self.init) {
|
if (self.init) {
|
||||||
self.init.print(output);
|
if (self.init instanceof AST_Definitions) {
|
||||||
|
self.init.print(output);
|
||||||
|
} else {
|
||||||
|
parenthesize_for_noin(self.init, output, true);
|
||||||
|
}
|
||||||
output.print(";");
|
output.print(";");
|
||||||
output.space();
|
output.space();
|
||||||
} else {
|
} else {
|
||||||
@@ -734,7 +750,7 @@ function OutputStream(options) {
|
|||||||
// to the inner IF). This function checks for this case and
|
// to the inner IF). This function checks for this case and
|
||||||
// adds the block brackets if needed.
|
// adds the block brackets if needed.
|
||||||
if (!self.body)
|
if (!self.body)
|
||||||
return output.semicolon();
|
return output.force_semicolon();
|
||||||
if (self.body instanceof AST_Do
|
if (self.body instanceof AST_Do
|
||||||
&& output.option("ie_proof")) {
|
&& output.option("ie_proof")) {
|
||||||
// https://github.com/mishoo/UglifyJS/issues/#issue/57 IE
|
// https://github.com/mishoo/UglifyJS/issues/#issue/57 IE
|
||||||
@@ -758,7 +774,7 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
self.body.print(output);
|
force_statement(self.body, output);
|
||||||
};
|
};
|
||||||
DEFPRINT(AST_If, function(self, output){
|
DEFPRINT(AST_If, function(self, output){
|
||||||
output.print("if");
|
output.print("if");
|
||||||
@@ -866,13 +882,32 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_Const, function(self, output){
|
DEFPRINT(AST_Const, function(self, output){
|
||||||
self._do_print(output, "const");
|
self._do_print(output, "const");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
DEFPRINT(AST_VarDef, function(self, output){
|
DEFPRINT(AST_VarDef, function(self, output){
|
||||||
self.name.print(output);
|
self.name.print(output);
|
||||||
if (self.value) {
|
if (self.value) {
|
||||||
output.space();
|
output.space();
|
||||||
output.print("=");
|
output.print("=");
|
||||||
output.space();
|
output.space();
|
||||||
self.value.print(output);
|
var p = output.parent(1);
|
||||||
|
var noin = p instanceof AST_For || p instanceof AST_ForIn;
|
||||||
|
parenthesize_for_noin(self.value, output, noin);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -891,7 +926,7 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_New, function(self, output){
|
DEFPRINT(AST_New, function(self, output){
|
||||||
output.print("new");
|
output.print("new");
|
||||||
output.space();
|
output.space();
|
||||||
AST_Call.prototype.print.call(self, output);
|
AST_Call.prototype._codegen(self, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Seq.DEFMETHOD("_do_print", function(output){
|
AST_Seq.DEFMETHOD("_do_print", function(output){
|
||||||
@@ -919,7 +954,7 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_Dot, function(self, output){
|
DEFPRINT(AST_Dot, function(self, output){
|
||||||
var expr = self.expression;
|
var expr = self.expression;
|
||||||
expr.print(output);
|
expr.print(output);
|
||||||
if (expr instanceof AST_Number) {
|
if (expr instanceof AST_Number && expr.getValue() >= 0) {
|
||||||
if (!/[xa-f.]/i.test(output.last())) {
|
if (!/[xa-f.]/i.test(output.last())) {
|
||||||
output.print(".");
|
output.print(".");
|
||||||
}
|
}
|
||||||
@@ -971,8 +1006,7 @@ function OutputStream(options) {
|
|||||||
if (len > 0) output.space();
|
if (len > 0) output.space();
|
||||||
a.forEach(function(exp, i){
|
a.forEach(function(exp, i){
|
||||||
if (i) output.comma();
|
if (i) output.comma();
|
||||||
if (!(exp instanceof AST_Undefined))
|
exp.print(output);
|
||||||
exp.print(output);
|
|
||||||
});
|
});
|
||||||
if (len > 0) output.space();
|
if (len > 0) output.space();
|
||||||
});
|
});
|
||||||
@@ -1023,6 +1057,7 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_Undefined, function(self, output){
|
DEFPRINT(AST_Undefined, function(self, output){
|
||||||
output.print("void 0");
|
output.print("void 0");
|
||||||
});
|
});
|
||||||
|
DEFPRINT(AST_Hole, noop);
|
||||||
DEFPRINT(AST_Infinity, function(self, output){
|
DEFPRINT(AST_Infinity, function(self, output){
|
||||||
output.print("1/0");
|
output.print("1/0");
|
||||||
});
|
});
|
||||||
@@ -1046,6 +1081,9 @@ function OutputStream(options) {
|
|||||||
if (output.option("ascii_only"))
|
if (output.option("ascii_only"))
|
||||||
str = output.to_ascii(str);
|
str = output.to_ascii(str);
|
||||||
output.print(str);
|
output.print(str);
|
||||||
|
var p = output.parent();
|
||||||
|
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
||||||
|
output.print(" ");
|
||||||
});
|
});
|
||||||
|
|
||||||
function force_statement(stat, output) {
|
function force_statement(stat, output) {
|
||||||
|
|||||||
17
lib/parse.js
17
lib/parse.js
@@ -881,11 +881,14 @@ function parse($TEXT, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var function_ = function(in_statement, ctor) {
|
var function_ = function(in_statement, ctor) {
|
||||||
var name = is("name") ? as_symbol(in_statement
|
var is_accessor = ctor === AST_Accessor;
|
||||||
? AST_SymbolDefun
|
var name = (is("name") ? as_symbol(in_statement
|
||||||
: ctor === AST_Accessor
|
? AST_SymbolDefun
|
||||||
? AST_SymbolAccessor
|
: is_accessor
|
||||||
: AST_SymbolLambda) : null;
|
? AST_SymbolAccessor
|
||||||
|
: AST_SymbolLambda)
|
||||||
|
: is_accessor && (is("string") || is("num")) ? as_atom_node()
|
||||||
|
: null);
|
||||||
if (in_statement && !name)
|
if (in_statement && !name)
|
||||||
unexpected();
|
unexpected();
|
||||||
expect("(");
|
expect("(");
|
||||||
@@ -1128,7 +1131,7 @@ function parse($TEXT, options) {
|
|||||||
if (first) first = false; else expect(",");
|
if (first) first = false; else expect(",");
|
||||||
if (allow_trailing_comma && is("punc", closing)) break;
|
if (allow_trailing_comma && is("punc", closing)) break;
|
||||||
if (is("punc", ",") && allow_empty) {
|
if (is("punc", ",") && allow_empty) {
|
||||||
a.push(new AST_Undefined({ start: S.token, end: S.token }));
|
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||||
} else {
|
} else {
|
||||||
a.push(expression(false));
|
a.push(expression(false));
|
||||||
}
|
}
|
||||||
@@ -1355,7 +1358,7 @@ function parse($TEXT, options) {
|
|||||||
left : left,
|
left : left,
|
||||||
operator : val,
|
operator : val,
|
||||||
right : maybe_assign(no_in),
|
right : maybe_assign(no_in),
|
||||||
end : peek()
|
end : prev()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
croak("Invalid assignment");
|
croak("Invalid assignment");
|
||||||
|
|||||||
25
lib/scope.js
25
lib/scope.js
@@ -84,9 +84,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
node.init_scope_vars(nesting);
|
node.init_scope_vars(nesting);
|
||||||
var save_scope = node.parent_scope = scope;
|
var save_scope = node.parent_scope = scope;
|
||||||
|
var save_labels = labels;
|
||||||
++nesting;
|
++nesting;
|
||||||
scope = node;
|
scope = node;
|
||||||
|
labels = new Dictionary();
|
||||||
descend();
|
descend();
|
||||||
|
labels = save_labels;
|
||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
--nesting;
|
--nesting;
|
||||||
return true; // don't descend again in TreeWalker
|
return true; // don't descend again in TreeWalker
|
||||||
@@ -110,9 +113,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
labels.del(l.name);
|
labels.del(l.name);
|
||||||
return true; // no descend again
|
return true; // no descend again
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolDeclaration) {
|
|
||||||
node.init_scope_vars();
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Symbol) {
|
if (node instanceof AST_Symbol) {
|
||||||
node.scope = scope;
|
node.scope = scope;
|
||||||
}
|
}
|
||||||
@@ -128,8 +128,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
// scope. Don't like this fix but seems we can't do any
|
// scope. Don't like this fix but seems we can't do any
|
||||||
// better. IE: please die. Please!
|
// better. IE: please die. Please!
|
||||||
(node.scope = scope.parent_scope).def_function(node);
|
(node.scope = scope.parent_scope).def_function(node);
|
||||||
|
|
||||||
node.init.push(tw.parent());
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolDefun) {
|
else if (node instanceof AST_SymbolDefun) {
|
||||||
// Careful here, the scope where this should be defined is
|
// Careful here, the scope where this should be defined is
|
||||||
@@ -138,14 +136,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
// instanceof AST_Scope) but we get to the symbol a bit
|
// instanceof AST_Scope) but we get to the symbol a bit
|
||||||
// later.
|
// later.
|
||||||
(node.scope = scope.parent_scope).def_function(node);
|
(node.scope = scope.parent_scope).def_function(node);
|
||||||
node.init.push(tw.parent());
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolVar
|
else if (node instanceof AST_SymbolVar
|
||||||
|| node instanceof AST_SymbolConst) {
|
|| node instanceof AST_SymbolConst) {
|
||||||
var def = scope.def_variable(node);
|
var def = scope.def_variable(node);
|
||||||
def.constant = node instanceof AST_SymbolConst;
|
def.constant = node instanceof AST_SymbolConst;
|
||||||
def = tw.parent();
|
def.init = tw.parent().value;
|
||||||
if (def.value) node.init.push(def);
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolCatch) {
|
else if (node instanceof AST_SymbolCatch) {
|
||||||
// XXX: this is wrong according to ECMA-262 (12.4). the
|
// XXX: this is wrong according to ECMA-262 (12.4). the
|
||||||
@@ -246,10 +242,6 @@ AST_SymbolRef.DEFMETHOD("reference", function() {
|
|||||||
this.frame = this.scope.nesting - def.scope.nesting;
|
this.frame = this.scope.nesting - def.scope.nesting;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_SymbolDeclaration.DEFMETHOD("init_scope_vars", function(){
|
|
||||||
this.init = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_Label.DEFMETHOD("init_scope_vars", function(){
|
AST_Label.DEFMETHOD("init_scope_vars", function(){
|
||||||
this.references = [];
|
this.references = [];
|
||||||
});
|
});
|
||||||
@@ -351,6 +343,7 @@ AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
|
|||||||
return defaults(options, {
|
return defaults(options, {
|
||||||
except : [],
|
except : [],
|
||||||
eval : false,
|
eval : false,
|
||||||
|
sort : false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -371,12 +364,16 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
return true; // don't descend again in TreeWalker
|
return true; // don't descend again in TreeWalker
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
var p = tw.parent();
|
var p = tw.parent(), a = [];
|
||||||
node.variables.each(function(symbol){
|
node.variables.each(function(symbol){
|
||||||
if (options.except.indexOf(symbol.name) < 0) {
|
if (options.except.indexOf(symbol.name) < 0) {
|
||||||
to_mangle.push(symbol);
|
a.push(symbol);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (options.sort) a.sort(function(a, b){
|
||||||
|
return b.references.length - a.references.length;
|
||||||
|
});
|
||||||
|
to_mangle.push.apply(to_mangle, a);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Label) {
|
if (node instanceof AST_Label) {
|
||||||
|
|||||||
@@ -255,6 +255,14 @@ Dictionary.prototype = {
|
|||||||
this._values["$" + key] = val;
|
this._values["$" + key] = val;
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
add: function(key, val) {
|
||||||
|
if (this.has(key)) {
|
||||||
|
this.get(key).push(val);
|
||||||
|
} else {
|
||||||
|
this.set(key, [ val ]);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
get: function(key) { return this._values["$" + key] },
|
get: function(key) { return this._values["$" + key] },
|
||||||
del: function(key) {
|
del: function(key) {
|
||||||
if (this.has(key)) {
|
if (this.has(key)) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"main": "tools/node.js",
|
"main": "tools/node.js",
|
||||||
"version": "2.2.1",
|
"version": "2.2.5",
|
||||||
"engines": { "node" : ">=0.4.0" },
|
"engines": { "node" : ">=0.4.0" },
|
||||||
"maintainers": [{
|
"maintainers": [{
|
||||||
"name": "Mihai Bazon",
|
"name": "Mihai Bazon",
|
||||||
|
|||||||
12
test/compress/arrays.js
Normal file
12
test/compress/arrays.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
holes_and_undefined: {
|
||||||
|
input: {
|
||||||
|
x = [1, 2, undefined];
|
||||||
|
y = [1, , 2, ];
|
||||||
|
z = [1, undefined, 3];
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
x=[1,2,void 0];
|
||||||
|
y=[1,,2];
|
||||||
|
z=[1,void 0,3];
|
||||||
|
}
|
||||||
|
}
|
||||||
17
test/compress/issue-105.js
Normal file
17
test/compress/issue-105.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
typeof_eq_undefined: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
unsafe: false
|
||||||
|
};
|
||||||
|
input: { a = typeof b.c != "undefined" }
|
||||||
|
expect: { a = "undefined" != typeof b.c }
|
||||||
|
}
|
||||||
|
|
||||||
|
typeof_eq_undefined_unsafe: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
unsafe: true
|
||||||
|
};
|
||||||
|
input: { a = typeof b.c != "undefined" }
|
||||||
|
expect: { a = b.c !== void 0 }
|
||||||
|
}
|
||||||
30
test/compress/issue-59.js
Normal file
30
test/compress/issue-59.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
keep_continue: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
while (a) {
|
||||||
|
if (b) {
|
||||||
|
switch (true) {
|
||||||
|
case c():
|
||||||
|
d();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
while (a) {
|
||||||
|
if (b) {
|
||||||
|
switch (true) {
|
||||||
|
case c():
|
||||||
|
d();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,6 +56,9 @@ exports.minify = function(files, options) {
|
|||||||
inSourceMap : null,
|
inSourceMap : null,
|
||||||
fromString : false,
|
fromString : false,
|
||||||
warnings : false,
|
warnings : false,
|
||||||
|
mangle : {},
|
||||||
|
output : null,
|
||||||
|
compress : {}
|
||||||
});
|
});
|
||||||
if (typeof files == "string")
|
if (typeof files == "string")
|
||||||
files = [ files ];
|
files = [ files ];
|
||||||
@@ -73,16 +76,20 @@ exports.minify = function(files, options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 2. compress
|
// 2. compress
|
||||||
toplevel.figure_out_scope();
|
if (options.compress) {
|
||||||
var sq = UglifyJS.Compressor({
|
var compress = { warnings: options.warnings };
|
||||||
warnings: options.warnings,
|
UglifyJS.merge(compress, options.compress);
|
||||||
});
|
toplevel.figure_out_scope();
|
||||||
toplevel = toplevel.transform(sq);
|
var sq = UglifyJS.Compressor(compress);
|
||||||
|
toplevel = toplevel.transform(sq);
|
||||||
|
}
|
||||||
|
|
||||||
// 3. mangle
|
// 3. mangle
|
||||||
toplevel.figure_out_scope();
|
if (options.mangle) {
|
||||||
toplevel.compute_char_frequency();
|
toplevel.figure_out_scope();
|
||||||
toplevel.mangle_names();
|
toplevel.compute_char_frequency();
|
||||||
|
toplevel.mangle_names(options.mangle);
|
||||||
|
}
|
||||||
|
|
||||||
// 4. output
|
// 4. output
|
||||||
var map = null;
|
var map = null;
|
||||||
@@ -95,7 +102,11 @@ exports.minify = function(files, options) {
|
|||||||
orig: inMap,
|
orig: inMap,
|
||||||
root: options.sourceRoot
|
root: options.sourceRoot
|
||||||
});
|
});
|
||||||
var stream = UglifyJS.OutputStream({ source_map: map });
|
var output = { source_map: map };
|
||||||
|
if (options.output) {
|
||||||
|
UglifyJS.merge(output, options.output);
|
||||||
|
}
|
||||||
|
var stream = UglifyJS.OutputStream(output);
|
||||||
toplevel.print(stream);
|
toplevel.print(stream);
|
||||||
return {
|
return {
|
||||||
code : stream + "",
|
code : stream + "",
|
||||||
|
|||||||
Reference in New Issue
Block a user