Compare commits

..

1 Commits

Author SHA1 Message Date
Mihai Bazon
c7d3c07f5a v2.4.17 2015-03-11 00:03:12 +02:00
35 changed files with 370 additions and 7602 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,2 @@
/node_modules/
/npm-debug.log
tmp/ tmp/
node_modules/

View File

@@ -1,9 +1,6 @@
language: node_js language: node_js
before_install: "npm install -g npm" before_install: "npm install -g npm"
node_js: node_js:
- "0.12" - "0.8"
- "0.10" - "0.10"
- "4" - "0.11"
matrix:
fast_finish: true
sudo: false

235
README.md
View File

@@ -52,90 +52,70 @@ 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 --source-map Specify an output file where to generate source map.
map. [string]
--source-map-root The path to the original source to be included --source-map-root The path to the original source to be included in the
in the source map. source map. [string]
--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 sourceMappingURL. Defaults to the value passed with
with --source-map. --source-map. [string]
--source-map-include-sources Pass this flag if you want to include the --source-map-include-sources
content of source files in the source map as Pass this flag if you want to include the content of
sourcesContent property. source files in the source map as sourcesContent
--in-source-map Input source map, useful if you're compressing property. [boolean]
JS that was generated from some other original --in-source-map Input source map, useful if you're compressing JS that was
code. generated from some other original code.
--screw-ie8 Pass this flag if you don't care about full --screw-ie8 Pass this flag if you don't care about full compliance
compliance with Internet Explorer 6-8 quirks with Internet Explorer 6-8 quirks (by default UglifyJS
(by default UglifyJS will try to be IE-proof). will try to be IE-proof). [boolean]
--expr Parse a single expression, rather than a --expr Parse a single expression, rather than a program (for
program (for parsing JSON) parsing JSON) [boolean]
-p, --prefix Skip prefix for original filenames that appear -p, --prefix Skip prefix for original filenames that appear in source
in source maps. For example -p 3 will drop 3 maps. For example -p 3 will drop 3 directories from file
directories from file names and ensure they are names and ensure they are relative paths. You can also
relative paths. You can also specify -p specify -p relative, which will make UglifyJS figure out
relative, which will make UglifyJS figure out itself the relative paths between original sources, the
itself the relative paths between original source map and the output file. [string]
sources, the source map and the output file. -o, --output Output file (default STDOUT).
-o, --output Output file (default STDOUT). -b, --beautify Beautify output/specify output options. [string]
-b, --beautify Beautify output/specify output options. -m, --mangle Mangle names/pass mangler options. [string]
-m, --mangle Mangle names/pass mangler options. -r, --reserved Reserved names to exclude from mangling.
-r, --reserved Reserved names to exclude from mangling. -c, --compress Enable compressor/pass compressor options. Pass options
-c, --compress Enable compressor/pass compressor options. Pass like -c hoist_vars=false,if_return=false. Use -c with no
options like -c argument to use the default compression options. [string]
hoist_vars=false,if_return=false. Use -c with -d, --define Global definitions [string]
no argument to use the default compression -e, --enclose Embed everything in a big function, with a configurable
options. parameter/argument list. [string]
-d, --define Global definitions --comments Preserve copyright comments in the output. By default this
-e, --enclose Embed everything in a big function, with a works like Google Closure, keeping JSDoc-style comments
configurable parameter/argument list. that contain "@license" or "@preserve". You can optionally
--comments Preserve copyright comments in the output. By pass one of the following arguments to this flag:
default this works like Google Closure, keeping - "all" to keep all comments
JSDoc-style comments that contain "@license" or - a valid JS regexp (needs to start with a slash) to keep
"@preserve". You can optionally pass one of the only comments that match.
following arguments to this flag: Note that currently not *all* comments can be kept when
- "all" to keep all comments compression is on, because of dead code removal or
- a valid JS regexp (needs to start with a cascading statements into sequences. [string]
slash) to keep only comments that match. --preamble Preamble to prepend to the output. You can use this to
Note that currently not *all* comments can be insert a comment, for example for licensing information.
kept when compression is on, because of dead This will not be parsed, but the source map will adjust
code removal or cascading statements into for its presence.
sequences. --stats Display operations run time on STDERR. [boolean]
--preamble Preamble to prepend to the output. You can use --acorn Use Acorn for parsing. [boolean]
this to insert a comment, for example for --spidermonkey Assume input files are SpiderMonkey AST format (as JSON).
licensing information. This will not be [boolean]
parsed, but the source map will adjust for its --self Build itself (UglifyJS2) as a library (implies
presence. --wrap=UglifyJS --export-all) [boolean]
--stats Display operations run time on STDERR. --wrap Embed everything in a big function, making the “exports”
--acorn Use Acorn for parsing. and “global” variables available. You need to pass an
--spidermonkey Assume input files are SpiderMonkey AST format argument to this option to specify the name that your
(as JSON). module will take when included in, say, a browser.
--self Build itself (UglifyJS2) as a library (implies [string]
--wrap=UglifyJS --export-all) --export-all Only used when --wrap, this tells UglifyJS to add code to
--wrap Embed everything in a big function, making the automatically export all globals. [boolean]
“exports” and “global” variables available. You --lint Display some scope warnings [boolean]
need to pass an argument to this option to -v, --verbose Verbose [boolean]
specify the name that your module will take -V, --version Print version number and exit. [boolean]
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
--mangle-regex Only mangle property names matching the regex
--name-cache File to hold mangled names mappings
--pure-funcs List of functions that can be safely removed if
their return value is not used [array]
``` ```
Specify `--output` (`-o`) to declare the output file. Otherwise the output Specify `--output` (`-o`) to declare the output file. Otherwise the output
@@ -209,73 +189,6 @@ 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.
You can also use a regular expression to define which property names should be
mangled. For example, `--mangle-regex="/^_/"` will only mangle property names
that start with an underscore.
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
@@ -352,11 +265,6 @@ to set `true`; it's effectively a shortcut for `foo=true`).
compressor from discarding unused function arguments. You need this compressor from discarding unused function arguments. You need this
for code which relies on `Function.length`. for code which relies on `Function.length`.
- `keep_fnames` -- default `false`. Pass `true` to prevent the
compressor from mangling/discarding function names. Useful for code relying on
`Function.prototype.name`.
### The `unsafe` option ### The `unsafe` option
It enables some transformations that *might* break code logic in certain It enables some transformations that *might* break code logic in certain
@@ -364,15 +272,14 @@ 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
@@ -603,16 +510,6 @@ 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).

View File

@@ -1,77 +0,0 @@
#! /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;
}
}

View File

