terser 5.3.7 → 5.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -324,6 +324,9 @@ function set_annotation(node, annotation) {
324
324
 
325
325
  ***********************************************************************/
326
326
 
327
+ var LATEST_RAW = ""; // Only used for numbers and template strings
328
+ var LATEST_TEMPLATE_END = true;
329
+
327
330
  var KEYWORDS = "break case catch class const continue debugger default delete do else export extends finally for function if in instanceof let new return switch throw try typeof var void while with";
328
331
  var KEYWORDS_ATOM = "false null true";
329
332
  var RESERVED_WORDS = "enum implements import interface package private protected public static super this " + KEYWORDS_ATOM + " " + KEYWORDS;
@@ -379,6 +382,9 @@ var OPERATORS = makePredicate([
379
382
  "=",
380
383
  "+=",
381
384
  "-=",
385
+ "||=",
386
+ "&&=",
387
+ "??=",
382
388
  "/=",
383
389
  "*=",
384
390
  "**=",
@@ -476,12 +482,14 @@ function is_identifier_char(ch) {
476
482
  return UNICODE.ID_Continue.test(ch);
477
483
  }
478
484
 
485
+ const BASIC_IDENT = /^[a-z_$][a-z0-9_$]*$/i;
486
+
479
487
  function is_basic_identifier_string(str) {
480
- return /^[a-z_$][a-z0-9_$]*$/i.test(str);
488
+ return BASIC_IDENT.test(str);
481
489
  }
482
490
 
483
491
  function is_identifier_string(str, allow_surrogates) {
484
- if (/^[a-z_$][a-z0-9_$]*$/i.test(str)) {
492
+ if (BASIC_IDENT.test(str)) {
485
493
  return true;
486
494
  }
487
495
  if (!allow_surrogates && /[\ud800-\udfff]/.test(str)) {
@@ -639,29 +647,23 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
639
647
  } else if (!is_comment) {
640
648
  prev_was_dot = false;
641
649
  }
642
- var ret = {
643
- type : type,
644
- value : value,
645
- line : S.tokline,
646
- col : S.tokcol,
647
- pos : S.tokpos,
648
- endline : S.line,
649
- endcol : S.col,
650
- endpos : S.pos,
651
- nlb : S.newline_before,
652
- file : filename
653
- };
654
- if (/^(?:num|string|regexp)$/i.test(type)) {
655
- ret.raw = $TEXT.substring(ret.pos, ret.endpos);
656
- }
650
+ const line = S.tokline;
651
+ const col = S.tokcol;
652
+ const pos = S.tokpos;
653
+ const nlb = S.newline_before;
654
+ const file = filename;
655
+ let comments_before = [];
656
+ let comments_after = [];
657
+
657
658
  if (!is_comment) {
658
- ret.comments_before = S.comments_before;
659
- ret.comments_after = S.comments_before = [];
659
+ comments_before = S.comments_before;
660
+ comments_after = S.comments_before = [];
660
661
  }
661
662
  S.newline_before = false;
662
- ret = new AST_Token(ret);
663
- if (!is_comment) previous_token = ret;
664
- return ret;
663
+ const tok = new AST_Token(type, value, line, col, pos, nlb, comments_before, comments_after, file);
664
+
665
+ if (!is_comment) previous_token = tok;
666
+ return tok;
665
667
  }
666
668
 
667
669
  function skip_whitespace() {
@@ -713,6 +715,9 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
713
715
  return RE_NUM_LITERAL.test(ch);
714
716
  });
715
717
  if (prefix) num = prefix + num;
718
+
719
+ LATEST_RAW = num;
720
+
716
721
  if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
717
722
  parse_error("Legacy octal literals are not allowed in strict mode");
718
723
  }
@@ -820,15 +825,17 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
820
825
  }
821
826
 
822
827
  var read_string = with_eof_error("Unterminated string constant", function() {
823
- var quote = next(), ret = "";
828
+ const start_pos = S.pos;
829
+ var quote = next(), ret = [];
824
830
  for (;;) {
825
831
  var ch = next(true, true);
826
832
  if (ch == "\\") ch = read_escaped_char(true, true);
827
833
  else if (ch == "\r" || ch == "\n") parse_error("Unterminated string constant");
828
834
  else if (ch == quote) break;
829
- ret += ch;
835
+ ret.push(ch);
830
836
  }
831
- var tok = token("string", ret);
837
+ var tok = token("string", ret.join(""));
838
+ LATEST_RAW = S.text.slice(start_pos, S.pos);
832
839
  tok.quote = quote;
833
840
  return tok;
834
841
  });
@@ -847,7 +854,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
847
854
  next(true, true);
848
855
  S.brace_counter++;
849
856
  tok = token(begin ? "template_head" : "template_substitution", content);
850
- tok.raw = raw;
857
+ LATEST_RAW = raw;
858
+ LATEST_TEMPLATE_END = false;
851
859
  return tok;
852
860
  }
853
861
 
@@ -863,8 +871,8 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
863
871
  }
864
872
  S.template_braces.pop();
865
873
  tok = token(begin ? "template_head" : "template_substitution", content);
866
- tok.raw = raw;
867
- tok.end = true;
874
+ LATEST_RAW = raw;
875
+ LATEST_TEMPLATE_END = true;
868
876
  return tok;
869
877
  });
870
878
 
