Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6fa291571 | ||
|
|
bce4307e9e | ||
|
|
96ad94ab41 | ||
|
|
a5b60217ce | ||
|
|
44fd6694eb | ||
|
|
e48db3a8b6 | ||
|
|
e637bdaf4e | ||
|
|
d558abbdb7 | ||
|
|
4aed0830e5 | ||
|
|
d2dda34b2a | ||
|
|
c3a10c135e | ||
|
|
92e4340732 | ||
|
|
7b22f2031f | ||
|
|
3b14582d6b | ||
|
|
274e1b3dc7 | ||
|
|
de58b0289d | ||
|
|
efea52a4f4 | ||
|
|
763bd36b60 | ||
|
|
0552dbd93c | ||
|
|
18c63ff3d8 | ||
|
|
e04ef56243 | ||
|
|
5d60484553 | ||
|
|
3c846e6f7b | ||
|
|
2850dc69fd | ||
|
|
94205c3a37 | ||
|
|
2ada34b229 | ||
|
|
db396da734 | ||
|
|
0262b4244c | ||
|
|
73ca767d06 | ||
|
|
3ec11c781b | ||
|
|
a79ff060d0 | ||
|
|
43991f8d2f | ||
|
|
6b82069e1a | ||
|
|
276b9a31cd | ||
|
|
5801fa39e9 | ||
|
|
f0ab1b02e6 | ||
|
|
36c28e02fd | ||
|
|
e1c3861832 | ||
|
|
ecfd881ac6 | ||
|
|
81b7335267 | ||
|
|
bb010c2253 | ||
|
|
03b6121194 | ||
|
|
3ef092332b | ||
|
|
540c19792f | ||
|
|
80d1c8206b | ||
|
|
d36faffeca | ||
|
|
7c8c9b94bc | ||
|
|
f5eeed7665 | ||
|
|
80cfd063e2 | ||
|
|
aa45f6586e | ||
|
|
0c80d21e01 | ||
|
|
375c88245a | ||
|
|
ea3430102c | ||
|
|
9de7199b88 | ||
|
|
ae07714927 | ||
|
|
0e41a3fad4 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
|
/node_modules/
|
||||||
|
/npm-debug.log
|
||||||
tmp/
|
tmp/
|
||||||
node_modules/
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
before_install: "npm install -g npm"
|
before_install: "npm install -g npm"
|
||||||
node_js:
|
node_js:
|
||||||
- "0.8"
|
- "iojs"
|
||||||
- "0.10"
|
- "0.12"
|
||||||
- "0.11"
|
- "0.11"
|
||||||
|
- "0.10"
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
sudo: false
|
||||||
|
|||||||
223
README.md
223
README.md
@@ -52,70 +52,87 @@ a double dash to prevent input files being used as option arguments:
|
|||||||
The available options are:
|
The available options are:
|
||||||
|
|
||||||
```
|
```
|
||||||
--source-map Specify an output file where to generate source map.
|
--source-map Specify an output file where to generate source
|
||||||
[string]
|
map.
|
||||||
--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
|
||||||
source map. [string]
|
in the source map.
|
||||||
--source-map-url The path to the source map to be added in //#
|
--source-map-url The path to the source map to be added in //#
|
||||||
sourceMappingURL. Defaults to the value passed with
|
sourceMappingURL. Defaults to the value passed
|
||||||
--source-map. [string]
|
with --source-map.
|
||||||
--source-map-include-sources
|
--source-map-include-sources Pass this flag if you want to include the
|
||||||
Pass this flag if you want to include the content of
|
content of source files in the source map as
|
||||||
source files in the source map as sourcesContent
|
sourcesContent property.
|
||||||
property. [boolean]
|
--in-source-map Input source map, useful if you're compressing
|
||||||
--in-source-map Input source map, useful if you're compressing JS that was
|
JS that was generated from some other original
|
||||||
generated from some other original code.
|
code.
|
||||||
--screw-ie8 Pass this flag if you don't care about full compliance
|
--screw-ie8 Pass this flag if you don't care about full
|
||||||
with Internet Explorer 6-8 quirks (by default UglifyJS
|
compliance with Internet Explorer 6-8 quirks
|
||||||
will try to be IE-proof). [boolean]
|
(by default UglifyJS will try to be IE-proof).
|
||||||
--expr Parse a single expression, rather than a program (for
|
--expr Parse a single expression, rather than a
|
||||||
parsing JSON) [boolean]
|
program (for parsing JSON)
|
||||||
-p, --prefix Skip prefix for original filenames that appear in source
|
-p, --prefix Skip prefix for original filenames that appear
|
||||||
maps. For example -p 3 will drop 3 directories from file
|
in source maps. For example -p 3 will drop 3
|
||||||
names and ensure they are relative paths. You can also
|
directories from file names and ensure they are
|
||||||
specify -p relative, which will make UglifyJS figure out
|
relative paths. You can also specify -p
|
||||||
itself the relative paths between original sources, the
|
relative, which will make UglifyJS figure out
|
||||||
source map and the output file. [string]
|
itself the relative paths between original
|
||||||
-o, --output Output file (default STDOUT).
|
sources, the source map and the output file.
|
||||||
-b, --beautify Beautify output/specify output options. [string]
|
-o, --output Output file (default STDOUT).
|
||||||
-m, --mangle Mangle names/pass mangler options. [string]
|
-b, --beautify Beautify output/specify output options.
|
||||||
-r, --reserved Reserved names to exclude from mangling.
|
-m, --mangle Mangle names/pass mangler options.
|
||||||
-c, --compress Enable compressor/pass compressor options. Pass options
|
-r, --reserved Reserved names to exclude from mangling.
|
||||||
like -c hoist_vars=false,if_return=false. Use -c with no
|
-c, --compress Enable compressor/pass compressor options. Pass
|
||||||
argument to use the default compression options. [string]
|
options like -c
|
||||||
-d, --define Global definitions [string]
|
hoist_vars=false,if_return=false. Use -c with
|
||||||
-e, --enclose Embed everything in a big function, with a configurable
|
no argument to use the default compression
|
||||||
parameter/argument list. [string]
|
options.
|
||||||
--comments Preserve copyright comments in the output. By default this
|
-d, --define Global definitions
|
||||||
works like Google Closure, keeping JSDoc-style comments
|
-e, --enclose Embed everything in a big function, with a
|
||||||
that contain "@license" or "@preserve". You can optionally
|
configurable parameter/argument list.
|
||||||
pass one of the following arguments to this flag:
|
--comments Preserve copyright comments in the output. By
|
||||||
- "all" to keep all comments
|
default this works like Google Closure, keeping
|
||||||
- a valid JS regexp (needs to start with a slash) to keep
|
JSDoc-style comments that contain "@license" or
|
||||||
only comments that match.
|
"@preserve". You can optionally pass one of the
|
||||||
Note that currently not *all* comments can be kept when
|
following arguments to this flag:
|
||||||
compression is on, because of dead code removal or
|
- "all" to keep all comments
|
||||||
cascading statements into sequences. [string]
|
- a valid JS regexp (needs to start with a
|
||||||
--preamble Preamble to prepend to the output. You can use this to
|
slash) to keep only comments that match.
|
||||||
insert a comment, for example for licensing information.
|
Note that currently not *all* comments can be
|
||||||
This will not be parsed, but the source map will adjust
|
kept when compression is on, because of dead
|
||||||
for its presence.
|
code removal or cascading statements into
|
||||||
--stats Display operations run time on STDERR. [boolean]
|
sequences.
|
||||||
--acorn Use Acorn for parsing. [boolean]
|
--preamble Preamble to prepend to the output. You can use
|
||||||
--spidermonkey Assume input files are SpiderMonkey AST format (as JSON).
|
this to insert a comment, for example for
|
||||||
[boolean]
|
licensing information. This will not be
|
||||||
--self Build itself (UglifyJS2) as a library (implies
|
parsed, but the source map will adjust for its
|
||||||
--wrap=UglifyJS --export-all) [boolean]
|
presence.
|
||||||
--wrap Embed everything in a big function, making the “exports”
|
--stats Display operations run time on STDERR.
|
||||||
and “global” variables available. You need to pass an
|
--acorn Use Acorn for parsing.
|
||||||
argument to this option to specify the name that your
|
--spidermonkey Assume input files are SpiderMonkey AST format
|
||||||
module will take when included in, say, a browser.
|
(as JSON).
|
||||||
[string]
|
--self Build itself (UglifyJS2) as a library (implies
|
||||||
--export-all Only used when --wrap, this tells UglifyJS to add code to
|
--wrap=UglifyJS --export-all)
|
||||||
automatically export all globals. [boolean]
|
--wrap Embed everything in a big function, making the
|
||||||
--lint Display some scope warnings [boolean]
|
“exports” and “global” variables available. You
|
||||||
-v, --verbose Verbose [boolean]
|
need to pass an argument to this option to
|
||||||
-V, --version Print version number and exit. [boolean]
|
specify the name that your module will take
|
||||||
|
when included in, say, a browser.
|
||||||
|
--export-all Only used when --wrap, this tells UglifyJS to
|
||||||
|
add code to automatically export all globals.
|
||||||
|
--lint Display some scope warnings
|
||||||
|
-v, --verbose Verbose
|
||||||
|
-V, --version Print version number and exit.
|
||||||
|
--noerr Don't throw an error for unknown options in -c,
|
||||||
|
-b or -m.
|
||||||
|
--bare-returns Allow return outside of functions. Useful when
|
||||||
|
minifying CommonJS modules.
|
||||||
|
--keep-fnames Do not mangle/drop function names. Useful for
|
||||||
|
code relying on Function.prototype.name.
|
||||||
|
--reserved-file File containing reserved names
|
||||||
|
--reserve-domprops Make (most?) DOM properties reserved for
|
||||||
|
--mangle-props
|
||||||
|
--mangle-props Mangle property names
|
||||||
|
--name-cache File to hold mangled names mappings
|
||||||
```
|
```
|
||||||
|
|
||||||
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
||||||
@@ -189,6 +206,69 @@ comma-separated list of names. For example:
|
|||||||
|
|
||||||
to prevent the `require`, `exports` and `$` names from being changed.
|
to prevent the `require`, `exports` and `$` names from being changed.
|
||||||
|
|
||||||
|
### Mangling property names (`--mangle-props`)
|
||||||
|
|
||||||
|
**Note:** this will probably break your code. Mangling property names is a
|
||||||
|
separate step, different from variable name mangling. Pass
|
||||||
|
`--mangle-props`. It will mangle all properties that are seen in some
|
||||||
|
object literal, or that are assigned to. For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var x = {
|
||||||
|
foo: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
x.bar = 2;
|
||||||
|
x["baz"] = 3;
|
||||||
|
x[condition ? "moo" : "boo"] = 4;
|
||||||
|
console.log(x.something());
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above code, `foo`, `bar`, `baz`, `moo` and `boo` will be replaced
|
||||||
|
with single characters, while `something()` will be left as is.
|
||||||
|
|
||||||
|
In order for this to be of any use, we should avoid mangling standard JS
|
||||||
|
names. For instance, if your code would contain `x.length = 10`, then
|
||||||
|
`length` becomes a candidate for mangling and it will be mangled throughout
|
||||||
|
the code, regardless if it's being used as part of your own objects or
|
||||||
|
accessing an array's length. To avoid that, you can use `--reserved-file`
|
||||||
|
to pass a filename that should contain the names to be excluded from
|
||||||
|
mangling. This file can be used both for excluding variable names and
|
||||||
|
property names. It could look like this, for example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"vars": [ "define", "require", ... ],
|
||||||
|
"props": [ "length", "prototype", ... ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`--reserved-file` can be an array of file names (either a single
|
||||||
|
comma-separated argument, or you can pass multiple `--reserved-file`
|
||||||
|
arguments) — in this case it will exclude names from all those files.
|
||||||
|
|
||||||
|
A default exclusion file is provided in `tools/domprops.json` which should
|
||||||
|
cover most standard JS and DOM properties defined in various browsers. Pass
|
||||||
|
`--reserve-domprops` to read that in.
|
||||||
|
|
||||||
|
When you compress multiple files using this option, in order for them to
|
||||||
|
work together in the end we need to ensure somehow that one property gets
|
||||||
|
mangled to the same name in all of them. For this, pass `--name-cache
|
||||||
|
filename.json` and UglifyJS will maintain these mappings in a file which can
|
||||||
|
then be reused. It should be initially empty. Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
rm -f /tmp/cache.json # start fresh
|
||||||
|
uglifyjs file1.js file2.js --mangle-props --name-cache /tmp/cache.json -o part1.js
|
||||||
|
uglifyjs file3.js file4.js --mangle-props --name-cache /tmp/cache.json -o part2.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, `part1.js` and `part2.js` will be consistent with each other in terms
|
||||||
|
of mangled property names.
|
||||||
|
|
||||||
|
Using the name cache is not necessary if you compress all your files in a
|
||||||
|
single call to UglifyJS.
|
||||||
|
|
||||||
## Compressor options
|
## Compressor options
|
||||||
|
|
||||||
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
|
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
|
||||||
@@ -272,14 +352,15 @@ contrived cases, but should be fine for most code. You might want to try it
|
|||||||
on your own code, it should reduce the minified size. Here's what happens
|
on your own code, it should reduce the minified size. Here's what happens
|
||||||
when this flag is on:
|
when this flag is on:
|
||||||
|
|
||||||
- `new Array(1, 2, 3)` or `Array(1, 2, 3)` → `[1, 2, 3 ]`
|
- `new Array(1, 2, 3)` or `Array(1, 2, 3)` → `[ 1, 2, 3 ]`
|
||||||
- `new Object()` → `{}`
|
- `new Object()` → `{}`
|
||||||
- `String(exp)` or `exp.toString()` → `"" + exp`
|
- `String(exp)` or `exp.toString()` → `"" + exp`
|
||||||
- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`
|
- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`
|
||||||
- `typeof foo == "undefined"` → `foo === void 0`
|
- `typeof foo == "undefined"` → `foo === void 0`
|
||||||
- `void 0` → `undefined` (if there is a variable named "undefined" in
|
- `void 0` → `undefined` (if there is a variable named "undefined" in
|
||||||
scope; we do it because the variable name will be mangled, typically
|
scope; we do it because the variable name will be mangled, typically
|
||||||
reduced to a single character).
|
reduced to a single character)
|
||||||
|
- discards unused function arguments (affects `function.length`)
|
||||||
|
|
||||||
### Conditional compilation
|
### Conditional compilation
|
||||||
|
|
||||||
@@ -510,6 +591,16 @@ var result = UglifyJS.minify("compiled.js", {
|
|||||||
// same as before, it returns `code` and `map`
|
// same as before, it returns `code` and `map`
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If your input source map is not in a file, you can pass it in as an object
|
||||||
|
using the `inSourceMap` argument:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify("compiled.js", {
|
||||||
|
inSourceMap: JSON.parse(my_source_map_string),
|
||||||
|
outSourceMap: "minified.js.map"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
The `inSourceMap` is only used if you also request `outSourceMap` (it makes
|
The `inSourceMap` is only used if you also request `outSourceMap` (it makes
|
||||||
no sense otherwise).
|
no sense otherwise).
|
||||||
|
|
||||||
|
|||||||
77
bin/extract-props.js
Executable file
77
bin/extract-props.js
Executable file
@@ -0,0 +1,77 @@
|
|||||||
|
#! /usr/bin/env node
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var U2 = require("../tools/node");
|
||||||
|
var fs = require("fs");
|
||||||
|
var yargs = require("yargs");
|
||||||
|
var ARGS = yargs
|
||||||
|
.describe("o", "Output file")
|
||||||
|
.argv;
|
||||||
|
var files = ARGS._.slice();
|
||||||
|
var output = {
|
||||||
|
vars: {},
|
||||||
|
props: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ARGS.o) try {
|
||||||
|
output = JSON.parse(fs.readFileSync(ARGS.o, "utf8"));
|
||||||
|
} catch(ex) {}
|
||||||
|
|
||||||
|
files.forEach(getProps);
|
||||||
|
|
||||||
|
if (ARGS.o) {
|
||||||
|
fs.writeFileSync(ARGS.o, JSON.stringify(output, null, 2), "utf8");
|
||||||
|
} else {
|
||||||
|
console.log("%s", JSON.stringify(output, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProps(filename) {
|
||||||
|
var code = fs.readFileSync(filename, "utf8");
|
||||||
|
var ast = U2.parse(code);
|
||||||
|
|
||||||
|
ast.walk(new U2.TreeWalker(function(node){
|
||||||
|
if (node instanceof U2.AST_ObjectKeyVal) {
|
||||||
|
add(node.key);
|
||||||
|
}
|
||||||
|
else if (node instanceof U2.AST_ObjectProperty) {
|
||||||
|
add(node.key.name);
|
||||||
|
}
|
||||||
|
else if (node instanceof U2.AST_Dot) {
|
||||||
|
add(node.property);
|
||||||
|
}
|
||||||
|
else if (node instanceof U2.AST_Sub) {
|
||||||
|
addStrings(node.property);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
function addStrings(node) {
|
||||||
|
var out = {};
|
||||||
|
try {
|
||||||
|
(function walk(node){
|
||||||
|
node.walk(new U2.TreeWalker(function(node){
|
||||||
|
if (node instanceof U2.AST_Seq) {
|
||||||
|
walk(node.cdr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof U2.AST_String) {
|
||||||
|
add(node.value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof U2.AST_Conditional) {
|
||||||
|
walk(node.consequent);
|
||||||
|
walk(node.alternative);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw out;
|
||||||
|
}));
|
||||||
|
})(node);
|
||||||
|
} catch(ex) {
|
||||||
|
if (ex !== out) throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(name) {
|
||||||
|
output.props[name] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
121
bin/uglifyjs
121
bin/uglifyjs
@@ -67,6 +67,10 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.describe("bare-returns", "Allow return outside of functions. Useful when minifying CommonJS modules.")
|
.describe("bare-returns", "Allow return outside of functions. Useful when minifying CommonJS modules.")
|
||||||
.describe("keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.")
|
.describe("keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.")
|
||||||
.describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)")
|
.describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)")
|
||||||
|
.describe("reserved-file", "File containing reserved names")
|
||||||
|
.describe("reserve-domprops", "Make (most?) DOM properties reserved for --mangle-props")
|
||||||
|
.describe("mangle-props", "Mangle property names")
|
||||||
|
.describe("name-cache", "File to hold mangled names mappings")
|
||||||
|
|
||||||
.alias("p", "prefix")
|
.alias("p", "prefix")
|
||||||
.alias("o", "output")
|
.alias("o", "output")
|
||||||
@@ -84,13 +88,21 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.string("source-map-root")
|
.string("source-map-root")
|
||||||
.string("source-map-url")
|
.string("source-map-url")
|
||||||
.string("b")
|
.string("b")
|
||||||
|
.string("beautify")
|
||||||
.string("m")
|
.string("m")
|
||||||
|
.string("mangle")
|
||||||
.string("c")
|
.string("c")
|
||||||
|
.string("compress")
|
||||||
.string("d")
|
.string("d")
|
||||||
|
.string("define")
|
||||||
.string("e")
|
.string("e")
|
||||||
|
.string("enclose")
|
||||||
.string("comments")
|
.string("comments")
|
||||||
.string("wrap")
|
.string("wrap")
|
||||||
.string("p")
|
.string("p")
|
||||||
|
.string("prefix")
|
||||||
|
.string("name-cache")
|
||||||
|
.array("reserved-file")
|
||||||
|
|
||||||
.boolean("expr")
|
.boolean("expr")
|
||||||
.boolean("source-map-include-sources")
|
.boolean("source-map-include-sources")
|
||||||
@@ -98,14 +110,18 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.boolean("export-all")
|
.boolean("export-all")
|
||||||
.boolean("self")
|
.boolean("self")
|
||||||
.boolean("v")
|
.boolean("v")
|
||||||
|
.boolean("verbose")
|
||||||
.boolean("stats")
|
.boolean("stats")
|
||||||
.boolean("acorn")
|
.boolean("acorn")
|
||||||
.boolean("spidermonkey")
|
.boolean("spidermonkey")
|
||||||
.boolean("lint")
|
.boolean("lint")
|
||||||
.boolean("V")
|
.boolean("V")
|
||||||
|
.boolean("version")
|
||||||
.boolean("noerr")
|
.boolean("noerr")
|
||||||
.boolean("bare-returns")
|
.boolean("bare-returns")
|
||||||
.boolean("keep-fnames")
|
.boolean("keep-fnames")
|
||||||
|
.boolean("mangle-props")
|
||||||
|
.boolean("reserve-domprops")
|
||||||
|
|
||||||
.wrap(80)
|
.wrap(80)
|
||||||
|
|
||||||
@@ -116,24 +132,24 @@ normalize(ARGS);
|
|||||||
|
|
||||||
if (ARGS.noerr) {
|
if (ARGS.noerr) {
|
||||||
UglifyJS.DefaultsError.croak = function(msg, defs) {
|
UglifyJS.DefaultsError.croak = function(msg, defs) {
|
||||||
sys.error("WARN: " + msg);
|
print_error("WARN: " + msg);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.version || ARGS.V) {
|
if (ARGS.version || ARGS.V) {
|
||||||
var json = require("../package.json");
|
var json = require("../package.json");
|
||||||
sys.puts(json.name + ' ' + json.version);
|
print(json.name + ' ' + json.version);
|
||||||
process.exit(0);
|
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));
|
print(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2));
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.h || ARGS.help) {
|
if (ARGS.h || ARGS.help) {
|
||||||
sys.puts(yargs.help());
|
print(yargs.help());
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +160,15 @@ if (ARGS.acorn) {
|
|||||||
var COMPRESS = getOptions("c", true);
|
var COMPRESS = getOptions("c", true);
|
||||||
var MANGLE = getOptions("m", true);
|
var MANGLE = getOptions("m", true);
|
||||||
var BEAUTIFY = getOptions("b", true);
|
var BEAUTIFY = getOptions("b", true);
|
||||||
|
var RESERVED = null;
|
||||||
|
|
||||||
|
if (ARGS.reserved_file) ARGS.reserved_file.forEach(function(filename){
|
||||||
|
RESERVED = UglifyJS.readReservedFile(filename, RESERVED);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ARGS.reserve_domprops) {
|
||||||
|
RESERVED = UglifyJS.readDefaultReservedFile(RESERVED);
|
||||||
|
}
|
||||||
|
|
||||||
if (ARGS.d) {
|
if (ARGS.d) {
|
||||||
if (COMPRESS) COMPRESS.global_defs = getOptions("d");
|
if (COMPRESS) COMPRESS.global_defs = getOptions("d");
|
||||||
@@ -153,6 +178,19 @@ if (ARGS.r) {
|
|||||||
if (MANGLE) MANGLE.except = ARGS.r.replace(/^\s+|\s+$/g).split(/\s*,+\s*/);
|
if (MANGLE) MANGLE.except = ARGS.r.replace(/^\s+|\s+$/g).split(/\s*,+\s*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RESERVED && MANGLE) {
|
||||||
|
if (!MANGLE.except) MANGLE.except = RESERVED.vars;
|
||||||
|
else MANGLE.except = MANGLE.except.concat(RESERVED.vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readNameCache(key) {
|
||||||
|
return UglifyJS.readNameCache(ARGS.name_cache, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeNameCache(key, cache) {
|
||||||
|
return UglifyJS.writeNameCache(ARGS.name_cache, key, cache);
|
||||||
|
}
|
||||||
|
|
||||||
if (ARGS.quotes === true) {
|
if (ARGS.quotes === true) {
|
||||||
ARGS.quotes = 3;
|
ARGS.quotes = 3;
|
||||||
}
|
}
|
||||||
@@ -177,13 +215,13 @@ if (ARGS.keep_fnames) {
|
|||||||
if (BEAUTIFY)
|
if (BEAUTIFY)
|
||||||
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
|
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
|
||||||
|
|
||||||
if (ARGS.comments) {
|
if (ARGS.comments != null) {
|
||||||
if (/^\/.*\/[a-zA-Z]*$/.test(ARGS.comments)) {
|
if (/^\/.*\/[a-zA-Z]*$/.test(ARGS.comments)) {
|
||||||
var regex_pos = ARGS.comments.lastIndexOf("/");
|
var regex_pos = ARGS.comments.lastIndexOf("/");
|
||||||
try {
|
try {
|
||||||
OUTPUT_OPTIONS.comments = new RegExp(ARGS.comments.substr(1, regex_pos - 1), ARGS.comments.substr(regex_pos + 1));
|
OUTPUT_OPTIONS.comments = new RegExp(ARGS.comments.substr(1, regex_pos - 1), ARGS.comments.substr(regex_pos + 1));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
sys.error("ERROR: Invalid --comments: " + e.message);
|
print_error("ERROR: Invalid --comments: " + e.message);
|
||||||
}
|
}
|
||||||
} else if (ARGS.comments == "all") {
|
} else if (ARGS.comments == "all") {
|
||||||
OUTPUT_OPTIONS.comments = true;
|
OUTPUT_OPTIONS.comments = true;
|
||||||
@@ -203,7 +241,7 @@ var files = ARGS._.slice();
|
|||||||
|
|
||||||
if (ARGS.self) {
|
if (ARGS.self) {
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
sys.error("WARN: Ignoring input files since --self was passed");
|
print_error("WARN: Ignoring input files since --self was passed");
|
||||||
}
|
}
|
||||||
files = UglifyJS.FILES;
|
files = UglifyJS.FILES;
|
||||||
if (!ARGS.wrap) ARGS.wrap = "UglifyJS";
|
if (!ARGS.wrap) ARGS.wrap = "UglifyJS";
|
||||||
@@ -215,7 +253,7 @@ var ORIG_MAP = ARGS.in_source_map;
|
|||||||
if (ORIG_MAP) {
|
if (ORIG_MAP) {
|
||||||
ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP));
|
ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP));
|
||||||
if (files.length == 0) {
|
if (files.length == 0) {
|
||||||
sys.error("INFO: Using file from the input source map: " + ORIG_MAP.file);
|
print_error("INFO: Using file from the input source map: " + ORIG_MAP.file);
|
||||||
files = [ ORIG_MAP.file ];
|
files = [ ORIG_MAP.file ];
|
||||||
}
|
}
|
||||||
if (ARGS.source_map_root == null) {
|
if (ARGS.source_map_root == null) {
|
||||||
@@ -228,12 +266,12 @@ if (files.length == 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (files.indexOf("-") >= 0 && ARGS.source_map) {
|
if (files.indexOf("-") >= 0 && ARGS.source_map) {
|
||||||
sys.error("ERROR: Source map doesn't work with input from STDIN");
|
print_error("ERROR: Source map doesn't work with input from STDIN");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (files.filter(function(el){ return el == "-" }).length > 1) {
|
if (files.filter(function(el){ return el == "-" }).length > 1) {
|
||||||
sys.error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
|
print_error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,9 +294,9 @@ try {
|
|||||||
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
|
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex instanceof UglifyJS.DefaultsError) {
|
if (ex instanceof UglifyJS.DefaultsError) {
|
||||||
sys.error(ex.msg);
|
print_error(ex.msg);
|
||||||
sys.error("Supported options:");
|
print_error("Supported options:");
|
||||||
sys.error(sys.inspect(ex.defs));
|
print_error(sys.inspect(ex.defs));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,7 +304,7 @@ try {
|
|||||||
async.eachLimit(files, 1, function (file, cb) {
|
async.eachLimit(files, 1, function (file, cb) {
|
||||||
read_whole_file(file, function (err, code) {
|
read_whole_file(file, function (err, code) {
|
||||||
if (err) {
|
if (err) {
|
||||||
sys.error("ERROR: can't read file: " + file);
|
print_error("ERROR: can't read file: " + file);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (ARGS.p != null) {
|
if (ARGS.p != null) {
|
||||||
@@ -303,9 +341,9 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
});
|
});
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
||||||
sys.error("Parse error at " + file + ":" + ex.line + "," + ex.col);
|
print_error("Parse error at " + file + ":" + ex.line + "," + ex.col);
|
||||||
sys.error(ex.message);
|
print_error(ex.message);
|
||||||
sys.error(ex.stack);
|
print_error(ex.stack);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
@@ -319,11 +357,11 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL);
|
TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ARGS.wrap) {
|
if (ARGS.wrap != null) {
|
||||||
TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all);
|
TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.enclose) {
|
if (ARGS.enclose != null) {
|
||||||
var arg_parameter_list = ARGS.enclose;
|
var arg_parameter_list = ARGS.enclose;
|
||||||
if (arg_parameter_list === true) {
|
if (arg_parameter_list === true) {
|
||||||
arg_parameter_list = [];
|
arg_parameter_list = [];
|
||||||
@@ -334,11 +372,23 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
TOPLEVEL = TOPLEVEL.wrap_enclose(arg_parameter_list);
|
TOPLEVEL = TOPLEVEL.wrap_enclose(arg_parameter_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ARGS.mangle_props || ARGS.name_cache) (function(){
|
||||||
|
var reserved = RESERVED ? RESERVED.props : null;
|
||||||
|
var cache = readNameCache("props");
|
||||||
|
TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, {
|
||||||
|
reserved : reserved,
|
||||||
|
cache : cache,
|
||||||
|
only_cache : !ARGS.mangle_props
|
||||||
|
});
|
||||||
|
writeNameCache("props", cache);
|
||||||
|
})();
|
||||||
|
|
||||||
var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint;
|
var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint;
|
||||||
|
var TL_CACHE = readNameCache("vars");
|
||||||
|
|
||||||
if (SCOPE_IS_NEEDED) {
|
if (SCOPE_IS_NEEDED) {
|
||||||
time_it("scope", function(){
|
time_it("scope", function(){
|
||||||
TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8 });
|
TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8, cache: TL_CACHE });
|
||||||
if (ARGS.lint) {
|
if (ARGS.lint) {
|
||||||
TOPLEVEL.scope_warnings();
|
TOPLEVEL.scope_warnings();
|
||||||
}
|
}
|
||||||
@@ -353,17 +403,20 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
|
|
||||||
if (SCOPE_IS_NEEDED) {
|
if (SCOPE_IS_NEEDED) {
|
||||||
time_it("scope", function(){
|
time_it("scope", function(){
|
||||||
TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8 });
|
TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8, cache: TL_CACHE });
|
||||||
if (MANGLE) {
|
if (MANGLE && !TL_CACHE) {
|
||||||
TOPLEVEL.compute_char_frequency(MANGLE);
|
TOPLEVEL.compute_char_frequency(MANGLE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MANGLE) time_it("mangle", function(){
|
if (MANGLE) time_it("mangle", function(){
|
||||||
|
MANGLE.cache = TL_CACHE;
|
||||||
TOPLEVEL.mangle_names(MANGLE);
|
TOPLEVEL.mangle_names(MANGLE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
writeNameCache("vars", TL_CACHE);
|
||||||
|
|
||||||
if (ARGS.source_map_include_sources) {
|
if (ARGS.source_map_include_sources) {
|
||||||
for (var file in SOURCES_CONTENT) {
|
for (var file in SOURCES_CONTENT) {
|
||||||
if (SOURCES_CONTENT.hasOwnProperty(file)) {
|
if (SOURCES_CONTENT.hasOwnProperty(file)) {
|
||||||
@@ -391,15 +444,15 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
if (OUTPUT_FILE) {
|
if (OUTPUT_FILE) {
|
||||||
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
|
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
|
||||||
} else {
|
} else {
|
||||||
sys.print(output);
|
print(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.stats) {
|
if (ARGS.stats) {
|
||||||
sys.error(UglifyJS.string_template("Timing information (compressed {count} files):", {
|
print_error(UglifyJS.string_template("Timing information (compressed {count} files):", {
|
||||||
count: files.length
|
count: files.length
|
||||||
}));
|
}));
|
||||||
for (var i in STATS) if (STATS.hasOwnProperty(i)) {
|
for (var i in STATS) if (STATS.hasOwnProperty(i)) {
|
||||||
sys.error(UglifyJS.string_template("- {name}: {time}s", {
|
print_error(UglifyJS.string_template("- {name}: {time}s", {
|
||||||
name: i,
|
name: i,
|
||||||
time: (STATS[i] / 1000).toFixed(3)
|
time: (STATS[i] / 1000).toFixed(3)
|
||||||
}));
|
}));
|
||||||
@@ -418,15 +471,15 @@ function normalize(o) {
|
|||||||
|
|
||||||
function getOptions(x, constants) {
|
function getOptions(x, constants) {
|
||||||
x = ARGS[x];
|
x = ARGS[x];
|
||||||
if (!x) return null;
|
if (x == null) return null;
|
||||||
var ret = {};
|
var ret = {};
|
||||||
if (x !== true) {
|
if (x !== "") {
|
||||||
var ast;
|
var ast;
|
||||||
try {
|
try {
|
||||||
ast = UglifyJS.parse(x, { expression: true });
|
ast = UglifyJS.parse(x, { expression: true });
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
||||||
sys.error("Error parsing arguments in: " + x);
|
print_error("Error parsing arguments in: " + x);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,8 +498,8 @@ function getOptions(x, constants) {
|
|||||||
ret[name] = true;
|
ret[name] = true;
|
||||||
return true; // no descend
|
return true; // no descend
|
||||||
}
|
}
|
||||||
sys.error(node.TYPE)
|
print_error(node.TYPE)
|
||||||
sys.error("Error parsing arguments in: " + x);
|
print_error("Error parsing arguments in: " + x);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -478,3 +531,11 @@ function time_it(name, cont) {
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function print_error(msg) {
|
||||||
|
console.error("%s", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function print(txt) {
|
||||||
|
console.log("%s", txt);
|
||||||
|
}
|
||||||
|
|||||||
@@ -489,7 +489,7 @@ merge(Compressor.prototype, {
|
|||||||
seq = [];
|
seq = [];
|
||||||
};
|
};
|
||||||
statements.forEach(function(stat){
|
statements.forEach(function(stat){
|
||||||
if (stat instanceof AST_SimpleStatement) seq.push(stat.body);
|
if (stat instanceof AST_SimpleStatement && seq.length < 2000) seq.push(stat.body);
|
||||||
else push_seq(), ret.push(stat);
|
else push_seq(), ret.push(stat);
|
||||||
});
|
});
|
||||||
push_seq();
|
push_seq();
|
||||||
@@ -1086,7 +1086,7 @@ merge(Compressor.prototype, {
|
|||||||
var tt = new TreeTransformer(
|
var tt = new TreeTransformer(
|
||||||
function before(node, descend, in_list) {
|
function before(node, descend, in_list) {
|
||||||
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
|
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
|
||||||
if (!compressor.option("keep_fargs")) {
|
if (compressor.option("unsafe") && !compressor.option("keep_fargs")) {
|
||||||
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
||||||
var sym = a[i];
|
var sym = a[i];
|
||||||
if (sym.unreferenced()) {
|
if (sym.unreferenced()) {
|
||||||
@@ -1168,12 +1168,12 @@ merge(Compressor.prototype, {
|
|||||||
return make_node(AST_EmptyStatement, node);
|
return make_node(AST_EmptyStatement, node);
|
||||||
}
|
}
|
||||||
if (def.length == 0) {
|
if (def.length == 0) {
|
||||||
return side_effects;
|
return in_list ? MAP.splice(side_effects.body) : side_effects;
|
||||||
}
|
}
|
||||||
node.definitions = def;
|
node.definitions = def;
|
||||||
if (side_effects) {
|
if (side_effects) {
|
||||||
side_effects.body.unshift(node);
|
side_effects.body.unshift(node);
|
||||||
node = side_effects;
|
return in_list ? MAP.splice(side_effects.body) : side_effects;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -2267,16 +2267,8 @@ merge(Compressor.prototype, {
|
|||||||
OPT(AST_Infinity, function (self, compressor) {
|
OPT(AST_Infinity, function (self, compressor) {
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator : '/',
|
operator : '/',
|
||||||
left : make_node(AST_Number, null, {value: 1}),
|
left : make_node(AST_Number, self, {value: 1}),
|
||||||
right : make_node(AST_Number, null, {value: 0})
|
right : make_node(AST_Number, self, {value: 0})
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
OPT(AST_NaN, function (self, compressor) {
|
|
||||||
return make_node(AST_Binary, self, {
|
|
||||||
operator : '/',
|
|
||||||
left : make_node(AST_Number, null, {value: 0}),
|
|
||||||
right : make_node(AST_Number, null, {value: 0})
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2343,6 +2335,7 @@ merge(Compressor.prototype, {
|
|||||||
&& alternative instanceof AST_Assign
|
&& alternative instanceof AST_Assign
|
||||||
&& consequent.operator == alternative.operator
|
&& consequent.operator == alternative.operator
|
||||||
&& consequent.left.equivalent_to(alternative.left)
|
&& consequent.left.equivalent_to(alternative.left)
|
||||||
|
&& !consequent.left.has_side_effects(compressor)
|
||||||
) {
|
) {
|
||||||
/*
|
/*
|
||||||
* Stuff like this:
|
* Stuff like this:
|
||||||
@@ -2363,6 +2356,7 @@ merge(Compressor.prototype, {
|
|||||||
if (consequent instanceof AST_Call
|
if (consequent instanceof AST_Call
|
||||||
&& alternative.TYPE === consequent.TYPE
|
&& alternative.TYPE === consequent.TYPE
|
||||||
&& consequent.args.length == alternative.args.length
|
&& consequent.args.length == alternative.args.length
|
||||||
|
&& !consequent.expression.has_side_effects(compressor)
|
||||||
&& consequent.expression.equivalent_to(alternative.expression)) {
|
&& consequent.expression.equivalent_to(alternative.expression)) {
|
||||||
if (consequent.args.length == 0) {
|
if (consequent.args.length == 0) {
|
||||||
return make_node(AST_Seq, self, {
|
return make_node(AST_Seq, self, {
|
||||||
@@ -2480,7 +2474,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function literals_in_boolean_context(self, compressor) {
|
function literals_in_boolean_context(self, compressor) {
|
||||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
if (compressor.option("booleans") && compressor.in_boolean_context() && !self.has_side_effects(compressor)) {
|
||||||
return make_node(AST_True, self);
|
return make_node(AST_True, self);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
|||||||
@@ -176,7 +176,6 @@ function OutputStream(options) {
|
|||||||
might_need_space = false;
|
might_need_space = false;
|
||||||
}
|
}
|
||||||
might_need_semicolon = false;
|
might_need_semicolon = false;
|
||||||
maybe_newline();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
|
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
|
||||||
|
|||||||
21
lib/parse.js
21
lib/parse.js
@@ -108,7 +108,7 @@ var OPERATORS = makePredicate([
|
|||||||
"||"
|
"||"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"));
|
var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF"));
|
||||||
|
|
||||||
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
|
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
|
||||||
|
|
||||||
@@ -187,8 +187,9 @@ function parse_js_number(num) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function JS_Parse_Error(message, line, col, pos) {
|
function JS_Parse_Error(message, filename, line, col, pos) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
this.filename = filename;
|
||||||
this.line = line;
|
this.line = line;
|
||||||
this.col = col;
|
this.col = col;
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
@@ -200,7 +201,7 @@ JS_Parse_Error.prototype.toString = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function js_error(message, filename, line, col, pos) {
|
function js_error(message, filename, line, col, pos) {
|
||||||
throw new JS_Parse_Error(message, line, col, pos);
|
throw new JS_Parse_Error(message, filename, line, col, pos);
|
||||||
};
|
};
|
||||||
|
|
||||||
function is_token(token, type, val) {
|
function is_token(token, type, val) {
|
||||||
@@ -212,7 +213,7 @@ var EX_EOF = {};
|
|||||||
function tokenizer($TEXT, filename, html5_comments) {
|
function tokenizer($TEXT, filename, html5_comments) {
|
||||||
|
|
||||||
var S = {
|
var S = {
|
||||||
text : $TEXT.replace(/\uFEFF/g, ''),
|
text : $TEXT,
|
||||||
filename : filename,
|
filename : filename,
|
||||||
pos : 0,
|
pos : 0,
|
||||||
tokpos : 0,
|
tokpos : 0,
|
||||||
@@ -297,7 +298,8 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function skip_whitespace() {
|
function skip_whitespace() {
|
||||||
while (WHITESPACE_CHARS(peek()))
|
var ch;
|
||||||
|
while (WHITESPACE_CHARS(ch = peek()) || ch == "\u2028" || ch == "\u2029")
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -352,8 +354,13 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
case 120 : return String.fromCharCode(hex_bytes(2)); // \x
|
case 120 : return String.fromCharCode(hex_bytes(2)); // \x
|
||||||
case 117 : return String.fromCharCode(hex_bytes(4)); // \u
|
case 117 : return String.fromCharCode(hex_bytes(4)); // \u
|
||||||
case 10 : return ""; // newline
|
case 10 : return ""; // newline
|
||||||
default : return ch;
|
case 13 : // \r
|
||||||
|
if (peek() == "\n") { // DOS newline
|
||||||
|
next(true, in_string);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return ch;
|
||||||
};
|
};
|
||||||
|
|
||||||
function hex_bytes(n) {
|
function hex_bytes(n) {
|
||||||
@@ -370,7 +377,7 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
var read_string = with_eof_error("Unterminated string constant", function(quote_char){
|
var read_string = with_eof_error("Unterminated string constant", function(quote_char){
|
||||||
var quote = next(), ret = "";
|
var quote = next(), ret = "";
|
||||||
for (;;) {
|
for (;;) {
|
||||||
var ch = next(true);
|
var ch = next(true, true);
|
||||||
if (ch == "\\") {
|
if (ch == "\\") {
|
||||||
// read OctalEscapeSequence (XXX: deprecated if "strict mode")
|
// read OctalEscapeSequence (XXX: deprecated if "strict mode")
|
||||||
// https://github.com/mishoo/UglifyJS/issues/178
|
// https://github.com/mishoo/UglifyJS/issues/178
|
||||||
|
|||||||
217
lib/propmangle.js
Normal file
217
lib/propmangle.js
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
/***********************************************************************
|
||||||
|
|
||||||
|
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||||
|
https://github.com/mishoo/UglifyJS2
|
||||||
|
|
||||||
|
-------------------------------- (C) ---------------------------------
|
||||||
|
|
||||||
|
Author: Mihai Bazon
|
||||||
|
<mihai.bazon@gmail.com>
|
||||||
|
http://mihai.bazon.net/blog
|
||||||
|
|
||||||
|
Distributed under the BSD license:
|
||||||
|
|
||||||
|
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials
|
||||||
|
provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||||
|
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||||
|
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
|
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function find_builtins() {
|
||||||
|
var a = [];
|
||||||
|
[ Object, Array, Function, Number,
|
||||||
|
String, Boolean, Error, Math,
|
||||||
|
Date, RegExp
|
||||||
|
].forEach(function(ctor){
|
||||||
|
Object.getOwnPropertyNames(ctor).map(add);
|
||||||
|
if (ctor.prototype) {
|
||||||
|
Object.getOwnPropertyNames(ctor.prototype).map(add);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
function add(name) {
|
||||||
|
push_uniq(a, name);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mangle_properties(ast, options) {
|
||||||
|
options = defaults(options, {
|
||||||
|
reserved : null,
|
||||||
|
cache : null,
|
||||||
|
only_cache : false
|
||||||
|
});
|
||||||
|
|
||||||
|
var reserved = options.reserved;
|
||||||
|
if (reserved == null)
|
||||||
|
reserved = find_builtins();
|
||||||
|
|
||||||
|
var cache = options.cache;
|
||||||
|
if (cache == null) {
|
||||||
|
cache = {
|
||||||
|
cname: -1,
|
||||||
|
props: new Dictionary()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var names_to_mangle = [];
|
||||||
|
|
||||||
|
// step 1: find candidates to mangle
|
||||||
|
ast.walk(new TreeWalker(function(node){
|
||||||
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
|
add(node.key);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
|
// setter or getter, since KeyVal is handled above
|
||||||
|
add(node.key.name);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Dot) {
|
||||||
|
if (this.parent() instanceof AST_Assign) {
|
||||||
|
add(node.property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Sub) {
|
||||||
|
if (this.parent() instanceof AST_Assign) {
|
||||||
|
addStrings(node.property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// step 2: transform the tree, renaming properties
|
||||||
|
return ast.transform(new TreeTransformer(function(node){
|
||||||
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
|
if (should_mangle(node.key)) {
|
||||||
|
node.key = mangle(node.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
|
// setter or getter
|
||||||
|
if (should_mangle(node.key.name)) {
|
||||||
|
node.key.name = mangle(node.key.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Dot) {
|
||||||
|
if (should_mangle(node.property)) {
|
||||||
|
node.property = mangle(node.property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Sub) {
|
||||||
|
node.property = mangleStrings(node.property);
|
||||||
|
}
|
||||||
|
// else if (node instanceof AST_String) {
|
||||||
|
// if (should_mangle(node.value)) {
|
||||||
|
// AST_Node.warn(
|
||||||
|
// "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", {
|
||||||
|
// file : node.start.file,
|
||||||
|
// line : node.start.line,
|
||||||
|
// col : node.start.col,
|
||||||
|
// prop : node.value
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}));
|
||||||
|
|
||||||
|
// only function declarations after this line
|
||||||
|
|
||||||
|
function can_mangle(name) {
|
||||||
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
|
if (options.only_cache) {
|
||||||
|
return cache.props.has(name);
|
||||||
|
}
|
||||||
|
if (/^[0-9.]+$/.test(name)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function should_mangle(name) {
|
||||||
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
|
return cache.props.has(name)
|
||||||
|
|| names_to_mangle.indexOf(name) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(name) {
|
||||||
|
if (can_mangle(name))
|
||||||
|
push_uniq(names_to_mangle, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mangle(name) {
|
||||||
|
var mangled = cache.props.get(name);
|
||||||
|
if (!mangled) {
|
||||||
|
do {
|
||||||
|
mangled = base54(++cache.cname);
|
||||||
|
} while (!can_mangle(mangled));
|
||||||
|
cache.props.set(name, mangled);
|
||||||
|
}
|
||||||
|
return mangled;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addStrings(node) {
|
||||||
|
var out = {};
|
||||||
|
try {
|
||||||
|
(function walk(node){
|
||||||
|
node.walk(new TreeWalker(function(node){
|
||||||
|
if (node instanceof AST_Seq) {
|
||||||
|
walk(node.cdr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_String) {
|
||||||
|
add(node.value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Conditional) {
|
||||||
|
walk(node.consequent);
|
||||||
|
walk(node.alternative);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw out;
|
||||||
|
}));
|
||||||
|
})(node);
|
||||||
|
} catch(ex) {
|
||||||
|
if (ex !== out) throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mangleStrings(node) {
|
||||||
|
return node.transform(new TreeTransformer(function(node){
|
||||||
|
if (node instanceof AST_Seq) {
|
||||||
|
node.cdr = mangleStrings(node.cdr);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_String) {
|
||||||
|
if (should_mangle(node.value)) {
|
||||||
|
node.value = mangle(node.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Conditional) {
|
||||||
|
node.consequent = mangleStrings(node.consequent);
|
||||||
|
node.alternative = mangleStrings(node.alternative);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
29
lib/scope.js
29
lib/scope.js
@@ -67,18 +67,26 @@ SymbolDef.prototype = {
|
|||||||
|| this.orig[0] instanceof AST_SymbolDefun));
|
|| this.orig[0] instanceof AST_SymbolDefun));
|
||||||
},
|
},
|
||||||
mangle: function(options) {
|
mangle: function(options) {
|
||||||
if (!this.mangled_name && !this.unmangleable(options)) {
|
var cache = options.cache && options.cache.props;
|
||||||
|
if (this.global && cache && cache.has(this.name)) {
|
||||||
|
this.mangled_name = cache.get(this.name);
|
||||||
|
}
|
||||||
|
else if (!this.mangled_name && !this.unmangleable(options)) {
|
||||||
var s = this.scope;
|
var s = this.scope;
|
||||||
if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda)
|
if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda)
|
||||||
s = s.parent_scope;
|
s = s.parent_scope;
|
||||||
this.mangled_name = s.next_mangled(options, this);
|
this.mangled_name = s.next_mangled(options, this);
|
||||||
|
if (this.global && cache) {
|
||||||
|
cache.set(this.name, this.mangled_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
screw_ie8: false
|
screw_ie8: false,
|
||||||
|
cache: null
|
||||||
});
|
});
|
||||||
|
|
||||||
// pass 1: setup scope chaining and handle definitions
|
// pass 1: setup scope chaining and handle definitions
|
||||||
@@ -183,6 +191,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
|
||||||
|
if (options.cache) {
|
||||||
|
this.cname = options.cache.cname;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
||||||
@@ -344,6 +356,15 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
// the AST_SymbolDeclaration that it points to).
|
// the AST_SymbolDeclaration that it points to).
|
||||||
var lname = -1;
|
var lname = -1;
|
||||||
var to_mangle = [];
|
var to_mangle = [];
|
||||||
|
|
||||||
|
if (options.cache) {
|
||||||
|
this.globals.each(function(symbol){
|
||||||
|
if (options.except.indexOf(symbol.name) < 0) {
|
||||||
|
to_mangle.push(symbol);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node instanceof AST_LabeledStatement) {
|
if (node instanceof AST_LabeledStatement) {
|
||||||
// lname is incremented when we get to the AST_Label
|
// lname is incremented when we get to the AST_Label
|
||||||
@@ -378,6 +399,10 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
});
|
});
|
||||||
this.walk(tw);
|
this.walk(tw);
|
||||||
to_mangle.forEach(function(def){ def.mangle(options) });
|
to_mangle.forEach(function(def){ def.mangle(options) });
|
||||||
|
|
||||||
|
if (options.cache) {
|
||||||
|
options.cache.cname = this.cname;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
||||||
|
|||||||
12
lib/utils.js
12
lib/utils.js
@@ -106,10 +106,12 @@ function defaults(args, defs, croak) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function merge(obj, ext) {
|
function merge(obj, ext) {
|
||||||
|
var count = 0;
|
||||||
for (var i in ext) if (ext.hasOwnProperty(i)) {
|
for (var i in ext) if (ext.hasOwnProperty(i)) {
|
||||||
obj[i] = ext[i];
|
obj[i] = ext[i];
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
return obj;
|
return count;
|
||||||
};
|
};
|
||||||
|
|
||||||
function noop() {};
|
function noop() {};
|
||||||
@@ -298,5 +300,11 @@ Dictionary.prototype = {
|
|||||||
for (var i in this._values)
|
for (var i in this._values)
|
||||||
ret.push(f(this._values[i], i.substr(1)));
|
ret.push(f(this._values[i], i.substr(1)));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
},
|
||||||
|
toObject: function() { return this._values }
|
||||||
|
};
|
||||||
|
Dictionary.fromObject = function(obj) {
|
||||||
|
var dict = new Dictionary();
|
||||||
|
dict._size = merge(dict._values, obj);
|
||||||
|
return dict;
|
||||||
};
|
};
|
||||||
|
|||||||
80
package.json
80
package.json
@@ -1,37 +1,51 @@
|
|||||||
{
|
{
|
||||||
"name": "uglify-js",
|
"name": "uglify-js",
|
||||||
"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",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"version": "2.4.16",
|
"license": "BSD",
|
||||||
"engines": { "node" : ">=0.4.0" },
|
"version": "2.4.23",
|
||||||
"maintainers": [{
|
"engines": {
|
||||||
"name": "Mihai Bazon",
|
"node": ">=0.4.0"
|
||||||
"email": "mihai.bazon@gmail.com",
|
},
|
||||||
"web": "http://lisperator.net/"
|
"maintainers": [
|
||||||
}],
|
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
|
||||||
"repository": {
|
],
|
||||||
"type": "git",
|
"repository": {
|
||||||
"url": "https://github.com/mishoo/UglifyJS2.git"
|
"type": "git",
|
||||||
},
|
"url": "https://github.com/mishoo/UglifyJS2.git"
|
||||||
"dependencies": {
|
},
|
||||||
"async" : "~0.2.6",
|
"bugs": {
|
||||||
"source-map" : "0.1.34",
|
"url": "https://github.com/mishoo/UglifyJS2/issues"
|
||||||
"yargs": "~1.3.3",
|
},
|
||||||
"uglify-to-browserify": "~1.0.0"
|
"main": "tools/node.js",
|
||||||
},
|
"bin": {
|
||||||
"devDependencies": {
|
"uglifyjs": "bin/uglifyjs"
|
||||||
"acorn": "~0.6.0",
|
},
|
||||||
"escodegen": "~1.3.3",
|
"files": [
|
||||||
"esfuzz": "~0.3.1",
|
"bin",
|
||||||
"estraverse": "~1.5.1"
|
"lib",
|
||||||
},
|
"tools",
|
||||||
"browserify": {
|
"LICENSE"
|
||||||
"transform": [ "uglify-to-browserify" ]
|
],
|
||||||
},
|
"dependencies": {
|
||||||
"bin": {
|
"async": "~0.2.6",
|
||||||
"uglifyjs" : "bin/uglifyjs"
|
"source-map": "0.1.34",
|
||||||
},
|
"uglify-to-browserify": "~1.0.0",
|
||||||
"license": "BSD",
|
"yargs": "~3.5.4"
|
||||||
"scripts": {"test": "node test/run-tests.js"}
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"acorn": "~0.6.0",
|
||||||
|
"escodegen": "~1.3.3",
|
||||||
|
"esfuzz": "~0.3.1",
|
||||||
|
"estraverse": "~1.5.1"
|
||||||
|
},
|
||||||
|
"browserify": {
|
||||||
|
"transform": [
|
||||||
|
"uglify-to-browserify"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "node test/run-tests.js"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,9 @@ ifs_4: {
|
|||||||
x(foo)[10].bar.baz = something_else();
|
x(foo)[10].bar.baz = something_else();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
x(foo)[10].bar.baz = (foo && bar) ? something() : something_else();
|
foo && bar
|
||||||
|
? x(foo)[10].bar.baz = something()
|
||||||
|
: x(foo)[10].bar.baz = something_else();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +135,7 @@ ifs_6: {
|
|||||||
comparisons: true
|
comparisons: true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
|
var x;
|
||||||
if (!foo && !bar && !baz && !boo) {
|
if (!foo && !bar && !baz && !boo) {
|
||||||
x = 10;
|
x = 10;
|
||||||
} else {
|
} else {
|
||||||
@@ -140,6 +143,7 @@ ifs_6: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var x;
|
||||||
x = foo || bar || baz || boo ? 20 : 10;
|
x = foo || bar || baz || boo ? 20 : 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,6 +153,7 @@ cond_1: {
|
|||||||
conditionals: true
|
conditionals: true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
|
var do_something; // if undeclared it's assumed to have side-effects
|
||||||
if (some_condition()) {
|
if (some_condition()) {
|
||||||
do_something(x);
|
do_something(x);
|
||||||
} else {
|
} else {
|
||||||
@@ -156,6 +161,7 @@ cond_1: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var do_something;
|
||||||
do_something(some_condition() ? x : y);
|
do_something(some_condition() ? x : y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,6 +171,7 @@ cond_2: {
|
|||||||
conditionals: true
|
conditionals: true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
|
var x, FooBar;
|
||||||
if (some_condition()) {
|
if (some_condition()) {
|
||||||
x = new FooBar(1);
|
x = new FooBar(1);
|
||||||
} else {
|
} else {
|
||||||
@@ -172,6 +179,7 @@ cond_2: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var x, FooBar;
|
||||||
x = new FooBar(some_condition() ? 1 : 2);
|
x = new FooBar(some_condition() ? 1 : 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,6 +189,7 @@ cond_3: {
|
|||||||
conditionals: true
|
conditionals: true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
|
var FooBar;
|
||||||
if (some_condition()) {
|
if (some_condition()) {
|
||||||
new FooBar(1);
|
new FooBar(1);
|
||||||
} else {
|
} else {
|
||||||
@@ -188,6 +197,7 @@ cond_3: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var FooBar;
|
||||||
some_condition() ? new FooBar(1) : FooBar(2);
|
some_condition() ? new FooBar(1) : FooBar(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,6 +207,7 @@ cond_4: {
|
|||||||
conditionals: true
|
conditionals: true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
|
var do_something;
|
||||||
if (some_condition()) {
|
if (some_condition()) {
|
||||||
do_something();
|
do_something();
|
||||||
} else {
|
} else {
|
||||||
@@ -204,6 +215,7 @@ cond_4: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var do_something;
|
||||||
some_condition(), do_something();
|
some_condition(), do_something();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -303,6 +315,7 @@ cond_7_1: {
|
|||||||
evaluate : true
|
evaluate : true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
|
var x;
|
||||||
// access to global should be assumed to have side effects
|
// access to global should be assumed to have side effects
|
||||||
if (y) {
|
if (y) {
|
||||||
x = 1+1;
|
x = 1+1;
|
||||||
@@ -311,6 +324,7 @@ cond_7_1: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var x;
|
||||||
x = (y, 2);
|
x = (y, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,6 +335,7 @@ cond_8: {
|
|||||||
evaluate : true
|
evaluate : true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
|
var a;
|
||||||
// compress these
|
// compress these
|
||||||
a = condition ? true : false;
|
a = condition ? true : false;
|
||||||
|
|
||||||
@@ -355,6 +370,7 @@ cond_8: {
|
|||||||
|
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var a;
|
||||||
a = !!condition;
|
a = !!condition;
|
||||||
a = !condition;
|
a = !condition;
|
||||||
a = !!condition();
|
a = !!condition();
|
||||||
@@ -367,4 +383,4 @@ cond_8: {
|
|||||||
a = condition ? 0 : true;
|
a = condition ? 0 : true;
|
||||||
a = condition ? 1 : 0;
|
a = condition ? 1 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
unused_funarg_1: {
|
unused_funarg_1: {
|
||||||
options = { unused: true };
|
options = { unused: true, unsafe: true };
|
||||||
input: {
|
input: {
|
||||||
function f(a, b, c, d, e) {
|
function f(a, b, c, d, e) {
|
||||||
return a + b;
|
return a + b;
|
||||||
@@ -13,7 +13,7 @@ unused_funarg_1: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unused_funarg_2: {
|
unused_funarg_2: {
|
||||||
options = { unused: true };
|
options = { unused: true, unsafe: true };
|
||||||
input: {
|
input: {
|
||||||
function f(a, b, c, d, e) {
|
function f(a, b, c, d, e) {
|
||||||
return a + c;
|
return a + c;
|
||||||
@@ -165,7 +165,7 @@ used_var_in_catch: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
keep_fnames: {
|
keep_fnames: {
|
||||||
options = { unused: true, keep_fnames: true };
|
options = { unused: true, keep_fnames: true, unsafe: true };
|
||||||
input: {
|
input: {
|
||||||
function foo() {
|
function foo() {
|
||||||
return function bar(baz) {};
|
return function bar(baz) {};
|
||||||
@@ -176,4 +176,4 @@ keep_fnames: {
|
|||||||
return function bar() {};
|
return function bar() {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ NaN_and_Infinity_must_have_parens: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
(1/0).toString();
|
(1/0).toString();
|
||||||
(0/0).toString();
|
NaN.toString(); // transformation to 0/0 dropped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,12 @@ function run_compress_tests() {
|
|||||||
warnings: false
|
warnings: false
|
||||||
});
|
});
|
||||||
var cmp = new U.Compressor(options, true);
|
var cmp = new U.Compressor(options, true);
|
||||||
var expect = make_code(as_toplevel(test.expect), false);
|
var expect;
|
||||||
|
if (test.expect) {
|
||||||
|
expect = make_code(as_toplevel(test.expect), false);
|
||||||
|
} else {
|
||||||
|
expect = test.expect_exact;
|
||||||
|
}
|
||||||
var input = as_toplevel(test.input);
|
var input = as_toplevel(test.input);
|
||||||
var input_code = make_code(test.input);
|
var input_code = make_code(test.input);
|
||||||
var output = input.transform(cmp);
|
var output = input.transform(cmp);
|
||||||
@@ -150,7 +155,7 @@ function parse_test(file) {
|
|||||||
}
|
}
|
||||||
if (node instanceof U.AST_LabeledStatement) {
|
if (node instanceof U.AST_LabeledStatement) {
|
||||||
assert.ok(
|
assert.ok(
|
||||||
node.label.name == "input" || node.label.name == "expect",
|
node.label.name == "input" || node.label.name == "expect" || node.label.name == "expect_exact",
|
||||||
tmpl("Unsupported label {name} [{line},{col}]", {
|
tmpl("Unsupported label {name} [{line},{col}]", {
|
||||||
name: node.label.name,
|
name: node.label.name,
|
||||||
line: node.label.start.line,
|
line: node.label.start.line,
|
||||||
@@ -162,7 +167,16 @@ function parse_test(file) {
|
|||||||
if (stat.body.length == 1) stat = stat.body[0];
|
if (stat.body.length == 1) stat = stat.body[0];
|
||||||
else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
|
else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
|
||||||
}
|
}
|
||||||
test[node.label.name] = stat;
|
if (node.label.name === "expect_exact") {
|
||||||
|
if (!(stat.TYPE === "SimpleStatement" && stat.body.TYPE === "String")) {
|
||||||
|
throw new Error(
|
||||||
|
"The value of the expect_exact clause should be a string, " +
|
||||||
|
"like `expect_exact: \"some.exact.javascript;\"`");
|
||||||
|
}
|
||||||
|
test[node.label.name] = stat.body.start.value
|
||||||
|
} else {
|
||||||
|
test[node.label.name] = stat;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
5603
tools/domprops.json
Normal file
5603
tools/domprops.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,8 @@
|
|||||||
var path = require("path");
|
var path = require("path");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var vm = require("vm");
|
var vm = require("vm");
|
||||||
var sys = require("util");
|
|
||||||
|
|
||||||
var UglifyJS = vm.createContext({
|
var UglifyJS = vm.createContext({
|
||||||
sys : sys,
|
|
||||||
console : console,
|
console : console,
|
||||||
process : process,
|
process : process,
|
||||||
Buffer : Buffer,
|
Buffer : Buffer,
|
||||||
@@ -19,7 +17,7 @@ function load_global(file) {
|
|||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
// XXX: in case of a syntax error, the message is kinda
|
// XXX: in case of a syntax error, the message is kinda
|
||||||
// useless. (no location information).
|
// useless. (no location information).
|
||||||
sys.debug("ERROR in file: " + file + " / " + ex);
|
console.log("ERROR in file: " + file + " / " + ex);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -33,7 +31,8 @@ var FILES = exports.FILES = [
|
|||||||
"../lib/output.js",
|
"../lib/output.js",
|
||||||
"../lib/compress.js",
|
"../lib/compress.js",
|
||||||
"../lib/sourcemap.js",
|
"../lib/sourcemap.js",
|
||||||
"../lib/mozilla-ast.js"
|
"../lib/mozilla-ast.js",
|
||||||
|
"../lib/propmangle.js"
|
||||||
].map(function(file){
|
].map(function(file){
|
||||||
return fs.realpathSync(path.join(path.dirname(__filename), file));
|
return fs.realpathSync(path.join(path.dirname(__filename), file));
|
||||||
});
|
});
|
||||||
@@ -41,7 +40,7 @@ var FILES = exports.FILES = [
|
|||||||
FILES.forEach(load_global);
|
FILES.forEach(load_global);
|
||||||
|
|
||||||
UglifyJS.AST_Node.warn_function = function(txt) {
|
UglifyJS.AST_Node.warn_function = function(txt) {
|
||||||
sys.error("WARN: " + txt);
|
console.error("WARN: %s", txt);
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX: perhaps we shouldn't export everything but heck, I'm lazy.
|
// XXX: perhaps we shouldn't export everything but heck, I'm lazy.
|
||||||
@@ -192,3 +191,63 @@ exports.describe_ast = function() {
|
|||||||
doitem(UglifyJS.AST_Node);
|
doitem(UglifyJS.AST_Node);
|
||||||
return out + "";
|
return out + "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function readReservedFile(filename, reserved) {
|
||||||
|
if (!reserved) {
|
||||||
|
reserved = { vars: [], props: [] };
|
||||||
|
}
|
||||||
|
var data = fs.readFileSync(filename, "utf8");
|
||||||
|
data = JSON.parse(data);
|
||||||
|
if (data.vars) {
|
||||||
|
data.vars.forEach(function(name){
|
||||||
|
UglifyJS.push_uniq(reserved.vars, name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (data.props) {
|
||||||
|
data.props.forEach(function(name){
|
||||||
|
UglifyJS.push_uniq(reserved.props, name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return reserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.readReservedFile = readReservedFile;
|
||||||
|
|
||||||
|
exports.readDefaultReservedFile = function(reserved) {
|
||||||
|
return readReservedFile(path.join(__dirname, "domprops.json"), reserved);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.readNameCache = function(filename, key) {
|
||||||
|
var cache = null;
|
||||||
|
if (filename) {
|
||||||
|
try {
|
||||||
|
var cache = fs.readFileSync(filename, "utf8");
|
||||||
|
cache = JSON.parse(cache)[key];
|
||||||
|
if (!cache) throw "init";
|
||||||
|
cache.props = UglifyJS.Dictionary.fromObject(cache.props);
|
||||||
|
} catch(ex) {
|
||||||
|
cache = {
|
||||||
|
cname: -1,
|
||||||
|
props: new UglifyJS.Dictionary()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.writeNameCache = function(filename, key, cache) {
|
||||||
|
if (filename) {
|
||||||
|
var data;
|
||||||
|
try {
|
||||||
|
data = fs.readFileSync(filename, "utf8");
|
||||||
|
data = JSON.parse(data);
|
||||||
|
} catch(ex) {
|
||||||
|
data = {};
|
||||||
|
}
|
||||||
|
data[key] = {
|
||||||
|
cname: cache.cname,
|
||||||
|
props: cache.props.toObject()
|
||||||
|
};
|
||||||
|
fs.writeFileSync(filename, JSON.stringify(data, null, 2), "utf8");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
61
tools/props.html
Normal file
61
tools/props.html
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>(function(){
|
||||||
|
var props = {};
|
||||||
|
|
||||||
|
function addObject(obj) {
|
||||||
|
if (obj == null) return;
|
||||||
|
try {
|
||||||
|
Object.getOwnPropertyNames(obj).forEach(add);
|
||||||
|
} catch(ex) {}
|
||||||
|
if (obj.prototype) {
|
||||||
|
Object.getOwnPropertyNames(obj.prototype).forEach(add);
|
||||||
|
}
|
||||||
|
if (typeof obj == "function") {
|
||||||
|
try {
|
||||||
|
Object.getOwnPropertyNames(new obj).forEach(add);
|
||||||
|
} catch(ex) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(name) {
|
||||||
|
props[name] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.getOwnPropertyNames(window).forEach(function(thing){
|
||||||
|
addObject(window[thing]);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
addObject(new Event("click"));
|
||||||
|
addObject(new Event("contextmenu"));
|
||||||
|
addObject(new Event("mouseup"));
|
||||||
|
addObject(new Event("mousedown"));
|
||||||
|
addObject(new Event("keydown"));
|
||||||
|
addObject(new Event("keypress"));
|
||||||
|
addObject(new Event("keyup"));
|
||||||
|
} catch(ex) {}
|
||||||
|
|
||||||
|
var ta = document.createElement("textarea");
|
||||||
|
ta.style.width = "100%";
|
||||||
|
ta.style.height = "20em";
|
||||||
|
ta.style.boxSizing = "border-box";
|
||||||
|
<!-- ta.value = Object.keys(props).sort(cmp).map(function(name){ -->
|
||||||
|
<!-- return JSON.stringify(name); -->
|
||||||
|
<!-- }).join(",\n"); -->
|
||||||
|
ta.value = JSON.stringify({
|
||||||
|
vars: [],
|
||||||
|
props: Object.keys(props).sort(cmp)
|
||||||
|
}, null, 2);
|
||||||
|
document.body.appendChild(ta);
|
||||||
|
|
||||||
|
function cmp(a, b) {
|
||||||
|
a = a.toLowerCase();
|
||||||
|
b = b.toLowerCase();
|
||||||
|
return a < b ? -1 : a > b ? 1 : 0;
|
||||||
|
}
|
||||||
|
})();</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user