Skip to content

Commit bcebacb

Browse files
authored
fix corner cases in preserve_line (#3212)
1 parent 018a5a7 commit bcebacb

15 files changed

Lines changed: 533 additions & 378 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -857,8 +857,8 @@ can pass additional arguments that control the code output:
857857
adjust for this text. Can be used to insert a comment containing
858858
licensing information, for example.
859859

860-
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
861-
only works if `beautify` is set to `false`.
860+
- `preserve_line` (default `false`) -- pass `true` to retain line numbering on
861+
a best effort basis.
862862

863863
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
864864
objects

bin/uglifyjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ if (program.mangleProps) {
100100
if (typeof program.mangleProps != "object") program.mangleProps = {};
101101
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
102102
require("../tools/domprops").forEach(function(name) {
103-
UglifyJS._push_uniq(program.mangleProps.reserved, name);
103+
UglifyJS.push_uniq(program.mangleProps.reserved, name);
104104
});
105105
}
106106
if (typeof options.mangle != "object") options.mangle = {};

lib/output.js

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -198,16 +198,24 @@ function OutputStream(options) {
198198
/* -----[ beautification/minification ]----- */
199199

200200
var has_parens = false;
201+
var line_end = 0;
202+
var line_fixed = true;
201203
var might_need_space = false;
202204
var might_need_semicolon = false;
203-
var might_add_newline = 0;
204205
var need_newline_indented = false;
205206
var need_space = false;
206207
var newline_insert = -1;
207208
var last = "";
208209
var mapping_token, mapping_name, mappings = options.source_map && [];
209210

210-
var do_add_mapping = mappings ? function() {
211+
var adjust_mappings = mappings ? function(line, col) {
212+
mappings.forEach(function(mapping) {
213+
mapping.line += line;
214+
mapping.col += col;
215+
});
216+
} : noop;
217+
218+
var flush_mappings = mappings ? function() {
211219
mappings.forEach(function(mapping) {
212220
try {
213221
options.source_map.add(
@@ -230,31 +238,30 @@ function OutputStream(options) {
230238
mappings = [];
231239
} : noop;
232240

233-
var ensure_line_len = options.max_line_len ? function() {
234-
if (current_col > options.max_line_len) {
235-
if (might_add_newline) {
236-
var left = OUTPUT.slice(0, might_add_newline);
237-
var right = OUTPUT.slice(might_add_newline);
238-
if (mappings) {
239-
var delta = right.length - current_col;
240-
mappings.forEach(function(mapping) {
241-
mapping.line++;
242-
mapping.col += delta;
243-
});
244-
}
245-
OUTPUT = left + "\n" + right;
246-
current_line++;
247-
current_pos++;
248-
current_col = right.length;
249-
}
241+
function insert_newlines(count) {
242+
var index = OUTPUT.lastIndexOf("\n");
243+
if (line_end < index) line_end = index;
244+
var left = OUTPUT.slice(0, line_end);
245+
var right = OUTPUT.slice(line_end);
246+
adjust_mappings(count, right.length - current_col);
247+
current_line += count;
248+
current_pos += count;
249+
current_col = right.length;
250+
OUTPUT = left;
251+
while (count--) OUTPUT += "\n";
252+
OUTPUT += right;
253+
}
254+
255+
var fix_line = options.max_line_len ? function() {
256+
if (line_fixed) {
250257
if (current_col > options.max_line_len) {
251258
AST_Node.warn("Output exceeds {max_line_len} characters", options);
252259
}
260+
return;
253261
}
254-
if (might_add_newline) {
255-
might_add_newline = 0;
256-
do_add_mapping();
257-
}
262+
if (current_col > options.max_line_len) insert_newlines(1);
263+
line_fixed = true;
264+
flush_mappings();
258265
} : noop;
259266

260267
var requireSemicolonChars = makePredicate("( [ + * / - , .");
@@ -286,7 +293,7 @@ function OutputStream(options) {
286293
current_col++;
287294
current_pos++;
288295
} else {
289-
ensure_line_len();
296+
fix_line();
290297
OUTPUT += "\n";
291298
current_pos++;
292299
current_line++;
@@ -304,18 +311,6 @@ function OutputStream(options) {
304311
}
305312
}
306313

307-
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
308-
var target_line = stack[stack.length - 1].start.line;
309-
while (current_line < target_line) {
310-
ensure_line_len();
311-
OUTPUT += "\n";
312-
current_pos++;
313-
current_line++;
314-
current_col = 0;
315-
might_need_space = false;
316-
}
317-
}
318-
319314
if (might_need_space) {
320315
if ((is_identifier_char(prev)
321316
&& (is_identifier_char(ch) || ch == "\\"))
@@ -337,7 +332,7 @@ function OutputStream(options) {
337332
col: current_col
338333
});
339334
mapping_token = false;
340-
if (!might_add_newline) do_add_mapping();
335+
if (line_fixed) flush_mappings();
341336
}
342337

343338
OUTPUT += str;
@@ -347,7 +342,7 @@ function OutputStream(options) {
347342
current_line += n;
348343
current_col += a[0].length;
349344
if (n > 0) {
350-
ensure_line_len();
345+
fix_line();
351346
current_col = a[n].length;
352347
}
353348
last = str;
@@ -374,9 +369,10 @@ function OutputStream(options) {
374369
return ret;
375370
} : function(col, cont) { return cont() };
376371

377-
var may_add_newline = options.max_line_len ? function() {
378-
ensure_line_len();
379-
might_add_newline = OUTPUT.length;
372+
var may_add_newline = options.max_line_len || options.preserve_line ? function() {
373+
fix_line();
374+
line_end = OUTPUT.length;
375+
line_fixed = false;
380376
} : noop;
381377

382378
var newline = options.beautify ? function() {
@@ -455,9 +451,7 @@ function OutputStream(options) {
455451
} : noop;
456452

457453
function get() {
458-
if (might_add_newline) {
459-
ensure_line_len();
460-
}
454+
if (!line_fixed) fix_line();
461455
return OUTPUT;
462456
}
463457

@@ -622,7 +616,14 @@ function OutputStream(options) {
622616
col : function() { return current_col },
623617
pos : function() { return current_pos },
624618
push_node : function(node) { stack.push(node) },
625-
pop_node : function() { return stack.pop() },
619+
pop_node : options.preserve_line ? function() {
620+
var node = stack.pop();
621+
if (node.start && node.start.line > current_line) {
622+
insert_newlines(node.start.line - current_line);
623+
}
624+
} : function() {
625+
stack.pop();
626+
},
626627
parent : function(n) {
627628
return stack[stack.length - 2 - (n || 0)];
628629
}

lib/utils.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,7 @@ var MAP = (function() {
162162
})();
163163

164164
function push_uniq(array, el) {
165-
if (array.indexOf(el) < 0)
166-
array.push(el);
165+
if (array.indexOf(el) < 0) return array.push(el);
167166
}
168167

169168
function string_template(text, props) {

test/compress/evaluate.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,7 @@ issue_2231_1: {
11991199
}
12001200
expect_stdout: true
12011201
expect_warnings: [
1202-
"WARN: Error evaluating Object.keys(void 0) [test/compress/evaluate.js:1195,20]",
1202+
"WARN: Error evaluating Object.keys(void 0) [test/compress/evaluate.js:1,20]",
12031203
]
12041204
}
12051205

@@ -1216,7 +1216,7 @@ issue_2231_2: {
12161216
}
12171217
expect_stdout: true
12181218
expect_warnings: [
1219-
"WARN: Error evaluating Object.getOwnPropertyNames(null) [test/compress/evaluate.js:1212,20]",
1219+
"WARN: Error evaluating Object.getOwnPropertyNames(null) [test/compress/evaluate.js:1,20]",
12201220
]
12211221
}
12221222

@@ -1354,14 +1354,14 @@ issue_2535_3: {
13541354
}
13551355
expect_stdout: true
13561356
expect_warnings: [
1357-
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1340,20]",
1358-
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1341,20]",
1359-
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1342,20]",
1360-
"WARN: Condition left of && always false [test/compress/evaluate.js:1342,20]",
1361-
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1343,20]",
1362-
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1344,20]",
1363-
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:1345,20]",
1364-
"WARN: Condition left of || always true [test/compress/evaluate.js:1345,20]",
1357+
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:1,20]",
1358+
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:2,20]",
1359+
"WARN: Dropping side-effect-free && [test/compress/evaluate.js:3,20]",
1360+
"WARN: Condition left of && always false [test/compress/evaluate.js:3,20]",
1361+
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:4,20]",
1362+
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:5,20]",
1363+
"WARN: Dropping side-effect-free || [test/compress/evaluate.js:6,20]",
1364+
"WARN: Condition left of || always true [test/compress/evaluate.js:6,20]",
13651365
]
13661366
}
13671367

test/compress/global_defs.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ mixed: {
141141
console.log(CONFIG);
142142
}
143143
expect_warnings: [
144-
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:127,22]",
145-
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:128,22]",
146-
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:130,8]",
144+
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:4,22]",
145+
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:5,22]",
146+
"WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:7,8]",
147147
]
148148
}
149149