@@ -67,13 +67,6 @@ 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("mangle-regex", "Only mangle property names matching the regex")
.describe("name-cache", "File to hold mangled names mappings")
.describe("pure-funcs", "List of functions that can be safely removed if their return value is not used")
.describe("dump-spidermonkey-ast", "Dump SpiderMonkey AST to stdout.")
.alias("p", "prefix") .alias("p", "prefix")
.alias("o", "output") .alias("o", "output")
@@ -91,22 +84,13 @@ 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")
.array("pure-funcs")
.boolean("expr") .boolean("expr")
.boolean("source-map-include-sources") .boolean("source-map-include-sources")
@@ -114,19 +98,14 @@ 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("dump-spidermonkey-ast")
.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)
@@ -137,24 +116,24 @@ normalize(ARGS);
if (ARGS.noerr) { if (ARGS.noerr) {
UglifyJS.DefaultsError.croak = function(msg, defs) { UglifyJS.DefaultsError.croak = function(msg, defs) {
print_error("WARN: " + msg); sys.error("WARN: " + msg);
}; };
} }
if (ARGS.version || ARGS.V) { if (ARGS.version || ARGS.V) {
var json = require("../package.json"); var json = require("../package.json");
print(json.name + ' ' + json.version); sys.puts(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();
print(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2)); sys.puts(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) {
print(yargs.help()); sys.puts(yargs.help());
process.exit(0); process.exit(0);
} }
@@ -165,50 +144,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");
} }
if (ARGS.pure_funcs) {
if (COMPRESS) COMPRESS.pure_funcs = ARGS.pure_funcs;
}
if (ARGS.r) { 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);
}
function extractRegex(str) {
if (/^\/.*\/[a-zA-Z]*$/.test(str)) {
var regex_pos = str.lastIndexOf("/");
return new RegExp(str.substr(1, regex_pos - 1), str.substr(regex_pos + 1));
} else {
throw new Error("Invalid regular expression: " + str);
}
}
if (ARGS.quotes === true) { if (ARGS.quotes === true) {
ARGS.quotes = 3; ARGS.quotes = 3;
} }
@@ -233,12 +177,13 @@ if (ARGS.keep_fnames) {
if (BEAUTIFY) if (BEAUTIFY)
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY); UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
if (ARGS.comments != null) { if (ARGS.comments) {
if (/^\/.*\/[a-zA-Z]*$/.test(ARGS.comments)) { if (/^\/.*\/[a-zA-Z]*$/.test(ARGS.comments)) {
var regex_pos = ARGS.comments.lastIndexOf("/");
try { try {
OUTPUT_OPTIONS.comments = extractRegex(ARGS.comments); OUTPUT_OPTIONS.comments = new RegExp(ARGS.comments.substr(1, regex_pos - 1), ARGS.comments.substr(regex_pos + 1));
} catch (e) { } catch (e) {
print_error("ERROR: Invalid --comments: " + e.message); sys.error("ERROR: Invalid --comments: " + e.message);
} }
} else if (ARGS.comments == "all") { } else if (ARGS.comments == "all") {
OUTPUT_OPTIONS.comments = true; OUTPUT_OPTIONS.comments = true;
@@ -258,10 +203,11 @@ var files = ARGS._.slice();
if (ARGS.self) { if (ARGS.self) {
if (files.length > 0) { if (files.length > 0) {
print_error("WARN: Ignoring input files since --self was passed"); sys.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";
ARGS.export_all = true;
} }
var ORIG_MAP = ARGS.in_source_map; var ORIG_MAP = ARGS.in_source_map;
@@ -269,7 +215,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) {
print_error("INFO: Using file from the input source map: " + ORIG_MAP.file); sys.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) {
@@ -282,12 +228,12 @@ if (files.length == 0) {
} }
if (files.indexOf("-") >= 0 && ARGS.source_map) { if (files.indexOf("-") >= 0 && ARGS.source_map) {
print_error("ERROR: Source map doesn't work with input from STDIN"); sys.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) {
print_error("ERROR: Can read a single file from STDIN (two or more dashes specified)"); sys.error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
process.exit(1); process.exit(1);
} }
@@ -310,9 +256,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) {
print_error(ex.msg); sys.error(ex.msg);
print_error("Supported options:"); sys.error("Supported options:");
print_error(sys.inspect(ex.defs)); sys.error(sys.inspect(ex.defs));
process.exit(1); process.exit(1);
} }
} }
@@ -320,7 +266,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) {
print_error("ERROR: can't read file: " + file); sys.error("ERROR: can't read file: " + file);
process.exit(1); process.exit(1);
} }
if (ARGS.p != null) { if (ARGS.p != null) {
@@ -357,9 +303,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) {
print_error("Parse error at " + file + ":" + ex.line + "," + ex.col); sys.error("Parse error at " + file + ":" + ex.line + "," + ex.col);
print_error(ex.message); sys.error(ex.message);
print_error(ex.stack); sys.error(ex.stack);
process.exit(1); process.exit(1);
} }
throw ex; throw ex;
@@ -373,11 +319,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 != null) { if (ARGS.wrap) {
TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all); TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all);
} }
if (ARGS.enclose != null) { if (ARGS.enclose) {
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 = [];
@@ -388,33 +334,11 @@ 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 SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint;
var reserved = RESERVED ? RESERVED.props : null;
var cache = readNameCache("props");
var regex;
try {
regex = ARGS.mangle_regex ? extractRegex(ARGS.mangle_regex) : null;
} catch (e) {
print_error("ERROR: Invalid --mangle-regex: " + e.message);
process.exit(1);
}
TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, {
reserved : reserved,
cache : cache,
only_cache : !ARGS.mangle_props,
regex : regex
});
writeNameCache("props", cache);
})();
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, cache: TL_CACHE }); TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8 });
if (ARGS.lint) { if (ARGS.lint) {
TOPLEVEL.scope_warnings(); TOPLEVEL.scope_warnings();
} }
@@ -429,20 +353,17 @@ 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, cache: TL_CACHE }); TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8 });
if (MANGLE && !TL_CACHE) { if (MANGLE) {
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)) {
@@ -451,38 +372,34 @@ async.eachLimit(files, 1, function (file, cb) {
} }
} }
if (ARGS.dump_spidermonkey_ast) { time_it("generate", function(){
print(JSON.stringify(TOPLEVEL.to_mozilla_ast(), null, 2)); TOPLEVEL.print(output);
});
output = output.get();
if (SOURCE_MAP) {
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
var source_map_url = ARGS.source_map_url || (
P_RELATIVE
? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map)
: ARGS.source_map
);
output += "\n//# sourceMappingURL=" + source_map_url;
}
if (OUTPUT_FILE) {
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
} else { } else {
time_it("generate", function(){ sys.print(output);
TOPLEVEL.print(output);
});
output = output.get();
if (SOURCE_MAP) {
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
var source_map_url = ARGS.source_map_url || (
P_RELATIVE
? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map)
: ARGS.source_map
);
output += "\n//# sourceMappingURL=" + source_map_url;
}
if (OUTPUT_FILE) {
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
} else {
print(output);
}
} }
if (ARGS.stats) { if (ARGS.stats) {
print_error(UglifyJS.string_template("Timing information (compressed {count} files):", { sys.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)) {
print_error(UglifyJS.string_template("- {name}: {time}s", { sys.error(UglifyJS.string_template("- {name}: {time}s", {
name: i, name: i,
time: (STATS[i] / 1000).toFixed(3) time: (STATS[i] / 1000).toFixed(3)
})); }));
@@ -501,15 +418,15 @@ function normalize(o) {
function getOptions(x, constants) { function getOptions(x, constants) {
x = ARGS[x]; x = ARGS[x];
if (x == null) return null; if (!x) return null;
var ret = {}; var ret = {};
if (x !== "") { if (x !== true) {
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) {
print_error("Error parsing arguments in: " + x); sys.error("Error parsing arguments in: " + x);
process.exit(1); process.exit(1);
} }
} }
@@ -528,8 +445,8 @@ function getOptions(x, constants) {
ret[name] = true; ret[name] = true;
return true; // no descend return true; // no descend
} }
print_error(node.TYPE) sys.error(node.TYPE)
print_error("Error parsing arguments in: " + x); sys.error("Error parsing arguments in: " + x);
process.exit(1); process.exit(1);
})); }));
} }
@@ -561,11 +478,3 @@ function time_it(name, cont) {
} }
return ret; return ret;
} }
function print_error(msg) {
console.error("%s", msg);
}
function print(txt) {
console.log("%s", txt);
}

View File

