fix corner cases in preserve_line (#3212)
This commit is contained in:
@@ -857,8 +857,8 @@ can pass additional arguments that control the code output:
|
||||
adjust for this text. Can be used to insert a comment containing
|
||||
licensing information, for example.
|
||||
|
||||
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
|
||||
only works if `beautify` is set to `false`.
|
||||
- `preserve_line` (default `false`) -- pass `true` to retain line numbering on
|
||||
a best effort basis.
|
||||
|
||||
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
||||
objects
|
||||
|
||||
@@ -100,7 +100,7 @@ if (program.mangleProps) {
|
||||
if (typeof program.mangleProps != "object") program.mangleProps = {};
|
||||
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
|
||||
require("../tools/domprops").forEach(function(name) {
|
||||
UglifyJS._push_uniq(program.mangleProps.reserved, name);
|
||||
UglifyJS.push_uniq(program.mangleProps.reserved, name);
|
||||
});
|
||||
}
|
||||
if (typeof options.mangle != "object") options.mangle = {};
|
||||
|
||||
@@ -198,16 +198,24 @@ function OutputStream(options) {
|
||||
/* -----[ beautification/minification ]----- */
|
||||
|
||||
var has_parens = false;
|
||||
var line_end = 0;
|
||||
var line_fixed = true;
|
||||
var might_need_space = false;
|
||||
var might_need_semicolon = false;
|
||||
var might_add_newline = 0;
|
||||
var need_newline_indented = false;
|
||||
var need_space = false;
|
||||
var newline_insert = -1;
|
||||
var last = "";
|
||||
var mapping_token, mapping_name, mappings = options.source_map && [];
|
||||
|
||||
var do_add_mapping = mappings ? function() {
|
||||
var adjust_mappings = mappings ? function(line, col) {
|
||||
mappings.forEach(function(mapping) {
|
||||
mapping.line += line;
|
||||
mapping.col += col;
|
||||
});
|
||||
} : noop;
|
||||
|
||||
var flush_mappings = mappings ? function() {
|
||||
mappings.forEach(function(mapping) {
|
||||
try {
|
||||
options.source_map.add(
|
||||
@@ -230,31 +238,30 @@ function OutputStream(options) {
|
||||
mappings = [];
|
||||
} : noop;
|
||||
|
||||
var ensure_line_len = options.max_line_len ? function() {
|
||||
if (current_col > options.max_line_len) {
|
||||
if (might_add_newline) {
|
||||
var left = OUTPUT.slice(0, might_add_newline);
|
||||
var right = OUTPUT.slice(might_add_newline);
|
||||
if (mappings) {
|
||||
var delta = right.length - current_col;
|
||||
mappings.forEach(function(mapping) {
|
||||
mapping.line++;
|
||||
mapping.col += delta;
|
||||
});
|
||||
}
|
||||
OUTPUT = left + "\n" + right;
|
||||
current_line++;
|
||||
current_pos++;
|
||||
function insert_newlines(count) {
|
||||
var index = OUTPUT.lastIndexOf("\n");
|
||||
if (line_end < index) line_end = index;
|
||||
var left = OUTPUT.slice(0, line_end);
|
||||
var right = OUTPUT.slice(line_end);
|
||||
adjust_mappings(count, right.length - current_col);
|
||||
current_line += count;
|
||||
current_pos += count;
|
||||
current_col = right.length;
|
||||
OUTPUT = left;
|
||||
while (count--) OUTPUT += "\n";
|
||||
OUTPUT += right;
|
||||
}
|
||||
|
||||
var fix_line = options.max_line_len ? function() {
|
||||
if (line_fixed) {
|
||||
if (current_col > options.max_line_len) {
|
||||
AST_Node.warn("Output exceeds {max_line_len} characters", options);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (might_add_newline) {
|
||||
might_add_newline = 0;
|
||||
do_add_mapping();
|
||||
}
|
||||
if (current_col > options.max_line_len) insert_newlines(1);
|
||||
line_fixed = true;
|
||||
flush_mappings();
|
||||
} : noop;
|
||||
|
||||
var requireSemicolonChars = makePredicate("( [ + * / - , .");
|
||||
@@ -286,7 +293,7 @@ function OutputStream(options) {
|
||||
current_col++;
|
||||
current_pos++;
|
||||
} else {
|
||||
ensure_line_len();
|
||||
fix_line();
|
||||
OUTPUT += "\n";
|
||||
current_pos++;
|
||||
current_line++;
|
||||
@@ -304,18 +311,6 @@ function OutputStream(options) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
|
||||
var target_line = stack[stack.length - 1].start.line;
|
||||
while (current_line < target_line) {
|
||||
ensure_line_len();
|
||||
OUTPUT += "\n";
|
||||
current_pos++;
|
||||
current_line++;
|
||||
current_col = 0;
|
||||
might_need_space = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (might_need_space) {
|
||||
if ((is_identifier_char(prev)
|
||||
&& (is_identifier_char(ch) || ch == "\\"))
|
||||
@@ -337,7 +332,7 @@ function OutputStream(options) {
|
||||
col: current_col
|
||||
});
|
||||
mapping_token = false;
|
||||
if (!might_add_newline) do_add_mapping();
|
||||
if (line_fixed) flush_mappings();
|
||||
}
|
||||
|
||||
OUTPUT += str;
|
||||
@@ -347,7 +342,7 @@ function OutputStream(options) {
|
||||
current_line += n;
|
||||
current_col += a[0].length;
|
||||
if (n > 0) {
|
||||
ensure_line_len();
|
||||
fix_line();
|
||||
current_col = a[n].length;
|
||||
}
|
||||
last = str;
|
||||
@@ -374,9 +369,10 @@ function OutputStream(options) {
|
||||
return ret;
|
||||
} : function(col, cont) { return cont() };
|
||||
|
||||
var may_add_newline = options.max_line_len ? function() {
|
||||
ensure_line_len();
|
||||
might_add_newline = OUTPUT.length;
|
||||
var may_add_newline = options.max_line_len || options.preserve_line ? function() {
|
||||
fix_line();
|
||||
line_end = OUTPUT.length;
|
||||
line_fixed = false;
|
||||
} : noop;
|
||||
|
||||
var newline = options.beautify ? function() {
|
||||
@@ -455,9 +451,7 @@ function OutputStream(options) {
|
||||
} : noop;
|
||||
|
||||
function get() {
|
||||
if (might_add_newline) {
|
||||
ensure_line_len();
|
||||
}
|
||||
if (!line_fixed) fix_line();
|
||||
return OUTPUT;
|
||||
}
|
||||
|
||||
@@ -622,7 +616,14 @@ function OutputStream(options) {
|
||||
col : function() { return current_col },
|
||||
pos : function() { return current_pos },
|
||||
push_node : function(node) { stack.push(node) },
|
||||
pop_node : function() { return stack.pop() },
|
||||
pop_node : options.preserve_line ? function() {
|
||||
var node = stack.pop();
|
||||
if (node.start && node.start.line > current_line) {
|
||||
insert_newlines(node.start.line - current_line);
|
||||
}
|
||||
} : function() {
|
||||
stack.pop();
|
||||
},
|
||||
parent : function(n) {
|
||||
return stack[stack.length - 2 - (n || 0)];
|
||||
}
|
||||
|
||||
@@ -162,8 +162,7 @@ var MAP = (function() {
|
||||
})();
|
||||
|
||||
function push_uniq(array, el) {
|
||||
if (array.indexOf(el) < 0)
|
||||
array.push(el);
|
||||
if (array.indexOf(el) < 0) return array.push(el);
|
||||
}
|
||||
|
||||
function string_template(text, props) {
|
||||
|
||||
@@ -1199,7 +1199,7 @@ issue_2231_1: {
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_warnings: [
|
||||
"WARN: Error evaluating Object.keys(void 0) [test/compress/evaluate.js:1195,20]",
|
||||
"WARN: Error evaluating Object.keys(void 0) [test/compress/evaluate.js:1,20]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1216,7 +1216,7 @@ issue_2231_2: {
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_warnings: [
|
||||
"WARN: Error evaluating Object.getOwnPropertyNames(null) [test/compress/evaluate.js:1212,20]",
|
||||
"WARN: Error evaluating Object.getOwnPropertyNames(null) [test/compress/evaluate.js:1,20]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1354,14 +1354,14 @@ issue_2535_3: {
|
||||
}
|
||||
expect_stdout: true
|
||||
expect_warnings: [
|
||||
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1340,20]",
|
||||
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1341,20]",
|
||||
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1342,20]",
|
||||
"WARN: Condition left of && always false [test/compress/evaluate.js:1342,20]",
|
||||
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1343,20]",
|
||||
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1344,20]",
|
||||
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1345,20]",
|
||||
"WARN: Condition left of || always true [test/compress/evaluate.js:1345,20]",
|
||||
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1,20]",
|
||||
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:2,20]",
|
||||
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:3,20]",
|
||||
"WARN: Condition left of && always false [test/compress/evaluate.js:3,20]",
|
||||
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:4,20]",
|
||||
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:5,20]",
|
||||
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:6,20]",
|
||||
"WARN: Condition left of || always true [test/compress/evaluate.js:6,20]",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -141,9 +141,9 @@ mixed: {
|
||||
console.log(CONFIG);
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]",
|
||||
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:128,22]",
|
||||
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:130,8]",
|
||||
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:4,22]",
|
||||
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:5,22]",
|
||||
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:7,8]",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -36,10 +36,10 @@ non_hoisted_function_after_return: {
|
||||
}
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:20,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:23,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:26,12]",
|
||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:27,21]"
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -85,18 +85,18 @@ non_hoisted_function_after_return_2a: {
|
||||
}
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:68,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:68,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:71,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:71,16]",
|
||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:68,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:75,21]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
||||
"WARN: pass 0: last_count: Infinity, count: 37",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:73,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:73,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:76,12]",
|
||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:71,20]",
|
||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:73,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
|
||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
|
||||
"WARN: pass 1: last_count: 37, count: 18",
|
||||
]
|
||||
}
|
||||
@@ -139,12 +139,11 @@ non_hoisted_function_after_return_2b: {
|
||||
}
|
||||
}
|
||||
expect_warnings: [
|
||||
// duplicate warnings no longer emitted
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:126,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:126,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:128,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:128,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:132,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:6,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -191,10 +190,10 @@ non_hoisted_function_after_return_strict: {
|
||||
}
|
||||
expect_stdout: "8 7"
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:171,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:174,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:177,12]",
|
||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:178,21]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:11,12]",
|
||||
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:12,21]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -245,18 +244,18 @@ non_hoisted_function_after_return_2a_strict: {
|
||||
}
|
||||
expect_stdout: "5 6"
|
||||
expect_warnings: [
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:224,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:224,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:227,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:227,16]",
|
||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:224,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:231,21]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
|
||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
|
||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
||||
"WARN: pass 0: last_count: Infinity, count: 48",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:229,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:229,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:232,12]",
|
||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:227,20]",
|
||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:229,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||
"WARN: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
|
||||
"WARN: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
|
||||
"WARN: pass 1: last_count: 48, count: 29",
|
||||
]
|
||||
}
|
||||
@@ -304,11 +303,10 @@ non_hoisted_function_after_return_2b_strict: {
|
||||
}
|
||||
expect_stdout: "5 6"
|
||||
expect_warnings: [
|
||||
// duplicate warnings no longer emitted
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:287,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:287,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:289,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:289,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:293,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -48,13 +48,13 @@ pure_function_calls: {
|
||||
a.b(), f.g();
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,8]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:16,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:29,37]",
|
||||
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:29,16]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:27,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:37,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:38,31]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:3,8]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:3,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,37]",
|
||||
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:16,16]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:14,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:24,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:25,31]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -110,17 +110,17 @@ pure_function_calls_toplevel: {
|
||||
a.b(), f.g();
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:77,8]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:77,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:90,37]",
|
||||
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:90,16]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:88,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:105,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:106,31]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:82,33]",
|
||||
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:82,12]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:98,45]",
|
||||
"WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:98,12]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:3,8]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:3,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:16,37]",
|
||||
"WARN: Dropping unused variable iife2 [test/compress/issue-1261.js:16,16]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:14,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:31,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:32,31]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:8,33]",
|
||||
"WARN: Dropping unused variable iife1 [test/compress/issue-1261.js:8,12]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:24,45]",
|
||||
"WARN: Dropping unused variable MyClass [test/compress/issue-1261.js:24,12]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -155,29 +155,29 @@ should_warn: {
|
||||
baz();
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,61]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:135,23]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:135,23]",
|
||||
"WARN: Boolean || always true [test/compress/issue-1261.js:136,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:136,23]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:136,23]",
|
||||
"WARN: Condition left of || always true [test/compress/issue-1261.js:137,8]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:137,8]",
|
||||
"WARN: Boolean && always false [test/compress/issue-1261.js:138,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:138,23]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:138,23]",
|
||||
"WARN: Condition left of && always false [test/compress/issue-1261.js:139,8]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:139,8]",
|
||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:140,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:140,23]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:140,23]",
|
||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:141,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:141,31]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:141,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:142,23]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:143,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:143,24]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:144,31]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:144,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:1,61]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:1,23]",
|
||||
"WARN: Dropping side-effect-free statement [test/compress/issue-1261.js:1,23]",
|
||||
"WARN: Boolean || always true [test/compress/issue-1261.js:2,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:2,23]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:2,23]",
|
||||
"WARN: Condition left of || always true [test/compress/issue-1261.js:3,8]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:3,8]",
|
||||
"WARN: Boolean && always false [test/compress/issue-1261.js:4,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:4,23]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:4,23]",
|
||||
"WARN: Condition left of && always false [test/compress/issue-1261.js:5,8]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:5,8]",
|
||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:6,23]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:6,23]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:6,23]",
|
||||
"WARN: + in boolean context always true [test/compress/issue-1261.js:7,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:7,31]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:7,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:8,23]",
|
||||
"WARN: Condition always true [test/compress/issue-1261.js:9,8]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:9,24]",
|
||||
"WARN: Dropping __PURE__ call [test/compress/issue-1261.js:10,31]",
|
||||
"WARN: Condition always false [test/compress/issue-1261.js:10,8]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -64,11 +64,11 @@ mixed: {
|
||||
x = 0;
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: global_defs ENV redefined [test/compress/issue-208.js:45,12]",
|
||||
"WARN: global_defs FOO redefined [test/compress/issue-208.js:46,12]",
|
||||
"WARN: global_defs FOO redefined [test/compress/issue-208.js:48,10]",
|
||||
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:49,8]",
|
||||
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:50,8]",
|
||||
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:51,8]",
|
||||
"WARN: global_defs ENV redefined [test/compress/issue-208.js:1,12]",
|
||||
"WARN: global_defs FOO redefined [test/compress/issue-208.js:2,12]",
|
||||
"WARN: global_defs FOO redefined [test/compress/issue-208.js:4,10]",
|
||||
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:5,8]",
|
||||
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:6,8]",
|
||||
"WARN: global_defs DEBUG redefined [test/compress/issue-208.js:7,8]",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -93,6 +93,6 @@ regexp: {
|
||||
RegExp("should", "fail");
|
||||
}
|
||||
expect_warnings: [
|
||||
'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:86,2]',
|
||||
'WARN: Error converting RegExp("should","fail") [test/compress/issue-269.js:5,2]',
|
||||
]
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ warn: {
|
||||
}().length);
|
||||
}
|
||||
expect_warnings: [
|
||||
"WARN: Function.protoype.caller not supported [test/compress/issue-2719.js:17,19]",
|
||||
"WARN: Function.protoype.arguments not supported [test/compress/issue-2719.js:17,19]",
|
||||
"WARN: Function.protoype.caller not supported [test/compress/issue-2719.js:5,19]",
|
||||
"WARN: Function.protoype.arguments not supported [test/compress/issue-2719.js:5,19]",
|
||||
]
|
||||
}
|
||||
|
||||
181
test/compress/preserve_line.js
Normal file
181
test/compress/preserve_line.js
Normal file
@@ -0,0 +1,181 @@
|
||||
return_1: {
|
||||
beautify = {
|
||||
beautify: false,
|
||||
preserve_line: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
return (
|
||||
f.toString() != 42
|
||||
);
|
||||
}());
|
||||
}
|
||||
expect_exact: [
|
||||
"console.log(function f(){",
|
||||
"",
|
||||
"return 42!=f.toString()}());",
|
||||
]
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
return_2: {
|
||||
beautify = {
|
||||
beautify: true,
|
||||
preserve_line: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
return (
|
||||
f.toString() != 42
|
||||
);
|
||||
}());
|
||||
}
|
||||
expect_exact: [
|
||||
"console.log(function f() {",
|
||||
"",
|
||||
" return 42 != f.toString();",
|
||||
"}());",
|
||||
]
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
return_3: {
|
||||
options = {}
|
||||
beautify = {
|
||||
beautify: false,
|
||||
preserve_line: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
return (
|
||||
f.toString() != 42
|
||||
);
|
||||
}());
|
||||
}
|
||||
expect_exact: [
|
||||
"console.log(function f(){",
|
||||
"",
|
||||
"return 42!=f.toString()}());",
|
||||
]
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
return_4: {
|
||||
options = {}
|
||||
beautify = {
|
||||
beautify: true,
|
||||
preserve_line: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function f() {
|
||||
return (
|
||||
f.toString() != 42
|
||||
);
|
||||
}());
|
||||
}
|
||||
expect_exact: [
|
||||
"console.log(function f() {",
|
||||
"",
|
||||
" return 42 != f.toString();",
|
||||
"}());",
|
||||
]
|
||||
expect_stdout: "true"
|
||||
}
|
||||
|
||||
return_5: {
|
||||
beautify = {
|
||||
beautify: false,
|
||||
preserve_line: true,
|
||||
}
|
||||
input: {
|
||||
_is_selected = function(tags, slug) {
|
||||
var ref;
|
||||
return (ref = _.find(tags, {
|
||||
slug: slug
|
||||
})) != null ? ref.selected : void 0;
|
||||
};
|
||||
}
|
||||
expect_exact: [
|
||||
"_is_selected=function(tags,slug){",
|
||||
"var ref",
|
||||
"",
|
||||
"",
|
||||
";return null!=(ref=_.find(tags,{slug:slug}))?ref.selected:void 0};",
|
||||
]
|
||||
}
|
||||
|
||||
return_6: {
|
||||
beautify = {
|
||||
beautify: true,
|
||||
preserve_line: true,
|
||||
}
|
||||
input: {
|
||||
_is_selected = function(tags, slug) {
|
||||
var ref;
|
||||
return (ref = _.find(tags, {
|
||||
slug: slug
|
||||
})) != null ? ref.selected : void 0;
|
||||
};
|
||||
}
|
||||
expect_exact: [
|
||||
"_is_selected = function(tags, slug) {",
|
||||
" var ref;",
|
||||
"",
|
||||
"",
|
||||
" return null != (ref = _.find(tags, {",
|
||||
" slug: slug",
|
||||
" })) ? ref.selected : void 0;",
|
||||
"};",
|
||||
]
|
||||
}
|
||||
|
||||
return_7: {
|
||||
options = {}
|
||||
mangle = {}
|
||||
beautify = {
|
||||
beautify: false,
|
||||
preserve_line: true,
|
||||
}
|
||||
input: {
|
||||
_is_selected = function(tags, slug) {
|
||||
var ref;
|
||||
return (ref = _.find(tags, {
|
||||
slug: slug
|
||||
})) != null ? ref.selected : void 0;
|
||||
};
|
||||
}
|
||||
expect_exact: [
|
||||
"_is_selected=function(e,l){",
|
||||
"var n",
|
||||
"",
|
||||
"",
|
||||
";return null!=(n=_.find(e,{slug:l}))?n.selected:void 0};",
|
||||
]
|
||||
}
|
||||
|
||||
return_8: {
|
||||
options = {}
|
||||
mangle = {}
|
||||
beautify = {
|
||||
beautify: true,
|
||||
preserve_line: true,
|
||||
}
|
||||
input: {
|
||||
_is_selected = function(tags, slug) {
|
||||
var ref;
|
||||
return (ref = _.find(tags, {
|
||||
slug: slug
|
||||
})) != null ? ref.selected : void 0;
|
||||
};
|
||||
}
|
||||
expect_exact: [
|
||||
"_is_selected = function(e, l) {",
|
||||
" var n;",
|
||||
"",
|
||||
"",
|
||||
" return null != (n = _.find(e, {",
|
||||
" slug: l",
|
||||
" })) ? n.selected : void 0;",
|
||||
"};",
|
||||
]
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
exports["Compressor"] = Compressor;
|
||||
exports["JS_Parse_Error"] = JS_Parse_Error;
|
||||
exports["OutputStream"] = OutputStream;
|
||||
exports["SourceMap"] = SourceMap;
|
||||
exports["TreeWalker"] = TreeWalker;
|
||||
exports["base54"] = base54;
|
||||
exports["Compressor"] = Compressor;
|
||||
exports["defaults"] = defaults;
|
||||
exports["is_identifier"] = is_identifier;
|
||||
exports["JS_Parse_Error"] = JS_Parse_Error;
|
||||
exports["mangle_properties"] = mangle_properties;
|
||||
exports["minify"] = minify;
|
||||
exports["OutputStream"] = OutputStream;
|
||||
exports["parse"] = parse;
|
||||
exports["push_uniq"] = push_uniq;
|
||||
exports["reserve_quoted_keys"] = reserve_quoted_keys;
|
||||
exports["SourceMap"] = SourceMap;
|
||||
exports["string_template"] = string_template;
|
||||
exports["tokenizer"] = tokenizer;
|
||||
exports["is_identifier"] = is_identifier;
|
||||
exports["TreeTransformer"] = TreeTransformer;
|
||||
exports["TreeWalker"] = TreeWalker;
|
||||
|
||||
@@ -23,68 +23,200 @@ require("./mocha.js");
|
||||
|
||||
/* -----[ utils ]----- */
|
||||
|
||||
function tmpl() {
|
||||
return U.string_template.apply(this, arguments);
|
||||
function evaluate(code) {
|
||||
if (code instanceof U.AST_Node) code = make_code(code, { beautify: true });
|
||||
return new Function("return(" + code + ")")();
|
||||
}
|
||||
|
||||
function log() {
|
||||
var txt = tmpl.apply(this, arguments);
|
||||
console.log("%s", txt);
|
||||
console.log("%s", tmpl.apply(null, arguments));
|
||||
}
|
||||
|
||||
function log_directory(dir) {
|
||||
log("*** Entering [{dir}]", { dir: dir });
|
||||
function make_code(ast, options) {
|
||||
var stream = U.OutputStream(options);
|
||||
ast.print(stream);
|
||||
return stream.get();
|
||||
}
|
||||
|
||||
function log_start_file(file) {
|
||||
log("--- {file}", { file: file });
|
||||
}
|
||||
|
||||
function log_test(name) {
|
||||
log(" Running test [{name}]", { name: name });
|
||||
}
|
||||
|
||||
function find_test_files(dir) {
|
||||
return fs.readdirSync(dir).filter(function(name) {
|
||||
return /\.js$/i.test(name);
|
||||
function parse_test(file) {
|
||||
var script = fs.readFileSync(file, "utf8");
|
||||
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS2/issues/348
|
||||
try {
|
||||
var ast = U.parse(script, {
|
||||
filename: file
|
||||
});
|
||||
}
|
||||
|
||||
function test_directory(dir) {
|
||||
return path.resolve(tests_dir, dir);
|
||||
}
|
||||
|
||||
function as_toplevel(input, mangle_options) {
|
||||
if (!(input instanceof U.AST_BlockStatement))
|
||||
throw new Error("Unsupported input syntax");
|
||||
for (var i = 0; i < input.body.length; i++) {
|
||||
var stat = input.body[i];
|
||||
if (stat instanceof U.AST_SimpleStatement && stat.body instanceof U.AST_String)
|
||||
input.body[i] = new U.AST_Directive(stat.body);
|
||||
else break;
|
||||
} catch (e) {
|
||||
console.log("Caught error while parsing tests in " + file + "\n");
|
||||
console.log(e);
|
||||
throw e;
|
||||
}
|
||||
var toplevel = new U.AST_Toplevel(input);
|
||||
toplevel.figure_out_scope(mangle_options);
|
||||
return toplevel;
|
||||
var tests = {};
|
||||
var tw = new U.TreeWalker(function(node, descend) {
|
||||
if (node instanceof U.AST_LabeledStatement
|
||||
&& tw.parent() instanceof U.AST_Toplevel) {
|
||||
var name = node.label.name;
|
||||
if (name in tests) {
|
||||
throw new Error('Duplicated test name "' + name + '" in ' + file);
|
||||
}
|
||||
tests[name] = get_one_test(name, node.body);
|
||||
return true;
|
||||
}
|
||||
if (!(node instanceof U.AST_Toplevel)) croak(node);
|
||||
});
|
||||
ast.walk(tw);
|
||||
return tests;
|
||||
|
||||
function croak(node) {
|
||||
throw new Error(tmpl("Can't understand test file {file} [{line},{col}]\n{code}", {
|
||||
file: file,
|
||||
line: node.start.line,
|
||||
col: node.start.col,
|
||||
code: make_code(node, { beautify: false })
|
||||
}));
|
||||
}
|
||||
|
||||
function read_string(stat) {
|
||||
if (stat.TYPE == "SimpleStatement") {
|
||||
var body = stat.body;
|
||||
switch(body.TYPE) {
|
||||
case "String":
|
||||
return body.value;
|
||||
case "Array":
|
||||
return body.elements.map(function(element) {
|
||||
if (element.TYPE !== "String")
|
||||
throw new Error("Should be array of strings");
|
||||
return element.value;
|
||||
}).join("\n");
|
||||
}
|
||||
}
|
||||
throw new Error("Should be string or array of strings");
|
||||
}
|
||||
|
||||
function get_one_test(name, block) {
|
||||
var test = { name: name, options: {} };
|
||||
var tw = new U.TreeWalker(function(node, descend) {
|
||||
if (node instanceof U.AST_Assign) {
|
||||
if (!(node.left instanceof U.AST_SymbolRef)) {
|
||||
croak(node);
|
||||
}
|
||||
var name = node.left.name;
|
||||
test[name] = evaluate(node.right);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof U.AST_LabeledStatement) {
|
||||
var label = node.label;
|
||||
assert.ok([
|
||||
"input",
|
||||
"expect",
|
||||
"expect_exact",
|
||||
"expect_warnings",
|
||||
"expect_stdout",
|
||||
"node_version",
|
||||
].indexOf(label.name) >= 0, tmpl("Unsupported label {name} [{line},{col}]", {
|
||||
name: label.name,
|
||||
line: label.start.line,
|
||||
col: label.start.col
|
||||
}));
|
||||
var stat = node.body;
|
||||
if (label.name == "expect_exact" || label.name == "node_version") {
|
||||
test[label.name] = read_string(stat);
|
||||
} else if (label.name == "expect_stdout") {
|
||||
var body = stat.body;
|
||||
if (body instanceof U.AST_Boolean) {
|
||||
test[label.name] = body.value;
|
||||
} else if (body instanceof U.AST_Call) {
|
||||
var ctor = global[body.expression.name];
|
||||
assert.ok(ctor === Error || ctor.prototype instanceof Error, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
||||
line: label.start.line,
|
||||
col: label.start.col
|
||||
}));
|
||||
test[label.name] = ctor.apply(null, body.args.map(function(node) {
|
||||
assert.ok(node instanceof U.AST_Constant, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
||||
line: label.start.line,
|
||||
col: label.start.col
|
||||
}));
|
||||
return node.value;
|
||||
}));
|
||||
} else {
|
||||
test[label.name] = read_string(stat) + "\n";
|
||||
}
|
||||
} else {
|
||||
test[label.name] = stat;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
block.walk(tw);
|
||||
return test;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to reminify original input with standard options
|
||||
// to see if it matches expect_stdout.
|
||||
function reminify(orig_options, input_code, input_formatted, expect_stdout) {
|
||||
for (var i = 0; i < minify_options.length; i++) {
|
||||
var options = JSON.parse(minify_options[i]);
|
||||
if (options.compress) [
|
||||
"keep_fargs",
|
||||
"keep_fnames",
|
||||
].forEach(function(name) {
|
||||
if (name in orig_options) {
|
||||
options.compress[name] = orig_options[name];
|
||||
}
|
||||
});
|
||||
var options_formatted = JSON.stringify(options, null, 4);
|
||||
var result = U.minify(input_code, options);
|
||||
if (result.error) {
|
||||
log("!!! failed input reminify\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n--ERROR---\n{error}\n\n", {
|
||||
input: input_formatted,
|
||||
options: options_formatted,
|
||||
error: result.error,
|
||||
});
|
||||
return false;
|
||||
} else {
|
||||
var stdout = run_code(result.code);
|
||||
if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) {
|
||||
stdout = expect_stdout;
|
||||
}
|
||||
if (!sandbox.same_stdout(expect_stdout, stdout)) {
|
||||
log("!!! failed running reminified input\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n---OUTPUT---\n{output}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||
input: input_formatted,
|
||||
options: options_formatted,
|
||||
output: result.code,
|
||||
expected_type: typeof expect_stdout == "string" ? "STDOUT" : "ERROR",
|
||||
expected: expect_stdout,
|
||||
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
||||
actual: stdout,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function run_code(code) {
|
||||
var result = sandbox.run_code(code, true);
|
||||
return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result;
|
||||
}
|
||||
|
||||
function run_compress_tests() {
|
||||
var dir = test_directory("compress");
|
||||
log_directory("compress");
|
||||
var files = find_test_files(dir);
|
||||
function test_file(file) {
|
||||
log_start_file(file);
|
||||
var dir = path.resolve(tests_dir, "compress");
|
||||
fs.readdirSync(dir).filter(function(name) {
|
||||
return /\.js$/i.test(name);
|
||||
}).forEach(function(file) {
|
||||
log("--- {file}", { file: file });
|
||||
function test_case(test) {
|
||||
log_test(test.name);
|
||||
log(" Running test [{name}]", { name: test.name });
|
||||
var output_options = test.beautify || {};
|
||||
var expect;
|
||||
if (test.expect) {
|
||||
expect = make_code(as_toplevel(test.expect, test.mangle), output_options);
|
||||
expect = make_code(to_toplevel(test.expect, test.mangle), output_options);
|
||||
} else {
|
||||
expect = test.expect_exact;
|
||||
}
|
||||
var input = as_toplevel(test.input, test.mangle);
|
||||
var input_code = make_code(input, output_options);
|
||||
var input = to_toplevel(test.input, test.mangle);
|
||||
var input_code = make_code(input);
|
||||
var input_formatted = make_code(test.input, {
|
||||
beautify: true,
|
||||
quote_style: 3,
|
||||
@@ -209,185 +341,27 @@ function run_compress_tests() {
|
||||
failed_files[file] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
files.forEach(function(file) {
|
||||
test_file(file);
|
||||
});
|
||||
}
|
||||
|
||||
function parse_test(file) {
|
||||
var script = fs.readFileSync(file, "utf8");
|
||||
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS2/issues/348
|
||||
try {
|
||||
var ast = U.parse(script, {
|
||||
filename: file
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Caught error while parsing tests in " + file + "\n");
|
||||
console.log(e);
|
||||
throw e;
|
||||
}
|
||||
var tests = {};
|
||||
var tw = new U.TreeWalker(function(node, descend) {
|
||||
if (node instanceof U.AST_LabeledStatement
|
||||
&& tw.parent() instanceof U.AST_Toplevel) {
|
||||
var name = node.label.name;
|
||||
if (name in tests) {
|
||||
throw new Error('Duplicated test name "' + name + '" in ' + file);
|
||||
}
|
||||
tests[name] = get_one_test(name, node.body);
|
||||
return true;
|
||||
}
|
||||
if (!(node instanceof U.AST_Toplevel)) croak(node);
|
||||
});
|
||||
ast.walk(tw);
|
||||
return tests;
|
||||
function tmpl() {
|
||||
return U.string_template.apply(null, arguments);
|
||||
}
|
||||
|
||||
function croak(node) {
|
||||
throw new Error(tmpl("Can't understand test file {file} [{line},{col}]\n{code}", {
|
||||
file: file,
|
||||
line: node.start.line,
|
||||
col: node.start.col,
|
||||
code: make_code(node, { beautify: false })
|
||||
}));
|
||||
}
|
||||
|
||||
function read_string(stat) {
|
||||
if (stat.TYPE == "SimpleStatement") {
|
||||
var body = stat.body;
|
||||
switch(body.TYPE) {
|
||||
case "String":
|
||||
return body.value;
|
||||
case "Array":
|
||||
return body.elements.map(function(element) {
|
||||
if (element.TYPE !== "String")
|
||||
throw new Error("Should be array of strings");
|
||||
return element.value;
|
||||
}).join("\n");
|
||||
}
|
||||
}
|
||||
throw new Error("Should be string or array of strings");
|
||||
}
|
||||
|
||||
function get_one_test(name, block) {
|
||||
var test = { name: name, options: {} };
|
||||
var tw = new U.TreeWalker(function(node, descend) {
|
||||
if (node instanceof U.AST_Assign) {
|
||||
if (!(node.left instanceof U.AST_SymbolRef)) {
|
||||
croak(node);
|
||||
}
|
||||
var name = node.left.name;
|
||||
test[name] = evaluate(node.right);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof U.AST_LabeledStatement) {
|
||||
var label = node.label;
|
||||
assert.ok(
|
||||
[
|
||||
"input",
|
||||
"expect",
|
||||
"expect_exact",
|
||||
"expect_warnings",
|
||||
"expect_stdout",
|
||||
"node_version",
|
||||
].indexOf(label.name) >= 0,
|
||||
tmpl("Unsupported label {name} [{line},{col}]", {
|
||||
name: label.name,
|
||||
line: label.start.line,
|
||||
col: label.start.col
|
||||
})
|
||||
);
|
||||
var stat = node.body;
|
||||
if (label.name == "expect_exact" || label.name == "node_version") {
|
||||
test[label.name] = read_string(stat);
|
||||
} else if (label.name == "expect_stdout") {
|
||||
var body = stat.body;
|
||||
if (body instanceof U.AST_Boolean) {
|
||||
test[label.name] = body.value;
|
||||
} else if (body instanceof U.AST_Call) {
|
||||
var ctor = global[body.expression.name];
|
||||
assert.ok(ctor === Error || ctor.prototype instanceof Error, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
||||
line: label.start.line,
|
||||
col: label.start.col
|
||||
}));
|
||||
test[label.name] = ctor.apply(null, body.args.map(function(node) {
|
||||
assert.ok(node instanceof U.AST_Constant, tmpl("Unsupported expect_stdout format [{line},{col}]", {
|
||||
line: label.start.line,
|
||||
col: label.start.col
|
||||
}));
|
||||
return node.value;
|
||||
}));
|
||||
function to_toplevel(input, mangle_options) {
|
||||
if (!(input instanceof U.AST_BlockStatement)) throw new Error("Unsupported input syntax");
|
||||
var directive = true;
|
||||
var offset = input.start.line;
|
||||
var tokens = [];
|
||||
var toplevel = new U.AST_Toplevel(input.transform(new U.TreeTransformer(function(node) {
|
||||
if (U.push_uniq(tokens, node.start)) node.start.line -= offset;
|
||||
if (!directive || node === input) return;
|
||||
if (node instanceof U.AST_SimpleStatement && node.body instanceof U.AST_String) {
|
||||
return new U.AST_Directive(node.body);
|
||||
} else {
|
||||
test[label.name] = read_string(stat) + "\n";
|
||||
directive = false;
|
||||
}
|
||||
} else {
|
||||
test[label.name] = stat;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
block.walk(tw);
|
||||
return test;
|
||||
};
|
||||
}
|
||||
|
||||
function make_code(ast, options) {
|
||||
var stream = U.OutputStream(options);
|
||||
ast.print(stream);
|
||||
return stream.get();
|
||||
}
|
||||
|
||||
function evaluate(code) {
|
||||
if (code instanceof U.AST_Node)
|
||||
code = make_code(code, { beautify: true });
|
||||
return new Function("return(" + code + ")")();
|
||||
}
|
||||
|
||||
function run_code(code) {
|
||||
var result = sandbox.run_code(code, true);
|
||||
return typeof result == "string" ? result.replace(/\u001b\[\d+m/g, "") : result;
|
||||
}
|
||||
|
||||
// Try to reminify original input with standard options
|
||||
// to see if it matches expect_stdout.
|
||||
function reminify(orig_options, input_code, input_formatted, expect_stdout) {
|
||||
for (var i = 0; i < minify_options.length; i++) {
|
||||
var options = JSON.parse(minify_options[i]);
|
||||
if (options.compress) [
|
||||
"keep_fargs",
|
||||
"keep_fnames",
|
||||
].forEach(function(name) {
|
||||
if (name in orig_options) {
|
||||
options.compress[name] = orig_options[name];
|
||||
}
|
||||
});
|
||||
var options_formatted = JSON.stringify(options, null, 4);
|
||||
var result = U.minify(input_code, options);
|
||||
if (result.error) {
|
||||
log("!!! failed input reminify\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n--ERROR---\n{error}\n\n", {
|
||||
input: input_formatted,
|
||||
options: options_formatted,
|
||||
error: result.error,
|
||||
});
|
||||
return false;
|
||||
} else {
|
||||
var stdout = run_code(result.code);
|
||||
if (typeof expect_stdout != "string" && typeof stdout != "string" && expect_stdout.name == stdout.name) {
|
||||
stdout = expect_stdout;
|
||||
}
|
||||
if (!sandbox.same_stdout(expect_stdout, stdout)) {
|
||||
log("!!! failed running reminified input\n---INPUT---\n{input}\n---OPTIONS---\n{options}\n---OUTPUT---\n{output}\n---EXPECTED {expected_type}---\n{expected}\n---ACTUAL {actual_type}---\n{actual}\n\n", {
|
||||
input: input_formatted,
|
||||
options: options_formatted,
|
||||
output: result.code,
|
||||
expected_type: typeof expect_stdout == "string" ? "STDOUT" : "ERROR",
|
||||
expected: expect_stdout,
|
||||
actual_type: typeof stdout == "string" ? "STDOUT" : "ERROR",
|
||||
actual: stdout,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})));
|
||||
toplevel.figure_out_scope(mangle_options);
|
||||
return toplevel;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
exports["Dictionary"] = Dictionary;
|
||||
exports["TreeWalker"] = TreeWalker;
|
||||
exports["TreeTransformer"] = TreeTransformer;
|
||||
exports["minify"] = minify;
|
||||
exports["parse"] = parse;
|
||||
exports["_push_uniq"] = push_uniq;
|
||||
exports["push_uniq"] = push_uniq;
|
||||
exports["TreeTransformer"] = TreeTransformer;
|
||||
exports["TreeWalker"] = TreeWalker;
|
||||
|
||||
Reference in New Issue
Block a user