Skip to content

Commit

Permalink
fix corner cases in preserve_line (#3212)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlamsl committed Jul 12, 2018
1 parent 018a5a7 commit bcebacb
Show file tree
Hide file tree
Showing 15 changed files with 533 additions and 378 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion bin/uglifyjs
Expand Up @@ -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 = {};
Expand Down
91 changes: 46 additions & 45 deletions lib/output.js
Expand Up @@ -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(
Expand All @@ -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++;
current_col = right.length;
}
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("( [ + * / - , .");
Expand Down Expand Up @@ -286,7 +293,7 @@ function OutputStream(options) {
current_col++;
current_pos++;
} else {
ensure_line_len();
fix_line();
OUTPUT += "\n";
current_pos++;
current_line++;
Expand All @@ -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 == "\\"))
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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() {
Expand Down Expand Up @@ -455,9 +451,7 @@ function OutputStream(options) {
} : noop;

function get() {
if (might_add_newline) {
ensure_line_len();
}
if (!line_fixed) fix_line();
return OUTPUT;
}

Expand Down Expand Up @@ -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)];
}
Expand Down
3 changes: 1 addition & 2 deletions lib/utils.js
Expand Up @@ -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) {
Expand Down
20 changes: 10 additions & 10 deletions test/compress/evaluate.js
Expand Up @@ -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]",
]
}

Expand All @@ -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]",
]
}

Expand Down Expand Up @@ -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]",
]
}

Expand Down
6 changes: 3 additions & 3 deletions test/compress/global_defs.js
Expand Up @@ -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]",
]
}

Expand Down
82 changes: 40 additions & 42 deletions test/compress/issue-1034.js
Expand Up @@ -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]"
]
}

Expand Down Expand Up @@ -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",
]
}
Expand Down Expand Up @@ -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]",
]
}

Expand Down Expand Up @@ -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]",
]
}

Expand Down Expand Up @@ -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",
]
}
Expand Down Expand Up @@ -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]",
]
}

0 comments on commit bcebacb

Please sign in to comment.