@@ -81,11 +81,10 @@ function DEFNODE(type, props, methods, base) {
ctor.DEFMETHOD = function(name, method) { ctor.DEFMETHOD = function(name, method) {
this.prototype[name] = method; this.prototype[name] = method;
}; };
exports["AST_" + type] = ctor;
return ctor; return ctor;
}; };
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file raw", { var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file", {
}, null); }, null);
var AST_Node = DEFNODE("Node", "start end", { var AST_Node = DEFNODE("Node", "start end", {
@@ -330,11 +329,12 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
} }
})); }));
} }
var wrapped_tl = "(function(exports, global){ '$ORIG'; '$EXPORTS'; global['" + name + "'] = exports; }({}, (function(){return this}())))"; var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))";
wrapped_tl = parse(wrapped_tl); wrapped_tl = parse(wrapped_tl);
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){ wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
if (node instanceof AST_Directive) { if (node instanceof AST_SimpleStatement) {
switch (node.value) { node = node.body;
if (node instanceof AST_String) switch (node.getValue()) {
case "$ORIG": case "$ORIG":
return MAP.splice(self.body); return MAP.splice(self.body);
case "$EXPORTS": case "$EXPORTS":
@@ -864,11 +864,10 @@ var AST_String = DEFNODE("String", "value quote", {
} }
}, AST_Constant); }, AST_Constant);
var AST_Number = DEFNODE("Number", "value literal", { var AST_Number = DEFNODE("Number", "value", {
$documentation: "A number literal", $documentation: "A number literal",
$propdoc: { $propdoc: {
value: "[number] the numeric value", value: "[number] the numeric value"
literal: "[string] numeric value as string (optional)"
} }
}, AST_Constant); }, AST_Constant);
@@ -927,36 +926,27 @@ var AST_True = DEFNODE("True", null, {
function TreeWalker(callback) { function TreeWalker(callback) {
this.visit = callback; this.visit = callback;
this.stack = []; this.stack = [];
this.directives = Object.create(null);
}; };
TreeWalker.prototype = { TreeWalker.prototype = {
_visit: function(node, descend) { _visit: function(node, descend) {
this.push(node); this.stack.push(node);
var ret = this.visit(node, descend ? function(){ var ret = this.visit(node, descend ? function(){
descend.call(node); descend.call(node);
} : noop); } : noop);
if (!ret && descend) { if (!ret && descend) {
descend.call(node); descend.call(node);
} }
this.pop(node); this.stack.pop();
return ret; return ret;
}, },
parent: function(n) { parent: function(n) {
return this.stack[this.stack.length - 2 - (n || 0)]; return this.stack[this.stack.length - 2 - (n || 0)];
}, },
push: function (node) { push: function (node) {
if (node instanceof AST_Lambda) {
this.directives = Object.create(this.directives);
} else if (node instanceof AST_Directive) {
this.directives[node.value] = this.directives[node.value] ? "up" : true;
}
this.stack.push(node); this.stack.push(node);
}, },
pop: function(node) { pop: function() {
this.stack.pop(); return this.stack.pop();
if (node instanceof AST_Lambda) {
this.directives = Object.getPrototypeOf(this.directives);
}
}, },
self: function() { self: function() {
return this.stack[this.stack.length - 1]; return this.stack[this.stack.length - 1];
@@ -969,16 +959,7 @@ TreeWalker.prototype = {
} }
}, },
has_directive: function(type) { has_directive: function(type) {
var dir = this.directives[type]; return this.find_parent(AST_Scope).has_directive(type);
if (dir) return dir;
var node = this.stack[this.stack.length - 1];
if (node instanceof AST_Scope) {
for (var i = 0; i < node.body.length; ++i) {
var st = node.body[i];
if (!(st instanceof AST_Directive)) break;
if (st.value == type) return true;
}
}
}, },
in_boolean_context: function() { in_boolean_context: function() {
var stack = this.stack; var stack = this.stack;

View File

@@ -61,7 +61,7 @@ function Compressor(options, false_by_default) {
loops : !false_by_default, loops : !false_by_default,
unused : !false_by_default, unused : !false_by_default,
hoist_funs : !false_by_default, hoist_funs : !false_by_default,
keep_fargs : true, keep_fargs : false,
keep_fnames : false, keep_fnames : false,
hoist_vars : false, hoist_vars : false,
if_return : !false_by_default, if_return : !false_by_default,
@@ -111,7 +111,6 @@ merge(Compressor.prototype, {
node.DEFMETHOD("optimize", function(compressor){ node.DEFMETHOD("optimize", function(compressor){
var self = this; var self = this;
if (self._optimized) return self; if (self._optimized) return self;
if (compressor.has_directive("use asm")) return self;
var opt = optimizer(self, compressor); var opt = optimizer(self, compressor);
opt._optimized = true; opt._optimized = true;
if (opt === self) return opt; if (opt === self) return opt;
@@ -490,7 +489,7 @@ merge(Compressor.prototype, {
seq = []; seq = [];
}; };
statements.forEach(function(stat){ statements.forEach(function(stat){
if (stat instanceof AST_SimpleStatement && seq.length < 2000) seq.push(stat.body); if (stat instanceof AST_SimpleStatement) seq.push(stat.body);
else push_seq(), ret.push(stat); else push_seq(), ret.push(stat);
}); });
push_seq(); push_seq();
@@ -897,7 +896,6 @@ merge(Compressor.prototype, {
def(AST_Call, function(compressor){ def(AST_Call, function(compressor){
var pure = compressor.option("pure_funcs"); var pure = compressor.option("pure_funcs");
if (!pure) return true; if (!pure) return true;
if (typeof pure == "function") return pure(this);
return pure.indexOf(this.expression.print_to_string()) < 0; return pure.indexOf(this.expression.print_to_string()) < 0;
}); });
@@ -991,7 +989,7 @@ merge(Compressor.prototype, {
/* -----[ optimizers ]----- */ /* -----[ optimizers ]----- */
OPT(AST_Directive, function(self, compressor){ OPT(AST_Directive, function(self, compressor){
if (compressor.has_directive(self.value) === "up") { if (self.scope.has_directive(self.value) !== self.scope) {
return make_node(AST_EmptyStatement, self); return make_node(AST_EmptyStatement, self);
} }
return self; return self;
@@ -1027,7 +1025,6 @@ merge(Compressor.prototype, {
AST_Scope.DEFMETHOD("drop_unused", function(compressor){ AST_Scope.DEFMETHOD("drop_unused", function(compressor){
var self = this; var self = this;
if (compressor.has_directive("use asm")) return self;
if (compressor.option("unused") if (compressor.option("unused")
&& !(self instanceof AST_Toplevel) && !(self instanceof AST_Toplevel)
&& !self.uses_eval && !self.uses_eval
@@ -1171,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 in_list ? MAP.splice(side_effects.body) : side_effects; return side_effects;
} }
node.definitions = def; node.definitions = def;
if (side_effects) { if (side_effects) {
side_effects.body.unshift(node); side_effects.body.unshift(node);
return in_list ? MAP.splice(side_effects.body) : side_effects; node = side_effects;
} }
return node; return node;
} }
@@ -1207,10 +1204,9 @@ merge(Compressor.prototype, {
}); });
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){ AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
var self = this;
if (compressor.has_directive("use asm")) return self;
var hoist_funs = compressor.option("hoist_funs"); var hoist_funs = compressor.option("hoist_funs");
var hoist_vars = compressor.option("hoist_vars"); var hoist_vars = compressor.option("hoist_vars");
var self = this;
if (hoist_funs || hoist_vars) { if (hoist_funs || hoist_vars) {
var dirs = []; var dirs = [];
var hoisted = []; var hoisted = [];
@@ -1913,11 +1909,15 @@ merge(Compressor.prototype, {
if (!compressor.option("side_effects")) if (!compressor.option("side_effects"))
return self; return self;
if (!self.car.has_side_effects(compressor)) { if (!self.car.has_side_effects(compressor)) {
// we shouldn't compress (1,func)(something) to // we shouldn't compress (1,eval)(something) to
// func(something) because that changes the meaning of // eval(something) because that changes the meaning of
// the func (becomes lexical instead of global). // eval (becomes lexical instead of global).
var p = compressor.parent(); var p;
if (!(p instanceof AST_Call && p.expression === self)) { if (!(self.cdr instanceof AST_SymbolRef
&& self.cdr.name == "eval"
&& self.cdr.undeclared()
&& (p = compressor.parent()) instanceof AST_Call
&& p.expression === self)) {
return self.cdr; return self.cdr;
} }
} }
@@ -2031,14 +2031,15 @@ merge(Compressor.prototype, {
var commutativeOperators = makePredicate("== === != !== * & | ^"); var commutativeOperators = makePredicate("== === != !== * & | ^");
OPT(AST_Binary, function(self, compressor){ OPT(AST_Binary, function(self, compressor){
function reverse(op, force) { var reverse = compressor.has_directive("use asm") ? noop
if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) { : function(op, force) {
if (op) self.operator = op; if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) {
var tmp = self.left; if (op) self.operator = op;
self.left = self.right; var tmp = self.left;
self.right = tmp; self.left = self.right;
} self.right = tmp;
} }
};
if (commutativeOperators(self.operator)) { if (commutativeOperators(self.operator)) {
if (self.right instanceof AST_Constant if (self.right instanceof AST_Constant
&& !(self.left instanceof AST_Constant)) { && !(self.left instanceof AST_Constant)) {
@@ -2103,34 +2104,6 @@ merge(Compressor.prototype, {
} }
break; break;
} }
if (compressor.option("conditionals")) {
if (self.operator == "&&") {
var ll = self.left.evaluate(compressor);
if (ll.length > 1) {
if (ll[1]) {
compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
var rr = self.right.evaluate(compressor);
return rr[0];
} else {
compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
return ll[0];
}
}
}
else if (self.operator == "||") {
var ll = self.left.evaluate(compressor);
if (ll.length > 1) {
if (ll[1]) {
compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start);
return ll[0];
} else {
compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start);
var rr = self.right.evaluate(compressor);
return rr[0];
}
}
}
}
if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) { if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
case "&&": case "&&":
var ll = self.left.evaluate(compressor); var ll = self.left.evaluate(compressor);
@@ -2182,7 +2155,7 @@ merge(Compressor.prototype, {
} }
break; break;
} }
if (compressor.option("comparisons") && self.is_boolean()) { if (compressor.option("comparisons")) {
if (!(compressor.parent() instanceof AST_Binary) if (!(compressor.parent() instanceof AST_Binary)
|| compressor.parent() instanceof AST_Assign) { || compressor.parent() instanceof AST_Assign) {
var negated = make_node(AST_UnaryPrefix, self, { var negated = make_node(AST_UnaryPrefix, self, {
@@ -2257,11 +2230,10 @@ merge(Compressor.prototype, {
} }
} }
} }
// x && (y && z) ==> x && y && z // x * (y * z) ==> x * y * z
// x || (y || z) ==> x || y || z
if (self.right instanceof AST_Binary if (self.right instanceof AST_Binary
&& self.right.operator == self.operator && self.right.operator == self.operator
&& (self.operator == "&&" || self.operator == "||")) && (self.operator == "*" || self.operator == "&&" || self.operator == "||"))
{ {
self.left = make_node(AST_Binary, self.left, { self.left = make_node(AST_Binary, self.left, {
operator : self.operator, operator : self.operator,
@@ -2275,15 +2247,7 @@ merge(Compressor.prototype, {
}); });
OPT(AST_SymbolRef, function(self, compressor){ OPT(AST_SymbolRef, function(self, compressor){
function isLHS(symbol, parent) { if (self.undeclared()) {
return (
parent instanceof AST_Binary &&
parent.operator === '=' &&
parent.left === symbol
);
}
if (self.undeclared() && !isLHS(self, compressor.parent())) {
var defines = compressor.option("global_defs"); var defines = compressor.option("global_defs");
if (defines && defines.hasOwnProperty(self.name)) { if (defines && defines.hasOwnProperty(self.name)) {
return make_node_from_constant(compressor, defines[self.name], self); return make_node_from_constant(compressor, defines[self.name], self);
@@ -2303,8 +2267,16 @@ 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, self, {value: 1}), left : make_node(AST_Number, null, {value: 1}),
right : make_node(AST_Number, self, {value: 0}) right : make_node(AST_Number, null, {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})
}); });
}); });
@@ -2371,7 +2343,6 @@ 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:
@@ -2392,7 +2363,6 @@ 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, {
@@ -2510,7 +2480,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() && !self.has_side_effects(compressor)) { if (compressor.option("booleans") && compressor.in_boolean_context()) {
return make_node(AST_True, self); return make_node(AST_True, self);
} }
return self; return self;
@@ -2519,11 +2489,4 @@ merge(Compressor.prototype, {
OPT(AST_Object, literals_in_boolean_context); OPT(AST_Object, literals_in_boolean_context);
OPT(AST_RegExp, literals_in_boolean_context); OPT(AST_RegExp, literals_in_boolean_context);
OPT(AST_Return, function(self, compressor){
if (self.value instanceof AST_Undefined) {
self.value = null;
}
return self;
});
})(); })();

View File

@@ -146,14 +146,7 @@
case "boolean": case "boolean":
return new (val ? AST_True : AST_False)(args); return new (val ? AST_True : AST_False)(args);
default: default:
var rx = M.regex; args.value = val;
if (rx && rx.pattern) {
// RegExpLiteral as per ESTree AST spec
args.value = new RegExp(rx.pattern, rx.flags).toString();
} else {
// support legacy RegExp
args.value = M.regex && M.raw ? M.raw : val;
}
return new AST_RegExp(args); return new AST_RegExp(args);
} }
}, },
@@ -341,19 +334,6 @@
}; };
}); });
def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
var value = M.value;
return {
type: "Literal",
value: value,
raw: value.toString(),
regex: {
pattern: value.source,
flags: value.toString().match(/[gimuy]*$/)[0]
}
};
});
def_to_moz(AST_Constant, function To_Moz_Literal(M) { def_to_moz(AST_Constant, function To_Moz_Literal(M) {
var value = M.value; var value = M.value;
if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) { if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) {
@@ -363,15 +343,13 @@
prefix: true, prefix: true,
argument: { argument: {
type: "Literal", type: "Literal",
value: -value, value: -value
raw: M.start.raw
} }
}; };
} }
return { return {
type: "Literal", type: "Literal",
value: value, value: value
raw: M.start.raw
}; };
}); });
@@ -391,12 +369,6 @@
/* -----[ tools ]----- */ /* -----[ tools ]----- */
function raw_token(moznode) {
if (moznode.type == "Literal") {
return moznode.raw != null ? moznode.raw : moznode.value + "";
}
}
function my_start_token(moznode) { function my_start_token(moznode) {
var loc = moznode.loc, start = loc && loc.start; var loc = moznode.loc, start = loc && loc.start;
var range = moznode.range; var range = moznode.range;
@@ -407,8 +379,7 @@
pos : range ? range[0] : moznode.start, pos : range ? range[0] : moznode.start,
endline : start && start.line, endline : start && start.line,
endcol : start && start.column, endcol : start && start.column,
endpos : range ? range[0] : moznode.start, endpos : range ? range[0] : moznode.start
raw : raw_token(moznode),
}); });
}; };
@@ -422,14 +393,13 @@
pos : range ? range[1] : moznode.end, pos : range ? range[1] : moznode.end,
endline : end && end.line, endline : end && end.line,
endcol : end && end.column, endcol : end && end.column,
endpos : range ? range[1] : moznode.end, endpos : range ? range[1] : moznode.end
raw : raw_token(moznode),
}); });
}; };
function map(moztype, mytype, propmap) { function map(moztype, mytype, propmap) {
var moz_to_me = "function From_Moz_" + moztype + "(M){\n"; var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
moz_to_me += "return new U2." + mytype.name + "({\n" + moz_to_me += "return new " + mytype.name + "({\n" +
"start: my_start_token(M),\n" + "start: my_start_token(M),\n" +
"end: my_end_token(M)"; "end: my_end_token(M)";
@@ -472,8 +442,8 @@
//me_to_moz = parse(me_to_moz).print_to_string({ beautify: true }); //me_to_moz = parse(me_to_moz).print_to_string({ beautify: true });
//console.log(moz_to_me); //console.log(moz_to_me);
moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( moz_to_me = new Function("my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
exports, my_start_token, my_end_token, from_moz my_start_token, my_end_token, from_moz
); );
me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")( me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")(
to_moz, to_moz_block to_moz, to_moz_block

View File

@@ -60,7 +60,6 @@ function OutputStream(options) {
bracketize : false, bracketize : false,
semicolons : true, semicolons : true,
comments : false, comments : false,
shebang : true,
preserve_line : false, preserve_line : false,
screw_ie8 : false, screw_ie8 : false,
preamble : null, preamble : null,
@@ -88,14 +87,13 @@ function OutputStream(options) {
function make_string(str, quote) { function make_string(str, quote) {
var dq = 0, sq = 0; var dq = 0, sq = 0;
str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s){ str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s){
switch (s) { switch (s) {
case "\\": return "\\\\"; case "\\": return "\\\\";
case "\b": return "\\b"; case "\b": return "\\b";
case "\f": return "\\f"; case "\f": return "\\f";
case "\n": return "\\n"; case "\n": return "\\n";
case "\r": return "\\r"; case "\r": return "\\r";
case "\x0B": return options.screw_ie8 ? "\\v" : "\\x0B";
case "\u2028": return "\\u2028"; case "\u2028": return "\\u2028";
case "\u2029": return "\\u2029"; case "\u2029": return "\\u2029";
case '"': ++dq; return '"'; case '"': ++dq; return '"';
@@ -126,11 +124,8 @@ function OutputStream(options) {
function encode_string(str, quote) { function encode_string(str, quote) {
var ret = make_string(str, quote); var ret = make_string(str, quote);
if (options.inline_script) { if (options.inline_script)
ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
ret = ret.replace(/\x3c!--/g, "\\x3c!--");
ret = ret.replace(/--\x3e/g, "--\\x3e");
}
return ret; return ret;
}; };
@@ -166,8 +161,6 @@ function OutputStream(options) {
str = String(str); str = String(str);
var ch = str.charAt(0); var ch = str.charAt(0);
if (might_need_semicolon) { if (might_need_semicolon) {
might_need_semicolon = false;
if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) { if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {
if (options.semicolons || requireSemicolonChars(ch)) { if (options.semicolons || requireSemicolonChars(ch)) {
OUTPUT += ";"; OUTPUT += ";";
@@ -178,17 +171,12 @@ function OutputStream(options) {
current_pos++; current_pos++;
current_line++; current_line++;
current_col = 0; current_col = 0;
if (/^\s+$/.test(str)) {
// reset the semicolon flag, since we didn't print one
// now and might still have to later
might_need_semicolon = true;
}
} }
if (!options.beautify) if (!options.beautify)
might_need_space = false; might_need_space = 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]) {
@@ -382,13 +370,8 @@ function OutputStream(options) {
nodetype.DEFMETHOD("_codegen", generator); nodetype.DEFMETHOD("_codegen", generator);
}; };
var use_asm = false;
AST_Node.DEFMETHOD("print", function(stream, force_parens){ AST_Node.DEFMETHOD("print", function(stream, force_parens){
var self = this, generator = self._codegen, prev_use_asm = use_asm; var self = this, generator = self._codegen;
if (self instanceof AST_Directive && self.value == "use asm") {
use_asm = true;
}
function doit() { function doit() {
self.add_comments(stream); self.add_comments(stream);
self.add_source_map(stream); self.add_source_map(stream);
@@ -401,9 +384,6 @@ function OutputStream(options) {
doit(); doit();
} }
stream.pop_node(); stream.pop_node();
if (self instanceof AST_Lambda) {
use_asm = prev_use_asm;
}
}); });
AST_Node.DEFMETHOD("print_to_string", function(options){ AST_Node.DEFMETHOD("print_to_string", function(options){
@@ -416,69 +396,63 @@ function OutputStream(options) {
AST_Node.DEFMETHOD("add_comments", function(output){ AST_Node.DEFMETHOD("add_comments", function(output){
var c = output.option("comments"), self = this; var c = output.option("comments"), self = this;
var start = self.start; if (c) {
if (start && !start._comments_dumped) { var start = self.start;
start._comments_dumped = true; if (start && !start._comments_dumped) {
var comments = start.comments_before || []; start._comments_dumped = true;
var comments = start.comments_before || [];
// XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112 // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
// and https://github.com/mishoo/UglifyJS2/issues/372 // and https://github.com/mishoo/UglifyJS2/issues/372
if (self instanceof AST_Exit && self.value) { if (self instanceof AST_Exit && self.value) {
self.value.walk(new TreeWalker(function(node){ self.value.walk(new TreeWalker(function(node){
if (node.start && node.start.comments_before) { if (node.start && node.start.comments_before) {
comments = comments.concat(node.start.comments_before); comments = comments.concat(node.start.comments_before);
node.start.comments_before = []; node.start.comments_before = [];
} }
if (node instanceof AST_Function || if (node instanceof AST_Function ||
node instanceof AST_Array || node instanceof AST_Array ||
node instanceof AST_Object) node instanceof AST_Object)
{ {
return true; // don't go inside. return true; // don't go inside.
} }
})); }));
}
if (!c) {
comments = comments.filter(function(comment) {
return comment.type == "comment5";
});
} else if (c.test) {
comments = comments.filter(function(comment){
return c.test(comment.value) || comment.type == "comment5";
});
} else if (typeof c == "function") {
comments = comments.filter(function(comment){
return c(self, comment) || comment.type == "comment5";
});
}
// Keep single line comments after nlb, after nlb
if (!output.option("beautify") && comments.length > 0 &&
/comment[134]/.test(comments[0].type) &&
output.col() !== 0 && comments[0].nlb)
{
output.print("\n");
}
comments.forEach(function(c){
if (/comment[134]/.test(c.type)) {
output.print("//" + c.value + "\n");
output.indent();
} }
else if (c.type == "comment2") {
output.print("/*" + c.value + "*/"); if (c.test) {
if (start.nlb) { comments = comments.filter(function(comment){
output.print("\n"); return c.test(comment.value);
});
} else if (typeof c == "function") {
comments = comments.filter(function(comment){
return c(self, comment);
});
}
// Keep single line comments after nlb, after nlb
if (!output.option("beautify") && comments.length > 0 &&
/comment[134]/.test(comments[0].type) &&
output.col() !== 0 && comments[0].nlb)
{
output.print("\n");
}
comments.forEach(function(c){
if (/comment[134]/.test(c.type)) {
output.print("//" + c.value + "\n");
output.indent(); output.indent();
} else {
output.space();
} }
} else if (c.type == "comment2") {
else if (output.pos() === 0 && c.type == "comment5" && output.option("shebang")) { output.print("/*" + c.value + "*/");
output.print("#!" + c.value + "\n"); if (start.nlb) {
output.indent(); output.print("\n");
} output.indent();
}); } else {
output.space();
}
}
});
}
} }
}); });
@@ -1057,24 +1031,16 @@ function OutputStream(options) {
output.print(self.operator); output.print(self.operator);
}); });
DEFPRINT(AST_Binary, function(self, output){ DEFPRINT(AST_Binary, function(self, output){
var op = self.operator;
self.left.print(output); self.left.print(output);
if (op[0] == ">" /* ">>" ">>>" ">" ">=" */ output.space();
&& self.left instanceof AST_UnaryPostfix output.print(self.operator);
&& self.left.operator == "--") { if (self.operator == "<"
// space is mandatory to avoid outputting -->
output.print(" ");
} else {
// the space is optional depending on "beautify"
output.space();
}
output.print(op);
if ((op == "<" || op == "<<")
&& self.right instanceof AST_UnaryPrefix && self.right instanceof AST_UnaryPrefix
&& self.right.operator == "!" && self.right.operator == "!"
&& self.right.expression instanceof AST_UnaryPrefix && self.right.expression instanceof AST_UnaryPrefix
&& self.right.expression.operator == "--") { && self.right.expression.operator == "--") {
// space is mandatory to avoid outputting <!-- // space is mandatory to avoid outputting <!--
// http://javascript.spec.whatwg.org/#comment-syntax
output.print(" "); output.print(" ");
} else { } else {
// the space is optional depending on "beautify" // the space is optional depending on "beautify"
@@ -1178,11 +1144,7 @@ function OutputStream(options) {
output.print_string(self.getValue(), self.quote); output.print_string(self.getValue(), self.quote);
}); });
DEFPRINT(AST_Number, function(self, output){ DEFPRINT(AST_Number, function(self, output){
if (use_asm && self.start.raw != null) { output.print(make_num(self.getValue()));
output.print(self.start.raw);
} else {
output.print(make_num(self.getValue()));
}
}); });
function regexp_safe_literal(code) { function regexp_safe_literal(code) {
@@ -1358,12 +1320,6 @@ function OutputStream(options) {
DEFMAP(AST_Finally, basic_sourcemap_gen); DEFMAP(AST_Finally, basic_sourcemap_gen);
DEFMAP(AST_Definitions, basic_sourcemap_gen); DEFMAP(AST_Definitions, basic_sourcemap_gen);
DEFMAP(AST_Constant, basic_sourcemap_gen); DEFMAP(AST_Constant, basic_sourcemap_gen);
DEFMAP(AST_ObjectSetter, function(self, output){
output.add_mapping(self.start, self.key.name);
});
DEFMAP(AST_ObjectGetter, function(self, output){
output.add_mapping(self.start, self.key.name);
});
DEFMAP(AST_ObjectProperty, function(self, output){ DEFMAP(AST_ObjectProperty, function(self, output){
output.add_mapping(self.start, self.key); output.add_mapping(self.start, self.key);
}); });

View File

@@ -59,6 +59,7 @@ var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
var RE_OCT_NUMBER = /^0[0-7]+$/; var RE_OCT_NUMBER = /^0[0-7]+$/;
var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
var OPERATORS = makePredicate([ var OPERATORS = makePredicate([
"in", "in",
@@ -107,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\uFEFF")); 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 PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:")); var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
@@ -181,15 +182,13 @@ function parse_js_number(num) {
return parseInt(num.substr(2), 16); return parseInt(num.substr(2), 16);
} else if (RE_OCT_NUMBER.test(num)) { } else if (RE_OCT_NUMBER.test(num)) {
return parseInt(num.substr(1), 8); return parseInt(num.substr(1), 8);
} else { } else if (RE_DEC_NUMBER.test(num)) {
var val = parseFloat(num); return parseFloat(num);
if (val == num) return val;
} }
}; };
function JS_Parse_Error(message, filename, line, col, pos) { function JS_Parse_Error(message, 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;
@@ -201,7 +200,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, filename, line, col, pos); throw new JS_Parse_Error(message, line, col, pos);
}; };
function is_token(token, type, val) { function is_token(token, type, val) {
@@ -210,10 +209,10 @@ function is_token(token, type, val) {
var EX_EOF = {}; var EX_EOF = {};
function tokenizer($TEXT, filename, html5_comments, shebang) { function tokenizer($TEXT, filename, html5_comments) {
var S = { var S = {
text : $TEXT, text : $TEXT.replace(/\uFEFF/g, ''),
filename : filename, filename : filename,
pos : 0, pos : 0,
tokpos : 0, tokpos : 0,
@@ -285,9 +284,6 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
nlb : S.newline_before, nlb : S.newline_before,
file : filename file : filename
}; };
if (/^(?:num|string|regexp)$/i.test(type)) {
ret.raw = $TEXT.substring(ret.pos, ret.endpos);
}
if (!is_comment) { if (!is_comment) {
ret.comments_before = S.comments_before; ret.comments_before = S.comments_before;
S.comments_before = []; S.comments_before = [];
@@ -301,8 +297,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}; };
function skip_whitespace() { function skip_whitespace() {
var ch; while (WHITESPACE_CHARS(peek()))
while (WHITESPACE_CHARS(ch = peek()) || ch == "\u2028" || ch == "\u2029")
next(); next();
}; };
@@ -357,13 +352,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
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
case 13 : // \r default : return ch;
if (peek() == "\n") { // DOS newline
next(true, in_string);
return "";
}
} }
return ch;
}; };
function hex_bytes(n) { function hex_bytes(n) {
@@ -380,7 +370,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
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, true); var ch = next(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
@@ -483,11 +473,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
regexp += ch; regexp += ch;
} }
var mods = read_name(); var mods = read_name();
try { return token("regexp", new RegExp(regexp, mods));
return token("regexp", new RegExp(regexp, mods));
} catch(e) {
parse_error(e.message);
}
}); });
function read_operator(prefix) { function read_operator(prefix) {
@@ -571,13 +557,6 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
if (PUNC_CHARS(ch)) return token("punc", next()); if (PUNC_CHARS(ch)) return token("punc", next());
if (OPERATOR_CHARS(ch)) return read_operator(); if (OPERATOR_CHARS(ch)) return read_operator();
if (code == 92 || is_identifier_start(code)) return read_word(); if (code == 92 || is_identifier_start(code)) return read_word();
if (shebang) {
if (S.pos == 0 && looking_at("#!")) {
forward(2);
return skip_line_comment("comment5");
}
}
parse_error("Unexpected character '" + ch + "'"); parse_error("Unexpected character '" + ch + "'");
}; };
@@ -647,13 +626,12 @@ function parse($TEXT, options) {
expression : false, expression : false,
html5_comments : true, html5_comments : true,
bare_returns : false, bare_returns : false,
shebang : true,
}); });
var S = { var S = {
input : (typeof $TEXT == "string" input : (typeof $TEXT == "string"
? tokenizer($TEXT, options.filename, ? tokenizer($TEXT, options.filename,
options.html5_comments, options.shebang) options.html5_comments)
: $TEXT), : $TEXT),
token : null, token : null,
prev : null, prev : null,
@@ -1125,7 +1103,7 @@ function parse($TEXT, options) {
}); });
}; };
var new_ = function(allow_calls) { var new_ = function() {
var start = S.token; var start = S.token;
expect_token("operator", "new"); expect_token("operator", "new");
var newexp = expr_atom(false), args; var newexp = expr_atom(false), args;
@@ -1140,7 +1118,7 @@ function parse($TEXT, options) {
expression : newexp, expression : newexp,
args : args, args : args,
end : prev() end : prev()
}), allow_calls); }), true);
}; };
function as_atom_node() { function as_atom_node() {
@@ -1184,7 +1162,7 @@ function parse($TEXT, options) {
var expr_atom = function(allow_calls) { var expr_atom = function(allow_calls) {
if (is("operator", "new")) { if (is("operator", "new")) {
return new_(allow_calls); return new_();
} }
var start = S.token; var start = S.token;
if (is("punc")) { if (is("punc")) {

View File

@@ -1,223 +0,0 @@
/***********************************************************************
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,
regex : null
});
var reserved = options.reserved;
if (reserved == null)
reserved = find_builtins();
var cache = options.cache;
if (cache == null) {
cache = {
cname: -1,
props: new Dictionary()
};
}
var regex = options.regex;
var names_to_mangle = [];
var unmangleable = [];
// 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) {
node.key = mangle(node.key);
}
else if (node instanceof AST_ObjectProperty) {
// setter or getter
node.key.name = mangle(node.key.name);
}
else if (node instanceof AST_Dot) {
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 (unmangleable.indexOf(name) >= 0) return false;
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 (regex && !regex.test(name)) return false;
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);
if (!should_mangle(name)) {
push_uniq(unmangleable, name);
}
}
function mangle(name) {
if (!should_mangle(name)) {
return 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) {
node.value = mangle(node.value);
}
else if (node instanceof AST_Conditional) {
node.consequent = mangleStrings(node.consequent);
node.alternative = mangleStrings(node.alternative);
}
return node;
}));
}
}

View File

@@ -67,32 +67,23 @@ SymbolDef.prototype = {
|| this.orig[0] instanceof AST_SymbolDefun)); || this.orig[0] instanceof AST_SymbolDefun));
}, },
mangle: function(options) { mangle: function(options) {
var cache = options.cache && options.cache.props; if (!this.mangled_name && !this.unmangleable(options)) {
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
var self = this; var self = this;
var scope = self.parent_scope = null; var scope = self.parent_scope = null;
var labels = new Dictionary();
var defun = null; var defun = null;
var nesting = 0; var nesting = 0;
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
@@ -109,24 +100,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
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_defun = defun; var save_defun = defun;
var save_labels = labels;
defun = scope = node; defun = scope = node;
labels = new Dictionary();
++nesting; descend(); --nesting; ++nesting; descend(); --nesting;
scope = save_scope; scope = save_scope;
defun = save_defun; defun = save_defun;
labels = save_labels;
return true; // don't descend again in TreeWalker return true; // don't descend again in TreeWalker
} }
if (node instanceof AST_LabeledStatement) { if (node instanceof AST_Directive) {
var l = node.label; node.scope = scope;
if (labels.has(l.name)) { push_uniq(scope.directives, node.value);
throw new Error(string_template("Label {name} defined twice", l)); return true;
}
labels.set(l.name, l);
descend();
labels.del(l.name);
return true; // no descend again
} }
if (node instanceof AST_With) { if (node instanceof AST_With) {
for (var s = scope; s; s = s.parent_scope) for (var s = scope; s; s = s.parent_scope)
@@ -136,10 +119,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
if (node instanceof AST_Symbol) { if (node instanceof AST_Symbol) {
node.scope = scope; node.scope = scope;
} }
if (node instanceof AST_Label) {
node.thedef = node;
node.references = [];
}
if (node instanceof AST_SymbolLambda) { if (node instanceof AST_SymbolLambda) {
defun.def_function(node); defun.def_function(node);
} }
@@ -161,15 +140,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
(options.screw_ie8 ? scope : defun) (options.screw_ie8 ? scope : defun)
.def_variable(node); .def_variable(node);
} }
else if (node instanceof AST_LabelRef) {
var sym = labels.get(node.name);
if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
name: node.name,
line: node.start.line,
col: node.start.col
}));
node.thedef = sym;
}
}); });
self.walk(tw); self.walk(tw);
@@ -184,10 +154,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
func = prev_func; func = prev_func;
return true; return true;
} }
if (node instanceof AST_LoopControl && node.label) {
node.label.thedef.references.push(node);
return true;
}
if (node instanceof AST_SymbolRef) { if (node instanceof AST_SymbolRef) {
var name = node.name; var name = node.name;
var sym = node.scope.find_variable(name); var sym = node.scope.find_variable(name);
@@ -217,13 +183,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){
this.directives = []; // contains the directives defined in this scope, i.e. "use strict"
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope) this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
@@ -234,6 +197,10 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
this.nesting = nesting; // the nesting level of this scope (0 means toplevel) this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
}); });
AST_Scope.DEFMETHOD("strict", function(){
return this.has_directive("use strict");
});
AST_Lambda.DEFMETHOD("init_scope_vars", function(){ AST_Lambda.DEFMETHOD("init_scope_vars", function(){
AST_Scope.prototype.init_scope_vars.apply(this, arguments); AST_Scope.prototype.init_scope_vars.apply(this, arguments);
this.uses_arguments = false; this.uses_arguments = false;
@@ -257,6 +224,11 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
|| (this.parent_scope && this.parent_scope.find_variable(name)); || (this.parent_scope && this.parent_scope.find_variable(name));
}); });
AST_Scope.DEFMETHOD("has_directive", function(value){
return this.parent_scope && this.parent_scope.has_directive(value)
|| (this.directives.indexOf(value) >= 0 ? this : null);
});
AST_Scope.DEFMETHOD("def_function", function(symbol){ AST_Scope.DEFMETHOD("def_function", function(symbol){
this.functions.set(symbol.name, this.def_variable(symbol)); this.functions.set(symbol.name, this.def_variable(symbol));
}); });
@@ -372,15 +344,6 @@ 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
@@ -415,10 +378,6 @@ 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){

View File

@@ -70,7 +70,7 @@ TreeTransformer.prototype = new TreeWalker;
if (y !== undefined) x = y; if (y !== undefined) x = y;
} }
} }
tw.pop(this); tw.pop();
return x; return x;
}); });
}; };

View File

@@ -106,12 +106,10 @@ 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 count; return obj;
}; };
function noop() {}; function noop() {};
@@ -300,11 +298,5 @@ 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;
}; };

128
npm-shrinkwrap.json generated
View File

@@ -1,128 +0,0 @@
{
"name": "uglify-js",
"version": "2.4.24",
"dependencies": {
"abbrev": {
"version": "1.0.7",
"from": "abbrev@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
},
"amdefine": {
"version": "1.0.0",
"from": "amdefine@>=0.0.4",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"
},
"async": {
"version": "0.2.10",
"from": "async@>=0.2.6 <0.3.0",
"resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
},
"camelcase": {
"version": "1.2.1",
"from": "camelcase@>=1.0.2 <2.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
},
"decamelize": {
"version": "1.0.0",
"from": "decamelize@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz"
},
"deep-is": {
"version": "0.1.3",
"from": "deep-is@>=0.1.2 <0.2.0",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
},
"esprima": {
"version": "1.1.1",
"from": "esprima@>=1.1.1 <1.2.0",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.1.1.tgz"
},
"estraverse": {
"version": "1.5.1",
"from": "estraverse@>=1.5.1 <1.6.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz"
},
"esutils": {
"version": "1.0.0",
"from": "esutils@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz"
},
"fast-levenshtein": {
"version": "1.0.7",
"from": "fast-levenshtein@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
},
"levn": {
"version": "0.2.5",
"from": "levn@>=0.2.5 <0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
},
"nopt": {
"version": "2.1.2",
"from": "nopt@>=2.1.2 <2.2.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-2.1.2.tgz"
},
"optionator": {
"version": "0.5.0",
"from": "optionator@>=0.5.0 <0.6.0",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz"
},
"prelude-ls": {
"version": "1.1.2",
"from": "prelude-ls@>=1.1.1 <1.2.0",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
},
"reflect": {
"version": "0.1.3",
"from": "git://github.com/zaach/reflect.js.git",
"resolved": "git://github.com/zaach/reflect.js.git#286bcd79661c96ecc404357d3c0e35fdb54a6967"
},
"source-map": {
"version": "0.5.1",
"from": "source-map@>=0.5.1 <0.6.0",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.1.tgz"
},
"type-check": {
"version": "0.3.1",
"from": "type-check@>=0.3.1 <0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
},
"uglify-js": {
"version": "2.4.24",
"from": "git://github.com/mishoo/UglifyJS2.git",
"resolved": "git://github.com/mishoo/UglifyJS2.git#2a06c7758e24a64740473c8031eafbb7fefa213f",
"dependencies": {
"source-map": {
"version": "0.1.34",
"from": "source-map@0.1.34",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz"
}
}
},
"uglify-to-browserify": {
"version": "1.0.2",
"from": "uglify-to-browserify@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz"
},
"window-size": {
"version": "0.1.0",
"from": "window-size@0.1.0",
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
},
"wordwrap": {
"version": "0.0.2",
"from": "wordwrap@0.0.2",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
},
"yargs": {
"version": "3.10.0",
"from": "yargs@>=3.10.0 <3.11.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz"
},
"zeparser": {
"version": "0.0.7",
"from": "git://github.com/qfox/ZeParser.git",
"resolved": "git://github.com/qfox/ZeParser.git#c99240c5ba7054c467733800ff38265958a2dda9"
}
}
}

View File

@@ -1,52 +1,37 @@
{ {
"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",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)", "main": "tools/node.js",
"license": "BSD-2-Clause", "version": "2.4.17",
"version": "2.6.0", "engines": { "node" : ">=0.4.0" },
"engines": { "maintainers": [{
"node": ">=0.8.0" "name": "Mihai Bazon",
}, "email": "mihai.bazon@gmail.com",
"maintainers": [ "web": "http://lisperator.net/"
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)" }],
], "repository": {
"repository": { "type": "git",
"type": "git", "url": "https://github.com/mishoo/UglifyJS2.git"
"url": "https://github.com/mishoo/UglifyJS2.git" },
}, "dependencies": {
"bugs": { "async" : "~0.2.6",
"url": "https://github.com/mishoo/UglifyJS2/issues" "source-map" : "0.1.34",
}, "yargs": "~1.3.3",
"main": "tools/node.js", "uglify-to-browserify": "~1.0.0"
"bin": { },
"uglifyjs": "bin/uglifyjs" "devDependencies": {
}, "acorn": "~0.6.0",
"files": [ "escodegen": "~1.3.3",
"bin", "esfuzz": "~0.3.1",
"lib", "estraverse": "~1.5.1"
"tools", },
"LICENSE" "browserify": {
], "transform": [ "uglify-to-browserify" ]
"dependencies": { },
"async": "~0.2.6", "bin": {
"source-map": "~0.5.1", "uglifyjs" : "bin/uglifyjs"
"uglify-to-browserify": "~1.0.0", },
"yargs": "~3.10.0" "license": "BSD",
}, "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": {
"shrinkwrap": "rm ./npm-shrinkwrap.json; rm -rf ./node_modules; npm i && npm shrinkwrap && npm outdated",
"test": "node test/run-tests.js"
}
} }

View File

@@ -1,106 +0,0 @@
asm_mixed: {
options = {
sequences : true,
properties : true,
dead_code : true,
drop_debugger : true,
conditionals : true,
comparisons : true,
evaluate : true,
booleans : true,
loops : true,
unused : true,
hoist_funs : true,
keep_fargs : true,
keep_fnames : false,
hoist_vars : true,
if_return : true,
join_vars : true,
cascade : true,
side_effects : true,
negate_iife : true
};
input: {
// adapted from http://asmjs.org/spec/latest/
function asm_GeometricMean(stdlib, foreign, buffer) {
"use asm";
var exp = stdlib.Math.exp;
var log = stdlib.Math.log;
var values = new stdlib.Float64Array(buffer);
function logSum(start, end) {
start = start|0;
end = end|0;
var sum = 0.0, p = 0, q = 0;
// asm.js forces byte addressing of the heap by requiring shifting by 3
for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) {
sum = sum + +log(values[p>>3]);
}
return +sum;
}
function geometricMean(start, end) {
start = start|0;
end = end|0;
return +exp(+logSum(start, end) / +((end - start)|0));
}
return { geometricMean: geometricMean };
}
function no_asm_GeometricMean(stdlib, foreign, buffer) {
var exp = stdlib.Math.exp;
var log = stdlib.Math.log;
var values = new stdlib.Float64Array(buffer);
function logSum(start, end) {
start = start|0;
end = end|0;
var sum = 0.0, p = 0, q = 0;
// asm.js forces byte addressing of the heap by requiring shifting by 3
for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) {
sum = sum + +log(values[p>>3]);
}
return +sum;
}
function geometricMean(start, end) {
start = start|0;
end = end|0;
return +exp(+logSum(start, end) / +((end - start)|0));
}
return { geometricMean: geometricMean };
}
}
expect: {
function asm_GeometricMean(stdlib, foreign, buffer) {
"use asm";
var exp = stdlib.Math.exp;
var log = stdlib.Math.log;
var values = new stdlib.Float64Array(buffer);
function logSum(start, end) {
start = start | 0;
end = end | 0;
var sum = 0.0, p = 0, q = 0;
for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0) {
sum = sum + +log(values[p >> 3]);
}
return +sum;
}
function geometricMean(start, end) {
start = start | 0;
end = end | 0;
return +exp(+logSum(start, end) / +(end - start | 0));
}
return { geometricMean: geometricMean };
}
function no_asm_GeometricMean(stdlib, foreign, buffer) {
function logSum(start, end) {
start = 0 | start, end = 0 | end;
var sum = 0, p = 0, q = 0;
for (p = start << 3, q = end << 3; (0 | q) > (0 | p); p = p + 8 | 0) sum += +log(values[p >> 3]);
return +sum;
}
function geometricMean(start, end) {
return start = 0 | start, end = 0 | end, +exp(+logSum(start, end) / +(end - start | 0));
}
var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer);
return { geometricMean: geometricMean };
}
}
}

View File

@@ -86,9 +86,7 @@ ifs_4: {
x(foo)[10].bar.baz = something_else(); x(foo)[10].bar.baz = something_else();
} }
expect: { expect: {
foo && bar x(foo)[10].bar.baz = (foo && bar) ? something() : something_else();
? x(foo)[10].bar.baz = something()
: x(foo)[10].bar.baz = something_else();
} }
} }
@@ -135,7 +133,6 @@ 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 {
@@ -143,7 +140,6 @@ ifs_6: {
} }
} }
expect: { expect: {
var x;
x = foo || bar || baz || boo ? 20 : 10; x = foo || bar || baz || boo ? 20 : 10;
} }
} }
@@ -153,7 +149,6 @@ 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 {
@@ -161,7 +156,6 @@ cond_1: {
} }
} }
expect: { expect: {
var do_something;
do_something(some_condition() ? x : y); do_something(some_condition() ? x : y);
} }
} }
@@ -171,7 +165,6 @@ 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 {
@@ -179,7 +172,6 @@ cond_2: {
} }
} }
expect: { expect: {
var x, FooBar;
x = new FooBar(some_condition() ? 1 : 2); x = new FooBar(some_condition() ? 1 : 2);
} }
} }
@@ -189,7 +181,6 @@ cond_3: {
conditionals: true conditionals: true
}; };
input: { input: {
var FooBar;
if (some_condition()) { if (some_condition()) {
new FooBar(1); new FooBar(1);
} else { } else {
@@ -197,7 +188,6 @@ cond_3: {
} }
} }
expect: { expect: {
var FooBar;
some_condition() ? new FooBar(1) : FooBar(2); some_condition() ? new FooBar(1) : FooBar(2);
} }
} }
@@ -207,7 +197,6 @@ cond_4: {
conditionals: true conditionals: true
}; };
input: { input: {
var do_something;
if (some_condition()) { if (some_condition()) {
do_something(); do_something();
} else { } else {
@@ -215,7 +204,6 @@ cond_4: {
} }
} }
expect: { expect: {
var do_something;
some_condition(), do_something(); some_condition(), do_something();
} }
} }
@@ -315,7 +303,6 @@ 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;
@@ -324,7 +311,6 @@ cond_7_1: {
} }
} }
expect: { expect: {
var x;
x = (y, 2); x = (y, 2);
} }
} }
@@ -335,7 +321,6 @@ cond_8: {
evaluate : true evaluate : true
}; };
input: { input: {
var a;
// compress these // compress these
a = condition ? true : false; a = condition ? true : false;
@@ -370,7 +355,6 @@ cond_8: {
} }
expect: { expect: {
var a;
a = !!condition; a = !!condition;
a = !condition; a = !condition;
a = !!condition(); a = !!condition();
@@ -383,164 +367,4 @@ cond_8: {
a = condition ? 0 : true; a = condition ? 0 : true;
a = condition ? 1 : 0; a = condition ? 1 : 0;
} }
} }
conditional_and: {
options = {
conditionals: true,
evaluate : true
};
input: {
var a;
// compress these
a = true && condition;
a = 1 && console.log("a");
a = 2 * 3 && 2 * condition;
a = 5 == 5 && condition + 3;
a = "string" && 4 - condition;
a = 5 + "" && condition / 5;
a = -4.5 && 6 << condition;
a = 6 && 7;
a = false && condition;
a = NaN && console.log("b");
a = 0 && console.log("c");
a = undefined && 2 * condition;
a = null && condition + 3;
a = 2 * 3 - 6 && 4 - condition;
a = 10 == 7 && condition / 5;
a = !"string" && 6 % condition;
a = 0 && 7;
// don't compress these
a = condition && true;
a = console.log("a") && 2;
a = 4 - condition && "string";
a = 6 << condition && -4.5;
a = condition && false;
a = console.log("b") && NaN;
a = console.log("c") && 0;
a = 2 * condition && undefined;
a = condition + 3 && null;
}
expect: {
var a;
a = condition;
a = console.log("a");
a = 2 * condition;
a = condition + 3;
a = 4 - condition;
a = condition / 5;
a = 6 << condition;
a = 7;
a = false;
a = NaN;
a = 0;
a = void 0;
a = null;
a = 0;
a = false;
a = false;
a = 0;
a = condition && true;
a = console.log("a") && 2;
a = 4 - condition && "string";
a = 6 << condition && -4.5;
a = condition && false;
a = console.log("b") && NaN;
a = console.log("c") && 0;
a = 2 * condition && void 0;
a = condition + 3 && null;
}
}
conditional_or: {
options = {
conditionals: true,
evaluate : true
};
input: {
var a;
// compress these
a = true || condition;
a = 1 || console.log("a");
a = 2 * 3 || 2 * condition;
a = 5 == 5 || condition + 3;
a = "string" || 4 - condition;
a = 5 + "" || condition / 5;
a = -4.5 || 6 << condition;
a = 6 || 7;
a = false || condition;
a = 0 || console.log("b");
a = NaN || console.log("c");
a = undefined || 2 * condition;
a = null || condition + 3;
a = 2 * 3 - 6 || 4 - condition;
a = 10 == 7 || condition / 5;
a = !"string" || 6 % condition;
a = null || 7;
a = console.log(undefined && condition || null);
a = console.log(undefined || condition && null);
// don't compress these
a = condition || true;
a = console.log("a") || 2;
a = 4 - condition || "string";
a = 6 << condition || -4.5;
a = condition || false;
a = console.log("b") || NaN;
a = console.log("c") || 0;
a = 2 * condition || undefined;
a = condition + 3 || null;
}
expect: {
var a;
a = true;
a = 1;
a = 6;
a = true;
a = "string";
a = "5";
a = -4.5;
a = 6;
a = condition;
a = console.log("b");
a = console.log("c");
a = 2 * condition;
a = condition + 3;
a = 4 - condition;
a = condition / 5;
a = 6 % condition;
a = 7;
a = console.log(null);
a = console.log(condition && null);
a = condition || true;
a = console.log("a") || 2;
a = 4 - condition || "string";
a = 6 << condition || -4.5;
a = condition || false;
a = console.log("b") || NaN;
a = console.log("c") || 0;
a = 2 * condition || void 0;
a = condition + 3 || null;
}
}

View File

@@ -1,5 +1,5 @@
unused_funarg_1: { unused_funarg_1: {
options = { unused: true, keep_fargs: false }; options = { unused: 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, keep_fargs: false }; options = { unused: 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, unsafe: true }; options = { unused: true, keep_fnames: true };
input: { input: {
function foo() { function foo() {
return function bar(baz) {}; return function bar(baz) {};
@@ -173,7 +173,7 @@ keep_fnames: {
} }
expect: { expect: {
function foo() { function foo() {
return function bar(baz) {}; return function bar() {};
} }
} }
} }

View File

@@ -1,71 +0,0 @@
html_comment_in_expression: {
input: {
function f(a, b, x, y) { return a < !--b && x-- > y; }
}
expect_exact: "function f(a,b,x,y){return a< !--b&&x-- >y}";
}
html_comment_in_less_than: {
input: {
function f(a, b) { return a < !--b; }
}
expect_exact: "function f(a,b){return a< !--b}";
}
html_comment_in_left_shift: {
input: {
function f(a, b) { return a << !--b; }
}
expect_exact: "function f(a,b){return a<< !--b}";
}
html_comment_in_right_shift: {
input: {
function f(a, b) { return a-- >> b; }
}
expect_exact: "function f(a,b){return a-- >>b}";
}
html_comment_in_zero_fill_right_shift: {
input: {
function f(a, b) { return a-- >>> b; }
}
expect_exact: "function f(a,b){return a-- >>>b}";
}
html_comment_in_greater_than: {
input: {
function f(a, b) { return a-- > b; }
}
expect_exact: "function f(a,b){return a-- >b}";
}
html_comment_in_greater_than_or_equal: {
input: {
function f(a, b) { return a-- >= b; }
}
expect_exact: "function f(a,b){return a-- >=b}";
}
html_comment_in_right_shift_assign: {
input: {
// Note: illegal javascript
function f(a, b) { return a-- >>= b; }
}
expect_exact: "function f(a,b){return a-- >>=b}";
}
html_comment_in_zero_fill_right_shift_assign: {
input: {
// Note: illegal javascript
function f(a, b) { return a-- >>>= b; }
}
expect_exact: "function f(a,b){return a-- >>>=b}";
}
html_comment_in_string_literal: {
input: {
function f() { return "<!--HTML-->comment in<!--string literal-->"; }
}
expect_exact: 'function f(){return"\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e"}';
}

View File

@@ -1,11 +0,0 @@
do_not_update_lhs: {
options = { global_defs: { DEBUG: false } };
input: { DEBUG = false; }
expect: { DEBUG = false; }
}
do_update_rhs: {
options = { global_defs: { DEBUG: false } };
input: { MY_DEBUG = DEBUG; }
expect: { MY_DEBUG = false; }
}

View File

@@ -6,7 +6,7 @@ NaN_and_Infinity_must_have_parens: {
} }
expect: { expect: {
(1/0).toString(); (1/0).toString();
NaN.toString(); // transformation to 0/0 dropped (0/0).toString();
} }
} }

View File

@@ -1,37 +0,0 @@
dont_reuse_prop: {
mangle_props = {
regex: /asd/
};
input: {
var obj = {};
obj.a = 123;
obj.asd = 256;
console.log(obj.a);
}
expect: {
var obj = {};
obj.a = 123;
obj.b = 256;
console.log(obj.a);
}
}
unmangleable_props_should_always_be_reserved: {
mangle_props = {
regex: /asd/
};
input: {
var obj = {};
obj.asd = 256;
obj.a = 123;
console.log(obj.a);
}
expect: {
var obj = {};
obj.b = 256;
obj.a = 123;
console.log(obj.a);
}
}

View File

@@ -1,29 +0,0 @@
negate_booleans_1: {
options = {
comparisons: true
};
input: {
var a = !a || !b || !c || !d || !e || !f;
}
expect: {
var a = !(a && b && c && d && e && f);
}
}
negate_booleans_2: {
options = {
comparisons: true
};
input: {
var match = !x && // should not touch this one
(!z || c) &&
(!k || d) &&
the_stuff();
}
expect: {
var match = !x &&
(!z || c) &&
(!k || d) &&
the_stuff();
}
}

View File

@@ -1,23 +0,0 @@
remove_redundant_sequence_items: {
options = { side_effects: true };
input: {
(0, 1, logThis)();
(0, 1, _decorators.logThis)();
}
expect: {
(0, logThis)();
(0, _decorators.logThis)();
}
}
dont_remove_lexical_binding_sequence: {
options = { side_effects: true };
input: {
(0, logThis)();
(0, _decorators.logThis)();
}
expect: {
(0, logThis)();
(0, _decorators.logThis)();
}
}

View File

@@ -1,12 +0,0 @@
new_statement: {
input: {
new x(1);
new x(1)(2);
new x(1)(2)(3);
new new x(1);
new new x(1)(2);
new (new x(1))(2);
(new new x(1))(2);
}
expect_exact: "new x(1);new x(1)(2);new x(1)(2)(3);new new x(1);new new x(1)(2);new new x(1)(2);(new new x(1))(2);"
}

View File

@@ -1,124 +0,0 @@
return_undefined: {
options = {
sequences : false,
if_return : true,
evaluate : true,
dead_code : true,
conditionals : true,
comparisons : true,
booleans : true,
unused : true,
side_effects : true,
properties : true,
drop_debugger : true,
loops : true,
hoist_funs : true,
keep_fargs : true,
keep_fnames : false,
hoist_vars : true,
join_vars : true,
cascade : true,
negate_iife : true
};
input: {
function f0() {
}
function f1() {
return undefined;
}
function f2() {
return void 0;
}
function f3() {
return void 123;
}
function f4() {
return;
}
function f5(a, b) {
console.log(a, b);
baz(a);
return;
}
function f6(a, b) {
console.log(a, b);
if (a) {
foo(b);
baz(a);
return a + b;
}
return undefined;
}
function f7(a, b) {
console.log(a, b);
if (a) {
foo(b);
baz(a);
return void 0;
}
return a + b;
}
function f8(a, b) {
foo(a);
bar(b);
return void 0;
}
function f9(a, b) {
foo(a);
bar(b);
return undefined;
}
function f10() {
return false;
}
function f11() {
return null;
}
function f12() {
return 0;
}
}
expect: {
function f0() {}
function f1() {}
function f2() {}
function f3() {}
function f4() {}
function f5(a, b) {
console.log(a, b);
baz(a);
}
function f6(a, b) {
console.log(a, b);
if (a) {
foo(b);
baz(a);
return a + b;
}
}
function f7(a, b) {
console.log(a, b);
if (!a)
return a + b;
foo(b);
baz(a);
}
function f8(a, b) {
foo(a);
bar(b);
}
function f9(a, b) {
foo(a);
bar(b);
}
function f10() {
return !1;
}
function f11() {
return null;
}
function f12() {
return 0;
}
}
}

View File

@@ -1,18 +0,0 @@
do_screw: {
options = { screw_ie8: true };
beautify = {
screw_ie8: true,
ascii_only: true
};
input: f("\v");
expect_exact: 'f("\\v");';
}
dont_screw: {
options = { screw_ie8: false };
beautify = { screw_ie8: false, ascii_only: true };
input: f("\v");
expect_exact: 'f("\\x0B");';
}

View File

@@ -100,4 +100,4 @@ module.exports = function(options) {
} }
process.stdout.write(prefix + "Probability of error is less than " + (100 / options.iterations) + "%, stopping.\n"); process.stdout.write(prefix + "Probability of error is less than " + (100 / options.iterations) + "%, stopping.\n");
}; };

View File

@@ -4,6 +4,7 @@ var U = require("../tools/node");
var path = require("path"); var path = require("path");
var fs = require("fs"); var fs = require("fs");
var assert = require("assert"); var assert = require("assert");
var sys = require("util");
var tests_dir = path.dirname(module.filename); var tests_dir = path.dirname(module.filename);
var failures = 0; var failures = 0;
@@ -11,14 +12,11 @@ var failed_files = {};
run_compress_tests(); run_compress_tests();
if (failures) { if (failures) {
console.error("\n!!! Failed " + failures + " test cases."); sys.error("\n!!! Failed " + failures + " test cases.");
console.error("!!! " + Object.keys(failed_files).join(", ")); sys.error("!!! " + Object.keys(failed_files).join(", "));
process.exit(1); process.exit(1);
} }
var run_sourcemaps_tests = require('./sourcemaps');
run_sourcemaps_tests();
var run_ast_conversion_tests = require("./mozilla-ast"); var run_ast_conversion_tests = require("./mozilla-ast");
run_ast_conversion_tests({ run_ast_conversion_tests({
@@ -33,7 +31,7 @@ function tmpl() {
function log() { function log() {
var txt = tmpl.apply(this, arguments); var txt = tmpl.apply(this, arguments);
console.log("%s", txt); sys.puts(txt);
} }
function log_directory(dir) { function log_directory(dir) {
@@ -86,21 +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 output_options = test.beautify || {}; var expect = make_code(as_toplevel(test.expect), false);
var expect;
if (test.expect) {
expect = make_code(as_toplevel(test.expect), output_options);
} else {
expect = test.expect_exact;
}
var input = as_toplevel(test.input); var input = as_toplevel(test.input);
var input_code = make_code(test.input, { beautify: true }); var input_code = make_code(test.input);
if (test.mangle_props) {
input = U.mangle_properties(input, test.mangle_props);
}
var output = input.transform(cmp); var output = input.transform(cmp);
output.figure_out_scope(); output.figure_out_scope();
output = make_code(output, output_options); output = make_code(output, false);
if (expect != output) { if (expect != output) {
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", { log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
input: input_code, input: input_code,
@@ -144,7 +133,7 @@ function parse_test(file) {
file: file, file: file,
line: node.start.line, line: node.start.line,
col: node.start.col, col: node.start.col,
code: make_code(node, { beautify: false }) code: make_code(node, false)
})); }));
} }
@@ -161,7 +150,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 == "expect_exact", node.label.name == "input" || node.label.name == "expect",
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,
@@ -173,16 +162,7 @@ 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();
} }
if (node.label.name === "expect_exact") { test[node.label.name] = stat;
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;
} }
}); });
@@ -191,15 +171,15 @@ function parse_test(file) {
}; };
} }
function make_code(ast, options) { function make_code(ast, beautify) {
options.inline_script = true; if (arguments.length == 1) beautify = true;
var stream = U.OutputStream(options); var stream = U.OutputStream({ beautify: beautify });
ast.print(stream); ast.print(stream);
return stream.get(); return stream.get();
} }
function evaluate(code) { function evaluate(code) {
if (code instanceof U.AST_Node) if (code instanceof U.AST_Node)
code = make_code(code, { beautify: true }); code = make_code(code);
return new Function("return(" + code + ")")(); return new Function("return(" + code + ")")();
} }

View File

@@ -1,40 +0,0 @@
var UglifyJS = require("..");
var ok = require("assert");
module.exports = function () {
console.log("--- Sourcemaps tests");
var basic = source_map([
'var x = 1 + 1;'
].join('\n'));
ok.equal(basic.version, 3);
ok.deepEqual(basic.names, ['x']);
var issue836 = source_map([
"({",
" get enabled() {",
" return 3;",
" },",
" set enabled(x) {",
" ;",
" }",
"});",
].join("\n"));
ok.deepEqual(issue836.names, ['enabled', 'x']);
}
function source_map(js) {
var source_map = UglifyJS.SourceMap();
var stream = UglifyJS.OutputStream({ source_map: source_map });
var parsed = UglifyJS.parse(js);
parsed.print(stream);
return JSON.parse(source_map.toString());
}
// Run standalone
if (module.parent === null) {
module.exports();
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +0,0 @@
exports["Compressor"] = Compressor;
exports["DefaultsError"] = DefaultsError;
exports["Dictionary"] = Dictionary;
exports["JS_Parse_Error"] = JS_Parse_Error;
exports["MAP"] = MAP;
exports["OutputStream"] = OutputStream;
exports["SourceMap"] = SourceMap;
exports["TreeTransformer"] = TreeTransformer;
exports["TreeWalker"] = TreeWalker;
exports["base54"] = base54;
exports["defaults"] = defaults;
exports["mangle_properties"] = mangle_properties;
exports["merge"] = merge;
exports["parse"] = parse;
exports["push_uniq"] = push_uniq;
exports["string_template"] = string_template;
exports["is_identifier"] = is_identifier;

View File

@@ -1,5 +1,28 @@
var path = require("path"); var path = require("path");
var fs = require("fs"); var fs = require("fs");
var vm = require("vm");
var sys = require("util");
var UglifyJS = vm.createContext({
sys : sys,
console : console,
process : process,
Buffer : Buffer,
MOZ_SourceMap : require("source-map")
});
function load_global(file) {
file = path.resolve(path.dirname(module.filename), file);
try {
var code = fs.readFileSync(file, "utf8");
return vm.runInContext(code, UglifyJS, file);
} catch(ex) {
// XXX: in case of a syntax error, the message is kinda
// useless. (no location information).
sys.debug("ERROR in file: " + file + " / " + ex);
process.exit(1);
}
};
var FILES = exports.FILES = [ var FILES = exports.FILES = [
"../lib/utils.js", "../lib/utils.js",
@@ -10,26 +33,24 @@ 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",
"./exports.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));
}); });
var UglifyJS = exports; FILES.forEach(load_global);
new Function("MOZ_SourceMap", "exports", FILES.map(function(file){
return fs.readFileSync(file, "utf8");
}).join("\n\n"))(
require("source-map"),
UglifyJS
);
UglifyJS.AST_Node.warn_function = function(txt) { UglifyJS.AST_Node.warn_function = function(txt) {
console.error("WARN: %s", txt); sys.error("WARN: " + txt);
}; };
// XXX: perhaps we shouldn't export everything but heck, I'm lazy.
for (var i in UglifyJS) {
if (UglifyJS.hasOwnProperty(i)) {
exports[i] = UglifyJS[i];
}
}
exports.minify = function(files, options) { exports.minify = function(files, options) {
options = UglifyJS.defaults(options, { options = UglifyJS.defaults(options, {
spidermonkey : false, spidermonkey : false,
@@ -53,20 +74,17 @@ exports.minify = function(files, options) {
} else { } else {
if (typeof files == "string") if (typeof files == "string")
files = [ files ]; files = [ files ];
files.forEach(function(file, i){ files.forEach(function(file){
var code = options.fromString var code = options.fromString
? file ? file
: fs.readFileSync(file, "utf8"); : fs.readFileSync(file, "utf8");
sourcesContent[file] = code; sourcesContent[file] = code;
toplevel = UglifyJS.parse(code, { toplevel = UglifyJS.parse(code, {
filename: options.fromString ? i : file, filename: options.fromString ? "?" : file,
toplevel: toplevel toplevel: toplevel
}); });
}); });
} }
if (options.wrap) {
toplevel = toplevel.wrap_commonjs(options.wrap, options.exportAll);
}
// 2. compress // 2. compress
if (options.compress) { if (options.compress) {
@@ -111,7 +129,7 @@ exports.minify = function(files, options) {
var stream = UglifyJS.OutputStream(output); var stream = UglifyJS.OutputStream(output);
toplevel.print(stream); toplevel.print(stream);
if (options.outSourceMap && "string" === typeof options.outSourceMap) { if(options.outSourceMap){
stream += "\n//# sourceMappingURL=" + options.outSourceMap; stream += "\n//# sourceMappingURL=" + options.outSourceMap;
} }
@@ -174,63 +192,3 @@ 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");
}
};

View File

@@ -1,61 +0,0 @@
<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>