source: frontend/node_modules/terser/lib/output.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 82.3 KB
Line 
1/***********************************************************************
2
3 A JavaScript tokenizer / parser / beautifier / compressor.
4 https://github.com/mishoo/UglifyJS2
5
6 -------------------------------- (C) ---------------------------------
7
8 Author: Mihai Bazon
9 <mihai.bazon@gmail.com>
10 http://mihai.bazon.net/blog
11
12 Distributed under the BSD license:
13
14 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
15
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
18 are met:
19
20 * Redistributions of source code must retain the above
21 copyright notice, this list of conditions and the following
22 disclaimer.
23
24 * Redistributions in binary form must reproduce the above
25 copyright notice, this list of conditions and the following
26 disclaimer in the documentation and/or other materials
27 provided with the distribution.
28
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
30 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
33 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
38 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
39 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 SUCH DAMAGE.
41
42 ***********************************************************************/
43
44"use strict";
45
46import {
47 defaults,
48 makePredicate,
49 noop,
50 regexp_source_fix,
51 sort_regexp_flags,
52 return_false,
53 return_true,
54} from "./utils/index.js";
55import { first_in_statement, left_is_object } from "./utils/first_in_statement.js";
56import {
57 AST_Array,
58 AST_Arrow,
59 AST_Assign,
60 AST_Await,
61 AST_BigInt,
62 AST_Binary,
63 AST_BlockStatement,
64 AST_Break,
65 AST_Call,
66 AST_Case,
67 AST_Catch,
68 AST_Chain,
69 AST_Class,
70 AST_ClassExpression,
71 AST_ClassPrivateProperty,
72 AST_ClassProperty,
73 AST_ClassStaticBlock,
74 AST_ConciseMethod,
75 AST_PrivateGetter,
76 AST_PrivateMethod,
77 AST_SymbolPrivateProperty,
78 AST_PrivateSetter,
79 AST_PrivateIn,
80 AST_Conditional,
81 AST_Const,
82 AST_Constant,
83 AST_Continue,
84 AST_Debugger,
85 AST_Default,
86 AST_DefaultAssign,
87 AST_Definitions,
88 AST_DefinitionsLike,
89 AST_Defun,
90 AST_Destructuring,
91 AST_Directive,
92 AST_Do,
93 AST_Dot,
94 AST_DotHash,
95 AST_EmptyStatement,
96 AST_Exit,
97 AST_Expansion,
98 AST_Export,
99 AST_Finally,
100 AST_For,
101 AST_ForIn,
102 AST_ForOf,
103 AST_Function,
104 AST_Hole,
105 AST_If,
106 AST_DynamicImport,
107 AST_Import,
108 AST_ImportMeta,
109 AST_Jump,
110 AST_LabeledStatement,
111 AST_Lambda,
112 AST_Let,
113 AST_LoopControl,
114 AST_NameMapping,
115 AST_New,
116 AST_NewTarget,
117 AST_Node,
118 AST_Number,
119 AST_Object,
120 AST_ObjectGetter,
121 AST_ObjectKeyVal,
122 AST_ObjectProperty,
123 AST_ObjectSetter,
124 AST_PrefixedTemplateString,
125 AST_PropAccess,
126 AST_RegExp,
127 AST_Return,
128 AST_Scope,
129 AST_Sequence,
130 AST_SimpleStatement,
131 AST_Statement,
132 AST_StatementWithBody,
133 AST_String,
134 AST_Sub,
135 AST_Super,
136 AST_Switch,
137 AST_SwitchBranch,
138 AST_Symbol,
139 AST_SymbolClassProperty,
140 AST_SymbolMethod,
141 AST_SymbolRef,
142 AST_TemplateSegment,
143 AST_TemplateString,
144 AST_This,
145 AST_Throw,
146 AST_Toplevel,
147 AST_Try,
148 AST_TryBlock,
149 AST_Unary,
150 AST_UnaryPostfix,
151 AST_UnaryPrefix,
152 AST_Using,
153 AST_Var,
154 AST_VarDefLike,
155 AST_While,
156 AST_With,
157 AST_Yield,
158 TreeWalker,
159 walk,
160 walk_abort
161} from "./ast.js";
162import {
163 get_full_char_code,
164 get_full_char,
165 is_identifier_char,
166 is_basic_identifier_string,
167 is_identifier_string,
168 PRECEDENCE,
169 ALL_RESERVED_WORDS,
170} from "./parse.js";
171
172const CODE_LINE_BREAK = 10;
173const CODE_SPACE = 32;
174
175const r_annotation = /[@#]__(PURE|INLINE|NOINLINE)__/;
176
177function is_some_comments(comment) {
178 // multiline comment
179 return (
180 (comment.type === "comment2" || comment.type === "comment1")
181 && /@preserve|@copyright|@lic|@cc_on|^\**!/i.test(comment.value)
182 );
183}
184
185const ROPE_COMMIT_WHEN = 8 * 1000;
186class Rope {
187 constructor() {
188 this.committed = "";
189 this.current = "";
190 }
191
192 append(str) {
193 /** When `this.current` is too long, commit it. */
194 if (this.current.length > ROPE_COMMIT_WHEN) {
195 this.committed += this.current + str;
196 this.current = "";
197 } else {
198 this.current += str;
199 }
200 }
201
202 insertAt(char, index) {
203 const { committed, current } = this;
204 if (index < committed.length) {
205 this.committed = committed.slice(0, index) + char + committed.slice(index);
206 } else if (index === committed.length) {
207 this.committed += char;
208 } else {
209 index -= committed.length;
210 this.committed += current.slice(0, index) + char;
211 this.current = current.slice(index);
212 }
213 }
214
215 charAt(index) {
216 const { committed } = this;
217 if (index < committed.length) return committed[index];
218 return this.current[index - committed.length];
219 }
220
221 charCodeAt(index) {
222 const { committed } = this;
223 if (index < committed.length) return committed.charCodeAt(index);
224 return this.current.charCodeAt(index - committed.length);
225 }
226
227 length() {
228 return this.committed.length + this.current.length;
229 }
230
231 expectDirective() {
232 // /^$|[;{][\s\n]*$/
233
234 let ch, n = this.length();
235
236 if (n <= 0) return true;
237
238 // Skip N whitespace from the end
239 while (
240 (ch = this.charCodeAt(--n))
241 && (ch == CODE_SPACE || ch == CODE_LINE_BREAK)
242 );
243
244 // either ";", or "{", or the string ended
245 return !ch || ch === 59 || ch === 123;
246 }
247
248 hasNLB() {
249 let n = this.length() - 1;
250 while (n >= 0) {
251 const code = this.charCodeAt(n--);
252
253 if (code === CODE_LINE_BREAK) return true;
254 if (code !== CODE_SPACE) return false;
255 }
256 return true;
257 }
258
259
260 toString() {
261 return this.committed + this.current;
262 }
263}
264
265function OutputStream(options) {
266
267 var readonly = !options;
268 options = defaults(options, {
269 ascii_only : false,
270 beautify : false,
271 braces : false,
272 comments : "some",
273 ecma : 5,
274 ie8 : false,
275 indent_level : 4,
276 indent_start : 0,
277 inline_script : true,
278 keep_numbers : false,
279 keep_quoted_props : false,
280 max_line_len : false,
281 preamble : null,
282 preserve_annotations : false,
283 quote_keys : false,
284 quote_style : 0,
285 safari10 : false,
286 semicolons : true,
287 shebang : true,
288 shorthand : undefined,
289 source_map : null,
290 webkit : false,
291 width : 80,
292 wrap_iife : false,
293 wrap_func_args : false,
294
295 _destroy_ast : false
296 }, true);
297
298 if (options.shorthand === undefined)
299 options.shorthand = options.ecma > 5;
300
301 // Convert comment option to RegExp if necessary and set up comments filter
302 var comment_filter = return_false; // Default case, throw all comments away
303 if (options.comments) {
304 let comments = options.comments;
305 if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) {
306 var regex_pos = options.comments.lastIndexOf("/");
307 comments = new RegExp(
308 options.comments.substr(1, regex_pos - 1),
309 options.comments.substr(regex_pos + 1)
310 );
311 }
312 if (comments instanceof RegExp) {
313 comment_filter = function(comment) {
314 return comment.type != "comment5" && comments.test(comment.value);
315 };
316 } else if (typeof comments === "function") {
317 comment_filter = function(comment) {
318 return comment.type != "comment5" && comments(this, comment);
319 };
320 } else if (comments === "some") {
321 comment_filter = is_some_comments;
322 } else { // NOTE includes "all" option
323 comment_filter = return_true;
324 }
325 }
326
327 if (options.preserve_annotations) {
328 let prev_comment_filter = comment_filter;
329 comment_filter = function (comment) {
330 return r_annotation.test(comment.value) || prev_comment_filter.apply(this, arguments);
331 };
332 }
333
334 var indentation = 0;
335 var current_col = 0;
336 var current_line = 1;
337 var current_pos = 0;
338 var OUTPUT = new Rope();
339 let printed_comments = new Set();
340
341 var to_utf8 = options.ascii_only ? function(str, identifier = false, regexp = false) {
342 if (options.ecma >= 2015 && !options.safari10 && !regexp) {
343 str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
344 var code = get_full_char_code(ch, 0).toString(16);
345 return "\\u{" + code + "}";
346 });
347 }
348 return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
349 var code = ch.charCodeAt(0).toString(16);
350 if (code.length <= 2 && !identifier) {
351 while (code.length < 2) code = "0" + code;
352 return "\\x" + code;
353 } else {
354 while (code.length < 4) code = "0" + code;
355 return "\\u" + code;
356 }
357 });
358 } : function(str) {
359 return str.replace(/[\ud800-\udbff][\udc00-\udfff]|([\ud800-\udbff]|[\udc00-\udfff])/g, function(match, lone) {
360 if (lone) {
361 return "\\u" + lone.charCodeAt(0).toString(16);
362 }
363 return match;
364 });
365 };
366
367 function make_string(str, quote) {
368 var dq = 0, sq = 0;
369 str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g,
370 function(s, i) {
371 switch (s) {
372 case '"': ++dq; return '"';
373 case "'": ++sq; return "'";
374 case "\\": return "\\\\";
375 case "\n": return "\\n";
376 case "\r": return "\\r";
377 case "\t": return "\\t";
378 case "\b": return "\\b";
379 case "\f": return "\\f";
380 case "\x0B": return options.ie8 ? "\\x0B" : "\\v";
381 case "\u2028": return "\\u2028";
382 case "\u2029": return "\\u2029";
383 case "\ufeff": return "\\ufeff";
384 case "\0":
385 return /[0-9]/.test(get_full_char(str, i+1)) ? "\\x00" : "\\0";
386 }
387 return s;
388 });
389 function quote_single() {
390 return "'" + str.replace(/\x27/g, "\\'") + "'";
391 }
392 function quote_double() {
393 return '"' + str.replace(/\x22/g, '\\"') + '"';
394 }
395 function quote_template() {
396 return "`" + str.replace(/`/g, "\\`") + "`";
397 }
398 str = to_utf8(str);
399 if (quote === "`") return quote_template();
400 switch (options.quote_style) {
401 case 1:
402 return quote_single();
403 case 2:
404 return quote_double();
405 case 3:
406 return quote == "'" ? quote_single() : quote_double();
407 default:
408 return dq > sq ? quote_single() : quote_double();
409 }
410 }
411
412 function encode_string(str, quote) {
413 var ret = make_string(str, quote);
414 if (options.inline_script) {
415 ret = ret.replace(/<\x2f(script)([>\/\t\n\f\r ])/gi, "<\\/$1$2");
416 ret = ret.replace(/\x3c!--/g, "\\x3c!--");
417 ret = ret.replace(/--\x3e/g, "--\\x3e");
418 }
419 return ret;
420 }
421
422 function make_name(name) {
423 name = name.toString();
424 name = to_utf8(name, true);
425 return name;
426 }
427
428 function make_indent(back) {
429 return " ".repeat(options.indent_start + indentation - back * options.indent_level);
430 }
431
432 /* -----[ beautification/minification ]----- */
433
434 var has_parens = false;
435 var might_need_space = false;
436 var might_need_semicolon = false;
437 var might_add_newline = 0;
438 var need_newline_indented = false;
439 var need_space = false;
440 var newline_insert = -1;
441 var last = "";
442 var mapping_token, mapping_name, mappings = options.source_map && [];
443
444 var do_add_mapping = mappings ? function() {
445 mappings.forEach(function(mapping) {
446 try {
447 let { name, token } = mapping;
448 if (name !== false) {
449 if (token.type == "name" || token.type === "privatename") {
450 name = token.value;
451 } else if (name instanceof AST_Symbol) {
452 name = token.type === "string" ? token.value : name.name;
453 }
454 }
455 options.source_map.add(
456 mapping.token.file,
457 mapping.line, mapping.col,
458 mapping.token.line, mapping.token.col,
459 is_basic_identifier_string(name) ? name : undefined
460 );
461 } catch(ex) {
462 // Ignore bad mapping
463 }
464 });
465 mappings = [];
466 } : noop;
467
468 var ensure_line_len = options.max_line_len ? function() {
469 if (current_col > options.max_line_len) {
470 if (might_add_newline) {
471 OUTPUT.insertAt("\n", might_add_newline);
472 const len_after_newline = OUTPUT.length() - might_add_newline - 1;
473 if (mappings) {
474 var delta = len_after_newline - current_col;
475 mappings.forEach(function(mapping) {
476 mapping.line++;
477 mapping.col += delta;
478 });
479 }
480 current_line++;
481 current_pos++;
482 current_col = len_after_newline;
483 }
484 }
485 if (might_add_newline) {
486 might_add_newline = 0;
487 do_add_mapping();
488 }
489 } : noop;
490
491 var requireSemicolonChars = makePredicate("( [ + * / - , . `");
492
493 function print(str) {
494 str = String(str);
495 var ch = get_full_char(str, 0);
496 if (need_newline_indented && ch) {
497 need_newline_indented = false;
498 if (ch !== "\n") {
499 print("\n");
500 indent();
501 }
502 }
503 if (need_space && ch) {
504 need_space = false;
505 if (!/[\s;})]/.test(ch)) {
506 space();
507 }
508 }
509 newline_insert = -1;
510 var prev = last.charAt(last.length - 1);
511 if (might_need_semicolon) {
512 might_need_semicolon = false;
513
514 if (prev === ":" && ch === "}" || (!ch || !";}".includes(ch)) && prev !== ";") {
515 if (options.semicolons || requireSemicolonChars.has(ch)) {
516 OUTPUT.append(";");
517 current_col++;
518 current_pos++;
519 } else {
520 ensure_line_len();
521 if (current_col > 0) {
522 OUTPUT.append("\n");
523 current_pos++;
524 current_line++;
525 current_col = 0;
526 }
527
528 if (/^\s+$/.test(str)) {
529 // reset the semicolon flag, since we didn't print one
530 // now and might still have to later
531 might_need_semicolon = true;
532 }
533 }
534
535 if (!options.beautify)
536 might_need_space = false;
537 }
538 }
539
540 if (might_need_space) {
541 if ((is_identifier_char(prev)
542 && (is_identifier_char(ch) || ch == "\\"))
543 || (ch == "/" && ch == prev)
544 || ((ch == "+" || ch == "-") && ch == last)
545 ) {
546 OUTPUT.append(" ");
547 current_col++;
548 current_pos++;
549 }
550 might_need_space = false;
551 }
552
553 if (mapping_token) {
554 mappings.push({
555 token: mapping_token,
556 name: mapping_name,
557 line: current_line,
558 col: current_col
559 });
560 mapping_token = false;
561 if (!might_add_newline) do_add_mapping();
562 }
563
564 OUTPUT.append(str);
565 has_parens = str[str.length - 1] == "(";
566 current_pos += str.length;
567 var a = str.split(/\r?\n/), n = a.length - 1;
568 current_line += n;
569 current_col += a[0].length;
570 if (n > 0) {
571 ensure_line_len();
572 current_col = a[n].length;
573 }
574 last = str;
575 }
576
577 var star = function() {
578 print("*");
579 };
580
581 var space = options.beautify ? function() {
582 print(" ");
583 } : function() {
584 might_need_space = true;
585 };
586
587 var indent = options.beautify ? function(half) {
588 if (options.beautify) {
589 print(make_indent(half ? 0.5 : 0));
590 }
591 } : noop;
592
593 var with_indent = options.beautify ? function(col, cont) {
594 if (col === true) col = next_indent();
595 var save_indentation = indentation;
596 indentation = col;
597 var ret = cont();
598 indentation = save_indentation;
599 return ret;
600 } : function(col, cont) { return cont(); };
601
602 var newline = options.beautify ? function() {
603 if (newline_insert < 0) return print("\n");
604 if (OUTPUT.charAt(newline_insert) != "\n") {
605 OUTPUT.insertAt("\n", newline_insert);
606 current_pos++;
607 current_line++;
608 }
609 newline_insert++;
610 } : options.max_line_len ? function() {
611 ensure_line_len();
612 might_add_newline = OUTPUT.length();
613 } : noop;
614
615 var semicolon = options.beautify ? function() {
616 print(";");
617 } : function() {
618 might_need_semicolon = true;
619 };
620
621 function force_semicolon() {
622 might_need_semicolon = false;
623 print(";");
624 }
625
626 function next_indent() {
627 return indentation + options.indent_level;
628 }
629
630 function with_block(cont) {
631 var ret;
632 print("{");
633 newline();
634 with_indent(next_indent(), function() {
635 ret = cont();
636 });
637 indent();
638 print("}");
639 return ret;
640 }
641
642 function with_parens(cont) {
643 print("(");
644 //XXX: still nice to have that for argument lists
645 //var ret = with_indent(current_col, cont);
646 var ret = cont();
647 print(")");
648 return ret;
649 }
650
651 function with_square(cont) {
652 print("[");
653 //var ret = with_indent(current_col, cont);
654 var ret = cont();
655 print("]");
656 return ret;
657 }
658
659 function comma() {
660 print(",");
661 space();
662 }
663
664 function colon() {
665 print(":");
666 space();
667 }
668
669 var add_mapping = mappings ? function(token, name) {
670 mapping_token = token;
671 mapping_name = name;
672 } : noop;
673
674 function get() {
675 if (might_add_newline) {
676 ensure_line_len();
677 }
678 return OUTPUT.toString();
679 }
680
681 function filter_comment(comment) {
682 if (!options.preserve_annotations) {
683 comment = comment.replace(r_annotation, " ");
684 }
685 if (/^\s*$/.test(comment)) {
686 return "";
687 }
688 return comment.replace(/(<\s*\/\s*)(script)/i, "<\\/$2");
689 }
690
691 function prepend_comments(node) {
692 var self = this;
693 var start = node.start;
694 if (!start) return;
695 var printed_comments = self.printed_comments;
696
697 // There cannot be a newline between return/yield and its value.
698 const keyword_with_value =
699 node instanceof AST_Exit && node.value
700 || (node instanceof AST_Await || node instanceof AST_Yield)
701 && node.expression;
702
703 if (
704 start.comments_before
705 && printed_comments.has(start.comments_before)
706 ) {
707 if (keyword_with_value) {
708 start.comments_before = [];
709 } else {
710 return;
711 }
712 }
713
714 var comments = start.comments_before;
715 if (!comments) {
716 comments = start.comments_before = [];
717 }
718 printed_comments.add(comments);
719
720 if (keyword_with_value) {
721 var tw = new TreeWalker(function(node) {
722 var parent = tw.parent();
723 if (parent instanceof AST_Exit
724 || parent instanceof AST_Await
725 || parent instanceof AST_Yield
726 || parent instanceof AST_Binary && parent.left === node
727 || parent.TYPE == "Call" && parent.expression === node
728 || parent instanceof AST_Conditional && parent.condition === node
729 || parent instanceof AST_Dot && parent.expression === node
730 || parent instanceof AST_Sequence && parent.expressions[0] === node
731 || parent instanceof AST_Sub && parent.expression === node
732 || parent instanceof AST_UnaryPostfix) {
733 if (!node.start) return;
734 var text = node.start.comments_before;
735 if (text && !printed_comments.has(text)) {
736 printed_comments.add(text);
737 comments = comments.concat(text);
738 }
739 } else {
740 return true;
741 }
742 });
743 tw.push(node);
744 keyword_with_value.walk(tw);
745 }
746
747 if (current_pos == 0) {
748 if (comments.length > 0 && options.shebang && comments[0].type === "comment5"
749 && !printed_comments.has(comments[0])) {
750 print("#!" + comments.shift().value + "\n");
751 indent();
752 }
753 var preamble = options.preamble;
754 if (preamble) {
755 print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
756 }
757 }
758
759 comments = comments.filter(comment_filter, node).filter(c => !printed_comments.has(c));
760 if (comments.length == 0) return;
761 var last_nlb = OUTPUT.hasNLB();
762 comments.forEach(function(c, i) {
763 printed_comments.add(c);
764 if (!last_nlb) {
765 if (c.nlb) {
766 print("\n");
767 indent();
768 last_nlb = true;
769 } else if (i > 0) {
770 space();
771 }
772 }
773
774 if (/comment[134]/.test(c.type)) {
775 var value = filter_comment(c.value);
776 if (value) {
777 print("//" + value + "\n");
778 indent();
779 }
780 last_nlb = true;
781 } else if (c.type == "comment2") {
782 var value = filter_comment(c.value);
783 if (value) {
784 print("/*" + value + "*/");
785 }
786 last_nlb = false;
787 }
788 });
789 if (!last_nlb) {
790 if (start.nlb) {
791 print("\n");
792 indent();
793 } else {
794 space();
795 }
796 }
797 }
798
799 function append_comments(node, tail) {
800 var self = this;
801 var token = node.end;
802 if (!token) return;
803 var printed_comments = self.printed_comments;
804 var comments = token[tail ? "comments_before" : "comments_after"];
805 if (!comments || printed_comments.has(comments)) return;
806 if (!(node instanceof AST_Statement || comments.every((c) =>
807 !/comment[134]/.test(c.type)
808 ))) return;
809 printed_comments.add(comments);
810 var insert = OUTPUT.length();
811 comments.filter(comment_filter, node).forEach(function(c, i) {
812 if (printed_comments.has(c)) return;
813 printed_comments.add(c);
814 need_space = false;
815 if (need_newline_indented) {
816 print("\n");
817 indent();
818 need_newline_indented = false;
819 } else if (c.nlb && (i > 0 || !OUTPUT.hasNLB())) {
820 print("\n");
821 indent();
822 } else if (i > 0 || !tail) {
823 space();
824 }
825 if (/comment[134]/.test(c.type)) {
826 const value = filter_comment(c.value);
827 if (value) {
828 print("//" + value);
829 }
830 need_newline_indented = true;
831 } else if (c.type == "comment2") {
832 const value = filter_comment(c.value);
833 if (value) {
834 print("/*" + value + "*/");
835 }
836 need_space = true;
837 }
838 });
839 if (OUTPUT.length() > insert) newline_insert = insert;
840 }
841
842 /**
843 * When output.option("_destroy_ast") is enabled, destroy the function.
844 * Call this after printing it.
845 */
846 const gc_scope =
847 options["_destroy_ast"]
848 ? function gc_scope(scope) {
849 scope.body.length = 0;
850 scope.argnames.length = 0;
851 }
852 : noop;
853
854 var stack = [];
855 return {
856 get : get,
857 toString : get,
858 indent : indent,
859 in_directive : false,
860 use_asm : null,
861 active_scope : null,
862 indentation : function() { return indentation; },
863 current_width : function() { return current_col - indentation; },
864 should_break : function() { return options.width && this.current_width() >= options.width; },
865 has_parens : function() { return has_parens; },
866 newline : newline,
867 print : print,
868 star : star,
869 space : space,
870 comma : comma,
871 colon : colon,
872 last : function() { return last; },
873 semicolon : semicolon,
874 force_semicolon : force_semicolon,
875 to_utf8 : to_utf8,
876 print_name : function(name) { print(make_name(name)); },
877 print_string : function(str, quote, escape_directive) {
878 var encoded = encode_string(str, quote);
879 if (escape_directive === true && !encoded.includes("\\")) {
880 // Insert semicolons to break directive prologue
881 if (!OUTPUT.expectDirective()) {
882 force_semicolon();
883 }
884 force_semicolon();
885 }
886 print(encoded);
887 },
888 print_template_string_chars: function(str) {
889 var encoded = encode_string(str, "`").replace(/\${/g, "\\${");
890 return print(encoded.substr(1, encoded.length - 2));
891 },
892 encode_string : encode_string,
893 next_indent : next_indent,
894 with_indent : with_indent,
895 with_block : with_block,
896 with_parens : with_parens,
897 with_square : with_square,
898 add_mapping : add_mapping,
899 option : function(opt) { return options[opt]; },
900 gc_scope,
901 printed_comments: printed_comments,
902 prepend_comments: readonly ? noop : prepend_comments,
903 append_comments : readonly || comment_filter === return_false ? noop : append_comments,
904 line : function() { return current_line; },
905 col : function() { return current_col; },
906 pos : function() { return current_pos; },
907 push_node : function(node) { stack.push(node); },
908 pop_node : function() { return stack.pop(); },
909 parent : function(n) {
910 return stack[stack.length - 2 - (n || 0)];
911 }
912 };
913
914}
915
916/* -----[ code generators ]----- */
917
918(function() {
919
920 /* -----[ utils ]----- */
921
922 function DEFPRINT(nodetype, generator) {
923 nodetype.DEFMETHOD("_codegen", generator);
924 }
925
926 AST_Node.DEFMETHOD("print", function(output, force_parens) {
927 var self = this, generator = self._codegen;
928 if (self instanceof AST_Scope) {
929 output.active_scope = self;
930 } else if (!output.use_asm && self instanceof AST_Directive && self.value == "use asm") {
931 output.use_asm = output.active_scope;
932 }
933 function doit() {
934 output.prepend_comments(self);
935 self.add_source_map(output);
936 generator(self, output);
937 output.append_comments(self);
938 }
939 output.push_node(self);
940 if (force_parens || self.needs_parens(output)) {
941 output.with_parens(doit);
942 } else {
943 doit();
944 }
945 output.pop_node();
946 if (self === output.use_asm) {
947 output.use_asm = null;
948 }
949 });
950 AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
951
952 AST_Node.DEFMETHOD("print_to_string", function(options) {
953 var output = OutputStream(options);
954 this.print(output);
955 return output.get();
956 });
957
958 /* -----[ PARENTHESES ]----- */
959
960 function PARENS(nodetype, func) {
961 if (Array.isArray(nodetype)) {
962 nodetype.forEach(function(nodetype) {
963 PARENS(nodetype, func);
964 });
965 } else {
966 nodetype.DEFMETHOD("needs_parens", func);
967 }
968 }
969
970 PARENS(AST_Node, return_false);
971
972 // a function expression needs parens around it when it's provably
973 // the first token to appear in a statement.
974 PARENS(AST_Function, function(output) {
975 if (!output.has_parens() && first_in_statement(output)) {
976 return true;
977 }
978
979 if (output.option("webkit")) {
980 var p = output.parent();
981 if (p instanceof AST_PropAccess && p.expression === this) {
982 return true;
983 }
984 }
985
986 if (output.option("wrap_iife")) {
987 var p = output.parent();
988 if (p instanceof AST_Call && p.expression === this) {
989 return true;
990 }
991 }
992
993 if (output.option("wrap_func_args")) {
994 var p = output.parent();
995 if (p instanceof AST_Call && p.args.includes(this)) {
996 return true;
997 }
998 }
999
1000 return false;
1001 });
1002
1003 PARENS(AST_Arrow, function(output) {
1004 var p = output.parent();
1005
1006 if (
1007 output.option("wrap_func_args")
1008 && p instanceof AST_Call
1009 && p.args.includes(this)
1010 ) {
1011 return true;
1012 }
1013 return p instanceof AST_PropAccess && p.expression === this
1014 || p instanceof AST_Conditional && p.condition === this;
1015 });
1016
1017 // same goes for an object literal (as in AST_Function), because
1018 // otherwise {...} would be interpreted as a block of code.
1019 PARENS(AST_Object, function(output) {
1020 return !output.has_parens() && first_in_statement(output);
1021 });
1022
1023 PARENS(AST_ClassExpression, first_in_statement);
1024
1025 PARENS(AST_Unary, function(output) {
1026 var p = output.parent();
1027 return p instanceof AST_PropAccess && p.expression === this
1028 || p instanceof AST_Call && p.expression === this
1029 || p instanceof AST_Binary
1030 && p.operator === "**"
1031 && this instanceof AST_UnaryPrefix
1032 && p.left === this
1033 && this.operator !== "++"
1034 && this.operator !== "--";
1035 });
1036
1037 PARENS(AST_Await, function(output) {
1038 var p = output.parent();
1039 return p instanceof AST_PropAccess && p.expression === this
1040 || p instanceof AST_Call && p.expression === this
1041 || p instanceof AST_Binary && p.operator === "**" && p.left === this
1042 || output.option("safari10") && p instanceof AST_UnaryPrefix;
1043 });
1044
1045 PARENS(AST_Sequence, function(output) {
1046 var p = output.parent();
1047 return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
1048 || p instanceof AST_Unary // !(foo, bar, baz)
1049 || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
1050 || p instanceof AST_VarDefLike // var a = (1, 2), b = a + a; ==> b == 4
1051 || p instanceof AST_PropAccess && this !== p.property // (1, {foo:2}).foo, (1, {foo:2})["foo"], not foo[1, 2]
1052 || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
1053 || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
1054 || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
1055 * ==> 20 (side effect, set a := 10 and b := 20) */
1056 || p instanceof AST_Arrow // x => (x, x)
1057 || p instanceof AST_DefaultAssign // x => (x = (0, function(){}))
1058 || p instanceof AST_Expansion // [...(a, b)]
1059 || p instanceof AST_ForOf && this === p.object // for (e of (foo, bar)) {}
1060 || p instanceof AST_Yield // yield (foo, bar)
1061 || p instanceof AST_Export // export default (foo, bar)
1062 ;
1063 });
1064
1065 PARENS(AST_Binary, function(output) {
1066 var p = output.parent();
1067 // (foo && bar)()
1068 if (p instanceof AST_Call && p.expression === this)
1069 return true;
1070 // typeof (foo && bar)
1071 if (p instanceof AST_Unary)
1072 return true;
1073 // (foo && bar)["prop"], (foo && bar).prop
1074 if (p instanceof AST_PropAccess && p.expression === this)
1075 return true;
1076 // this deals with precedence: 3 * (2 + 1)
1077 if (p instanceof AST_Binary) {
1078 const parent_op = p.operator;
1079 const op = this.operator;
1080
1081 // It is forbidden for ?? to be used with || or && without parens.
1082 if (op === "??" && (parent_op === "||" || parent_op === "&&")) {
1083 return true;
1084 }
1085 if (parent_op === "??" && (op === "||" || op === "&&")) {
1086 return true;
1087 }
1088
1089 const pp = PRECEDENCE[parent_op];
1090 const sp = PRECEDENCE[op];
1091 if (pp > sp
1092 || (pp == sp
1093 && (this === p.right || parent_op == "**"))) {
1094 return true;
1095 }
1096 }
1097 if (p instanceof AST_PrivateIn) {
1098 const op = this.operator;
1099
1100 const pp = PRECEDENCE["in"];
1101 const sp = PRECEDENCE[op];
1102 if (pp > sp || (pp == sp && this === p.value)) {
1103 return true;
1104 }
1105 }
1106 });
1107
1108 PARENS(AST_PrivateIn, function(output) {
1109 var p = output.parent();
1110 // (#x in this)()
1111 if (p instanceof AST_Call && p.expression === this) {
1112 return true;
1113 }
1114 // typeof (#x in this)
1115 if (p instanceof AST_Unary) {
1116 return true;
1117 }
1118 // (#x in this)["prop"], (#x in this).prop
1119 if (p instanceof AST_PropAccess && p.expression === this) {
1120 return true;
1121 }
1122 // same precedence as regular in operator
1123 if (p instanceof AST_Binary) {
1124 const parent_op = p.operator;
1125
1126 const pp = PRECEDENCE[parent_op];
1127 const sp = PRECEDENCE["in"];
1128 if (pp > sp
1129 || (pp == sp
1130 && (this === p.right || parent_op == "**"))) {
1131 return true;
1132 }
1133 }
1134 // rules are the same as binary in, but the class differs
1135 if (p instanceof AST_PrivateIn && this === p.value) {
1136 return true;
1137 }
1138 });
1139
1140 PARENS(AST_Yield, function(output) {
1141 var p = output.parent();
1142 // (yield 1) + (yield 2)
1143 // a = yield 3
1144 if (p instanceof AST_Binary && p.operator !== "=")
1145 return true;
1146 // (yield 1)()
1147 // new (yield 1)()
1148 if (p instanceof AST_Call && p.expression === this)
1149 return true;
1150 // (yield 1) ? yield 2 : yield 3
1151 if (p instanceof AST_Conditional && p.condition === this)
1152 return true;
1153 // -(yield 4)
1154 if (p instanceof AST_Unary)
1155 return true;
1156 // (yield x).foo
1157 // (yield x)['foo']
1158 if (p instanceof AST_PropAccess && p.expression === this)
1159 return true;
1160 });
1161
1162 PARENS(AST_Chain, function(output) {
1163 var p = output.parent();
1164 if (!(p instanceof AST_Call || p instanceof AST_PropAccess)) return false;
1165 return p.expression === this;
1166 });
1167
1168 PARENS(AST_PropAccess, function(output) {
1169 var p = output.parent();
1170 if (p instanceof AST_New && p.expression === this) {
1171 // i.e. new (foo.bar().baz)
1172 //
1173 // if there's one call into this subtree, then we need
1174 // parens around it too, otherwise the call will be
1175 // interpreted as passing the arguments to the upper New
1176 // expression.
1177 return walk(this, node => {
1178 if (node instanceof AST_Scope) return true;
1179 if (node instanceof AST_Call) {
1180 return walk_abort; // makes walk() return true.
1181 }
1182 });
1183 }
1184 });
1185
1186 PARENS(AST_Call, function(output) {
1187 var p = output.parent(), p1;
1188 if (p instanceof AST_New && p.expression === this
1189 || p instanceof AST_Export && p.is_default && this.expression instanceof AST_Function)
1190 return true;
1191
1192 // workaround for Safari bug.
1193 // https://bugs.webkit.org/show_bug.cgi?id=123506
1194 return this.expression instanceof AST_Function
1195 && p instanceof AST_PropAccess
1196 && p.expression === this
1197 && (p1 = output.parent(1)) instanceof AST_Assign
1198 && p1.left === p;
1199 });
1200
1201 PARENS(AST_New, function(output) {
1202 var p = output.parent();
1203 if (this.args.length === 0
1204 && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
1205 || p instanceof AST_Call && p.expression === this
1206 || p instanceof AST_PrefixedTemplateString && p.prefix === this)) // (new foo)(bar)
1207 return true;
1208 });
1209
1210 PARENS(AST_Number, function(output) {
1211 var p = output.parent();
1212 if (p instanceof AST_PropAccess && p.expression === this) {
1213 var value = this.getValue();
1214 if (value < 0 || /^0/.test(make_num(value))) {
1215 return true;
1216 }
1217 }
1218 });
1219
1220 PARENS(AST_BigInt, function(output) {
1221 var p = output.parent();
1222 if (p instanceof AST_PropAccess && p.expression === this) {
1223 var value = this.getValue();
1224 if (value.startsWith("-")) {
1225 return true;
1226 }
1227 }
1228 });
1229
1230 PARENS([ AST_Assign, AST_Conditional ], function(output) {
1231 var p = output.parent();
1232 // !(a = false) → true
1233 if (p instanceof AST_Unary)
1234 return true;
1235 // 1 + (a = 2) + 3 → 6, side effect setting a = 2
1236 if (p instanceof AST_Binary && !(p instanceof AST_Assign))
1237 return true;
1238 // (a = func)() —or— new (a = Object)()
1239 if (p instanceof AST_Call && p.expression === this)
1240 return true;
1241 // (a = foo) ? bar : baz
1242 if (p instanceof AST_Conditional && p.condition === this)
1243 return true;
1244 // (a = foo)["prop"] —or— (a = foo).prop
1245 if (p instanceof AST_PropAccess && p.expression === this)
1246 return true;
1247 // ({a, b} = {a: 1, b: 2}), a destructuring assignment
1248 if (this instanceof AST_Assign && this.left instanceof AST_Destructuring && this.left.is_array === false)
1249 return true;
1250 });
1251
1252 /* -----[ PRINTERS ]----- */
1253
1254 DEFPRINT(AST_Directive, function(self, output) {
1255 output.print_string(self.value, self.quote);
1256 output.semicolon();
1257 });
1258
1259 DEFPRINT(AST_Expansion, function (self, output) {
1260 output.print("...");
1261 self.expression.print(output);
1262 });
1263
1264 DEFPRINT(AST_Destructuring, function (self, output) {
1265 output.print(self.is_array ? "[" : "{");
1266 var len = self.names.length;
1267 self.names.forEach(function (name, i) {
1268 if (i > 0) output.comma();
1269 name.print(output);
1270 // If the final element is a hole, we need to make sure it
1271 // doesn't look like a trailing comma, by inserting an actual
1272 // trailing comma.
1273 if (i == len - 1 && name instanceof AST_Hole) output.comma();
1274 });
1275 output.print(self.is_array ? "]" : "}");
1276 });
1277
1278 DEFPRINT(AST_Debugger, function(self, output) {
1279 output.print("debugger");
1280 output.semicolon();
1281 });
1282
1283 /* -----[ statements ]----- */
1284
1285 function display_body(body, is_toplevel, output, allow_directives) {
1286 var last = body.length - 1;
1287 output.in_directive = allow_directives;
1288 body.forEach(function(stmt, i) {
1289 if (output.in_directive === true && !(stmt instanceof AST_Directive ||
1290 stmt instanceof AST_EmptyStatement ||
1291 (stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String)
1292 )) {
1293 output.in_directive = false;
1294 }
1295 if (!(stmt instanceof AST_EmptyStatement)) {
1296 output.indent();
1297 stmt.print(output);
1298 if (!(i == last && is_toplevel)) {
1299 output.newline();
1300 if (is_toplevel) output.newline();
1301 }
1302 }
1303 if (output.in_directive === true &&
1304 stmt instanceof AST_SimpleStatement &&
1305 stmt.body instanceof AST_String
1306 ) {
1307 output.in_directive = false;
1308 }
1309 });
1310 output.in_directive = false;
1311 }
1312
1313 AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
1314 print_maybe_braced_body(this.body, output);
1315 });
1316
1317 DEFPRINT(AST_Statement, function(self, output) {
1318 self.body.print(output);
1319 output.semicolon();
1320 });
1321 DEFPRINT(AST_Toplevel, function(self, output) {
1322 display_body(self.body, true, output, true);
1323 output.print("");
1324 });
1325 DEFPRINT(AST_LabeledStatement, function(self, output) {
1326 self.label.print(output);
1327 output.colon();
1328 self.body.print(output);
1329 });
1330 DEFPRINT(AST_SimpleStatement, function(self, output) {
1331 self.body.print(output);
1332 output.semicolon();
1333 });
1334 function print_braced_empty(self, output) {
1335 output.print("{");
1336 output.with_indent(output.next_indent(), function() {
1337 output.append_comments(self, true);
1338 });
1339 output.add_mapping(self.end);
1340 output.print("}");
1341 }
1342 function print_braced(self, output, allow_directives) {
1343 if (self.body.length > 0) {
1344 output.with_block(function() {
1345 display_body(self.body, false, output, allow_directives);
1346 output.add_mapping(self.end);
1347 });
1348 } else print_braced_empty(self, output);
1349 }
1350 DEFPRINT(AST_BlockStatement, function(self, output) {
1351 print_braced(self, output);
1352 });
1353 DEFPRINT(AST_EmptyStatement, function(self, output) {
1354 output.semicolon();
1355 });
1356 DEFPRINT(AST_Do, function(self, output) {
1357 output.print("do");
1358 output.space();
1359 make_block(self.body, output);
1360 output.space();
1361 output.print("while");
1362 output.space();
1363 output.with_parens(function() {
1364 self.condition.print(output);
1365 });
1366 output.semicolon();
1367 });
1368 DEFPRINT(AST_While, function(self, output) {
1369 output.print("while");
1370 output.space();
1371 output.with_parens(function() {
1372 self.condition.print(output);
1373 });
1374 output.space();
1375 self._do_print_body(output);
1376 });
1377 DEFPRINT(AST_For, function(self, output) {
1378 output.print("for");
1379 output.space();
1380 output.with_parens(function() {
1381 if (self.init) {
1382 if (self.init instanceof AST_DefinitionsLike) {
1383 self.init.print(output);
1384 } else {
1385 parenthesize_for_noin(self.init, output, true);
1386 }
1387 output.print(";");
1388 output.space();
1389 } else {
1390 output.print(";");
1391 }
1392 if (self.condition) {
1393 self.condition.print(output);
1394 output.print(";");
1395 output.space();
1396 } else {
1397 output.print(";");
1398 }
1399 if (self.step) {
1400 self.step.print(output);
1401 }
1402 });
1403 output.space();
1404 self._do_print_body(output);
1405 });
1406 DEFPRINT(AST_ForIn, function(self, output) {
1407 output.print("for");
1408 if (self.await) {
1409 output.space();
1410 output.print("await");
1411 }
1412 output.space();
1413 output.with_parens(function() {
1414 self.init.print(output);
1415 output.space();
1416 output.print(self instanceof AST_ForOf ? "of" : "in");
1417 output.space();
1418 self.object.print(output);
1419 });
1420 output.space();
1421 self._do_print_body(output);
1422 });
1423 DEFPRINT(AST_With, function(self, output) {
1424 output.print("with");
1425 output.space();
1426 output.with_parens(function() {
1427 self.expression.print(output);
1428 });
1429 output.space();
1430 self._do_print_body(output);
1431 });
1432
1433 /* -----[ functions ]----- */
1434 AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
1435 var self = this;
1436 if (!nokeyword) {
1437 if (self.async) {
1438 output.print("async");
1439 output.space();
1440 }
1441 output.print("function");
1442 if (self.is_generator) {
1443 output.star();
1444 }
1445 if (self.name) {
1446 output.space();
1447 }
1448 }
1449 if (self.name instanceof AST_Symbol) {
1450 self.name.print(output);
1451 } else if (nokeyword && self.name instanceof AST_Node) {
1452 output.with_square(function() {
1453 self.name.print(output); // Computed method name
1454 });
1455 }
1456 output.with_parens(function() {
1457 self.argnames.forEach(function(arg, i) {
1458 if (i) output.comma();
1459 arg.print(output);
1460 });
1461 });
1462 output.space();
1463 print_braced(self, output, true);
1464 });
1465 DEFPRINT(AST_Lambda, function(self, output) {
1466 self._do_print(output);
1467 output.gc_scope(self);
1468 });
1469
1470 DEFPRINT(AST_PrefixedTemplateString, function(self, output) {
1471 var tag = self.prefix;
1472 var parenthesize_tag = tag instanceof AST_Lambda
1473 || tag instanceof AST_Binary
1474 || tag instanceof AST_Conditional
1475 || tag instanceof AST_Sequence
1476 || tag instanceof AST_Unary
1477 || tag instanceof AST_Dot && tag.expression instanceof AST_Object;
1478 if (parenthesize_tag) output.print("(");
1479 self.prefix.print(output);
1480 if (parenthesize_tag) output.print(")");
1481 self.template_string.print(output);
1482 });
1483 DEFPRINT(AST_TemplateString, function(self, output) {
1484 var is_tagged = output.parent() instanceof AST_PrefixedTemplateString;
1485
1486 output.print("`");
1487 for (var i = 0; i < self.segments.length; i++) {
1488 if (!(self.segments[i] instanceof AST_TemplateSegment)) {
1489 output.print("${");
1490 self.segments[i].print(output);
1491 output.print("}");
1492 } else if (is_tagged) {
1493 output.print(self.segments[i].raw);
1494 } else {
1495 output.print_template_string_chars(self.segments[i].value);
1496 }
1497 }
1498 output.print("`");
1499 });
1500 DEFPRINT(AST_TemplateSegment, function(self, output) {
1501 output.print_template_string_chars(self.value);
1502 });
1503
1504 AST_Arrow.DEFMETHOD("_do_print", function(output) {
1505 var self = this;
1506 var parent = output.parent();
1507 var needs_parens = (parent instanceof AST_Binary &&
1508 !(parent instanceof AST_Assign) &&
1509 !(parent instanceof AST_DefaultAssign)) ||
1510 parent instanceof AST_Unary ||
1511 (parent instanceof AST_Call && self === parent.expression);
1512 if (needs_parens) { output.print("("); }
1513 if (self.async) {
1514 output.print("async");
1515 output.space();
1516 }
1517 if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) {
1518 self.argnames[0].print(output);
1519 } else {
1520 output.with_parens(function() {
1521 self.argnames.forEach(function(arg, i) {
1522 if (i) output.comma();
1523 arg.print(output);
1524 });
1525 });
1526 }
1527 output.space();
1528 output.print("=>");
1529 output.space();
1530 const first_statement = self.body[0];
1531 if (
1532 self.body.length === 1
1533 && first_statement instanceof AST_Return
1534 ) {
1535 const returned = first_statement.value;
1536 if (!returned) {
1537 output.print("{}");
1538 } else if (left_is_object(returned)) {
1539 output.print("(");
1540 returned.print(output);
1541 output.print(")");
1542 } else {
1543 returned.print(output);
1544 }
1545 } else {
1546 print_braced(self, output);
1547 }
1548 if (needs_parens) { output.print(")"); }
1549 output.gc_scope(self);
1550 });
1551
1552 /* -----[ exits ]----- */
1553 AST_Exit.DEFMETHOD("_do_print", function(output, kind) {
1554 output.print(kind);
1555 if (this.value) {
1556 output.space();
1557 const comments = this.value.start.comments_before;
1558 if (comments && comments.length && !output.printed_comments.has(comments)) {
1559 output.print("(");
1560 this.value.print(output);
1561 output.print(")");
1562 } else {
1563 this.value.print(output);
1564 }
1565 }
1566 output.semicolon();
1567 });
1568 DEFPRINT(AST_Return, function(self, output) {
1569 self._do_print(output, "return");
1570 });
1571 DEFPRINT(AST_Throw, function(self, output) {
1572 self._do_print(output, "throw");
1573 });
1574
1575 /* -----[ yield ]----- */
1576
1577 DEFPRINT(AST_Yield, function(self, output) {
1578 var star = self.is_star ? "*" : "";
1579 output.print("yield" + star);
1580 if (self.expression) {
1581 output.space();
1582 self.expression.print(output);
1583 }
1584 });
1585
1586 DEFPRINT(AST_Await, function(self, output) {
1587 output.print("await");
1588 output.space();
1589 var e = self.expression;
1590 var parens = !(
1591 e instanceof AST_Call
1592 || e instanceof AST_SymbolRef
1593 || e instanceof AST_PropAccess
1594 || e instanceof AST_Unary
1595 || e instanceof AST_Constant
1596 || e instanceof AST_Await
1597 || e instanceof AST_Object
1598 );
1599 if (parens) output.print("(");
1600 self.expression.print(output);
1601 if (parens) output.print(")");
1602 });
1603
1604 /* -----[ loop control ]----- */
1605 AST_LoopControl.DEFMETHOD("_do_print", function(output, kind) {
1606 output.print(kind);
1607 if (this.label) {
1608 output.space();
1609 this.label.print(output);
1610 }
1611 output.semicolon();
1612 });
1613 DEFPRINT(AST_Break, function(self, output) {
1614 self._do_print(output, "break");
1615 });
1616 DEFPRINT(AST_Continue, function(self, output) {
1617 self._do_print(output, "continue");
1618 });
1619
1620 /* -----[ if ]----- */
1621 function make_then(self, output) {
1622 var b = self.body;
1623 if (output.option("braces")
1624 || output.option("ie8") && b instanceof AST_Do)
1625 return make_block(b, output);
1626 // The squeezer replaces "block"-s that contain only a single
1627 // statement with the statement itself; technically, the AST
1628 // is correct, but this can create problems when we output an
1629 // IF having an ELSE clause where the THEN clause ends in an
1630 // IF *without* an ELSE block (then the outer ELSE would refer
1631 // to the inner IF). This function checks for this case and
1632 // adds the block braces if needed.
1633 if (!b) return output.force_semicolon();
1634 while (true) {
1635 if (b instanceof AST_If) {
1636 if (!b.alternative) {
1637 make_block(self.body, output);
1638 return;
1639 }
1640 b = b.alternative;
1641 } else if (b instanceof AST_StatementWithBody) {
1642 b = b.body;
1643 } else break;
1644 }
1645 print_maybe_braced_body(self.body, output);
1646 }
1647 DEFPRINT(AST_If, function(self, output) {
1648 output.print("if");
1649 output.space();
1650 output.with_parens(function() {
1651 self.condition.print(output);
1652 });
1653 output.space();
1654 if (self.alternative) {
1655 make_then(self, output);
1656 output.space();
1657 output.print("else");
1658 output.space();
1659 if (self.alternative instanceof AST_If)
1660 self.alternative.print(output);
1661 else
1662 print_maybe_braced_body(self.alternative, output);
1663 } else {
1664 self._do_print_body(output);
1665 }
1666 });
1667
1668 /* -----[ switch ]----- */
1669 DEFPRINT(AST_Switch, function(self, output) {
1670 output.print("switch");
1671 output.space();
1672 output.with_parens(function() {
1673 self.expression.print(output);
1674 });
1675 output.space();
1676 var last = self.body.length - 1;
1677 if (last < 0) print_braced_empty(self, output);
1678 else output.with_block(function() {
1679 self.body.forEach(function(branch, i) {
1680 output.indent(true);
1681 branch.print(output);
1682 if (i < last && branch.body.length > 0)
1683 output.newline();
1684 });
1685 });
1686 });
1687 AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
1688 output.newline();
1689 this.body.forEach(function(stmt) {
1690 output.indent();
1691 stmt.print(output);
1692 output.newline();
1693 });
1694 });
1695 DEFPRINT(AST_Default, function(self, output) {
1696 output.print("default:");
1697 self._do_print_body(output);
1698 });
1699 DEFPRINT(AST_Case, function(self, output) {
1700 output.print("case");
1701 output.space();
1702 self.expression.print(output);
1703 output.print(":");
1704 self._do_print_body(output);
1705 });
1706
1707 /* -----[ exceptions ]----- */
1708 DEFPRINT(AST_Try, function(self, output) {
1709 output.print("try");
1710 output.space();
1711 self.body.print(output);
1712 if (self.bcatch) {
1713 output.space();
1714 self.bcatch.print(output);
1715 }
1716 if (self.bfinally) {
1717 output.space();
1718 self.bfinally.print(output);
1719 }
1720 });
1721 DEFPRINT(AST_TryBlock, function(self, output) {
1722 print_braced(self, output);
1723 });
1724 DEFPRINT(AST_Catch, function(self, output) {
1725 output.print("catch");
1726 if (self.argname) {
1727 output.space();
1728 output.with_parens(function() {
1729 self.argname.print(output);
1730 });
1731 }
1732 output.space();
1733 print_braced(self, output);
1734 });
1735 DEFPRINT(AST_Finally, function(self, output) {
1736 output.print("finally");
1737 output.space();
1738 print_braced(self, output);
1739 });
1740
1741 /* -----[ var/const ]----- */
1742 AST_DefinitionsLike.DEFMETHOD("_do_print", function(output, kind) {
1743 output.print(kind);
1744 output.space();
1745 this.definitions.forEach(function(def, i) {
1746 if (i) output.comma();
1747 def.print(output);
1748 });
1749 var p = output.parent();
1750 var in_for = p instanceof AST_For || p instanceof AST_ForIn;
1751 var output_semicolon = !in_for || p && p.init !== this;
1752 if (output_semicolon)
1753 output.semicolon();
1754 });
1755 DEFPRINT(AST_Let, function(self, output) {
1756 self._do_print(output, "let");
1757 });
1758 DEFPRINT(AST_Var, function(self, output) {
1759 self._do_print(output, "var");
1760 });
1761 DEFPRINT(AST_Const, function(self, output) {
1762 self._do_print(output, "const");
1763 });
1764 DEFPRINT(AST_Using, function(self, output) {
1765 self._do_print(output, self.await ? "await using" : "using");
1766 });
1767 DEFPRINT(AST_Import, function(self, output) {
1768 output.print("import");
1769 output.space();
1770 if (self.phase) {
1771 output.print(self.phase);
1772 output.space();
1773 }
1774 if (self.imported_name) {
1775 self.imported_name.print(output);
1776 }
1777 if (self.imported_name && self.imported_names) {
1778 output.print(",");
1779 output.space();
1780 }
1781 if (self.imported_names) {
1782 if (self.imported_names.length === 1 &&
1783 self.imported_names[0].foreign_name.name === "*" &&
1784 !self.imported_names[0].foreign_name.quote) {
1785 self.imported_names[0].print(output);
1786 } else {
1787 output.print("{");
1788 self.imported_names.forEach(function (name_import, i) {
1789 output.space();
1790 name_import.print(output);
1791 if (i < self.imported_names.length - 1) {
1792 output.print(",");
1793 }
1794 });
1795 output.space();
1796 output.print("}");
1797 }
1798 }
1799 if (self.imported_name || self.imported_names) {
1800 output.space();
1801 output.print("from");
1802 output.space();
1803 }
1804 self.module_name.print(output);
1805 if (self.attributes) {
1806 output.print("with");
1807 self.attributes.print(output);
1808 }
1809 output.semicolon();
1810 });
1811 DEFPRINT(AST_ImportMeta, function(self, output) {
1812 output.print("import.meta");
1813 });
1814 DEFPRINT(AST_DynamicImport, function(self, output) {
1815 output.print("import." + self.phase);
1816 output.with_parens(function() {
1817 self.args.forEach(function(arg, i) {
1818 if (i) output.comma();
1819 arg.print(output);
1820 });
1821 });
1822 });
1823
1824 DEFPRINT(AST_NameMapping, function(self, output) {
1825 var is_import = output.parent() instanceof AST_Import;
1826 var definition = self.name.definition();
1827 var foreign_name = self.foreign_name;
1828 var names_are_different =
1829 (definition && definition.mangled_name || self.name.name) !==
1830 foreign_name.name;
1831 if (!names_are_different &&
1832 foreign_name.name === "*" &&
1833 !!foreign_name.quote != !!self.name.quote) {
1834 // export * as "*"
1835 names_are_different = true;
1836 }
1837 var foreign_name_is_name = !foreign_name.quote;
1838 if (names_are_different) {
1839 if (is_import) {
1840 if (foreign_name_is_name) {
1841 output.print(foreign_name.name);
1842 } else {
1843 output.print_string(foreign_name.name, foreign_name.quote);
1844 }
1845 } else {
1846 if (!self.name.quote) {
1847 self.name.print(output);
1848 } else {
1849 output.print_string(self.name.name, self.name.quote);
1850 }
1851
1852 }
1853 output.space();
1854 output.print("as");
1855 output.space();
1856 if (is_import) {
1857 self.name.print(output);
1858 } else {
1859 if (foreign_name_is_name) {
1860 output.print(foreign_name.name);
1861 } else {
1862 output.print_string(foreign_name.name, foreign_name.quote);
1863 }
1864 }
1865 } else {
1866 if (!self.name.quote) {
1867 self.name.print(output);
1868 } else {
1869 output.print_string(self.name.name, self.name.quote);
1870 }
1871 }
1872 });
1873
1874 DEFPRINT(AST_Export, function(self, output) {
1875 output.print("export");
1876 output.space();
1877 if (self.is_default) {
1878 output.print("default");
1879 output.space();
1880 }
1881 if (self.exported_names) {
1882 if (self.exported_names.length === 1 &&
1883 self.exported_names[0].name.name === "*" &&
1884 !self.exported_names[0].name.quote) {
1885 self.exported_names[0].print(output);
1886 } else {
1887 output.print("{");
1888 self.exported_names.forEach(function(name_export, i) {
1889 output.space();
1890 name_export.print(output);
1891 if (i < self.exported_names.length - 1) {
1892 output.print(",");
1893 }
1894 });
1895 output.space();
1896 output.print("}");
1897 }
1898 } else if (self.exported_value) {
1899 self.exported_value.print(output);
1900 } else if (self.exported_definition) {
1901 self.exported_definition.print(output);
1902 if (self.exported_definition instanceof AST_Definitions) return;
1903 }
1904 if (self.module_name) {
1905 output.space();
1906 output.print("from");
1907 output.space();
1908 self.module_name.print(output);
1909 }
1910 if (self.attributes) {
1911 output.print("with");
1912 self.attributes.print(output);
1913 }
1914 if (self.exported_value
1915 && !(self.exported_value instanceof AST_Defun ||
1916 self.exported_value instanceof AST_Function ||
1917 self.exported_value instanceof AST_Class)
1918 || self.module_name
1919 || self.exported_names
1920 ) {
1921 output.semicolon();
1922 }
1923 });
1924
1925 function parenthesize_for_noin(node, output, noin) {
1926 var parens = false;
1927 // need to take some precautions here:
1928 // https://github.com/mishoo/UglifyJS2/issues/60
1929 if (noin) {
1930 parens = walk(node, node => {
1931 // Don't go into scopes -- except arrow functions:
1932 // https://github.com/terser/terser/issues/1019#issuecomment-877642607
1933 if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) {
1934 return true;
1935 }
1936 if (
1937 node instanceof AST_Binary && node.operator == "in"
1938 || node instanceof AST_PrivateIn
1939 ) {
1940 return walk_abort; // makes walk() return true
1941 }
1942 });
1943 }
1944 node.print(output, parens);
1945 }
1946
1947 DEFPRINT(AST_VarDefLike, function(self, output) {
1948 self.name.print(output);
1949 if (self.value) {
1950 output.space();
1951 output.print("=");
1952 output.space();
1953 var p = output.parent(1);
1954 var noin = p instanceof AST_For || p instanceof AST_ForIn;
1955 parenthesize_for_noin(self.value, output, noin);
1956 }
1957 });
1958
1959 /* -----[ other expressions ]----- */
1960 DEFPRINT(AST_Call, function(self, output) {
1961 self.expression.print(output);
1962 if (self instanceof AST_New && self.args.length === 0)
1963 return;
1964 if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
1965 output.add_mapping(self.start);
1966 }
1967 if (self.optional) output.print("?.");
1968 output.with_parens(function() {
1969 self.args.forEach(function(expr, i) {
1970 if (i) output.comma();
1971 expr.print(output);
1972 });
1973 });
1974 });
1975 DEFPRINT(AST_New, function(self, output) {
1976 output.print("new");
1977 output.space();
1978 AST_Call.prototype._codegen(self, output);
1979 });
1980
1981 AST_Sequence.DEFMETHOD("_do_print", function(output) {
1982 this.expressions.forEach(function(node, index) {
1983 if (index > 0) {
1984 output.comma();
1985 if (output.should_break()) {
1986 output.newline();
1987 output.indent();
1988 }
1989 }
1990 node.print(output);
1991 });
1992 });
1993 DEFPRINT(AST_Sequence, function(self, output) {
1994 self._do_print(output);
1995 // var p = output.parent();
1996 // if (p instanceof AST_Statement) {
1997 // output.with_indent(output.next_indent(), function(){
1998 // self._do_print(output);
1999 // });
2000 // } else {
2001 // self._do_print(output);
2002 // }
2003 });
2004 DEFPRINT(AST_Dot, function(self, output) {
2005 var expr = self.expression;
2006 expr.print(output);
2007 var prop = self.property;
2008 var print_computed = ALL_RESERVED_WORDS.has(prop)
2009 ? output.option("ie8")
2010 : !is_identifier_string(
2011 prop,
2012 output.option("ecma") >= 2015 && !output.option("safari10")
2013 );
2014
2015 if (self.optional) output.print("?.");
2016
2017 if (print_computed) {
2018 output.print("[");
2019 output.add_mapping(self.end);
2020 output.print_string(prop);
2021 output.print("]");
2022 } else {
2023 if (expr instanceof AST_Number && expr.getValue() >= 0) {
2024 if (!/[xa-f.)]/i.test(output.last())) {
2025 output.print(".");
2026 }
2027 }
2028 if (!self.optional) output.print(".");
2029 // the name after dot would be mapped about here.
2030 output.add_mapping(self.end);
2031 output.print_name(prop);
2032 }
2033 });
2034 DEFPRINT(AST_DotHash, function(self, output) {
2035 var expr = self.expression;
2036 expr.print(output);
2037 var prop = self.property;
2038
2039 if (self.optional) output.print("?");
2040 output.print(".#");
2041 output.add_mapping(self.end);
2042 output.print_name(prop);
2043 });
2044 DEFPRINT(AST_Sub, function(self, output) {
2045 self.expression.print(output);
2046 if (self.optional) output.print("?.");
2047 output.print("[");
2048 self.property.print(output);
2049 output.print("]");
2050 });
2051 DEFPRINT(AST_Chain, function(self, output) {
2052 self.expression.print(output);
2053 });
2054 DEFPRINT(AST_UnaryPrefix, function(self, output) {
2055 var op = self.operator;
2056 if (op === "--" && output.last().endsWith("!")) {
2057 // avoid printing "<!--"
2058 output.print(" ");
2059 }
2060 output.print(op);
2061 if (/^[a-z]/i.test(op)
2062 || (/[+-]$/.test(op)
2063 && self.expression instanceof AST_UnaryPrefix
2064 && /^[+-]/.test(self.expression.operator))) {
2065 output.space();
2066 }
2067 self.expression.print(output);
2068 });
2069 DEFPRINT(AST_UnaryPostfix, function(self, output) {
2070 self.expression.print(output);
2071 output.print(self.operator);
2072 });
2073 DEFPRINT(AST_Binary, function(self, output) {
2074 var op = self.operator;
2075 self.left.print(output);
2076 if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
2077 && output.last().endsWith("--")) {
2078 // space is mandatory to avoid outputting -->
2079 output.print(" ");
2080 } else {
2081 // the space is optional depending on "beautify"
2082 output.space();
2083 }
2084 output.print(op);
2085 output.space();
2086 self.right.print(output);
2087 });
2088 DEFPRINT(AST_Conditional, function(self, output) {
2089 self.condition.print(output);
2090 output.space();
2091 output.print("?");
2092 output.space();
2093 self.consequent.print(output);
2094 output.space();
2095 output.colon();
2096 self.alternative.print(output);
2097 });
2098
2099 /* -----[ literals ]----- */
2100 DEFPRINT(AST_Array, function(self, output) {
2101 output.with_square(function() {
2102 var a = self.elements, len = a.length;
2103 if (len > 0) output.space();
2104 a.forEach(function(exp, i) {
2105 if (i) output.comma();
2106 exp.print(output);
2107 // If the final element is a hole, we need to make sure it
2108 // doesn't look like a trailing comma, by inserting an actual
2109 // trailing comma.
2110 if (i === len - 1 && exp instanceof AST_Hole)
2111 output.comma();
2112 });
2113 if (len > 0) output.space();
2114 });
2115 });
2116 DEFPRINT(AST_Object, function(self, output) {
2117 if (self.properties.length > 0) output.with_block(function() {
2118 self.properties.forEach(function(prop, i) {
2119 if (i) {
2120 output.print(",");
2121 output.newline();
2122 }
2123 output.indent();
2124 prop.print(output);
2125 });
2126 output.newline();
2127 });
2128 else print_braced_empty(self, output);
2129 });
2130 DEFPRINT(AST_Class, function(self, output) {
2131 output.print("class");
2132 output.space();
2133 if (self.name) {
2134 self.name.print(output);
2135 output.space();
2136 }
2137 if (self.extends) {
2138 var parens = (
2139 !(self.extends instanceof AST_SymbolRef)
2140 && !(self.extends instanceof AST_PropAccess)
2141 && !(self.extends instanceof AST_ClassExpression)
2142 && !(self.extends instanceof AST_Function)
2143 );
2144 output.print("extends");
2145 if (parens) {
2146 output.print("(");
2147 } else {
2148 output.space();
2149 }
2150 self.extends.print(output);
2151 if (parens) {
2152 output.print(")");
2153 } else {
2154 output.space();
2155 }
2156 }
2157 if (self.properties.length > 0) output.with_block(function() {
2158 self.properties.forEach(function(prop, i) {
2159 if (i) {
2160 output.newline();
2161 }
2162 output.indent();
2163 prop.print(output);
2164 });
2165 output.newline();
2166 });
2167 else output.print("{}");
2168 });
2169 DEFPRINT(AST_NewTarget, function(self, output) {
2170 output.print("new.target");
2171 });
2172
2173 /** Prints a prop name. Returns whether it can be used as a shorthand. */
2174 function print_property_name(key, quote, output) {
2175 if (output.option("quote_keys")) {
2176 output.print_string(key);
2177 return false;
2178 }
2179 if ("" + +key == key && key >= 0) {
2180 if (output.option("keep_numbers")) {
2181 output.print(key);
2182 return false;
2183 }
2184 output.print(make_num(key));
2185 return false;
2186 }
2187 var print_string = ALL_RESERVED_WORDS.has(key)
2188 ? output.option("ie8")
2189 : (
2190 output.option("ecma") < 2015 || output.option("safari10")
2191 ? !is_basic_identifier_string(key)
2192 : !is_identifier_string(key, true)
2193 );
2194 if (print_string || (quote && output.option("keep_quoted_props"))) {
2195 output.print_string(key, quote);
2196 return false;
2197 }
2198 output.print_name(key);
2199 return true;
2200 }
2201
2202 DEFPRINT(AST_ObjectKeyVal, function(self, output) {
2203 function get_name(self) {
2204 var def = self.definition();
2205 return def ? def.mangled_name || def.name : self.name;
2206 }
2207
2208 const try_shorthand = output.option("shorthand") && !(self.key instanceof AST_Node);
2209 if (
2210 try_shorthand
2211 && self.value instanceof AST_Symbol
2212 && get_name(self.value) === self.key
2213 && !ALL_RESERVED_WORDS.has(self.key)
2214 ) {
2215 const was_shorthand = print_property_name(self.key, self.quote, output);
2216 if (!was_shorthand) {
2217 output.colon();
2218 self.value.print(output);
2219 }
2220 } else if (
2221 try_shorthand
2222 && self.value instanceof AST_DefaultAssign
2223 && self.value.left instanceof AST_Symbol
2224 && get_name(self.value.left) === self.key
2225 ) {
2226 const was_shorthand = print_property_name(self.key, self.quote, output);
2227 if (!was_shorthand) {
2228 output.colon();
2229 self.value.left.print(output);
2230 }
2231 output.space();
2232 output.print("=");
2233 output.space();
2234 self.value.right.print(output);
2235 } else {
2236 if (!(self.key instanceof AST_Node)) {
2237 print_property_name(self.key, self.quote, output);
2238 } else {
2239 output.with_square(function() {
2240 self.key.print(output);
2241 });
2242 }
2243 output.colon();
2244 self.value.print(output);
2245 }
2246 });
2247 DEFPRINT(AST_ClassPrivateProperty, (self, output) => {
2248 if (self.static) {
2249 output.print("static");
2250 output.space();
2251 }
2252
2253 output.print("#");
2254
2255 print_property_name(self.key.name, undefined, output);
2256
2257 if (self.value) {
2258 output.print("=");
2259 self.value.print(output);
2260 }
2261
2262 output.semicolon();
2263 });
2264 DEFPRINT(AST_ClassProperty, (self, output) => {
2265 if (self.static) {
2266 output.print("static");
2267 output.space();
2268 }
2269
2270 if (self.key instanceof AST_SymbolClassProperty) {
2271 print_property_name(self.key.name, self.quote, output);
2272 } else {
2273 output.print("[");
2274 self.key.print(output);
2275 output.print("]");
2276 }
2277
2278 if (self.value) {
2279 output.print("=");
2280 self.value.print(output);
2281 }
2282
2283 output.semicolon();
2284 });
2285 AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, is_private, output) {
2286 var self = this;
2287 if (self.static) {
2288 output.print("static");
2289 output.space();
2290 }
2291 if (type) {
2292 output.print(type);
2293 output.space();
2294 }
2295 if (self.key instanceof AST_SymbolMethod) {
2296 if (is_private) output.print("#");
2297 print_property_name(self.key.name, self.quote, output);
2298 self.key.add_source_map(output);
2299 } else {
2300 output.with_square(function() {
2301 self.key.print(output);
2302 });
2303 }
2304 self.value._do_print(output, true);
2305 });
2306 DEFPRINT(AST_ObjectSetter, function(self, output) {
2307 self._print_getter_setter("set", false, output);
2308 });
2309 DEFPRINT(AST_ObjectGetter, function(self, output) {
2310 self._print_getter_setter("get", false, output);
2311 });
2312 DEFPRINT(AST_PrivateSetter, function(self, output) {
2313 self._print_getter_setter("set", true, output);
2314 });
2315 DEFPRINT(AST_PrivateGetter, function(self, output) {
2316 self._print_getter_setter("get", true, output);
2317 });
2318 DEFPRINT(AST_ConciseMethod, function(self, output) {
2319 var type;
2320 if (self.value.is_generator && self.value.async) {
2321 type = "async*";
2322 } else if (self.value.is_generator) {
2323 type = "*";
2324 } else if (self.value.async) {
2325 type = "async";
2326 }
2327 self._print_getter_setter(type, false, output);
2328 });
2329 DEFPRINT(AST_PrivateMethod, function(self, output) {
2330 var type;
2331 if (self.value.is_generator && self.value.async) {
2332 type = "async*";
2333 } else if (self.value.is_generator) {
2334 type = "*";
2335 } else if (self.value.async) {
2336 type = "async";
2337 }
2338 self._print_getter_setter(type, true, output);
2339 });
2340 DEFPRINT(AST_PrivateIn, function(self, output) {
2341 self.key.print(output);
2342 output.space();
2343 output.print("in");
2344 output.space();
2345 self.value.print(output);
2346 });
2347 DEFPRINT(AST_SymbolPrivateProperty, function(self, output) {
2348 output.print("#" + self.name);
2349 });
2350 DEFPRINT(AST_ClassStaticBlock, function (self, output) {
2351 output.print("static");
2352 output.space();
2353 print_braced(self, output);
2354 });
2355 AST_Symbol.DEFMETHOD("_do_print", function(output) {
2356 var def = this.definition();
2357 output.print_name(def ? def.mangled_name || def.name : this.name);
2358 });
2359 DEFPRINT(AST_Symbol, function (self, output) {
2360 self._do_print(output);
2361 });
2362 DEFPRINT(AST_Hole, noop);
2363 DEFPRINT(AST_This, function(self, output) {
2364 output.print("this");
2365 });
2366 DEFPRINT(AST_Super, function(self, output) {
2367 output.print("super");
2368 });
2369 DEFPRINT(AST_Constant, function(self, output) {
2370 output.print(self.getValue());
2371 });
2372 DEFPRINT(AST_String, function(self, output) {
2373 output.print_string(self.getValue(), self.quote, output.in_directive);
2374 });
2375 DEFPRINT(AST_Number, function(self, output) {
2376 if ((output.option("keep_numbers") || output.use_asm) && self.raw) {
2377 output.print(self.raw);
2378 } else {
2379 output.print(make_num(self.getValue()));
2380 }
2381 });
2382 DEFPRINT(AST_BigInt, function(self, output) {
2383 if (output.option("keep_numbers") && self.raw) {
2384 output.print(self.raw);
2385 } else {
2386 output.print(self.getValue() + "n");
2387 }
2388 });
2389
2390 const r_slash_script = /(<\s*\/\s*script)/i;
2391 const r_starts_with_script = /^\s*script/i;
2392 const slash_script_replace = (_, $1) => $1.replace("/", "\\/");
2393 DEFPRINT(AST_RegExp, function(self, output) {
2394 let { source, flags } = self.getValue();
2395 source = regexp_source_fix(source);
2396 flags = flags ? sort_regexp_flags(flags) : "";
2397
2398 // Avoid outputting end of script tag
2399 source = source.replace(r_slash_script, slash_script_replace);
2400 if (r_starts_with_script.test(source) && output.last().endsWith("<")) {
2401 output.print(" ");
2402 }
2403
2404 output.print(output.to_utf8(`/${source}/${flags}`, false, true));
2405
2406 const parent = output.parent();
2407 if (
2408 parent instanceof AST_Binary
2409 && /^\w/.test(parent.operator)
2410 && parent.left === self
2411 ) {
2412 output.print(" ");
2413 }
2414 });
2415
2416 /** if, for, while, may or may not have braces surrounding its body */
2417 function print_maybe_braced_body(stat, output) {
2418 if (output.option("braces")) {
2419 make_block(stat, output);
2420 } else {
2421 if (!stat || stat instanceof AST_EmptyStatement)
2422 output.force_semicolon();
2423 else if ((stat instanceof AST_DefinitionsLike && !(stat instanceof AST_Var)) || stat instanceof AST_Class)
2424 make_block(stat, output);
2425 else
2426 stat.print(output);
2427 }
2428 }
2429
2430 function best_of(a) {
2431 var best = a[0], len = best.length;
2432 for (var i = 1; i < a.length; ++i) {
2433 if (a[i].length < len) {
2434 best = a[i];
2435 len = best.length;
2436 }
2437 }
2438 return best;
2439 }
2440
2441 function make_num(num) {
2442 var str = num.toString(10).replace(/^0\./, ".").replace("e+", "e");
2443 var candidates = [ str ];
2444 if (Math.floor(num) === num) {
2445 if (num < 0) {
2446 candidates.push("-0x" + (-num).toString(16).toLowerCase());
2447 } else {
2448 candidates.push("0x" + num.toString(16).toLowerCase());
2449 }
2450 }
2451 var match, len, digits;
2452 if (match = /^\.0+/.exec(str)) {
2453 len = match[0].length;
2454 digits = str.slice(len);
2455 candidates.push(digits + "e-" + (digits.length + len - 1));
2456 } else if (match = /0+$/.exec(str)) {
2457 len = match[0].length;
2458 candidates.push(str.slice(0, -len) + "e" + len);
2459 } else if (match = /^(\d)\.(\d+)e(-?\d+)$/.exec(str)) {
2460 candidates.push(match[1] + match[2] + "e" + (match[3] - match[2].length));
2461 }
2462 return best_of(candidates);
2463 }
2464
2465 function make_block(stmt, output) {
2466 if (!stmt || stmt instanceof AST_EmptyStatement)
2467 output.print("{}");
2468 else if (stmt instanceof AST_BlockStatement)
2469 stmt.print(output);
2470 else output.with_block(function() {
2471 output.indent();
2472 stmt.print(output);
2473 output.newline();
2474 });
2475 }
2476
2477 /* -----[ source map generators ]----- */
2478
2479 function DEFMAP(nodetype, generator) {
2480 nodetype.forEach(function(nodetype) {
2481 nodetype.DEFMETHOD("add_source_map", generator);
2482 });
2483 }
2484
2485 DEFMAP([
2486 // We could easily add info for ALL nodes, but it seems to me that
2487 // would be quite wasteful, hence this noop in the base class.
2488 AST_Node,
2489 // since the label symbol will mark it
2490 AST_LabeledStatement,
2491 AST_Toplevel,
2492 ], noop);
2493
2494 // XXX: I'm not exactly sure if we need it for all of these nodes,
2495 // or if we should add even more.
2496 DEFMAP([
2497 AST_Array,
2498 AST_BlockStatement,
2499 AST_Catch,
2500 AST_Class,
2501 AST_Constant,
2502 AST_Debugger,
2503 AST_DefinitionsLike,
2504 AST_Directive,
2505 AST_Finally,
2506 AST_Jump,
2507 AST_Lambda,
2508 AST_New,
2509 AST_Object,
2510 AST_StatementWithBody,
2511 AST_Symbol,
2512 AST_Switch,
2513 AST_SwitchBranch,
2514 AST_TemplateString,
2515 AST_TemplateSegment,
2516 AST_Try,
2517 ], function(output) {
2518 output.add_mapping(this.start);
2519 });
2520
2521 DEFMAP([
2522 AST_ObjectGetter,
2523 AST_ObjectSetter,
2524 AST_PrivateGetter,
2525 AST_PrivateSetter,
2526 AST_ConciseMethod,
2527 AST_PrivateMethod,
2528 ], function(output) {
2529 output.add_mapping(this.start, false /*name handled below*/);
2530 });
2531
2532 DEFMAP([
2533 AST_SymbolMethod,
2534 AST_SymbolPrivateProperty
2535 ], function(output) {
2536 const tok_type = this.end && this.end.type;
2537 if (tok_type === "name" || tok_type === "privatename") {
2538 output.add_mapping(this.end, this.name);
2539 } else {
2540 output.add_mapping(this.end);
2541 }
2542 });
2543
2544 DEFMAP([ AST_ObjectProperty ], function(output) {
2545 output.add_mapping(this.start, this.key);
2546 });
2547})();
2548
2549export {
2550 OutputStream,
2551};
Note: See TracBrowser for help on using the repository browser.