source: imaps-frontend/node_modules/terser/lib/output.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

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