Merge branch 'master' into harmony
This commit is contained in:
@@ -1357,6 +1357,7 @@ merge(Compressor.prototype, {
|
|||||||
if (compressor.has_directive("use asm")) return self;
|
if (compressor.has_directive("use asm")) return self;
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& !self.uses_eval
|
&& !self.uses_eval
|
||||||
|
&& !self.uses_with
|
||||||
) {
|
) {
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
var in_use_ids = {}; // avoid expensive linear scans of in_use
|
var in_use_ids = {}; // avoid expensive linear scans of in_use
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ 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\v\t\x22\x27\u2028\u2029\0\ufeff]/g,
|
||||||
|
function(s, i){
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case '"': ++dq; return '"';
|
case '"': ++dq; return '"';
|
||||||
case "'": ++sq; return "'";
|
case "'": ++sq; return "'";
|
||||||
@@ -101,8 +102,9 @@ function OutputStream(options) {
|
|||||||
case "\x0B": return options.screw_ie8 ? "\\v" : "\\x0B";
|
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 "\0": return "\\x00";
|
|
||||||
case "\ufeff": return "\\ufeff";
|
case "\ufeff": return "\\ufeff";
|
||||||
|
case "\0":
|
||||||
|
return /[0-7]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
@@ -611,7 +613,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
PARENS(AST_New, function(output){
|
PARENS(AST_New, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (no_constructor_parens(this, output)
|
if (!need_constructor_parens(this, output)
|
||||||
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
||||||
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
||||||
return true;
|
return true;
|
||||||
@@ -1175,7 +1177,7 @@ function OutputStream(options) {
|
|||||||
/* -----[ other expressions ]----- */
|
/* -----[ other expressions ]----- */
|
||||||
DEFPRINT(AST_Call, function(self, output){
|
DEFPRINT(AST_Call, function(self, output){
|
||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
if (self instanceof AST_New && no_constructor_parens(self, output))
|
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
||||||
return;
|
return;
|
||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
self.args.forEach(function(expr, i){
|
self.args.forEach(function(expr, i){
|
||||||
@@ -1531,13 +1533,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 no_constructor_parens(self, output) {
|
function need_constructor_parens(self, output) {
|
||||||
return self.args.length == 0 && !output.option("beautify") ||
|
// Always print parentheses with arguments
|
||||||
!(self.expression instanceof AST_SymbolRef ||
|
return self.args.length > 0;
|
||||||
self.expression instanceof AST_Call ||
|
|
||||||
self.expression instanceof AST_Function ||
|
|
||||||
self.expression instanceof AST_Assign
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function best_of(a) {
|
function best_of(a) {
|
||||||
|
|||||||
63
lib/parse.js
63
lib/parse.js
@@ -234,7 +234,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
tokcol : 0,
|
tokcol : 0,
|
||||||
newline_before : false,
|
newline_before : false,
|
||||||
regex_allowed : false,
|
regex_allowed : false,
|
||||||
comments_before : []
|
comments_before : [],
|
||||||
|
directives : {},
|
||||||
|
directive_stack : []
|
||||||
};
|
};
|
||||||
|
|
||||||
function peek() { return S.text.charAt(S.pos); };
|
function peek() { return S.text.charAt(S.pos); };
|
||||||
@@ -403,8 +405,6 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
var ch = next(true, true);
|
var ch = next(true, true);
|
||||||
if (ch == "\\") {
|
if (ch == "\\") {
|
||||||
// read OctalEscapeSequence (XXX: deprecated if "strict mode")
|
|
||||||
// https://github.com/mishoo/UglifyJS/issues/178
|
|
||||||
var octal_len = 0, first = null;
|
var octal_len = 0, first = null;
|
||||||
ch = read_while(function(ch){
|
ch = read_while(function(ch){
|
||||||
if (ch >= "0" && ch <= "7") {
|
if (ch >= "0" && ch <= "7") {
|
||||||
@@ -417,8 +417,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
|
if (octal_len > 0) {
|
||||||
else ch = read_escaped_char(true);
|
if (ch !== "0" && next_token.has_directive("use strict"))
|
||||||
|
parse_error("Octal literals are not allowed in strict mode");
|
||||||
|
ch = String.fromCharCode(parseInt(ch, 8));
|
||||||
|
} else {
|
||||||
|
ch = read_escaped_char(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ("\r\n\u2028\u2029".indexOf(ch) >= 0) parse_error("Unterminated string constant");
|
else if ("\r\n\u2028\u2029".indexOf(ch) >= 0) parse_error("Unterminated string constant");
|
||||||
else if (ch == quote) break;
|
else if (ch == quote) break;
|
||||||
@@ -640,6 +645,35 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
return S;
|
return S;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
next_token.add_directive = function(directive) {
|
||||||
|
S.directive_stack[S.directive_stack.length - 1].push(directive);
|
||||||
|
|
||||||
|
if (S.directives[directive] === undefined) {
|
||||||
|
S.directives[directive] = 1;
|
||||||
|
} else {
|
||||||
|
S.directives[directive]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next_token.push_directives_stack = function() {
|
||||||
|
S.directive_stack.push([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
next_token.pop_directives_stack = function() {
|
||||||
|
var directives = S.directive_stack[S.directive_stack.length - 1];
|
||||||
|
|
||||||
|
for (var i = 0; i < directives.length; i++) {
|
||||||
|
S.directives[directives[i]]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
S.directive_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
next_token.has_directive = function(directive) {
|
||||||
|
return S.directives[directive] !== undefined &&
|
||||||
|
S.directives[directive] > 0;
|
||||||
|
}
|
||||||
|
|
||||||
return next_token;
|
return next_token;
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -818,9 +852,15 @@ function parse($TEXT, options) {
|
|||||||
handle_regexp();
|
handle_regexp();
|
||||||
switch (S.token.type) {
|
switch (S.token.type) {
|
||||||
case "string":
|
case "string":
|
||||||
|
if (S.in_directives) {
|
||||||
|
if (is_token(peek(), "punc", ";") || peek().nlb) {
|
||||||
|
S.input.add_directive(S.token.raw.substr(1, S.token.raw.length - 2));
|
||||||
|
} else {
|
||||||
|
S.in_directives = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
var dir = S.in_directives, stat = simple_statement();
|
var dir = S.in_directives, stat = simple_statement();
|
||||||
// XXXv2: decide how to fix directives
|
if (dir) {
|
||||||
if (dir && stat.body instanceof AST_String && !is("punc", ",")) {
|
|
||||||
return new AST_Directive({
|
return new AST_Directive({
|
||||||
start : stat.body.start,
|
start : stat.body.start,
|
||||||
end : stat.body.end,
|
end : stat.body.end,
|
||||||
@@ -1153,10 +1193,13 @@ function parse($TEXT, options) {
|
|||||||
S.in_directives = true;
|
S.in_directives = true;
|
||||||
S.in_loop = 0;
|
S.in_loop = 0;
|
||||||
S.labels = [];
|
S.labels = [];
|
||||||
if (block)
|
if (block) {
|
||||||
|
S.input.push_directives_stack();
|
||||||
var a = block_();
|
var a = block_();
|
||||||
else
|
S.input.pop_directives_stack();
|
||||||
|
} else {
|
||||||
var a = expression(false);
|
var a = expression(false);
|
||||||
|
}
|
||||||
--S.in_function;
|
--S.in_function;
|
||||||
S.in_loop = loop;
|
S.in_loop = loop;
|
||||||
S.labels = labels;
|
S.labels = labels;
|
||||||
@@ -2082,8 +2125,10 @@ function parse($TEXT, options) {
|
|||||||
return (function(){
|
return (function(){
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var body = [];
|
var body = [];
|
||||||
|
S.input.push_directives_stack();
|
||||||
while (!is("eof"))
|
while (!is("eof"))
|
||||||
body.push(statement());
|
body.push(statement());
|
||||||
|
S.input.pop_directives_stack();
|
||||||
var end = prev();
|
var end = prev();
|
||||||
var toplevel = options.toplevel;
|
var toplevel = options.toplevel;
|
||||||
if (toplevel) {
|
if (toplevel) {
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ ascii_only_true: {
|
|||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f() {
|
function f() {
|
||||||
return "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
return "\x000\x001\x007\x008\x00" +
|
||||||
|
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
||||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
||||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_exact: 'function f(){return"\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\x0B\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
|
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\x0B\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
|
||||||
}
|
}
|
||||||
|
|
||||||
ascii_only_false: {
|
ascii_only_false: {
|
||||||
@@ -22,11 +23,12 @@ ascii_only_false: {
|
|||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f() {
|
function f() {
|
||||||
return "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
return "\x000\x001\x007\x008\x00" +
|
||||||
|
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
||||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
||||||
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect_exact: 'function f(){return"\\x00\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\x0B\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
|
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\x0B\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ concat_1: {
|
|||||||
var d = 1 + x() + 2 + 3 + "boo";
|
var d = 1 + x() + 2 + 3 + "boo";
|
||||||
|
|
||||||
var e = 1 + x() + 2 + "X" + 3 + "boo";
|
var e = 1 + x() + 2 + "X" + 3 + "boo";
|
||||||
|
|
||||||
|
// be careful with concatentation with "\0" with octal-looking strings.
|
||||||
|
var f = "\0" + 360 + "\0" + 8 + "\0";
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = "foobar" + x() + "moofoo" + y() + "xyz" + q();
|
var a = "foobar" + x() + "moofoo" + y() + "xyz" + q();
|
||||||
@@ -18,5 +21,6 @@ concat_1: {
|
|||||||
var c = 1 + x() + 2 + "boo";
|
var c = 1 + x() + 2 + "boo";
|
||||||
var d = 1 + x() + 2 + 3 + "boo";
|
var d = 1 + x() + 2 + 3 + "boo";
|
||||||
var e = 1 + x() + 2 + "X3boo";
|
var e = 1 + x() + 2 + "X3boo";
|
||||||
|
var f = "\x00360\08\0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
147
test/compress/issue-1105.js
Normal file
147
test/compress/issue-1105.js
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
with_in_global_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = 42;
|
||||||
|
with(o) {
|
||||||
|
var foo = 'something'
|
||||||
|
}
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o=42;
|
||||||
|
with(o)
|
||||||
|
var foo = "something";
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
with_in_function_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
var o = 42;
|
||||||
|
with(o) {
|
||||||
|
var foo = "something"
|
||||||
|
}
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
var o=42;
|
||||||
|
with(o)
|
||||||
|
var foo = "something";
|
||||||
|
doSomething(o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compress_with_with_in_other_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
var o = 42;
|
||||||
|
with(o) {
|
||||||
|
var foo = "something"
|
||||||
|
}
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
var unused = 42;
|
||||||
|
return something();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
var o = 42;
|
||||||
|
with(o)
|
||||||
|
var foo = "something";
|
||||||
|
doSomething(o)
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
return something()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
with_using_existing_variable_outside_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var o = {};
|
||||||
|
var unused = {}; // Doesn't get removed because upper scope uses with
|
||||||
|
function foo() {
|
||||||
|
with(o) {
|
||||||
|
var foo = "something"
|
||||||
|
}
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
var o = {};
|
||||||
|
var unused = {};
|
||||||
|
function foo() {
|
||||||
|
with(o)
|
||||||
|
var foo = "something";
|
||||||
|
doSomething(o)
|
||||||
|
}
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check_drop_unused_in_peer_function: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function outer() {
|
||||||
|
var o = {};
|
||||||
|
var unused = {}; // should be kept
|
||||||
|
function foo() { // should be kept
|
||||||
|
function not_in_use() {
|
||||||
|
var nested_unused = "foo"; // should be dropped
|
||||||
|
return 24;
|
||||||
|
}
|
||||||
|
var unused = {}; // should be kept
|
||||||
|
with (o) {
|
||||||
|
var foo = "something";
|
||||||
|
}
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
var unused = {}; // should be dropped
|
||||||
|
doSomethingElse();
|
||||||
|
}
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function outer() {
|
||||||
|
var o = {};
|
||||||
|
var unused = {}; // should be kept
|
||||||
|
function foo() { // should be kept
|
||||||
|
function not_in_use() {
|
||||||
|
return 24;
|
||||||
|
}
|
||||||
|
var unused = {}; // should be kept
|
||||||
|
with (o)
|
||||||
|
var foo = "something";
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
doSomethingElse();
|
||||||
|
}
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,30 @@ new_statement: {
|
|||||||
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);"
|
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);"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_statements_2: {
|
||||||
|
input: {
|
||||||
|
new x;
|
||||||
|
new new x;
|
||||||
|
new new new x;
|
||||||
|
new true;
|
||||||
|
new (0);
|
||||||
|
new (!0);
|
||||||
|
new (bar = function(foo) {this.foo=foo;})(123);
|
||||||
|
new (bar = function(foo) {this.foo=foo;})();
|
||||||
|
}
|
||||||
|
expect_exact: "new x;new(new x);new(new(new x));new true;new 0;new(!0);new(bar=function(foo){this.foo=foo})(123);new(bar=function(foo){this.foo=foo});"
|
||||||
|
}
|
||||||
|
|
||||||
|
new_statements_3: {
|
||||||
|
input: {
|
||||||
|
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;})();
|
||||||
|
}
|
||||||
|
expect_exact: "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_with_rewritten_true_value: {
|
new_with_rewritten_true_value: {
|
||||||
options = { booleans: true }
|
options = { booleans: true }
|
||||||
input: {
|
input: {
|
||||||
@@ -18,3 +42,11 @@ new_with_rewritten_true_value: {
|
|||||||
}
|
}
|
||||||
expect_exact: "new(!0);"
|
expect_exact: "new(!0);"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_with_many_parameters: {
|
||||||
|
input: {
|
||||||
|
new foo.bar("baz");
|
||||||
|
new x(/123/, 456);
|
||||||
|
}
|
||||||
|
expect_exact: 'new foo.bar("baz");new x(/123/,456);'
|
||||||
|
}
|
||||||
|
|||||||
61
test/mocha/directives.js
Normal file
61
test/mocha/directives.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var uglify = require("../../");
|
||||||
|
|
||||||
|
describe("Directives", function() {
|
||||||
|
it ("Should allow tokenizer to store directives state", function() {
|
||||||
|
var tokenizer = uglify.tokenizer("", "foo.js");
|
||||||
|
|
||||||
|
// Stack level 0
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 2
|
||||||
|
tokenizer.push_directives_stack();
|
||||||
|
tokenizer.push_directives_stack();
|
||||||
|
tokenizer.add_directive("use strict");
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 3
|
||||||
|
tokenizer.push_directives_stack();
|
||||||
|
tokenizer.add_directive("use strict");
|
||||||
|
tokenizer.add_directive("use asm");
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 2
|
||||||
|
tokenizer.pop_directives_stack();
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 3
|
||||||
|
tokenizer.push_directives_stack();
|
||||||
|
tokenizer.add_directive("use thing");
|
||||||
|
tokenizer.add_directive("use\\\nasm");
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false); // Directives are strict!
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), true);
|
||||||
|
|
||||||
|
// Stack level 2
|
||||||
|
tokenizer.pop_directives_stack();
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 1
|
||||||
|
tokenizer.pop_directives_stack();
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 0
|
||||||
|
tokenizer.pop_directives_stack();
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -5,19 +5,31 @@ describe("New", function() {
|
|||||||
it("Should attach callback parens after some tokens", function() {
|
it("Should attach callback parens after some tokens", function() {
|
||||||
var tests = [
|
var tests = [
|
||||||
"new x(1);",
|
"new x(1);",
|
||||||
|
"new x;",
|
||||||
|
"new new x;",
|
||||||
"new (function(foo){this.foo=foo;})(1);",
|
"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 true;",
|
||||||
"new (0);",
|
"new (0);",
|
||||||
"new (!0);",
|
"new (!0);",
|
||||||
"new (bar = function(foo) {this.foo=foo;})(123);"
|
"new (bar = function(foo) {this.foo=foo;})(123);",
|
||||||
|
"new (bar = function(foo) {this.foo=foo;})();"
|
||||||
];
|
];
|
||||||
var expected = [
|
var expected = [
|
||||||
"new x(1);",
|
"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}(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 true;",
|
||||||
"new 0;",
|
"new 0;",
|
||||||
"new (!0);",
|
"new (!0);",
|
||||||
"new (bar = function(foo) {\n this.foo = foo;\n})(123);"
|
"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++) {
|
for (var i = 0; i < tests.length; i++) {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
|
|||||||
@@ -31,4 +31,51 @@ describe("String literals", function() {
|
|||||||
var output = UglifyJS.parse('var a = "a\\\nb";').print_to_string();
|
var output = UglifyJS.parse('var a = "a\\\nb";').print_to_string();
|
||||||
assert.equal(output, 'var a="ab";');
|
assert.equal(output, 'var a="ab";');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should throw error in strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||||
|
var inputs = [
|
||||||
|
'"use strict";\n"\\76";',
|
||||||
|
'"use strict";\nvar foo = "\\76";',
|
||||||
|
'"use strict";\n"\\1";',
|
||||||
|
'"use strict";\n"\\07";',
|
||||||
|
'"use strict";\n"\\011"'
|
||||||
|
];
|
||||||
|
|
||||||
|
var test = function(input) {
|
||||||
|
return function() {
|
||||||
|
var output = UglifyJS.parse(input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var error = function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
|
e.message === "Octal literals are not allowed in strict mode";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var input in inputs) {
|
||||||
|
assert.throws(test(inputs[input]), error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||||
|
var tests = [
|
||||||
|
['"\\76";', '">";'],
|
||||||
|
['"\\0"', '"\\0";'],
|
||||||
|
['"\\08"', '"\\08";'],
|
||||||
|
['"\\008"', '"\\08";'],
|
||||||
|
['"\\0008"', '"\\08";'],
|
||||||
|
['"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
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var test in tests) {
|
||||||
|
var output = UglifyJS.parse(tests[test][0]).print_to_string();
|
||||||
|
assert.equal(output, tests[test][1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not throw error when digit is 8 or 9", function() {
|
||||||
|
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\08";');
|
||||||
|
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\09";');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user