Merge branch 'master' into fix-harmony
This commit is contained in:
35
README.md
35
README.md
@@ -133,7 +133,16 @@ The available options are:
|
|||||||
--reserved-file File containing reserved names
|
--reserved-file File containing reserved names
|
||||||
--reserve-domprops Make (most?) DOM properties reserved for
|
--reserve-domprops Make (most?) DOM properties reserved for
|
||||||
--mangle-props
|
--mangle-props
|
||||||
--mangle-props Mangle property names
|
--mangle-props Mangle property names (default `0`). Set to
|
||||||
|
`true` or `1` to mangle all property names. Set
|
||||||
|
to `unquoted` or `2` to only mangle unquoted
|
||||||
|
property names. Mode `2` also enables the
|
||||||
|
`keep_quoted_props` beautifier option to
|
||||||
|
preserve the quotes around property names and
|
||||||
|
disables the `properties` compressor option to
|
||||||
|
prevent rewriting quoted properties with dot
|
||||||
|
notation. You can override these by setting
|
||||||
|
them explicitly on the command line.
|
||||||
--mangle-regex Only mangle property names matching the regex
|
--mangle-regex Only mangle property names matching the regex
|
||||||
--name-cache File to hold mangled names mappings
|
--name-cache File to hold mangled names mappings
|
||||||
--pure-funcs List of functions that can be safely removed if
|
--pure-funcs List of functions that can be safely removed if
|
||||||
@@ -291,12 +300,19 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
|||||||
|
|
||||||
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
|
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
|
||||||
|
|
||||||
|
- `unsafe_comps` (default: false) -- Reverse `<` and `<=` to `>` and `>=` to
|
||||||
|
allow improved compression. This might be unsafe when an at least one of two
|
||||||
|
operands is an object with computed values due the use of methods like `get`,
|
||||||
|
or `valueOf`. This could cause change in execution order after operands in the
|
||||||
|
comparison are switching. Compression only works if both `comparisons` and
|
||||||
|
`unsafe_comps` are both set to true.
|
||||||
|
|
||||||
- `conditionals` -- apply optimizations for `if`-s and conditional
|
- `conditionals` -- apply optimizations for `if`-s and conditional
|
||||||
expressions
|
expressions
|
||||||
|
|
||||||
- `comparisons` -- apply certain optimizations to binary nodes, for example:
|
- `comparisons` -- apply certain optimizations to binary nodes, for example:
|
||||||
`!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes,
|
`!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
|
||||||
e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
|
nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
|
||||||
|
|
||||||
- `evaluate` -- attempt to evaluate constant expressions
|
- `evaluate` -- attempt to evaluate constant expressions
|
||||||
|
|
||||||
@@ -415,7 +431,7 @@ them. If you are targeting < ES6 environments, use `/** @const */ var`.
|
|||||||
<a name="codegen-options"></a>
|
<a name="codegen-options"></a>
|
||||||
|
|
||||||
#### Conditional compilation, API
|
#### Conditional compilation, API
|
||||||
You can also use conditional compilation via the programmatic API. With the difference that the
|
You can also use conditional compilation via the programmatic API. With the difference that the
|
||||||
property name is `global_defs` and is a compressor property:
|
property name is `global_defs` and is a compressor property:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@@ -445,7 +461,7 @@ can pass additional arguments that control the code output:
|
|||||||
objects
|
objects
|
||||||
- `space-colon` (default `true`) -- insert a space after the colon signs
|
- `space-colon` (default `true`) -- insert a space after the colon signs
|
||||||
- `ascii-only` (default `false`) -- escape Unicode characters in strings and
|
- `ascii-only` (default `false`) -- escape Unicode characters in strings and
|
||||||
regexps
|
regexps (affects directives with non-ascii characters becoming invalid)
|
||||||
- `inline-script` (default `false`) -- escape the slash in occurrences of
|
- `inline-script` (default `false`) -- escape the slash in occurrences of
|
||||||
`</script` in strings
|
`</script` in strings
|
||||||
- `width` (default 80) -- only takes effect when beautification is on, this
|
- `width` (default 80) -- only takes effect when beautification is on, this
|
||||||
@@ -472,6 +488,8 @@ can pass additional arguments that control the code output:
|
|||||||
- `1` -- always use single quotes
|
- `1` -- always use single quotes
|
||||||
- `2` -- always use double quotes
|
- `2` -- always use double quotes
|
||||||
- `3` -- always use the original quotes
|
- `3` -- always use the original quotes
|
||||||
|
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
|
||||||
|
quotes from property names in object literals.
|
||||||
|
|
||||||
### Keeping copyright notices or other comments
|
### Keeping copyright notices or other comments
|
||||||
|
|
||||||
@@ -658,9 +676,14 @@ Other options:
|
|||||||
- `parse` (default {}) — pass an object if you wish to specify some
|
- `parse` (default {}) — pass an object if you wish to specify some
|
||||||
additional [parser options][parser]. (not all options available... see below)
|
additional [parser options][parser]. (not all options available... see below)
|
||||||
|
|
||||||
|
##### mangle
|
||||||
|
|
||||||
|
- `except` - pass an array of identifiers that should be excluded from mangling
|
||||||
|
|
||||||
##### mangleProperties options
|
##### mangleProperties options
|
||||||
|
|
||||||
- `regex` — Pass a RegExp to only mangle certain names (maps to the `--mange-regex` CLI arguments option)
|
- `regex` — Pass a RegExp to only mangle certain names (maps to the `--mangle-regex` CLI arguments option)
|
||||||
|
- `ignore_quoted` – Only mangle unquoted property names (maps to the `--mangle-props 2` CLI arguments option)
|
||||||
|
|
||||||
We could add more options to `UglifyJS.minify` — if you need additional
|
We could add more options to `UglifyJS.minify` — if you need additional
|
||||||
functionality please suggest!
|
functionality please suggest!
|
||||||
|
|||||||
24
bin/uglifyjs
24
bin/uglifyjs
@@ -69,7 +69,7 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.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("reserved-file", "File containing reserved names")
|
||||||
.describe("reserve-domprops", "Make (most?) DOM properties reserved for --mangle-props")
|
.describe("reserve-domprops", "Make (most?) DOM properties reserved for --mangle-props")
|
||||||
.describe("mangle-props", "Mangle property names")
|
.describe("mangle-props", "Mangle property names (0 - disabled, 1 - mangle all properties, 2 - mangle unquoted properies)")
|
||||||
.describe("mangle-regex", "Only mangle property names matching the regex")
|
.describe("mangle-regex", "Only mangle property names matching the regex")
|
||||||
.describe("name-cache", "File to hold mangled names mappings")
|
.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("pure-funcs", "List of functions that can be safely removed if their return value is not used")
|
||||||
@@ -125,7 +125,6 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.boolean("noerr")
|
.boolean("noerr")
|
||||||
.boolean("bare-returns")
|
.boolean("bare-returns")
|
||||||
.boolean("keep-fnames")
|
.boolean("keep-fnames")
|
||||||
.boolean("mangle-props")
|
|
||||||
.boolean("reserve-domprops")
|
.boolean("reserve-domprops")
|
||||||
|
|
||||||
.wrap(80)
|
.wrap(80)
|
||||||
@@ -213,12 +212,24 @@ if (ARGS.quotes === true) {
|
|||||||
ARGS.quotes = 3;
|
ARGS.quotes = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ARGS.mangle_props === true) {
|
||||||
|
ARGS.mangle_props = 1;
|
||||||
|
} else if (ARGS.mangle_props === "unquoted") {
|
||||||
|
ARGS.mangle_props = 2;
|
||||||
|
}
|
||||||
|
|
||||||
var OUTPUT_OPTIONS = {
|
var OUTPUT_OPTIONS = {
|
||||||
beautify : BEAUTIFY ? true : false,
|
beautify : BEAUTIFY ? true : false,
|
||||||
preamble : ARGS.preamble || null,
|
preamble : ARGS.preamble || null,
|
||||||
quote_style : ARGS.quotes != null ? ARGS.quotes : 0
|
quote_style : ARGS.quotes != null ? ARGS.quotes : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ARGS.mangle_props == 2) {
|
||||||
|
OUTPUT_OPTIONS.keep_quoted_props = true;
|
||||||
|
if (COMPRESS && !("properties" in COMPRESS))
|
||||||
|
COMPRESS.properties = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (ARGS.screw_ie8) {
|
if (ARGS.screw_ie8) {
|
||||||
if (COMPRESS) COMPRESS.screw_ie8 = true;
|
if (COMPRESS) COMPRESS.screw_ie8 = true;
|
||||||
if (MANGLE) MANGLE.screw_ie8 = true;
|
if (MANGLE) MANGLE.screw_ie8 = true;
|
||||||
@@ -401,10 +412,11 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, {
|
TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, {
|
||||||
reserved : reserved,
|
reserved : reserved,
|
||||||
cache : cache,
|
cache : cache,
|
||||||
only_cache : !ARGS.mangle_props,
|
only_cache : !ARGS.mangle_props,
|
||||||
regex : regex
|
regex : regex,
|
||||||
|
ignore_quoted : ARGS.mangle_props == 2
|
||||||
});
|
});
|
||||||
writeNameCache("props", cache);
|
writeNameCache("props", cache);
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1102,8 +1102,6 @@ merge(Compressor.prototype, {
|
|||||||
case "<=" : return ev(left, c) <= ev(right, c);
|
case "<=" : return ev(left, c) <= ev(right, c);
|
||||||
case ">" : return ev(left, c) > ev(right, c);
|
case ">" : return ev(left, c) > ev(right, c);
|
||||||
case ">=" : return ev(left, c) >= ev(right, c);
|
case ">=" : return ev(left, c) >= ev(right, c);
|
||||||
case "in" : return ev(left, c) in ev(right, c);
|
|
||||||
case "instanceof" : return ev(left, c) instanceof ev(right, c);
|
|
||||||
}
|
}
|
||||||
throw def;
|
throw def;
|
||||||
});
|
});
|
||||||
@@ -2580,9 +2578,11 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
self = best_of(self, negated);
|
self = best_of(self, negated);
|
||||||
}
|
}
|
||||||
switch (self.operator) {
|
if (compressor.option("unsafe_comps")) {
|
||||||
case "<": reverse(">"); break;
|
switch (self.operator) {
|
||||||
case "<=": reverse(">="); break;
|
case "<": reverse(">"); break;
|
||||||
|
case "<=": reverse(">="); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.operator == "+" && self.right instanceof AST_String
|
if (self.operator == "+" && self.right instanceof AST_String
|
||||||
|
|||||||
@@ -43,6 +43,8 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
|
||||||
|
|
||||||
function OutputStream(options) {
|
function OutputStream(options) {
|
||||||
|
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
@@ -64,7 +66,8 @@ function OutputStream(options) {
|
|||||||
preserve_line : false,
|
preserve_line : false,
|
||||||
screw_ie8 : false,
|
screw_ie8 : false,
|
||||||
preamble : null,
|
preamble : null,
|
||||||
quote_style : 0
|
quote_style : 0,
|
||||||
|
keep_quoted_props: false
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
var indentation = 0;
|
var indentation = 0;
|
||||||
@@ -359,7 +362,18 @@ function OutputStream(options) {
|
|||||||
force_semicolon : force_semicolon,
|
force_semicolon : force_semicolon,
|
||||||
to_ascii : to_ascii,
|
to_ascii : to_ascii,
|
||||||
print_name : function(name) { print(make_name(name)) },
|
print_name : function(name) { print(make_name(name)) },
|
||||||
print_string : function(str, quote) { print(encode_string(str, quote)) },
|
print_string : function(str, quote, escape_directive) {
|
||||||
|
var encoded = encode_string(str, quote);
|
||||||
|
if (escape_directive === true && encoded.indexOf("\\") === -1) {
|
||||||
|
// Insert semicolons to break directive prologue
|
||||||
|
if (!EXPECT_DIRECTIVE.test(OUTPUT)) {
|
||||||
|
force_semicolon();
|
||||||
|
}
|
||||||
|
force_semicolon();
|
||||||
|
}
|
||||||
|
print(encoded);
|
||||||
|
},
|
||||||
|
encode_string : encode_string,
|
||||||
next_indent : next_indent,
|
next_indent : next_indent,
|
||||||
with_indent : with_indent,
|
with_indent : with_indent,
|
||||||
with_block : with_block,
|
with_block : with_block,
|
||||||
@@ -391,10 +405,11 @@ function OutputStream(options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var use_asm = false;
|
var use_asm = false;
|
||||||
|
var in_directive = 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, prev_use_asm = use_asm;
|
||||||
if (self instanceof AST_Directive && self.value == "use asm") {
|
if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
|
||||||
use_asm = true;
|
use_asm = true;
|
||||||
}
|
}
|
||||||
function doit() {
|
function doit() {
|
||||||
@@ -409,7 +424,7 @@ function OutputStream(options) {
|
|||||||
doit();
|
doit();
|
||||||
}
|
}
|
||||||
stream.pop_node();
|
stream.pop_node();
|
||||||
if (self instanceof AST_Lambda) {
|
if (self instanceof AST_Scope) {
|
||||||
use_asm = prev_use_asm;
|
use_asm = prev_use_asm;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -683,9 +698,16 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
/* -----[ statements ]----- */
|
/* -----[ statements ]----- */
|
||||||
|
|
||||||
function display_body(body, is_toplevel, output) {
|
function display_body(body, is_toplevel, output, allow_directives) {
|
||||||
var last = body.length - 1;
|
var last = body.length - 1;
|
||||||
|
in_directive = allow_directives;
|
||||||
body.forEach(function(stmt, i){
|
body.forEach(function(stmt, i){
|
||||||
|
if (in_directive === true && !(stmt instanceof AST_Directive ||
|
||||||
|
stmt instanceof AST_EmptyStatement ||
|
||||||
|
(stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String)
|
||||||
|
)) {
|
||||||
|
in_directive = false;
|
||||||
|
}
|
||||||
if (!(stmt instanceof AST_EmptyStatement)) {
|
if (!(stmt instanceof AST_EmptyStatement)) {
|
||||||
output.indent();
|
output.indent();
|
||||||
stmt.print(output);
|
stmt.print(output);
|
||||||
@@ -694,7 +716,14 @@ function OutputStream(options) {
|
|||||||
if (is_toplevel) output.newline();
|
if (is_toplevel) output.newline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (in_directive === true &&
|
||||||
|
stmt instanceof AST_SimpleStatement &&
|
||||||
|
stmt.body instanceof AST_String
|
||||||
|
) {
|
||||||
|
in_directive = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
in_directive = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
|
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
|
||||||
@@ -706,7 +735,7 @@ function OutputStream(options) {
|
|||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Toplevel, function(self, output){
|
DEFPRINT(AST_Toplevel, function(self, output){
|
||||||
display_body(self.body, true, output);
|
display_body(self.body, true, output, true);
|
||||||
output.print("");
|
output.print("");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_LabeledStatement, function(self, output){
|
DEFPRINT(AST_LabeledStatement, function(self, output){
|
||||||
@@ -718,9 +747,9 @@ function OutputStream(options) {
|
|||||||
self.body.print(output);
|
self.body.print(output);
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
function print_bracketed(body, output) {
|
function print_bracketed(body, output, allow_directives) {
|
||||||
if (body.length > 0) output.with_block(function(){
|
if (body.length > 0) output.with_block(function(){
|
||||||
display_body(body, false, output);
|
display_body(body, false, output, allow_directives);
|
||||||
});
|
});
|
||||||
else output.print("{}");
|
else output.print("{}");
|
||||||
};
|
};
|
||||||
@@ -829,7 +858,7 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
print_bracketed(self.body, output);
|
print_bracketed(self.body, output, true);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Lambda, function(self, output){
|
DEFPRINT(AST_Lambda, function(self, output){
|
||||||
self._do_print(output);
|
self._do_print(output);
|
||||||
@@ -1363,7 +1392,11 @@ function OutputStream(options) {
|
|||||||
&& parseFloat(key) >= 0) {
|
&& parseFloat(key) >= 0) {
|
||||||
output.print(make_num(key));
|
output.print(make_num(key));
|
||||||
} else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
|
} else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
|
||||||
output.print_name(key);
|
if (quote && output.option("keep_quoted_props")) {
|
||||||
|
output.print_string(key, quote);
|
||||||
|
} else {
|
||||||
|
output.print_name(key);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
output.print_string(key, quote);
|
output.print_string(key, quote);
|
||||||
}
|
}
|
||||||
@@ -1433,10 +1466,10 @@ function OutputStream(options) {
|
|||||||
output.print(self.getValue());
|
output.print(self.getValue());
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_String, function(self, output){
|
DEFPRINT(AST_String, function(self, output){
|
||||||
output.print_string(self.getValue(), self.quote);
|
output.print_string(self.getValue(), self.quote, in_directive);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Number, function(self, output){
|
DEFPRINT(AST_Number, function(self, output){
|
||||||
if (use_asm && self.start.raw != null) {
|
if (use_asm && self.start && self.start.raw != null) {
|
||||||
output.print(self.start.raw);
|
output.print(self.start.raw);
|
||||||
} else {
|
} else {
|
||||||
output.print(make_num(self.getValue()));
|
output.print(make_num(self.getValue()));
|
||||||
@@ -1535,7 +1568,9 @@ function OutputStream(options) {
|
|||||||
// self should be AST_New. decide if we want to show parens or not.
|
// self should be AST_New. decide if we want to show parens or not.
|
||||||
function need_constructor_parens(self, output) {
|
function need_constructor_parens(self, output) {
|
||||||
// Always print parentheses with arguments
|
// Always print parentheses with arguments
|
||||||
return self.args.length > 0;
|
if (self.args.length > 0) return true;
|
||||||
|
|
||||||
|
return output.option("beautify");
|
||||||
};
|
};
|
||||||
|
|
||||||
function best_of(a) {
|
function best_of(a) {
|
||||||
|
|||||||
37
lib/parse.js
37
lib/parse.js
@@ -852,9 +852,10 @@ function parse($TEXT, options) {
|
|||||||
handle_regexp();
|
handle_regexp();
|
||||||
switch (S.token.type) {
|
switch (S.token.type) {
|
||||||
case "string":
|
case "string":
|
||||||
if (S.in_directives) {
|
var dir = false;
|
||||||
if (is_token(peek(), "punc", ";") || peek().nlb) {
|
if (S.in_directives === true) {
|
||||||
S.input.add_directive(S.token.raw.substr(1, S.token.raw.length - 2));
|
if ((is_token(peek(), "punc", ";") || peek().nlb) && S.token.raw.indexOf("\\") === -1) {
|
||||||
|
S.input.add_directive(S.token.value);
|
||||||
} else {
|
} else {
|
||||||
S.in_directives = false;
|
S.in_directives = false;
|
||||||
}
|
}
|
||||||
@@ -893,6 +894,7 @@ function parse($TEXT, options) {
|
|||||||
case "`":
|
case "`":
|
||||||
return simple_statement();
|
return simple_statement();
|
||||||
case ";":
|
case ";":
|
||||||
|
S.in_directives = false;
|
||||||
next();
|
next();
|
||||||
return new AST_EmptyStatement();
|
return new AST_EmptyStatement();
|
||||||
default:
|
default:
|
||||||
@@ -937,7 +939,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
case "return":
|
case "return":
|
||||||
if (S.in_function == 0 && !options.bare_returns)
|
if (S.in_function == 0 && !options.bare_returns)
|
||||||
croak("'return' outside of function");
|
croak("SyntaxError: 'return' outside of function");
|
||||||
return new AST_Return({
|
return new AST_Return({
|
||||||
value: ( is("punc", ";")
|
value: ( is("punc", ";")
|
||||||
? (next(), null)
|
? (next(), null)
|
||||||
@@ -954,7 +956,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
case "throw":
|
case "throw":
|
||||||
if (S.token.nlb)
|
if (S.token.nlb)
|
||||||
croak("Illegal newline after 'throw'");
|
croak("SyntaxError: Illegal newline after 'throw'");
|
||||||
return new AST_Throw({
|
return new AST_Throw({
|
||||||
value: (tmp = expression(true), semicolon(), tmp)
|
value: (tmp = expression(true), semicolon(), tmp)
|
||||||
});
|
});
|
||||||
@@ -972,6 +974,9 @@ function parse($TEXT, options) {
|
|||||||
return tmp = const_(), semicolon(), tmp;
|
return tmp = const_(), semicolon(), tmp;
|
||||||
|
|
||||||
case "with":
|
case "with":
|
||||||
|
if (S.input.has_directive("use strict")) {
|
||||||
|
croak("SyntaxError: Strict mode may not include a with statement");
|
||||||
|
}
|
||||||
return new AST_With({
|
return new AST_With({
|
||||||
expression : parenthesised(),
|
expression : parenthesised(),
|
||||||
body : statement()
|
body : statement()
|
||||||
@@ -1000,7 +1005,7 @@ function parse($TEXT, options) {
|
|||||||
// syntactically incorrect if it contains a
|
// syntactically incorrect if it contains a
|
||||||
// LabelledStatement that is enclosed by a
|
// LabelledStatement that is enclosed by a
|
||||||
// LabelledStatement with the same Identifier as label.
|
// LabelledStatement with the same Identifier as label.
|
||||||
croak("Label " + label.name + " defined twice");
|
croak("SyntaxError: Label " + label.name + " defined twice");
|
||||||
}
|
}
|
||||||
expect(":");
|
expect(":");
|
||||||
S.labels.push(label);
|
S.labels.push(label);
|
||||||
@@ -1013,7 +1018,7 @@ function parse($TEXT, options) {
|
|||||||
label.references.forEach(function(ref){
|
label.references.forEach(function(ref){
|
||||||
if (ref instanceof AST_Continue) {
|
if (ref instanceof AST_Continue) {
|
||||||
ref = ref.label.start;
|
ref = ref.label.start;
|
||||||
croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
|
croak("SyntaxError: Continue label `" + label.name + "` refers to non-IterationStatement.",
|
||||||
ref.line, ref.col, ref.pos);
|
ref.line, ref.col, ref.pos);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1033,11 +1038,11 @@ function parse($TEXT, options) {
|
|||||||
if (label != null) {
|
if (label != null) {
|
||||||
ldef = find_if(function(l){ return l.name == label.name }, S.labels);
|
ldef = find_if(function(l){ return l.name == label.name }, S.labels);
|
||||||
if (!ldef)
|
if (!ldef)
|
||||||
croak("Undefined label " + label.name);
|
croak("SyntaxError: Undefined label " + label.name);
|
||||||
label.thedef = ldef;
|
label.thedef = ldef;
|
||||||
}
|
}
|
||||||
else if (S.in_loop == 0)
|
else if (S.in_loop == 0)
|
||||||
croak(type.TYPE + " not inside a loop or switch");
|
croak("SyntaxError: " + type.TYPE + " not inside a loop or switch");
|
||||||
semicolon();
|
semicolon();
|
||||||
var stat = new type({ label: label });
|
var stat = new type({ label: label });
|
||||||
if (ldef) ldef.references.push(stat);
|
if (ldef) ldef.references.push(stat);
|
||||||
@@ -1058,7 +1063,7 @@ function parse($TEXT, options) {
|
|||||||
if (is_in || is_of) {
|
if (is_in || is_of) {
|
||||||
if ((init instanceof AST_Definitions) &&
|
if ((init instanceof AST_Definitions) &&
|
||||||
init.definitions.length > 1)
|
init.definitions.length > 1)
|
||||||
croak("Only one variable declaration allowed in for..in loop");
|
croak("SyntaxError: Only one variable declaration allowed in for..in loop");
|
||||||
next();
|
next();
|
||||||
if (is_in) {
|
if (is_in) {
|
||||||
return for_in(init);
|
return for_in(init);
|
||||||
@@ -1330,7 +1335,7 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!bcatch && !bfinally)
|
if (!bcatch && !bfinally)
|
||||||
croak("Missing catch/finally blocks");
|
croak("SyntaxError: Missing catch/finally blocks");
|
||||||
return new AST_Try({
|
return new AST_Try({
|
||||||
body : body,
|
body : body,
|
||||||
bcatch : bcatch,
|
bcatch : bcatch,
|
||||||
@@ -1497,8 +1502,8 @@ function parse($TEXT, options) {
|
|||||||
break;
|
break;
|
||||||
case "operator":
|
case "operator":
|
||||||
if (!is_identifier_string(tok.value)) {
|
if (!is_identifier_string(tok.value)) {
|
||||||
throw new JS_Parse_Error("Invalid getter/setter name: " + tok.value,
|
croak("SyntaxError: Invalid getter/setter name: " + tok.value,
|
||||||
tok.file, tok.line, tok.col, tok.pos);
|
tok.line, tok.col, tok.pos);
|
||||||
}
|
}
|
||||||
ret = _make_symbol(AST_SymbolRef);
|
ret = _make_symbol(AST_SymbolRef);
|
||||||
break;
|
break;
|
||||||
@@ -1917,7 +1922,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function as_symbol(type, noerror) {
|
function as_symbol(type, noerror) {
|
||||||
if (!is("name")) {
|
if (!is("name")) {
|
||||||
if (!noerror) croak("Name expected");
|
if (!noerror) croak("SyntaxError: Name expected");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (is("name", "yield") && S.input.has_directive("use strict")) {
|
if (is("name", "yield") && S.input.has_directive("use strict")) {
|
||||||
@@ -2003,7 +2008,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function make_unary(ctor, op, expr) {
|
function make_unary(ctor, op, expr) {
|
||||||
if ((op == "++" || op == "--") && !is_assignable(expr))
|
if ((op == "++" || op == "--") && !is_assignable(expr))
|
||||||
croak("Invalid use of " + op + " operator");
|
croak("SyntaxError: Invalid use of " + op + " operator");
|
||||||
return new ctor({ operator: op, expression: expr });
|
return new ctor({ operator: op, expression: expr });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2087,7 +2092,7 @@ function parse($TEXT, options) {
|
|||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
croak("Invalid assignment");
|
croak("SyntaxError: Invalid assignment");
|
||||||
}
|
}
|
||||||
if (is("arrow")) {
|
if (is("arrow")) {
|
||||||
left = new AST_SymbolFunarg({
|
left = new AST_SymbolFunarg({
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ function mangle_properties(ast, options) {
|
|||||||
reserved : null,
|
reserved : null,
|
||||||
cache : null,
|
cache : null,
|
||||||
only_cache : false,
|
only_cache : false,
|
||||||
regex : null
|
regex : null,
|
||||||
|
ignore_quoted : false
|
||||||
});
|
});
|
||||||
|
|
||||||
var reserved = options.reserved;
|
var reserved = options.reserved;
|
||||||
@@ -87,6 +88,7 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var regex = options.regex;
|
var regex = options.regex;
|
||||||
|
var ignore_quoted = options.ignore_quoted;
|
||||||
|
|
||||||
var names_to_mangle = [];
|
var names_to_mangle = [];
|
||||||
var unmangleable = [];
|
var unmangleable = [];
|
||||||
@@ -94,7 +96,8 @@ function mangle_properties(ast, options) {
|
|||||||
// step 1: find candidates to mangle
|
// step 1: find candidates to mangle
|
||||||
ast.walk(new TreeWalker(function(node){
|
ast.walk(new TreeWalker(function(node){
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
add(node.key);
|
if (!(ignore_quoted && node.quote))
|
||||||
|
add(node.key);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ObjectProperty) {
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter, since KeyVal is handled above
|
// setter or getter, since KeyVal is handled above
|
||||||
@@ -107,7 +110,8 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
else if (node instanceof AST_Sub) {
|
else if (node instanceof AST_Sub) {
|
||||||
if (this.parent() instanceof AST_Assign) {
|
if (this.parent() instanceof AST_Assign) {
|
||||||
addStrings(node.property);
|
if (!ignore_quoted)
|
||||||
|
addStrings(node.property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ConciseMethod) {
|
else if (node instanceof AST_ConciseMethod) {
|
||||||
@@ -118,7 +122,8 @@ function mangle_properties(ast, options) {
|
|||||||
// step 2: transform the tree, renaming properties
|
// step 2: transform the tree, renaming properties
|
||||||
return ast.transform(new TreeTransformer(function(node){
|
return ast.transform(new TreeTransformer(function(node){
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
node.key = mangle(node.key);
|
if (!(ignore_quoted && node.quote))
|
||||||
|
node.key = mangle(node.key);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ObjectProperty) {
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter
|
// setter or getter
|
||||||
@@ -128,7 +133,8 @@ function mangle_properties(ast, options) {
|
|||||||
node.property = mangle(node.property);
|
node.property = mangle(node.property);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Sub) {
|
else if (node instanceof AST_Sub) {
|
||||||
node.property = mangleStrings(node.property);
|
if (!ignore_quoted)
|
||||||
|
node.property = mangleStrings(node.property);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ConciseMethod) {
|
else if (node instanceof AST_ConciseMethod) {
|
||||||
if (should_mangle(node.name.name)) {
|
if (should_mangle(node.name.name)) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "2.6.2",
|
"version": "2.6.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ asm_mixed: {
|
|||||||
function logSum(start, end) {
|
function logSum(start, end) {
|
||||||
start = 0 | start, end = 0 | end;
|
start = 0 | start, end = 0 | end;
|
||||||
var sum = 0, p = 0, q = 0;
|
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]);
|
for (p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0) sum += +log(values[p >> 3]);
|
||||||
return +sum;
|
return +sum;
|
||||||
}
|
}
|
||||||
function geometricMean(start, end) {
|
function geometricMean(start, end) {
|
||||||
|
|||||||
76
test/compress/comparing.js
Normal file
76
test/compress/comparing.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
keep_comparisons: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
unsafe_comps: false
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj1 = {
|
||||||
|
valueOf: function() {triggeredFirst();}
|
||||||
|
}
|
||||||
|
var obj2 = {
|
||||||
|
valueOf: function() {triggeredSecond();}
|
||||||
|
}
|
||||||
|
var result1 = obj1 <= obj2;
|
||||||
|
var result2 = obj1 < obj2;
|
||||||
|
var result3 = obj1 >= obj2;
|
||||||
|
var result4 = obj1 > obj2;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj1 = {
|
||||||
|
valueOf: function() {triggeredFirst();}
|
||||||
|
}
|
||||||
|
var obj2 = {
|
||||||
|
valueOf: function() {triggeredSecond();}
|
||||||
|
}
|
||||||
|
var result1 = obj1 <= obj2;
|
||||||
|
var result2 = obj1 < obj2;
|
||||||
|
var result3 = obj1 >= obj2;
|
||||||
|
var result4 = obj1 > obj2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_comparisons_with_unsafe_comps: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
unsafe_comps: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj1 = {
|
||||||
|
valueOf: function() {triggeredFirst();}
|
||||||
|
}
|
||||||
|
var obj2 = {
|
||||||
|
valueOf: function() {triggeredSecond();}
|
||||||
|
}
|
||||||
|
var result1 = obj1 <= obj2;
|
||||||
|
var result2 = obj1 < obj2;
|
||||||
|
var result3 = obj1 >= obj2;
|
||||||
|
var result4 = obj1 > obj2;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj1 = {
|
||||||
|
valueOf: function() {triggeredFirst();}
|
||||||
|
}
|
||||||
|
var obj2 = {
|
||||||
|
valueOf: function() {triggeredSecond();}
|
||||||
|
}
|
||||||
|
var result1 = obj2 >= obj1;
|
||||||
|
var result2 = obj2 > obj1;
|
||||||
|
var result3 = obj1 >= obj2;
|
||||||
|
var result4 = obj1 > obj2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dont_change_in_or_instanceof_expressions: {
|
||||||
|
input: {
|
||||||
|
1 in 1;
|
||||||
|
null in null;
|
||||||
|
1 instanceof 1;
|
||||||
|
null instanceof null;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
1 in 1;
|
||||||
|
null in null;
|
||||||
|
1 instanceof 1;
|
||||||
|
null instanceof null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,3 +72,54 @@ evaluate_length: {
|
|||||||
a = ("foo" + b).length;
|
a = ("foo" + b).length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mangle_properties: {
|
||||||
|
mangle_props = {
|
||||||
|
ignore_quoted: false
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
a["foo"] = "bar";
|
||||||
|
a.color = "red";
|
||||||
|
x = {"bar": 10};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a["a"] = "bar";
|
||||||
|
a.b = "red";
|
||||||
|
x = {c: 10};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_unquoted_properties: {
|
||||||
|
mangle_props = {
|
||||||
|
ignore_quoted: true
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
beautify: false,
|
||||||
|
quote_style: 3,
|
||||||
|
keep_quoted_props: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f1() {
|
||||||
|
a["foo"] = "bar";
|
||||||
|
a.color = "red";
|
||||||
|
x = {"bar": 10};
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
a.foo = "bar";
|
||||||
|
a['color'] = "red";
|
||||||
|
x = {bar: 10};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f1() {
|
||||||
|
a["foo"] = "bar";
|
||||||
|
a.a = "red";
|
||||||
|
x = {"bar": 10};
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
a.b = "bar";
|
||||||
|
a['color'] = "red";
|
||||||
|
x = {c: 10};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -58,4 +58,313 @@ describe("Directives", function() {
|
|||||||
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
it("Should know which strings are directive and which ones are not", function() {
|
||||||
|
var test_directive = function(tokenizer, test) {
|
||||||
|
test.directives.map(function(directive) {
|
||||||
|
assert.strictEqual(tokenizer.has_directive(directive), true, directive + " in " + test.input);
|
||||||
|
});
|
||||||
|
test.non_directives.map(function(fake_directive) {
|
||||||
|
assert.strictEqual(tokenizer.has_directive(fake_directive), false, fake_directive + " in " + test.input);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = [
|
||||||
|
{
|
||||||
|
input: '"use strict"\n',
|
||||||
|
directives: ["use strict"],
|
||||||
|
non_directives: ["use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use\\\nstrict";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use strict"\n"use asm"\n"use bar"\n',
|
||||||
|
directives: ["use strict", "use asm", "use bar"],
|
||||||
|
non_directives: ["use foo", "use\\x20strict"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use \\\nstrict";"use strict";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"\\76";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: [">", "\\76"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use strict"', // no ; or newline
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ';"use strict"',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
// Duplicate above code but put it in a function
|
||||||
|
{
|
||||||
|
input: 'function foo() {"use strict"\n',
|
||||||
|
directives: ["use strict"],
|
||||||
|
non_directives: ["use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'function foo() {"use\\\nstrict";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'function foo() {"use strict"\n"use asm"\n"use bar"\n',
|
||||||
|
directives: ["use strict", "use asm", "use bar"],
|
||||||
|
non_directives: ["use foo", "use\\x20strict"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'function foo() {"use \\\nstrict";"use strict";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'var foo = function() {"\\76";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: [">", "\\76"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'var foo = function() {"use strict"', // no ; or newline
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'var foo = function() {;"use strict"',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
// Special cases
|
||||||
|
{
|
||||||
|
input: '"1";"2";"3";"4";;"5"',
|
||||||
|
directives: ["1", "2", "3", "4"],
|
||||||
|
non_directives: ["5", "6", "use strict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'if(1){"use strict";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use strict";try{"use asm";',
|
||||||
|
directives: ["use strict"],
|
||||||
|
non_directives: ["use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
// Fail parser deliberately to get state at failure
|
||||||
|
var tokenizer = uglify.tokenizer(tests[i].input + "]", "foo.js");
|
||||||
|
|
||||||
|
try {
|
||||||
|
var parser = uglify.parse(tokenizer);
|
||||||
|
throw new Error("Expected parser to fail");
|
||||||
|
} catch (e) {
|
||||||
|
assert.strictEqual(e instanceof uglify.JS_Parse_Error, true);
|
||||||
|
assert.strictEqual(e.message, "SyntaxError: Unexpected token: punc (])");
|
||||||
|
}
|
||||||
|
|
||||||
|
test_directive(tokenizer, tests[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should test EXPECT_DIRECTIVE RegExp", function() {
|
||||||
|
var tests = [
|
||||||
|
["", true],
|
||||||
|
["'test';", true],
|
||||||
|
["'test';;", true],
|
||||||
|
["'tests';\n", true],
|
||||||
|
["'tests'", false],
|
||||||
|
["'tests'; \n\t", true],
|
||||||
|
["'tests';\n\n", true],
|
||||||
|
["\n\n\"use strict\";\n\n", true]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(uglify.EXPECT_DIRECTIVE.test(tests[i][0]), tests[i][1], tests[i][0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should only print 2 semicolons spread over 2 lines in beautify mode", function() {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(
|
||||||
|
'"use strict";\'use strict\';"use strict";"use strict";;\'use strict\';console.log(\'use strict\');',
|
||||||
|
{fromString: true, output: {beautify: true, quote_style: 3}, compress: false}
|
||||||
|
).code,
|
||||||
|
'"use strict";\n\n\'use strict\';\n\n"use strict";\n\n"use strict";\n\n;\'use strict\';\n\nconsole.log(\'use strict\');'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not add double semicolons in non-scoped block statements to avoid strings becoming directives", function() {
|
||||||
|
var tests = [
|
||||||
|
[
|
||||||
|
'{"use\x20strict"}',
|
||||||
|
'{"use strict"}'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'function foo(){"use\x20strict";}', // Valid place for directives
|
||||||
|
'function foo(){"use strict"}'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'try{"use\x20strict"}catch(e){}finally{"use\x20strict"}',
|
||||||
|
'try{"use strict"}catch(e){}finally{"use strict"}'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'if(1){"use\x20strict"} else {"use strict"}',
|
||||||
|
'if(1){"use strict"}else{"use strict"}'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(tests[i][0], {fromString: true, quote_style: 3, compress: false, mangle: false}).code,
|
||||||
|
tests[i][1],
|
||||||
|
tests[i][0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should add double semicolon when relying on automatic semicolon insertion", function() {
|
||||||
|
var code = uglify.minify('"use strict";"use\\x20strict";',
|
||||||
|
{fromString: true, output: {semicolons: false}, compress: false}
|
||||||
|
).code;
|
||||||
|
assert.strictEqual(code, '"use strict";;"use strict"\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should check quote style of directives", function() {
|
||||||
|
var tests = [
|
||||||
|
// 0. Prefer double quotes, unless string contains more double quotes than single quotes
|
||||||
|
[
|
||||||
|
'"testing something";',
|
||||||
|
0,
|
||||||
|
'"testing something";'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'use strict';",
|
||||||
|
0,
|
||||||
|
'"use strict";'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"\\\'use strict\\\'";', // Not a directive as it contains quotes
|
||||||
|
0,
|
||||||
|
';"\'use strict\'";',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'\"use strict\"';",
|
||||||
|
0,
|
||||||
|
"'\"use strict\"';",
|
||||||
|
],
|
||||||
|
// 1. Always use single quote
|
||||||
|
[
|
||||||
|
'"testing something";',
|
||||||
|
1,
|
||||||
|
"'testing something';"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'use strict';",
|
||||||
|
1,
|
||||||
|
"'use strict';"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"\'use strict\'";',
|
||||||
|
1,
|
||||||
|
// Intentionally causes directive breakage at cost of less logic, usage should be rare anyway
|
||||||
|
"'\\'use strict\\'';",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'\\'use strict\\'';", // Not a valid directive
|
||||||
|
1,
|
||||||
|
"'\\'use strict\\'';" // But no ; necessary as directive stays invalid
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'\"use strict\"';",
|
||||||
|
1,
|
||||||
|
"'\"use strict\"';",
|
||||||
|
],
|
||||||
|
// 2. Always use double quote
|
||||||
|
[
|
||||||
|
'"testing something";',
|
||||||
|
2,
|
||||||
|
'"testing something";'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'use strict';",
|
||||||
|
2,
|
||||||
|
'"use strict";'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"\'use strict\'";',
|
||||||
|
2,
|
||||||
|
"\"'use strict'\";",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'\"use strict\"';",
|
||||||
|
2,
|
||||||
|
// Intentionally causes directive breakage at cost of less logic, usage should be rare anyway
|
||||||
|
'"\\\"use strict\\\"";',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"\\"use strict\\"";', // Not a valid directive
|
||||||
|
2,
|
||||||
|
'"\\"use strict\\"";' // But no ; necessary as directive stays invalid
|
||||||
|
],
|
||||||
|
// 3. Always use original
|
||||||
|
[
|
||||||
|
'"testing something";',
|
||||||
|
3,
|
||||||
|
'"testing something";'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'use strict';",
|
||||||
|
3,
|
||||||
|
"'use strict';",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"\'use strict\'";',
|
||||||
|
3,
|
||||||
|
'"\'use strict\'";',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'\"use strict\"';",
|
||||||
|
3,
|
||||||
|
"'\"use strict\"';",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(tests[i][0], {fromString: true, output:{quote_style: tests[i][1]}, compress: false}).code,
|
||||||
|
tests[i][2],
|
||||||
|
tests[i][0] + " using mode " + tests[i][1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it("Should be able to compress without side effects", function() {
|
||||||
|
// NOTE: the "use asm" directive disables any optimisation after being defined
|
||||||
|
var tests = [
|
||||||
|
[
|
||||||
|
'"use strict";"use strict";"use strict";"use foo";"use strict";;"use sloppy";doSomething("foo");',
|
||||||
|
'"use strict";"use foo";doSomething("foo");'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// Nothing gets optimised in the compressor because "use asm" is the first statement
|
||||||
|
'"use asm";"use\\x20strict";1+1;',
|
||||||
|
'"use asm";;"use strict";1+1;' // Yet, the parser noticed that "use strict" wasn't a directive
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(tests[i][0], {fromString: true, compress: {collapse_vars: true, side_effects: true}}).code,
|
||||||
|
tests[i][1],
|
||||||
|
tests[i][0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ describe("Getters and setters", function() {
|
|||||||
var fail = function(data) {
|
var fail = function(data) {
|
||||||
return function (e) {
|
return function (e) {
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
e.message === "Invalid getter/setter name: " + data.operator;
|
e.message === "SyntaxError: Invalid getter/setter name: " + data.operator;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,5 +7,56 @@ describe("minify", function() {
|
|||||||
var result = Uglify.minify(js, {fromString: true});
|
var result = Uglify.minify(js, {fromString: true});
|
||||||
assert.strictEqual(result.code, 'function foo(n){return n?3:7}');
|
assert.strictEqual(result.code, 'function foo(n){return n?3:7}');
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
describe("keep_quoted_props", function() {
|
||||||
|
it("Should preserve quotes in object literals", function() {
|
||||||
|
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true, output: {
|
||||||
|
keep_quoted_props: true
|
||||||
|
}});
|
||||||
|
assert.strictEqual(result.code, 'var foo={"x":1,y:2,"z":3};');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should preserve quote styles when quote_style is 3", function() {
|
||||||
|
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true, output: {
|
||||||
|
keep_quoted_props: true,
|
||||||
|
quote_style: 3
|
||||||
|
}});
|
||||||
|
assert.strictEqual(result.code, 'var foo={"x":1,y:2,\'z\':3};');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not preserve quotes in object literals when disabled", function() {
|
||||||
|
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true, output: {
|
||||||
|
keep_quoted_props: false,
|
||||||
|
quote_style: 3
|
||||||
|
}});
|
||||||
|
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("mangleProperties", function() {
|
||||||
|
it("Shouldn't mangle quoted properties", function() {
|
||||||
|
var js = 'a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};';
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true,
|
||||||
|
compress: {
|
||||||
|
properties: false
|
||||||
|
},
|
||||||
|
mangleProperties: {
|
||||||
|
ignore_quoted: true
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
keep_quoted_props: true,
|
||||||
|
quote_style: 3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert.strictEqual(result.code,
|
||||||
|
'a["foo"]="bar",a.a="red",x={"bar":10};');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -2,7 +2,49 @@ var assert = require("assert");
|
|||||||
var uglify = require("../../");
|
var uglify = require("../../");
|
||||||
|
|
||||||
describe("New", function() {
|
describe("New", function() {
|
||||||
it("Should attach callback parens after some tokens", function() {
|
it("Should add trailing parentheses for new expressions with zero arguments in beautify mode", function() {
|
||||||
|
var tests = [
|
||||||
|
"new x(1);",
|
||||||
|
"new x;",
|
||||||
|
"new new x;",
|
||||||
|
"new (function(foo){this.foo=foo;})(1);",
|
||||||
|
"new (function(foo){this.foo=foo;})();",
|
||||||
|
"new (function test(foo){this.foo=foo;})(1);",
|
||||||
|
"new (function test(foo){this.foo=foo;})();",
|
||||||
|
"new true;",
|
||||||
|
"new (0);",
|
||||||
|
"new (!0);",
|
||||||
|
"new (bar = function(foo) {this.foo=foo;})(123);",
|
||||||
|
"new (bar = function(foo) {this.foo=foo;})();"
|
||||||
|
];
|
||||||
|
var expected = [
|
||||||
|
"new x(1);",
|
||||||
|
"new x();",
|
||||||
|
"new new x()();",
|
||||||
|
"new function(foo) {\n this.foo = foo;\n}(1);",
|
||||||
|
"new function(foo) {\n this.foo = foo;\n}();",
|
||||||
|
"new function test(foo) {\n this.foo = foo;\n}(1);",
|
||||||
|
"new function test(foo) {\n this.foo = foo;\n}();",
|
||||||
|
"new true();",
|
||||||
|
"new 0();",
|
||||||
|
"new (!0)();",
|
||||||
|
"new (bar = function(foo) {\n this.foo = foo;\n})(123);",
|
||||||
|
"new (bar = function(foo) {\n this.foo = foo;\n})();"
|
||||||
|
];
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(tests[i], {
|
||||||
|
fromString: true,
|
||||||
|
output: {beautify: true},
|
||||||
|
compress: false,
|
||||||
|
mangle: false
|
||||||
|
}).code,
|
||||||
|
expected[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not add trailing parentheses for new expressions with zero arguments in non-beautify mode", function() {
|
||||||
var tests = [
|
var tests = [
|
||||||
"new x(1);",
|
"new x(1);",
|
||||||
"new x;",
|
"new x;",
|
||||||
@@ -20,22 +62,22 @@ describe("New", function() {
|
|||||||
var expected = [
|
var expected = [
|
||||||
"new x(1);",
|
"new x(1);",
|
||||||
"new x;",
|
"new x;",
|
||||||
"new (new x);",
|
"new(new x);",
|
||||||
"new function(foo) {\n this.foo = foo;\n}(1);",
|
"new function(foo){this.foo=foo}(1);",
|
||||||
"new function(foo) {\n this.foo = foo;\n};",
|
"new function(foo){this.foo=foo};",
|
||||||
"new function test(foo) {\n this.foo = foo;\n}(1);",
|
"new function test(foo){this.foo=foo}(1);",
|
||||||
"new function test(foo) {\n this.foo = foo;\n};",
|
"new function test(foo){this.foo=foo};",
|
||||||
"new true;",
|
"new true;",
|
||||||
"new 0;",
|
"new 0;",
|
||||||
"new (!0);",
|
"new(!0);",
|
||||||
"new (bar = function(foo) {\n this.foo = foo;\n})(123);",
|
"new(bar=function(foo){this.foo=foo})(123);",
|
||||||
"new (bar = function(foo) {\n this.foo = foo;\n});"
|
"new(bar=function(foo){this.foo=foo});"
|
||||||
];
|
];
|
||||||
for (var i = 0; i < tests.length; i++) {
|
for (var i = 0; i < tests.length; i++) {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
uglify.minify(tests[i], {
|
uglify.minify(tests[i], {
|
||||||
fromString: true,
|
fromString: true,
|
||||||
output: {beautify: true},
|
output: {beautify: false},
|
||||||
compress: false,
|
compress: false,
|
||||||
mangle: false
|
mangle: false
|
||||||
}).code,
|
}).code,
|
||||||
|
|||||||
@@ -59,13 +59,13 @@ describe("String literals", function() {
|
|||||||
|
|
||||||
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
|
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||||
var tests = [
|
var tests = [
|
||||||
['"\\76";', '">";'],
|
['"\\76";', ';">";'],
|
||||||
['"\\0"', '"\\0";'],
|
['"\\0"', '"\\0";'],
|
||||||
['"\\08"', '"\\08";'],
|
['"\\08"', '"\\08";'],
|
||||||
['"\\008"', '"\\08";'],
|
['"\\008"', '"\\08";'],
|
||||||
['"\\0008"', '"\\08";'],
|
['"\\0008"', '"\\08";'],
|
||||||
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
|
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
|
||||||
// ['"use\\\n strict";\n"\\07";', '"use\\\n strict";\n"\\u0007";'] // TODO No way to store this content literally yet as directive
|
['"use\\\n strict";\n"\\07";', ';"use strict";"\07";']
|
||||||
];
|
];
|
||||||
|
|
||||||
for (var test in tests) {
|
for (var test in tests) {
|
||||||
|
|||||||
16
test/mocha/with.js
Normal file
16
test/mocha/with.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var uglify = require("../../");
|
||||||
|
|
||||||
|
describe("With", function() {
|
||||||
|
it ("Should throw syntaxError when using with statement in strict mode", function() {
|
||||||
|
var code = '"use strict";\nthrow NotEarlyError;\nwith ({}) { }';
|
||||||
|
var test = function() {
|
||||||
|
uglify.parse(code);
|
||||||
|
}
|
||||||
|
var error = function(e) {
|
||||||
|
return e instanceof uglify.JS_Parse_Error &&
|
||||||
|
e.message === "SyntaxError: Strict mode may not include a with statement";
|
||||||
|
}
|
||||||
|
assert.throws(test, error);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#! /usr/bin/env node
|
#! /usr/bin/env node
|
||||||
|
|
||||||
|
global.UGLIFY_DEBUG = true;
|
||||||
|
|
||||||
var U = require("../tools/node");
|
var U = require("../tools/node");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
@@ -110,7 +112,11 @@ function run_compress_tests() {
|
|||||||
expect = test.expect_exact;
|
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, {
|
||||||
|
beautify: true,
|
||||||
|
quote_style: 3,
|
||||||
|
keep_quoted_props: true
|
||||||
|
});
|
||||||
if (test.mangle_props) {
|
if (test.mangle_props) {
|
||||||
input = U.mangle_properties(input, test.mangle_props);
|
input = U.mangle_properties(input, test.mangle_props);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,3 +17,7 @@ exports["string_template"] = string_template;
|
|||||||
exports["tokenizer"] = tokenizer;
|
exports["tokenizer"] = tokenizer;
|
||||||
exports["is_identifier"] = is_identifier;
|
exports["is_identifier"] = is_identifier;
|
||||||
exports["SymbolDef"] = SymbolDef;
|
exports["SymbolDef"] = SymbolDef;
|
||||||
|
|
||||||
|
if (typeof DEBUG !== "undefined" && DEBUG) {
|
||||||
|
exports["EXPECT_DIRECTIVE"] = EXPECT_DIRECTIVE;
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,11 +25,12 @@ var FILES = exports.FILES = [
|
|||||||
|
|
||||||
var UglifyJS = exports;
|
var UglifyJS = exports;
|
||||||
|
|
||||||
new Function("MOZ_SourceMap", "exports", FILES.map(function(file){
|
new Function("MOZ_SourceMap", "exports", "DEBUG", FILES.map(function(file){
|
||||||
return fs.readFileSync(file, "utf8");
|
return fs.readFileSync(file, "utf8");
|
||||||
}).join("\n\n"))(
|
}).join("\n\n"))(
|
||||||
require("source-map"),
|
require("source-map"),
|
||||||
UglifyJS
|
UglifyJS,
|
||||||
|
!!global.UGLIFY_DEBUG
|
||||||
);
|
);
|
||||||
|
|
||||||
UglifyJS.AST_Node.warn_function = function(txt) {
|
UglifyJS.AST_Node.warn_function = function(txt) {
|
||||||
|
|||||||
Reference in New Issue
Block a user