Merge remote-tracking branch 'origin_uglify/master'

This commit is contained in:
jchbh 2015-05-20 11:58:38 -07:00
commit a9d77afe80
13 changed files with 135 additions and 88 deletions

3
.gitignore vendored
View File

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

View File

@ -1,2 +0,0 @@
test
.travis.yml

View File

@ -1,5 +1,10 @@
language: node_js language: node_js
before_install: "npm install -g npm" before_install: "npm install -g npm"
node_js: node_js:
- "0.10" - "iojs"
- "0.12"
- "0.11" - "0.11"
- "0.10"
matrix:
fast_finish: true
sudo: false

View File

@ -132,24 +132,24 @@ normalize(ARGS);
if (ARGS.noerr) { if (ARGS.noerr) {
UglifyJS.DefaultsError.croak = function(msg, defs) { UglifyJS.DefaultsError.croak = function(msg, defs) {
sys.error("WARN: " + msg); print_error("WARN: " + msg);
}; };
} }
if (ARGS.version || ARGS.V) { if (ARGS.version || ARGS.V) {
var json = require("../package.json"); var json = require("../package.json");
sys.puts(json.name + ' ' + json.version); print(json.name + ' ' + json.version);
process.exit(0); process.exit(0);
} }
if (ARGS.ast_help) { if (ARGS.ast_help) {
var desc = UglifyJS.describe_ast(); var desc = UglifyJS.describe_ast();
sys.puts(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2)); print(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2));
process.exit(0); process.exit(0);
} }
if (ARGS.h || ARGS.help) { if (ARGS.h || ARGS.help) {
sys.puts(yargs.help()); print(yargs.help());
process.exit(0); process.exit(0);
} }
@ -221,7 +221,7 @@ if (ARGS.comments != null) {
try { try {
OUTPUT_OPTIONS.comments = new RegExp(ARGS.comments.substr(1, regex_pos - 1), ARGS.comments.substr(regex_pos + 1)); OUTPUT_OPTIONS.comments = new RegExp(ARGS.comments.substr(1, regex_pos - 1), ARGS.comments.substr(regex_pos + 1));
} catch (e) { } catch (e) {
sys.error("ERROR: Invalid --comments: " + e.message); print_error("ERROR: Invalid --comments: " + e.message);
} }
} else if (ARGS.comments == "all") { } else if (ARGS.comments == "all") {
OUTPUT_OPTIONS.comments = true; OUTPUT_OPTIONS.comments = true;
@ -241,7 +241,7 @@ var files = ARGS._.slice();
if (ARGS.self) { if (ARGS.self) {
if (files.length > 0) { if (files.length > 0) {
sys.error("WARN: Ignoring input files since --self was passed"); print_error("WARN: Ignoring input files since --self was passed");
} }
files = UglifyJS.FILES; files = UglifyJS.FILES;
if (!ARGS.wrap) ARGS.wrap = "UglifyJS"; if (!ARGS.wrap) ARGS.wrap = "UglifyJS";
@ -253,7 +253,7 @@ var ORIG_MAP = ARGS.in_source_map;
if (ORIG_MAP) { if (ORIG_MAP) {
ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP)); ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP));
if (files.length == 0) { if (files.length == 0) {
sys.error("INFO: Using file from the input source map: " + ORIG_MAP.file); print_error("INFO: Using file from the input source map: " + ORIG_MAP.file);
files = [ ORIG_MAP.file ]; files = [ ORIG_MAP.file ];
} }
if (ARGS.source_map_root == null) { if (ARGS.source_map_root == null) {
@ -266,12 +266,12 @@ if (files.length == 0) {
} }
if (files.indexOf("-") >= 0 && ARGS.source_map) { if (files.indexOf("-") >= 0 && ARGS.source_map) {
sys.error("ERROR: Source map doesn't work with input from STDIN"); print_error("ERROR: Source map doesn't work with input from STDIN");
process.exit(1); process.exit(1);
} }
if (files.filter(function(el){ return el == "-" }).length > 1) { if (files.filter(function(el){ return el == "-" }).length > 1) {
sys.error("ERROR: Can read a single file from STDIN (two or more dashes specified)"); print_error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
process.exit(1); process.exit(1);
} }
@ -294,9 +294,9 @@ try {
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS); var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
} catch(ex) { } catch(ex) {
if (ex instanceof UglifyJS.DefaultsError) { if (ex instanceof UglifyJS.DefaultsError) {
sys.error(ex.msg); print_error(ex.msg);
sys.error("Supported options:"); print_error("Supported options:");
sys.error(sys.inspect(ex.defs)); print_error(sys.inspect(ex.defs));
process.exit(1); process.exit(1);
} }
} }
@ -304,7 +304,7 @@ try {
async.eachLimit(files, 1, function (file, cb) { async.eachLimit(files, 1, function (file, cb) {
read_whole_file(file, function (err, code) { read_whole_file(file, function (err, code) {
if (err) { if (err) {
sys.error("ERROR: can't read file: " + file); print_error("ERROR: can't read file: " + file);
process.exit(1); process.exit(1);
} }
if (ARGS.p != null) { if (ARGS.p != null) {
@ -341,9 +341,9 @@ async.eachLimit(files, 1, function (file, cb) {
}); });
} catch(ex) { } catch(ex) {
if (ex instanceof UglifyJS.JS_Parse_Error) { if (ex instanceof UglifyJS.JS_Parse_Error) {
sys.error("Parse error at " + file + ":" + ex.line + "," + ex.col); print_error("Parse error at " + file + ":" + ex.line + "," + ex.col);
sys.error(ex.message); print_error(ex.message);
sys.error(ex.stack); print_error(ex.stack);
process.exit(1); process.exit(1);
} }
throw ex; throw ex;
@ -372,12 +372,13 @@ 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) (function(){ if (ARGS.mangle_props || ARGS.name_cache) (function(){
var reserved = RESERVED ? RESERVED.props : null; var reserved = RESERVED ? RESERVED.props : null;
var cache = readNameCache("props"); var cache = readNameCache("props");
TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, { TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, {
reserved: reserved, reserved : reserved,
cache: cache cache : cache,
only_cache : !ARGS.mangle_props
}); });
writeNameCache("props", cache); writeNameCache("props", cache);
})(); })();
@ -443,15 +444,15 @@ async.eachLimit(files, 1, function (file, cb) {
if (OUTPUT_FILE) { if (OUTPUT_FILE) {
fs.writeFileSync(OUTPUT_FILE, output, "utf8"); fs.writeFileSync(OUTPUT_FILE, output, "utf8");
} else { } else {
sys.print(output); print(output);
} }
if (ARGS.stats) { if (ARGS.stats) {
sys.error(UglifyJS.string_template("Timing information (compressed {count} files):", { print_error(UglifyJS.string_template("Timing information (compressed {count} files):", {
count: files.length count: files.length
})); }));
for (var i in STATS) if (STATS.hasOwnProperty(i)) { for (var i in STATS) if (STATS.hasOwnProperty(i)) {
sys.error(UglifyJS.string_template("- {name}: {time}s", { print_error(UglifyJS.string_template("- {name}: {time}s", {
name: i, name: i,
time: (STATS[i] / 1000).toFixed(3) time: (STATS[i] / 1000).toFixed(3)
})); }));
@ -478,7 +479,7 @@ function getOptions(x, constants) {
ast = UglifyJS.parse(x, { expression: true }); ast = UglifyJS.parse(x, { expression: true });
} catch(ex) { } catch(ex) {
if (ex instanceof UglifyJS.JS_Parse_Error) { if (ex instanceof UglifyJS.JS_Parse_Error) {
sys.error("Error parsing arguments in: " + x); print_error("Error parsing arguments in: " + x);
process.exit(1); process.exit(1);
} }
} }
@ -497,8 +498,8 @@ function getOptions(x, constants) {
ret[name] = true; ret[name] = true;
return true; // no descend return true; // no descend
} }
sys.error(node.TYPE) print_error(node.TYPE)
sys.error("Error parsing arguments in: " + x); print_error("Error parsing arguments in: " + x);
process.exit(1); process.exit(1);
})); }));
} }
@ -530,3 +531,11 @@ function time_it(name, cont) {
} }
return ret; return ret;
} }
function print_error(msg) {
console.error("%s", msg);
}
function print(txt) {
console.log("%s", txt);
}