test/compress/issue-1034.js

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ non_hoisted_function_after_return: {
3636
}
3737
}
3838
expect_warnings: [
39-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:20,16]",
40-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:23,16]",
41-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:26,12]",
42-
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:27,21]"
39+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
40+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
41+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
42+
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:11,21]"
4343
]
4444
}
4545

@@ -85,18 +85,18 @@ non_hoisted_function_after_return_2a: {
8585
}
8686
}
8787
expect_warnings: [
88-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:68,16]",
89-
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:68,16]",
90-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:71,16]",
91-
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:71,16]",
92-
"WARN: Dropping unused variable a [test/compress/issue-1034.js:68,20]",
93-
"WARN: Dropping unused function nope [test/compress/issue-1034.js:75,21]",
88+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:4,16]",
89+
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:4,16]",
90+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
91+
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
92+
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
93+
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
9494
"WARN: pass 0: last_count: Infinity, count: 37",
95-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:73,12]",
96-
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:73,12]",
97-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:76,12]",
98-
"WARN: Dropping unused variable b [test/compress/issue-1034.js:71,20]",
99-
"WARN: Dropping unused variable c [test/compress/issue-1034.js:73,16]",
95+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
96+
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
97+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
98+
"WARN: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
99+
"WARN: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
100100
"WARN: pass 1: last_count: 37, count: 18",
101101
]
102102
}
@@ -139,12 +139,11 @@ non_hoisted_function_after_return_2b: {
139139
}
140140
}
141141
expect_warnings: [
142-
// duplicate warnings no longer emitted
143-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:126,16]",
144-
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:126,16]",
145-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:128,12]",
146-
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:128,12]",
147-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:132,12]",
142+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:6,16]",
143+
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:6,16]",
144+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,12]",
145+
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,12]",
146+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
148147
]
149148
}
150149