@@ -897,7 +905,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
897
905
  });
898
906
 
899
907
  var read_name = with_eof_error("Unterminated identifier name", function() {
900
- var name, ch, escaped = false;
908
+ var name = [], ch, escaped = false;
901
909
  var read_escaped_identifier_char = function() {
902
910
  escaped = true;
903
911
  next();
@@ -908,17 +916,19 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
908
916
  };
909
917
 
910
918
  // Read first character (ID_Start)
911
- if ((name = peek()) === "\\") {
912
- name = read_escaped_identifier_char();
913
- if (!is_identifier_start(name)) {
919
+ if ((ch = peek()) === "\\") {
920
+ ch = read_escaped_identifier_char();
921
+ if (!is_identifier_start(ch)) {
914
922
  parse_error("First identifier char is an invalid identifier char");
915
923
  }
916
- } else if (is_identifier_start(name)) {
924
+ } else if (is_identifier_start(ch)) {
917
925
  next();
918
926
  } else {
919
927
  return "";
920
928
  }
921
929
 
930
+ name.push(ch);
931
+
922
932
  // Read ID_Continue
923
933
  while ((ch = peek()) != null) {
924
934
  if ((ch = peek()) === "\\") {
@@ -932,12 +942,13 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
932
942
  }
933
943
  next();
934
944
  }
935
- name += ch;
945
+ name.push(ch);
936
946
  }
937
- if (RESERVED_WORDS.has(name) && escaped) {
947
+ const name_str = name.join("");
948
+ if (RESERVED_WORDS.has(name_str) && escaped) {
938
949
  parse_error("Escaped characters are not allowed in keywords");
939
950
  }
940
- return name;
951
+ return name_str;
941
952
  });
942
953
 
943
954
  var read_regexp = with_eof_error("Unterminated regular expression", function(source) {
@@ -961,7 +972,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
961
972
  source += ch;
962
973
  }
963
974
  const flags = read_name();
964
- return token("regexp", { source, flags });
975
+ return token("regexp", "/" + source + "/" + flags);
965
976
  });
966
977
 
967
978
  function read_operator(prefix) {
@@ -1154,7 +1165,9 @@ var UNARY_PREFIX = makePredicate([
1154
1165
 
1155
1166
  var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
1156
1167
 
1157
- var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "**=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
1168
+ var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "??=", "&&=", "||=", "/=", "*=", "**=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
1169
+
1170
+ var LOGICAL_ASSIGNMENT = makePredicate([ "??=", "&&=", "||=" ]);
1158
1171
 
1159
1172
  var PRECEDENCE = (function(a, ret) {
1160
1173
  for (var i = 0; i < a.length; ++i) {
@@ -1192,7 +1205,7 @@ function parse($TEXT, options) {
1192
1205
  // Useful because comments_before property of call with parens outside
1193
1206
  // contains both comments inside and outside these parens. Used to find the
1194
1207
  // right #__PURE__ comments for an expression
1195
- const outer_comments_before_counts = new Map();
1208
+ const outer_comments_before_counts = new WeakMap();
1196
1209
 
1197
1210
  options = defaults(options, {
1198
1211
  bare_returns : false,
@@ -1326,7 +1339,7 @@ function parse($TEXT, options) {
1326
1339
  case "string":
1327
1340
  if (S.in_directives) {
1328
1341
  var token = peek();
1329
- if (!S.token.raw.includes("\\")
1342
+ if (!LATEST_RAW.includes("\\")
1330
1343
  && (is_token(token, "punc", ";")
1331
1344
  || is_token(token, "punc", "}")
1332
1345
  || has_newline_before(token)
@@ -2309,7 +2322,12 @@ function parse($TEXT, options) {
2309
2322
  ret = _make_symbol(AST_SymbolRef);
2310
2323
  break;
2311
2324
  case "num":
2312
- ret = new AST_Number({ start: tok, end: tok, value: tok.value });
2325
+ ret = new AST_Number({
2326
+ start: tok,
2327
+ end: tok,
2328
+ value: tok.value,
2329
+ raw: LATEST_RAW
2330
+ });
2313
2331
  break;
2314
2332
  case "big_int":
2315
2333
  ret = new AST_BigInt({ start: tok, end: tok, value: tok.value });
@@ -2323,7 +2341,9 @@ function parse($TEXT, options) {
2323
2341
  });
2324
2342
  break;
2325
2343
  case "regexp":
2326
- ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
2344
+ const [_, source, flags] = tok.value.match(/^\/(.*)\/(\w*)$/);
2345
+
2346
+ ret = new AST_RegExp({ start: tok, end: tok, value: { source, flags } });
2327
2347
  break;
2328
2348
  case "atom":
2329
2349
  switch (tok.value) {
@@ -2493,22 +2513,19 @@ function parse($TEXT, options) {
2493
2513
 
2494
2514
  segments.push(new AST_TemplateSegment({
2495
2515
  start: S.token,
2496
- raw: S.token.raw,
2516
+ raw: LATEST_RAW,
2497
2517
  value: S.token.value,
2498
2518
  end: S.token
2499
2519
  }));
2500
- while (!S.token.end) {
2520
+
2521
+ while (!LATEST_TEMPLATE_END) {
2501
2522
  next();
2502
2523
  handle_regexp();
2503
2524
  segments.push(expression(true));
2504
2525
 
2505
- if (!is_token("template_substitution")) {
2506
- unexpected();
2507
- }
2508
-
2509
2526
  segments.push(new AST_TemplateSegment({
2510
2527
  start: S.token,
2511
- raw: S.token.raw,
2528
+ raw: LATEST_RAW,
2512
2529
  value: S.token.value,
2513
2530
  end: S.token
2514
2531
  }));
@@ -2602,6 +2619,7 @@ function parse($TEXT, options) {
2602
2619
  left: value,
2603
2620
  operator: "=",
2604
2621
  right: expression(false),
2622
+ logical: false,
2605
2623
  end: prev()
2606
2624
  });
2607
2625
  }
@@ -3370,11 +3388,13 @@ function parse($TEXT, options) {
3370
3388
  if (is("operator") && ASSIGNMENT.has(val)) {
3371
3389
  if (is_assignable(left) || (left = to_destructuring(left)) instanceof AST_Destructuring) {
3372
3390
  next();
3391
+
3373
3392
  return new AST_Assign({
3374
3393
  start : start,
3375
3394
  left : left,
3376
3395
  operator : val,
3377
3396
  right : maybe_assign(no_in),
3397
+ logical : LOGICAL_ASSIGNMENT.has(val),
3378
3398
  end : prev()
3379
3399
  });
3380
3400
  }
@@ -3518,8 +3538,54 @@ function DEFNODE(type, props, methods, base = AST_Node) {
3518
3538
  return ctor;
3519
3539
  }
3520
3540
 
3521
- var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before comments_after file raw quote end", {
3522
- }, null);
3541
+ const has_tok_flag = (tok, flag) => Boolean(tok.flags & flag);
3542
+ const set_tok_flag = (tok, flag, truth) => {
3543
+ if (truth) {
3544
+ tok.flags |= flag;
3545
+ } else {
3546
+ tok.flags &= ~flag;
3547
+ }
3548
+ };
3549
+
3550
+ const TOK_FLAG_NLB = 0b0001;
3551
+ const TOK_FLAG_QUOTE_SINGLE = 0b0010;
3552
+ const TOK_FLAG_QUOTE_EXISTS = 0b0100;
3553
+
3554
+ class AST_Token {
3555
+ constructor(type, value, line, col, pos, nlb, comments_before, comments_after, file) {
3556
+ this.flags = (nlb ? 1 : 0);
3557
+
3558
+ this.type = type;
3559
+ this.value = value;
3560
+ this.line = line;
3561
+ this.col = col;
3562
+ this.pos = pos;
3563
+ this.comments_before = comments_before;
3564
+ this.comments_after = comments_after;
3565
+ this.file = file;
3566
+
3567
+ Object.seal(this);
3568
+ }
3569
+
3570
+ get nlb() {
3571
+ return has_tok_flag(this, TOK_FLAG_NLB);
3572
+ }
3573
+
3574
+ set nlb(new_nlb) {
3575
+ set_tok_flag(this, TOK_FLAG_NLB, new_nlb);
3576
+ }
3577
+
3578
+ get quote() {
3579
+ return !has_tok_flag(this, TOK_FLAG_QUOTE_EXISTS)
3580
+ ? ""
3581
+ : (has_tok_flag(this, TOK_FLAG_QUOTE_SINGLE) ? "'" : '"');
3582
+ }
3583
+
3584
+ set quote(quote_type) {
3585
+ set_tok_flag(this, TOK_FLAG_QUOTE_SINGLE, quote_type === "'");
3586
+ set_tok_flag(this, TOK_FLAG_QUOTE_EXISTS, !!quote_type);
3587
+ }
3588
+ }
3523
3589
 
3524
3590
  var AST_Node = DEFNODE("Node", "start end", {
3525
3591
  _clone: function(deep) {
@@ -3988,7 +4054,7 @@ var AST_TemplateSegment = DEFNODE("TemplateSegment", "value raw", {
3988
4054
  $documentation: "A segment of a template string literal",
3989
4055
  $propdoc: {
3990
4056
  value: "Content of the segment",
3991
- raw: "Raw content of the segment"
4057
+ raw: "Raw source of the segment",
3992
4058
  }
3993
4059
  });
3994
4060
 
@@ -4500,8 +4566,11 @@ var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative",
4500
4566
  },
4501
4567
  });
4502
4568
 
4503
- var AST_Assign = DEFNODE("Assign", null, {
4569
+ var AST_Assign = DEFNODE("Assign", "logical", {
4504
4570
  $documentation: "An assignment expression — `a = b + 5`",
4571
+ $propdoc: {
4572
+ logical: "Whether it's a logical assignment"
4573
+ }
4505
4574
  }, AST_Binary);
4506
4575
 
4507
4576
  var AST_DefaultAssign = DEFNODE("DefaultAssign", null, {
@@ -4792,11 +4861,11 @@ var AST_String = DEFNODE("String", "value quote", {
4792
4861
  }
4793
4862
  }, AST_Constant);
4794
4863
 
4795
- var AST_Number = DEFNODE("Number", "value literal", {
4864
+ var AST_Number = DEFNODE("Number", "value raw", {
4796
4865
  $documentation: "A number literal",
4797
4866
  $propdoc: {
4798
4867
  value: "[number] the numeric value",
4799
- literal: "[string] numeric value as string (optional)"
4868
+ raw: "[string] numeric value as string"
4800
4869
  }
4801
4870
  }, AST_Constant);
4802
4871
 
@@ -5875,6 +5944,7 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
5875
5944
  return new AST_String(args);
5876
5945
  case "number":
5877
5946
  args.value = val;
5947
+ args.raw = M.raw || val.toString();
5878
5948
  return new AST_Number(args);
5879
5949
  case "boolean":
5880
5950
  return new (val ? AST_True : AST_False)(args);
@@ -6399,22 +6469,10 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
6399
6469
 
6400
6470
  def_to_moz(AST_Constant, function To_Moz_Literal(M) {
6401
6471
  var value = M.value;
6402
- if (typeof value === "number" && (value < 0 || (value === 0 && 1 / value < 0))) {
6403
- return {
6404
- type: "UnaryExpression",
6405
- operator: "-",
6406
- prefix: true,
6407
- argument: {
6408
- type: "Literal",
6409
- value: -value,
6410
- raw: M.start.raw
6411
- }
6412
- };
6413
- }
6414
6472
  return {
6415
6473
  type: "Literal",
6416
6474
  value: value,
6417
- raw: M.start.raw
6475
+ raw: M.raw || M.print_to_string()
6418
6476
  };
6419
6477
  });
6420
6478
 
@@ -6439,40 +6497,36 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
6439
6497
 
6440
6498
  /* -----[ tools ]----- */
6441
6499
 
6442
- function raw_token(moznode) {
6443
- if (moznode.type == "Literal") {
6444
- return moznode.raw != null ? moznode.raw : moznode.value + "";
6445
- }
6446
- }
6447
-
6448
6500
  function my_start_token(moznode) {
6449
6501
  var loc = moznode.loc, start = loc && loc.start;
6450
6502
  var range = moznode.range;
6451
- return new AST_Token({
6452
- file : loc && loc.source,
6453
- line : start && start.line,
6454
- col : start && start.column,
6455
- pos : range ? range[0] : moznode.start,
6456
- endline : start && start.line,
6457
- endcol : start && start.column,
6458
- endpos : range ? range[0] : moznode.start,
6459
- raw : raw_token(moznode),
6460
- });
6503
+ return new AST_Token(
6504
+ "",
6505
+ "",
6506
+ start && start.line || 0,
6507
+ start && start.column || 0,
6508
+ range ? range [0] : moznode.start,
6509
+ false,
6510
+ [],
6511
+ [],
6512
+ loc && loc.source,
6513
+ );
6461
6514
  }
6462
6515
 
6463
6516
  function my_end_token(moznode) {
6464
6517
  var loc = moznode.loc, end = loc && loc.end;
6465
6518
  var range = moznode.range;
6466
- return new AST_Token({
6467
- file : loc && loc.source,
6468
- line : end && end.line,
6469
- col : end && end.column,
6470
- pos : range ? range[1] : moznode.end,
6471
- endline : end && end.line,
6472
- endcol : end && end.column,
6473
- endpos : range ? range[1] : moznode.end,
6474
- raw : raw_token(moznode),
6475
- });
6519
+ return new AST_Token(
6520
+ "",
6521
+ "",
6522
+ end && end.line || 0,
6523
+ end && end.column || 0,
6524
+ range ? range [0] : moznode.end,
6525
+ false,
6526
+ [],
6527
+ [],
6528
+ loc && loc.source,
6529
+ );
6476
6530
  }
6477
6531
 
6478
6532
  function map(moztype, mytype, propmap) {
@@ -6772,7 +6826,7 @@ function OutputStream(options) {
6772
6826
  let printed_comments = new Set();
6773
6827
 
6774
6828
  var to_utf8 = options.ascii_only ? function(str, identifier) {
6775
- if (options.ecma >= 2015) {
6829
+ if (options.ecma >= 2015 && !options.safari10) {
6776
6830
  str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
6777
6831
  var code = get_full_char_code(ch, 0).toString(16);
6778
6832
  return "\\u{" + code + "}";
@@ -7868,6 +7922,9 @@ function OutputStream(options) {
7868
7922
  }
7869
7923
  output.print("`");
7870
7924
  });
7925
+ DEFPRINT(AST_TemplateSegment, function(self, output) {
7926
+ output.print_template_string_chars(self.value);
7927
+ });
7871
7928
 
7872
7929
  AST_Arrow.DEFMETHOD("_do_print", function(output) {
7873
7930
  var self = this;
@@ -8309,7 +8366,10 @@ function OutputStream(options) {
8309
8366
  var prop = self.property;
8310
8367
  var print_computed = RESERVED_WORDS.has(prop)
8311
8368
  ? output.option("ie8")
8312
- : !is_identifier_string(prop, output.option("ecma") >= 2015);
8369
+ : !is_identifier_string(
8370
+ prop,
8371
+ output.option("ecma") >= 2015 || output.option("safari10")
8372
+ );
8313
8373
 
8314
8374
  if (self.optional) output.print("?.");
8315
8375
 
@@ -8479,7 +8539,7 @@ function OutputStream(options) {
8479
8539
  var print_string = RESERVED_WORDS.has(key)
8480
8540
  ? output.option("ie8")
8481
8541
  : (
8482
- output.option("ecma") < 2015
8542
+ output.option("ecma") < 2015 || output.option("safari10")
8483
8543
  ? !is_basic_identifier_string(key)
8484
8544
  : !is_identifier_string(key, true)
8485
8545
  );
@@ -8498,7 +8558,10 @@ function OutputStream(options) {
8498
8558
  var allowShortHand = output.option("shorthand");
8499
8559
  if (allowShortHand &&
8500
8560
  self.value instanceof AST_Symbol &&
8501
- is_identifier_string(self.key, output.option("ecma") >= 2015) &&
8561
+ is_identifier_string(
8562
+ self.key,
8563
+ output.option("ecma") >= 2015 || output.option("safari10")
8564
+ ) &&
8502
8565
  get_name(self.value) === self.key &&
8503
8566
  !RESERVED_WORDS.has(self.key)
8504
8567
  ) {
@@ -8507,7 +8570,10 @@ function OutputStream(options) {
8507
8570
  } else if (allowShortHand &&
8508
8571
  self.value instanceof AST_DefaultAssign &&
8509
8572
  self.value.left instanceof AST_Symbol &&
8510
- is_identifier_string(self.key, output.option("ecma") >= 2015) &&
8573
+ is_identifier_string(
8574
+ self.key,
8575
+ output.option("ecma") >= 2015 || output.option("safari10")
8576
+ ) &&
8511
8577
  get_name(self.value.left) === self.key
8512
8578
  ) {
8513
8579
  print_property_name(self.key, self.quote, output);
@@ -8605,8 +8671,8 @@ function OutputStream(options) {
8605
8671
  output.print_string(self.getValue(), self.quote, output.in_directive);
8606
8672
  });
8607
8673
  DEFPRINT(AST_Number, function(self, output) {
8608
- if ((output.option("keep_numbers") || output.use_asm) && self.start && self.start.raw != null) {
8609
- output.print(self.start.raw);
8674
+ if ((output.option("keep_numbers") || output.use_asm) && self.raw) {
8675
+ output.print(self.raw);
8610
8676
  } else {
8611
8677
  output.print(make_num(self.getValue()));
8612
8678
  }
@@ -10664,6 +10730,7 @@ AST_Scope.DEFMETHOD("process_expression", function(insert, compressor) {
10664
10730
  function read_property(obj, key) {
10665
10731
  key = get_value(key);
10666
10732
  if (key instanceof AST_Node) return;
10733
+
10667
10734
  var value;
10668
10735
  if (obj instanceof AST_Array) {
10669
10736
  var elements = obj.elements;
@@ -10678,6 +10745,7 @@ function read_property(obj, key) {
10678
10745
  if (!value && props[i].key === key) value = props[i].value;
10679
10746
  }
10680
10747
  }
10748
+
10681
10749
  return value instanceof AST_SymbolRef && value.fixed_value() || value;
10682
10750
  }
10683
10751
 
@@ -10810,38 +10878,56 @@ function is_modified(compressor, tw, node, value, level, immutable) {
10810
10878
  || value instanceof AST_This;
10811
10879
  }
10812
10880
 
10813
- function mark_escaped(tw, d, scope, node, value, level, depth) {
10881
+ // A definition "escapes" when its value can leave the point of use.
10882
+ // Example: `a = b || c`
10883
+ // In this example, "b" and "c" are escaping, because they're going into "a"
10884
+ //
10885
+ // def.escaped is != 0 when it escapes.
10886
+ //
10887
+ // When greater than 1, it means that N chained properties will be read off
10888
+ // of that def before an escape occurs. This is useful for evaluating
10889
+ // property accesses, where you need to know when to stop.
10890
+ function mark_escaped(tw, d, scope, node, value, level = 0, depth = 1) {
10814
10891
  var parent = tw.parent(level);
10815
10892
  if (value) {
10816
10893
  if (value.is_constant()) return;
10817
10894
  if (value instanceof AST_ClassExpression) return;
10818
10895
  }
10819
- if (parent instanceof AST_Assign && parent.operator == "=" && node === parent.right
10896
+
10897
+ if (
10898
+ parent instanceof AST_Assign && (parent.operator === "=" || parent.logical) && node === parent.right
10820
10899
  || parent instanceof AST_Call && (node !== parent.expression || parent instanceof AST_New)
10821
10900
  || parent instanceof AST_Exit && node === parent.value && node.scope !== d.scope
10822
10901
  || parent instanceof AST_VarDef && node === parent.value
10823
- || parent instanceof AST_Yield && node === parent.value && node.scope !== d.scope) {
10902
+ || parent instanceof AST_Yield && node === parent.value && node.scope !== d.scope
10903
+ ) {
10824
10904
  if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1;
10825
10905
  if (!d.escaped || d.escaped > depth) d.escaped = depth;
10826
10906
  return;
10827
- } else if (parent instanceof AST_Array
10907
+ } else if (
10908
+ parent instanceof AST_Array
10828
10909
  || parent instanceof AST_Await
10829
10910
  || parent instanceof AST_Binary && lazy_op.has(parent.operator)
10830
10911
  || parent instanceof AST_Conditional && node !== parent.condition
10831
10912
  || parent instanceof AST_Expansion
10832
- || parent instanceof AST_Sequence && node === parent.tail_node()) {
10913
+ || parent instanceof AST_Sequence && node === parent.tail_node()
10914
+ ) {
10833
10915
  mark_escaped(tw, d, scope, parent, parent, level + 1, depth);
10834
10916
  } else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
10835
10917
  var obj = tw.parent(level + 1);
10918
+
10836
10919
  mark_escaped(tw, d, scope, obj, obj, level + 2, depth);
10837
10920
  } else if (parent instanceof AST_PropAccess && node === parent.expression) {
10838
10921
  value = read_property(value, parent.property);
10922
+
10839
10923
  mark_escaped(tw, d, scope, parent, value, level + 1, depth + 1);
10840
10924
  if (value) return;
10841
10925
  }
10926
+
10842
10927
  if (level > 0) return;
10843
10928
  if (parent instanceof AST_Sequence && node !== parent.tail_node()) return;
10844
10929
  if (parent instanceof AST_SimpleStatement) return;
10930
+
10845
10931
  d.direct_access = true;
10846
10932
  }
10847
10933
 
@@ -10865,32 +10951,64 @@ function is_modified(compressor, tw, node, value, level, immutable) {
10865
10951
  suppress(node.left);
10866
10952
  return;
10867
10953
  }
10954
+
10955
+ const finish_walk = () => {
10956
+ if (node.logical) {
10957
+ node.left.walk(tw);
10958
+
10959
+ push(tw);
10960
+ node.right.walk(tw);
10961
+ pop(tw);
10962
+
10963
+ return true;
10964
+ }
10965
+ };
10966
+
10868
10967
  var sym = node.left;
10869
- if (!(sym instanceof AST_SymbolRef)) return;
10968
+ if (!(sym instanceof AST_SymbolRef)) return finish_walk();
10969
+
10870
10970
  var def = sym.definition();
10871
10971
  var safe = safe_to_assign(tw, def, sym.scope, node.right);
10872
10972
  def.assignments++;
10873
- if (!safe) return;
10973
+ if (!safe) return finish_walk();
10974
+
10874
10975
  var fixed = def.fixed;
10875
- if (!fixed && node.operator != "=") return;
10976
+ if (!fixed && node.operator != "=" && !node.logical) return finish_walk();
10977
+
10876
10978
  var eq = node.operator == "=";
10877
10979
  var value = eq ? node.right : node;
10878
- if (is_modified(compressor, tw, node, value, 0)) return;
10980
+ if (is_modified(compressor, tw, node, value, 0)) return finish_walk();
10981
+
10879
10982
  def.references.push(sym);
10880
- if (!eq) def.chained = true;
10881
- def.fixed = eq ? function() {
10882
- return node.right;
10883
- } : function() {
10884
- return make_node(AST_Binary, node, {
10885
- operator: node.operator.slice(0, -1),
10886
- left: fixed instanceof AST_Node ? fixed : fixed(),
10887
- right: node.right
10888
- });
10889
- };
10983
+
10984
+ if (!node.logical) {
10985
+ if (!eq) def.chained = true;
10986
+
10987
+ def.fixed = eq ? function() {
10988
+ return node.right;
10989
+ } : function() {
10990
+ return make_node(AST_Binary, node, {
10991
+ operator: node.operator.slice(0, -1),
10992
+ left: fixed instanceof AST_Node ? fixed : fixed(),
10993
+ right: node.right
10994
+ });
10995
+ };
10996
+ }
10997
+
10998
+ if (node.logical) {
10999
+ mark(tw, def, false);
11000
+ push(tw);
11001
+ node.right.walk(tw);
11002
+ pop(tw);
11003
+ return true;
11004
+ }
11005
+
10890
11006
  mark(tw, def, false);
10891
11007
  node.right.walk(tw);
10892
11008
  mark(tw, def, true);
11009
+
10893
11010
  mark_escaped(tw, def, sym.scope, node, value, 0, 1);
11011
+
10894
11012
  return true;
10895
11013
  });
10896
11014
  def_reduce_vars(AST_Binary, function(tw) {
@@ -11493,7 +11611,8 @@ function tighten_body(statements, compressor) {
11493
11611
  }
11494
11612
  // Stop immediately if these node types are encountered
11495
11613
  var parent = scanner.parent();
11496
- if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
11614
+ if (node instanceof AST_Assign
11615
+ && (node.logical || node.operator != "=" && lhs.equivalent_to(node.left))
11497
11616
  || node instanceof AST_Await
11498
11617
  || node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
11499
11618
  || node instanceof AST_Debugger
@@ -11561,6 +11680,7 @@ function tighten_body(statements, compressor) {
11561
11680
  }
11562
11681
  return make_node(AST_Assign, candidate, {
11563
11682
  operator: "=",
11683
+ logical: false,
11564
11684
  left: make_node(AST_SymbolRef, candidate.name, candidate.name),
11565
11685
  right: value
11566
11686
  });
@@ -11865,6 +11985,7 @@ function tighten_body(statements, compressor) {
11865
11985
  var parent = scanner.parent(level);
11866
11986
  if (parent instanceof AST_Assign) {
11867
11987
  if (write_only
11988
+ && !parent.logical
11868
11989
  && !(parent.left instanceof AST_PropAccess
11869
11990
  || lvalues.has(parent.left.name))) {
11870
11991
  return find_stop(parent, level + 1, write_only);
@@ -11919,7 +12040,9 @@ function tighten_body(statements, compressor) {
11919
12040
  }
11920
12041
 
11921
12042
  function get_lhs(expr) {
11922
- if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) {
12043
+ if (expr instanceof AST_Assign && expr.logical) {
12044
+ return false;
12045
+ } else if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) {
11923
12046
  var def = expr.name.definition();
11924
12047
  if (!member(expr.name, def.orig)) return;
11925
12048
  var referenced = def.references.length - def.replaced;
@@ -11930,14 +12053,20 @@ function tighten_body(statements, compressor) {
11930
12053
  return make_node(AST_SymbolRef, expr.name, expr.name);
11931
12054
  }
11932
12055
  } else {
11933
- const lhs = expr[expr instanceof AST_Assign ? "left" : "expression"];
12056
+ const lhs = expr instanceof AST_Assign
12057
+ ? expr.left
12058
+ : expr.expression;
11934
12059
  return !is_ref_of(lhs, AST_SymbolConst)
11935
12060
  && !is_ref_of(lhs, AST_SymbolLet) && lhs;
11936
12061
  }
11937
12062
  }
11938
12063
 
11939
12064
  function get_rvalue(expr) {
11940
- return expr[expr instanceof AST_Assign ? "right" : "value"];
12065
+ if (expr instanceof AST_Assign) {
12066
+ return expr.right;
12067
+ } else {
12068
+ return expr.value;
12069
+ }
11941
12070
  }
11942
12071
 
11943
12072
  function get_lvalues(expr) {
@@ -11996,7 +12125,9 @@ function tighten_body(statements, compressor) {
11996
12125
  && !(in_loop
11997
12126
  && (lvalues.has(lhs.name)
11998
12127
  || candidate instanceof AST_Unary
11999
- || candidate instanceof AST_Assign && candidate.operator != "="));
12128
+ || (candidate instanceof AST_Assign
12129
+ && !candidate.logical
12130
+ && candidate.operator != "=")));
12000
12131
  }
12001
12132
 
12002
12133
  function value_has_side_effects(expr) {
@@ -12423,7 +12554,7 @@ function tighten_body(statements, compressor) {
12423
12554
  var def = defn.definitions[defn.definitions.length - 1];
12424
12555
  if (!(def.value instanceof AST_Object)) return;
12425
12556
  var exprs;
12426
- if (body instanceof AST_Assign) {
12557
+ if (body instanceof AST_Assign && !body.logical) {
12427
12558
  exprs = [ body ];
12428
12559
  } else if (body instanceof AST_Sequence) {
12429
12560
  exprs = body.expressions.slice();
@@ -12646,6 +12777,8 @@ function is_undefined(node, compressor) {
12646
12777
  && (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
12647
12778
  });
12648
12779
  def_may_throw_on_access(AST_Assign, function(compressor) {
12780
+ if (this.logical) return true;
12781
+
12649
12782
  return this.operator == "="
12650
12783
  && this.right._dot_throw(compressor);
12651
12784
  });
@@ -13870,6 +14003,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
13870
14003
  var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
13871
14004
  const assign_as_unused = r_keep_assign.test(compressor.option("unused")) ? return_false : function(node) {
13872
14005
  if (node instanceof AST_Assign
14006
+ && !node.logical
13873
14007
  && (has_flag(node, WRITE_ONLY) || node.operator == "=")
13874
14008
  ) {
13875
14009
  return node.left;
@@ -14088,6 +14222,7 @@ AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
14088
14222
  sym.references.push(ref);
14089
14223
  var assign = make_node(AST_Assign, def, {
14090
14224
  operator: "=",
14225
+ logical: false,
14091
14226
  left: ref,
14092
14227
  right: def.value
14093
14228
  });
@@ -14523,6 +14658,8 @@ AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
14523
14658
  }
14524
14659
  });
14525
14660
  def_drop_side_effect_free(AST_Assign, function(compressor) {
14661
+ if (this.logical) return this;
14662
+
14526
14663
  var left = this.left;
14527
14664
  if (left.has_side_effects(compressor)
14528
14665
  || compressor.has_directive("use strict")
@@ -15119,6 +15256,7 @@ AST_Definitions.DEFMETHOD("to_assignments", function(compressor) {
15119
15256
  var name = make_node(AST_SymbolRef, def.name, def.name);
15120
15257
  assignments.push(make_node(AST_Assign, def, {
15121
15258
  operator : "=",
15259
+ logical: false,
15122
15260
  left : name,
15123
15261
  right : def.value
15124
15262
  }));
@@ -15149,6 +15287,17 @@ def_optimize(AST_Definitions, function(self) {
15149
15287
  return self;
15150
15288
  });
15151
15289
 
15290
+ def_optimize(AST_VarDef, function(self) {
15291
+ if (
15292
+ self.name instanceof AST_SymbolLet
15293
+ && self.value != null
15294
+ && is_undefined(self.value)
15295
+ ) {
15296
+ self.value = null;
15297
+ }
15298
+ return self;
15299
+ });
15300
+
15152
15301
  def_optimize(AST_Import, function(self) {
15153
15302
  return self;
15154
15303
  });
@@ -15733,6 +15882,7 @@ def_optimize(AST_Call, function(self, compressor) {
15733
15882
  def.references.push(sym);
15734
15883
  if (value) expressions.push(make_node(AST_Assign, self, {
15735
15884
  operator: "=",
15885
+ logical: false,
15736
15886
  left: sym,
15737
15887
  right: value.clone()
15738
15888
  }));
@@ -15776,6 +15926,7 @@ def_optimize(AST_Call, function(self, compressor) {
15776
15926
  def.references.push(sym);
15777
15927
  expressions.splice(pos++, 0, make_node(AST_Assign, var_def, {
15778
15928
  operator: "=",
15929
+ logical: false,
15779
15930
  left: sym,
15780
15931
  right: make_node(AST_Undefined, name)
15781
15932
  }));
@@ -16296,7 +16447,7 @@ def_optimize(AST_Binary, function(self, compressor) {
16296
16447
  var l = self.left;
16297
16448
  var r = self.right.evaluate(compressor);
16298
16449
  if (r != self.right) {
16299
- l.segments[l.segments.length - 1].value += r.toString();
16450
+ l.segments[l.segments.length - 1].value += String(r);
16300
16451
  return l;
16301
16452
  }
16302
16453
  }
@@ -16305,7 +16456,7 @@ def_optimize(AST_Binary, function(self, compressor) {
16305
16456
  var r = self.right;
16306
16457
  var l = self.left.evaluate(compressor);
16307
16458
  if (l != self.left) {
16308
- r.segments[0].value = l.toString() + r.segments[0].value ;
16459
+ r.segments[0].value = String(l) + r.segments[0].value;
16309
16460
  return r;
16310
16461
  }
16311
16462
  }
@@ -16733,6 +16884,10 @@ function is_reachable(self, defs) {
16733
16884
  const ASSIGN_OPS = makePredicate("+ - / * % >> << >>> | ^ &");
16734
16885
  const ASSIGN_OPS_COMMUTATIVE = makePredicate("* | ^ &");
16735
16886
  def_optimize(AST_Assign, function(self, compressor) {
16887
+ if (self.logical) {
16888
+ return self.lift_sequences(compressor);
16889
+ }
16890
+
16736
16891
  var def;
16737
16892
  if (compressor.option("dead_code")
16738
16893
  && self.left instanceof AST_SymbolRef
@@ -16950,16 +17105,20 @@ def_optimize(AST_Conditional, function(self, compressor) {
16950
17105
  // |
16951
17106
  // v
16952
17107
  // exp = foo ? something : something_else;
16953
- if (consequent instanceof AST_Assign
17108
+ if (
17109
+ consequent instanceof AST_Assign
16954
17110
  && alternative instanceof AST_Assign
16955
- && consequent.operator == alternative.operator
17111
+ && consequent.operator === alternative.operator
17112
+ && consequent.logical === alternative.logical
16956
17113
  && consequent.left.equivalent_to(alternative.left)
16957
17114
  && (!self.condition.has_side_effects(compressor)
16958
17115
  || consequent.operator == "="
16959
- && !consequent.left.has_side_effects(compressor))) {
17116
+ && !consequent.left.has_side_effects(compressor))
17117
+ ) {
16960
17118
  return make_node(AST_Assign, self, {
16961
17119
  operator: consequent.operator,
16962
17120
  left: consequent.left,
17121
+ logical: consequent.logical,
16963
17122
  right: make_node(AST_Conditional, self, {
16964
17123
  condition: self.condition,
16965
17124
  consequent: consequent.right,
@@ -17555,9 +17714,12 @@ def_optimize(AST_Yield, function(self, compressor) {
17555
17714
  });
17556
17715
 
17557
17716
  def_optimize(AST_TemplateString, function(self, compressor) {
17558
- if (!compressor.option("evaluate")
17559
- || compressor.parent() instanceof AST_PrefixedTemplateString)
17717
+ if (
17718
+ !compressor.option("evaluate")
17719
+ || compressor.parent() instanceof AST_PrefixedTemplateString
17720
+ ) {
17560
17721
  return self;
17722
+ }
17561
17723
 
17562
17724
  var segments = [];
17563
17725
  for (var i = 0; i < self.segments.length; i++) {
@@ -17593,7 +17755,17 @@ def_optimize(AST_TemplateString, function(self, compressor) {
17593
17755
  if (segments.length == 1) {
17594
17756
  return make_node(AST_String, self, segments[0]);
17595
17757
  }
17596
- if (segments.length === 3 && segments[1] instanceof AST_Node) {
17758
+
17759
+ if (
17760
+ segments.length === 3
17761
+ && segments[1] instanceof AST_Node
17762
+ && (
17763
+ segments[1].is_string(compressor)
17764
+ || segments[1].is_number(compressor)
17765
+ || is_nullish(segments[1])
17766
+ || compressor.option("unsafe")
17767
+ )
17768
+ ) {
17597
17769
  // `foo${bar}` => "foo" + bar
17598
17770
  if (segments[2].value === "") {
17599
17771
  return make_node(AST_Binary, self, {
@@ -17604,7 +17776,7 @@ def_optimize(AST_TemplateString, function(self, compressor) {
17604
17776
  right: segments[1],
17605
17777
  });
17606
17778
  }
17607
- // `{bar}baz` => bar + "baz"
17779
+ // `${bar}baz` => bar + "baz"
17608
17780
  if (segments[0].value === "") {
17609
17781
  return make_node(AST_Binary, self, {
17610
17782
  operator: "+",
@@ -26661,4 +26833,3 @@ exports._run_cli = run_cli;
26661
26833
  exports.minify = minify;
26662
26834
 
26663
26835
  })));
26664
- //# sourceMappingURL=bundle.min.js.map