View File

@ -1168,12 +1168,12 @@ merge(Compressor.prototype, {
return make_node(AST_EmptyStatement, node); return make_node(AST_EmptyStatement, node);
} }
if (def.length == 0) { if (def.length == 0) {
return side_effects; return in_list ? MAP.splice(side_effects.body) : side_effects;
} }
node.definitions = def; node.definitions = def;
if (side_effects) { if (side_effects) {
side_effects.body.unshift(node); side_effects.body.unshift(node);
node = side_effects; return in_list ? MAP.splice(side_effects.body) : side_effects;
} }
return node; return node;
} }
@ -2272,14 +2272,6 @@ merge(Compressor.prototype, {
}); });
}); });
OPT(AST_NaN, function (self, compressor) {
return make_node(AST_Binary, self, {
operator : '/',
left : make_node(AST_Number, self, {value: 0}),
right : make_node(AST_Number, self, {value: 0})
});
});
OPT(AST_Undefined, function(self, compressor){ OPT(AST_Undefined, function(self, compressor){
if (compressor.option("unsafe")) { if (compressor.option("unsafe")) {
var scope = compressor.find_parent(AST_Scope); var scope = compressor.find_parent(AST_Scope);
@ -2364,6 +2356,7 @@ merge(Compressor.prototype, {
if (consequent instanceof AST_Call if (consequent instanceof AST_Call
&& alternative.TYPE === consequent.TYPE && alternative.TYPE === consequent.TYPE
&& consequent.args.length == alternative.args.length && consequent.args.length == alternative.args.length
&& !consequent.expression.has_side_effects(compressor)
&& consequent.expression.equivalent_to(alternative.expression)) { && consequent.expression.equivalent_to(alternative.expression)) {
if (consequent.args.length == 0) { if (consequent.args.length == 0) {
return make_node(AST_Seq, self, { return make_node(AST_Seq, self, {

View File

@ -176,7 +176,6 @@ function OutputStream(options) {
might_need_space = false; might_need_space = false;
} }
might_need_semicolon = false; might_need_semicolon = false;
maybe_newline();
} }
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) { if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {

View File

@ -110,7 +110,7 @@ var OPERATORS = makePredicate([
"||" "||"
]); ]);
var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000")); var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF"));
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:")); var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
@ -215,7 +215,7 @@ var EX_EOF = {};
function tokenizer($TEXT, filename, html5_comments) { function tokenizer($TEXT, filename, html5_comments) {
var S = { var S = {
text : $TEXT.replace(/\uFEFF/g, ''), text : $TEXT,
filename : filename, filename : filename,
pos : 0, pos : 0,
tokpos : 0, tokpos : 0,
@ -356,8 +356,13 @@ function tokenizer($TEXT, filename, html5_comments) {
case 120 : return String.fromCharCode(hex_bytes(2)); // \x case 120 : return String.fromCharCode(hex_bytes(2)); // \x
case 117 : return String.fromCharCode(hex_bytes(4)); // \u case 117 : return String.fromCharCode(hex_bytes(4)); // \u
case 10 : return ""; // newline case 10 : return ""; // newline
default : return ch; case 13 : // \r
if (peek() == "\n") { // DOS newline
next(true, in_string);
return "";
} }
}
return ch;
}; };
function hex_bytes(n) { function hex_bytes(n) {
@ -374,7 +379,7 @@ function tokenizer($TEXT, filename, html5_comments) {
var read_string = with_eof_error("Unterminated string constant", function(quote_char){ var read_string = with_eof_error("Unterminated string constant", function(quote_char){
var quote = next(), ret = ""; var quote = next(), ret = "";
for (;;) { for (;;) {
var ch = next(true); var ch = next(true, true);
if (ch == "\\") { if (ch == "\\") {
// read OctalEscapeSequence (XXX: deprecated if "strict mode") // read OctalEscapeSequence (XXX: deprecated if "strict mode")
// https://github.com/mishoo/UglifyJS/issues/178 // https://github.com/mishoo/UglifyJS/issues/178

View File

@ -63,7 +63,8 @@ function find_builtins() {
function mangle_properties(ast, options) { function mangle_properties(ast, options) {
options = defaults(options, { options = defaults(options, {
reserved : null, reserved : null,
cache : null cache : null,
only_cache : false
}); });
var reserved = options.reserved; var reserved = options.reserved;
@ -140,11 +141,15 @@ function mangle_properties(ast, options) {
function can_mangle(name) { function can_mangle(name) {
if (reserved.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; if (/^[0-9.]+$/.test(name)) return false;
return true; return true;
} }
function should_mangle(name) { function should_mangle(name) {
if (reserved.indexOf(name) >= 0) return false;
return cache.props.has(name) return cache.props.has(name)
|| names_to_mangle.indexOf(name) >= 0; || names_to_mangle.indexOf(name) >= 0;
} }

View File

@ -2,23 +2,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",
"main": "tools/node.js", "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"version": "2.4.20", "license": "BSD",
"engines": { "node" : ">=0.4.0" }, "version": "2.4.23",
"maintainers": [{ "engines": {
"name": "Mihai Bazon", "node": ">=0.4.0"
"email": "mihai.bazon@gmail.com", },
"web": "http://lisperator.net/" "maintainers": [
}], "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/mishoo/UglifyJS2.git" "url": "https://github.com/mishoo/UglifyJS2.git"
}, },
"bugs": {
"url": "https://github.com/mishoo/UglifyJS2/issues"
},
"main": "tools/node.js",
"bin": {
"uglifyjs": "bin/uglifyjs"
},
"files": [
"bin",
"lib",
"tools",
"LICENSE"
],
"dependencies": { "dependencies": {
"async" : "~0.2.6", "async": "~0.2.6",
"source-map" : "0.1.34", "source-map": "0.1.34",
"yargs": "~3.5.4", "uglify-to-browserify": "~1.0.0",
"uglify-to-browserify": "~1.0.0" "yargs": "~3.5.4"
}, },
"devDependencies": { "devDependencies": {
"acorn": "~0.6.0", "acorn": "~0.6.0",
@ -27,11 +41,11 @@
"estraverse": "~1.5.1" "estraverse": "~1.5.1"
}, },
"browserify": { "browserify": {
"transform": [ "uglify-to-browserify" ] "transform": [
"uglify-to-browserify"
]
}, },
"bin": { "scripts": {
"uglifyjs" : "bin/uglifyjs" "test": "node test/run-tests.js"
}, }
"license": "BSD",
"scripts": {"test": "node test/run-tests.js"}
} }

View File

@ -153,6 +153,7 @@ cond_1: {
conditionals: true conditionals: true
}; };
input: { input: {
var do_something; // if undeclared it's assumed to have side-effects
if (some_condition()) { if (some_condition()) {
do_something(x); do_something(x);
} else { } else {
@ -160,6 +161,7 @@ cond_1: {
} }
} }
expect: { expect: {
var do_something;
do_something(some_condition() ? x : y); do_something(some_condition() ? x : y);
} }
} }
@ -169,7 +171,7 @@ cond_2: {
conditionals: true conditionals: true
}; };
input: { input: {
var x; var x, FooBar;
if (some_condition()) { if (some_condition()) {
x = new FooBar(1); x = new FooBar(1);
} else { } else {
@ -177,7 +179,7 @@ cond_2: {
} }
} }
expect: { expect: {
var x; var x, FooBar;
x = new FooBar(some_condition() ? 1 : 2); x = new FooBar(some_condition() ? 1 : 2);
} }
} }
@ -187,6 +189,7 @@ cond_3: {
conditionals: true conditionals: true
}; };
input: { input: {
var FooBar;
if (some_condition()) { if (some_condition()) {
new FooBar(1); new FooBar(1);
} else { } else {
@ -194,6 +197,7 @@ cond_3: {
} }
} }
expect: { expect: {
var FooBar;
some_condition() ? new FooBar(1) : FooBar(2); some_condition() ? new FooBar(1) : FooBar(2);
} }
} }
@ -203,6 +207,7 @@ cond_4: {
conditionals: true conditionals: true
}; };
input: { input: {
var do_something;
if (some_condition()) { if (some_condition()) {
do_something(); do_something();
} else { } else {
@ -210,6 +215,7 @@ cond_4: {
} }
} }
expect: { expect: {
var do_something;
some_condition(), do_something(); some_condition(), do_something();
} }
} }

View File

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

View File

@ -84,7 +84,12 @@ function run_compress_tests() {
warnings: false warnings: false
}); });
var cmp = new U.Compressor(options, true); var cmp = new U.Compressor(options, true);
var expect = make_code(as_toplevel(test.expect), false); var expect;
if (test.expect) {
expect = make_code(as_toplevel(test.expect), false);
} else {
expect = test.expect_exact;
}
var input = as_toplevel(test.input); var input = as_toplevel(test.input);
var input_code = make_code(test.input); var input_code = make_code(test.input);
var output = input.transform(cmp); var output = input.transform(cmp);
@ -150,7 +155,7 @@ function parse_test(file) {
} }
if (node instanceof U.AST_LabeledStatement) { if (node instanceof U.AST_LabeledStatement) {
assert.ok( assert.ok(
node.label.name == "input" || node.label.name == "expect", node.label.name == "input" || node.label.name == "expect" || node.label.name == "expect_exact",
tmpl("Unsupported label {name} [{line},{col}]", { tmpl("Unsupported label {name} [{line},{col}]", {
name: node.label.name, name: node.label.name,
line: node.label.start.line, line: node.label.start.line,
@ -162,7 +167,16 @@ function parse_test(file) {
if (stat.body.length == 1) stat = stat.body[0]; if (stat.body.length == 1) stat = stat.body[0];
else if (stat.body.length == 0) stat = new U.AST_EmptyStatement(); else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
} }
if (node.label.name === "expect_exact") {
if (!(stat.TYPE === "SimpleStatement" && stat.body.TYPE === "String")) {
throw new Error(
"The value of the expect_exact clause should be a string, " +
"like `expect_exact: \"some.exact.javascript;\"`");
}
test[node.label.name] = stat.body.start.value
} else {
test[node.label.name] = stat; test[node.label.name] = stat;
}
return true; return true;
} }
}); });

View File

@ -1,10 +1,8 @@
var path = require("path"); var path = require("path");
var fs = require("fs"); var fs = require("fs");
var vm = require("vm"); var vm = require("vm");
var sys = require("util");
var UglifyJS = vm.createContext({ var UglifyJS = vm.createContext({
sys : sys,
console : console, console : console,
process : process, process : process,
Buffer : Buffer, Buffer : Buffer,
@ -19,7 +17,7 @@ function load_global(file) {
} catch(ex) { } catch(ex) {
// XXX: in case of a syntax error, the message is kinda // XXX: in case of a syntax error, the message is kinda
// useless. (no location information). // useless. (no location information).
sys.debug("ERROR in file: " + file + " / " + ex); console.log("ERROR in file: " + file + " / " + ex);
process.exit(1); process.exit(1);
} }
}; };
@ -42,7 +40,7 @@ var FILES = exports.FILES = [
FILES.forEach(load_global); FILES.forEach(load_global);
UglifyJS.AST_Node.warn_function = function(txt) { UglifyJS.AST_Node.warn_function = function(txt) {
sys.error("WARN: " + txt); console.error("WARN: %s", txt);
}; };
// XXX: perhaps we shouldn't export everything but heck, I'm lazy. // XXX: perhaps we shouldn't export everything but heck, I'm lazy.