@@ -191,10 +190,10 @@ non_hoisted_function_after_return_strict: {
191190
}
192191
expect_stdout: "8 7"
193192
expect_warnings: [
194-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:171,16]",
195-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:174,16]",
196-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:177,12]",
197-
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:178,21]",
193+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
194+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
195+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:11,12]",
196+
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:12,21]",
198197
]
199198
}
200199

@@ -245,18 +244,18 @@ non_hoisted_function_after_return_2a_strict: {
245244
}
246245
expect_stdout: "5 6"
247246
expect_warnings: [
248-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:224,16]",
249-
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:224,16]",
250-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:227,16]",
251-
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:227,16]",
252-
"WARN: Dropping unused variable a [test/compress/issue-1034.js:224,20]",
253-
"WARN: Dropping unused function nope [test/compress/issue-1034.js:231,21]",
247+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:5,16]",
248+
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:5,16]",
249+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:8,16]",
250+
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
251+
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
252+
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
254253
"WARN: pass 0: last_count: Infinity, count: 48",
255-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:229,12]",
256-
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:229,12]",
257-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:232,12]",
258-
"WARN: Dropping unused variable b [test/compress/issue-1034.js:227,20]",
259-
"WARN: Dropping unused variable c [test/compress/issue-1034.js:229,16]",
254+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
255+
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
256+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
257+
"WARN: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
258+
"WARN: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
260259
"WARN: pass 1: last_count: 48, count: 29",
261260
]
262261
}
@@ -304,11 +303,10 @@ non_hoisted_function_after_return_2b_strict: {
304303
}
305304
expect_stdout: "5 6"
306305
expect_warnings: [
307-
// duplicate warnings no longer emitted
308-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:287,16]",
309-
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:287,16]",
310-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:289,12]",
311-
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:289,12]",
312-
"WARN: Dropping unreachable code [test/compress/issue-1034.js:293,12]",
306+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:7,16]",
307+
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
308+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
309+
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
310+
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
313311
]
314312
}

0 commit comments

Comments
 (0)