source: trip-planner-front/node_modules/terser/lib/output.js@ 571e0df

Last change on this file since 571e0df was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

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