@@ -2,14 +2,12 @@ var assert = require("assert");
|
||||
var UglifyJS = require("../node");
|
||||
|
||||
describe("Directives", function() {
|
||||
it ("Should allow tokenizer to store directives state", function() {
|
||||
it("Should allow tokenizer to store directives state", function() {
|
||||
var tokenizer = UglifyJS.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();
|
||||
@@ -17,7 +15,6 @@ describe("Directives", function() {
|
||||
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");
|
||||
@@ -25,13 +22,11 @@ describe("Directives", function() {
|
||||
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");
|
||||
@@ -39,152 +34,138 @@ describe("Directives", function() {
|
||||
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);
|
||||
});
|
||||
|
||||
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"]
|
||||
},
|
||||
[
|
||||
[
|
||||
'"use strict"\n',
|
||||
[ "use strict"],
|
||||
[ "use asm"]
|
||||
],
|
||||
[
|
||||
'"use\\\nstrict";',
|
||||
[],
|
||||
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
|
||||
],
|
||||
[
|
||||
'"use strict"\n"use asm"\n"use bar"\n',
|
||||
[ "use strict", "use asm", "use bar" ],
|
||||
[ "use foo", "use\\x20strict" ]
|
||||
],
|
||||
[
|
||||
'"use \\\nstrict";"use strict";',
|
||||
[],
|
||||
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
|
||||
],
|
||||
[
|
||||
'"\\76";',
|
||||
[],
|
||||
[ ">", "\\76" ]
|
||||
],
|
||||
[
|
||||
// no ; or newline
|
||||
'"use strict"',
|
||||
[],
|
||||
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
|
||||
],
|
||||
[
|
||||
';"use strict"',
|
||||
[],
|
||||
[ "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"]
|
||||
},
|
||||
[
|
||||
'function foo() {"use strict"\n',
|
||||
[ "use strict" ],
|
||||
[ "use asm" ]
|
||||
],
|
||||
[
|
||||
'function foo() {"use\\\nstrict";',
|
||||
[],
|
||||
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
|
||||
],
|
||||
[
|
||||
'function foo() {"use strict"\n"use asm"\n"use bar"\n',
|
||||
[ "use strict", "use asm", "use bar" ],
|
||||
[ "use foo", "use\\x20strict" ]
|
||||
],
|
||||
[
|
||||
'function foo() {"use \\\nstrict";"use strict";',
|
||||
[],
|
||||
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
|
||||
],
|
||||
[
|
||||
'var foo = function() {"\\76";',
|
||||
[],
|
||||
[ ">", "\\76" ]
|
||||
],
|
||||
[
|
||||
'var foo = function() {"use strict"', // no ; or newline
|
||||
[],
|
||||
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
|
||||
],
|
||||
[
|
||||
'var foo = function() {;"use strict"',
|
||||
[],
|
||||
[ "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 = UglifyJS.tokenizer(tests[i].input + "]", "foo.js");
|
||||
|
||||
try {
|
||||
var parser = UglifyJS.parse(tokenizer);
|
||||
throw new Error("Expected parser to fail");
|
||||
} catch (e) {
|
||||
assert.strictEqual(e instanceof UglifyJS.JS_Parse_Error, true);
|
||||
assert.strictEqual(e.message, "Unexpected token: punc (])");
|
||||
}
|
||||
|
||||
test_directive(tokenizer, tests[i]);
|
||||
}
|
||||
[
|
||||
'"1";"2";"3";"4";;"5"',
|
||||
[ "1", "2", "3", "4" ],
|
||||
[ "5", "6", "use strict", "use asm" ]
|
||||
],
|
||||
[
|
||||
'if(1){"use strict";',
|
||||
[],
|
||||
[ "use strict", "use\nstrict", "use \nstrict", "use asm" ]
|
||||
],
|
||||
[
|
||||
'"use strict";try{"use asm";',
|
||||
[ "use strict" ],
|
||||
[ "use\nstrict", "use \nstrict", "use asm" ]
|
||||
],
|
||||
].forEach(function(test) {
|
||||
var tokenizer = UglifyJS.tokenizer(test[0] + "]", "foo.js");
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(tokenizer);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unexpected token: punc (])"
|
||||
}, test[0]);
|
||||
test[1].forEach(function(directive) {
|
||||
assert.strictEqual(tokenizer.has_directive(directive), true, directive + " in " + test[0]);
|
||||
});
|
||||
test[2].forEach(function(fake_directive) {
|
||||
assert.strictEqual(tokenizer.has_directive(fake_directive), false, fake_directive + " in " + test[0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("Should test EXPECT_DIRECTIVE RegExp", function() {
|
||||
[
|
||||
["", 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]
|
||||
[ "", 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 ],
|
||||
].forEach(function(test) {
|
||||
var out = UglifyJS.OutputStream();
|
||||
out.print(test[0]);
|
||||
@@ -192,19 +173,33 @@ describe("Directives", function() {
|
||||
assert.strictEqual(out.get() === test[0] + ';""', test[1], test[0]);
|
||||
});
|
||||
});
|
||||
|
||||
it("Should only print 2 semicolons spread over 2 lines in beautify mode", function() {
|
||||
assert.strictEqual(
|
||||
UglifyJS.minify(
|
||||
'"use strict";\'use strict\';"use strict";"use strict";;\'use strict\';console.log(\'use strict\');',
|
||||
{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\');'
|
||||
);
|
||||
var result = UglifyJS.minify([
|
||||
'"use strict";',
|
||||
"'use strict';",
|
||||
'"use strict";',
|
||||
'"use strict";;',
|
||||
"'use strict';",
|
||||
"console.log('use strict');"
|
||||
].join(""), {
|
||||
compress: false,
|
||||
output: {
|
||||
beautify: true,
|
||||
quote_style: 3
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, [
|
||||
'"use strict";',
|
||||
"'use strict';",
|
||||
'"use strict";',
|
||||
'"use strict";',
|
||||
";'use strict';",
|
||||
"console.log('use strict');"
|
||||
].join("\n\n"));
|
||||
});
|
||||
|
||||
it("Should not add double semicolons in non-scoped block statements to avoid strings becoming directives", function() {
|
||||
var tests = [
|
||||
[
|
||||
[
|
||||
'{"use\x20strict"}',
|
||||
'{"use strict"}'
|
||||
@@ -221,26 +216,27 @@ describe("Directives", function() {
|
||||
'if(1){"use\x20strict"} else {"use strict"}',
|
||||
'if(1){"use strict"}else{"use strict"}'
|
||||
]
|
||||
];
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.strictEqual(
|
||||
UglifyJS.minify(tests[i][0], {compress: false, mangle: false}).code,
|
||||
tests[i][1],
|
||||
tests[i][0]
|
||||
);
|
||||
}
|
||||
].forEach(function(test) {
|
||||
var result = UglifyJS.minify(test[0], {
|
||||
compress: false,
|
||||
mangle: false
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, test[1], test[0]);
|
||||
});
|
||||
});
|
||||
|
||||
it("Should add double semicolon when relying on automatic semicolon insertion", function() {
|
||||
var code = UglifyJS.minify('"use strict";"use\\x20strict";',
|
||||
{output: {semicolons: false}, compress: false}
|
||||
).code;
|
||||
assert.strictEqual(code, '"use strict";;"use strict"\n');
|
||||
var result = UglifyJS.minify('"use strict";"use\\x20strict";', {
|
||||
compress: false,
|
||||
output: {
|
||||
semicolons: false
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.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";',
|
||||
@@ -337,45 +333,53 @@ describe("Directives", function() {
|
||||
3,
|
||||
"'\"use strict\"';",
|
||||
],
|
||||
];
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.strictEqual(
|
||||
UglifyJS.minify(tests[i][0], {output:{quote_style: tests[i][1]}, compress: false}).code,
|
||||
tests[i][2],
|
||||
tests[i][0] + " using mode " + tests[i][1]
|
||||
);
|
||||
}
|
||||
].forEach(function(test) {
|
||||
var result = UglifyJS.minify(test[0], {
|
||||
compress: false,
|
||||
output: {
|
||||
quote_style: test[1]
|
||||
}
|
||||
});
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, test[2], test[0] + " using mode " + test[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");',
|
||||
'function f(){ "use strict" }',
|
||||
'function f(){ "use asm" }',
|
||||
'function f(){ "use nondirective" }',
|
||||
'function f(){ ;"use strict" }',
|
||||
'function f(){ "use \n"; }',
|
||||
'"use strict";doSomething("foo");'
|
||||
],
|
||||
[
|
||||
// Nothing gets optimised in the compressor because "use asm" is the first statement
|
||||
// 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
|
||||
'function f(){"use strict"}',
|
||||
'function f(){"use asm"}',
|
||||
'function f(){"use nondirective"}',
|
||||
'function f(){}',
|
||||
'function f(){}',
|
||||
]
|
||||
];
|
||||
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
assert.strictEqual(
|
||||
UglifyJS.minify(tests[i][0]).code,
|
||||
tests[i][1],
|
||||
tests[i][0]
|
||||
);
|
||||
}
|
||||
// Yet, the parser noticed that "use strict" wasn't a directive
|
||||
'"use asm";;"use strict";1+1;',
|
||||
],
|
||||
[
|
||||
'function f(){ "use strict" }',
|
||||
'function f(){}'
|
||||
],
|
||||
[
|
||||
'function f(){ "use asm" }',
|
||||
'function f(){"use asm"}'
|
||||
],
|
||||
[
|
||||
'function f(){ "use nondirective" }',
|
||||
'function f(){}'
|
||||
],
|
||||
[
|
||||
'function f(){ ;"use strict" }',
|
||||
'function f(){}'
|
||||
],
|
||||
[
|
||||
'function f(){ "use \\n"; }',
|
||||
'function f(){}'
|
||||
],
|
||||
].forEach(function(test) {
|
||||
var result = UglifyJS.minify(test[0]);
|
||||
if (result.error) throw result.error;
|
||||
assert.strictEqual(result.code, test[1], test[0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user