terser 5.9.0 → 5.12.0

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.
@@ -1387,7 +1387,7 @@ function parse($TEXT, options) {
1387
1387
  }
1388
1388
  if (S.token.value == "import" && !is_token(peek(), "punc", "(") && !is_token(peek(), "punc", ".")) {
1389
1389
  next();
1390
- var node = import_();
1390
+ var node = import_statement();
1391
1391
  semicolon();
1392
1392
  return node;
1393
1393
  }
@@ -1539,7 +1539,7 @@ function parse($TEXT, options) {
1539
1539
  case "export":
1540
1540
  if (!is_token(peek(), "punc", "(")) {
1541
1541
  next();
1542
- var node = export_();
1542
+ var node = export_statement();
1543
1543
  if (is("punc", ";")) semicolon();
1544
1544
  return node;
1545
1545
  }
@@ -2716,7 +2716,7 @@ function parse($TEXT, options) {
2716
2716
  };
2717
2717
 
2718
2718
  const is_not_method_start = () =>
2719
- !is("punc", "(") && !is("punc", ",") && !is("punc", "}") && !is("operator", "=");
2719
+ !is("punc", "(") && !is("punc", ",") && !is("punc", "}") && !is("punc", ";") && !is("operator", "=");
2720
2720
 
2721
2721
  var is_async = false;
2722
2722
  var is_static = false;
@@ -2831,7 +2831,15 @@ function parse($TEXT, options) {
2831
2831
  }
2832
2832
  }
2833
2833
 
2834
- function import_() {
2834
+ function maybe_import_assertion() {
2835
+ if (is("name", "assert") && !has_newline_before(S.token)) {
2836
+ next();
2837
+ return object_or_destructuring_();
2838
+ }
2839
+ return null;
2840
+ }
2841
+
2842
+ function import_statement() {
2835
2843
  var start = prev();
2836
2844
 
2837
2845
  var imported_name;
@@ -2854,16 +2862,20 @@ function parse($TEXT, options) {
2854
2862
  unexpected();
2855
2863
  }
2856
2864
  next();
2865
+
2866
+ const assert_clause = maybe_import_assertion();
2867
+
2857
2868
  return new AST_Import({
2858
- start: start,
2859
- imported_name: imported_name,
2860
- imported_names: imported_names,
2869
+ start,
2870
+ imported_name,
2871
+ imported_names,
2861
2872
  module_name: new AST_String({
2862
2873
  start: mod_str,
2863
2874
  value: mod_str.value,
2864
2875
  quote: mod_str.quote,
2865
2876
  end: mod_str,
2866
2877
  }),
2878
+ assert_clause,
2867
2879
  end: S.token,
2868
2880
  });
2869
2881
  }
@@ -2971,7 +2983,7 @@ function parse($TEXT, options) {
2971
2983
  return names;
2972
2984
  }
2973
2985
 
2974
- function export_() {
2986
+ function export_statement() {
2975
2987
  var start = S.token;
2976
2988
  var is_default;
2977
2989
  var exported_names;
@@ -2989,6 +3001,8 @@ function parse($TEXT, options) {
2989
3001
  }
2990
3002
  next();
2991
3003
 
3004
+ const assert_clause = maybe_import_assertion();
3005
+
2992
3006
  return new AST_Export({
2993
3007
  start: start,
2994
3008
  is_default: is_default,
@@ -3000,6 +3014,7 @@ function parse($TEXT, options) {
3000
3014
  end: mod_str,
3001
3015
  }),
3002
3016
  end: prev(),
3017
+ assert_clause
3003
3018
  });
3004
3019
  } else {
3005
3020
  return new AST_Export({
@@ -3045,6 +3060,7 @@ function parse($TEXT, options) {
3045
3060
  exported_value: exported_value,
3046
3061
  exported_definition: exported_definition,
3047
3062
  end: prev(),
3063
+ assert_clause: null
3048
3064
  });
3049
3065
  }
3050
3066
 
@@ -4378,12 +4394,13 @@ var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", {
4378
4394
  },
4379
4395
  });
4380
4396
 
4381
- var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", {
4397
+ var AST_Import = DEFNODE("Import", "imported_name imported_names module_name assert_clause", {
4382
4398
  $documentation: "An `import` statement",
4383
4399
  $propdoc: {
4384
4400
  imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.",
4385
4401
  imported_names: "[AST_NameMapping*] The names of non-default imported variables",
4386
4402
  module_name: "[AST_String] String literal describing where this module came from",
4403
+ assert_clause: "[AST_Object?] The import assertion"
4387
4404
  },
4388
4405
  _walk: function(visitor) {
4389
4406
  return visitor._visit(this, function() {
@@ -4412,14 +4429,15 @@ var AST_ImportMeta = DEFNODE("ImportMeta", null, {
4412
4429
  $documentation: "A reference to import.meta",
4413
4430
  });
4414
4431
 
4415
- var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name", {
4432
+ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name assert_clause", {
4416
4433
  $documentation: "An `export` statement",
4417
4434
  $propdoc: {
4418
4435
  exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition",
4419
4436
  exported_value: "[AST_Node?] An exported value",
4420
4437
  exported_names: "[AST_NameMapping*?] List of exported names",
4421
4438
  module_name: "[AST_String?] Name of the file to load exports from",
4422
- is_default: "[Boolean] Whether this is the default exported value of this module"
4439
+ is_default: "[Boolean] Whether this is the default exported value of this module",
4440
+ assert_clause: "[AST_Object?] The import assertion"
4423
4441
  },
4424
4442
  _walk: function (visitor) {
4425
4443
  return visitor._visit(this, function () {
@@ -5672,6 +5690,24 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
5672
5690
  return body;
5673
5691
  };
5674
5692
 
5693
+ const assert_clause_from_moz = (assertions) => {
5694
+ if (assertions && assertions.length > 0) {
5695
+ return new AST_Object({
5696
+ start: my_start_token(assertions),
5697
+ end: my_end_token(assertions),
5698
+ properties: assertions.map((assertion_kv) =>
5699
+ new AST_ObjectKeyVal({
5700
+ start: my_start_token(assertion_kv),
5701
+ end: my_end_token(assertion_kv),
5702
+ key: assertion_kv.key.name || assertion_kv.key.value,
5703
+ value: from_moz(assertion_kv.value)
5704
+ })
5705
+ )
5706
+ });
5707
+ }
5708
+ return null;
5709
+ };
5710
+
5675
5711
  var MOZ_TO_ME = {
5676
5712
  Program: function(M) {
5677
5713
  return new AST_Toplevel({
@@ -5992,7 +6028,8 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
5992
6028
  end : my_end_token(M),
5993
6029
  imported_name: imported_name,
5994
6030
  imported_names : imported_names,
5995
- module_name : from_moz(M.source)
6031
+ module_name : from_moz(M.source),
6032
+ assert_clause: assert_clause_from_moz(M.assertions)
5996
6033
  });
5997
6034
  },
5998
6035
  ExportAllDeclaration: function(M) {
@@ -6005,7 +6042,8 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
6005
6042
  foreign_name: new AST_SymbolExportForeign({ name: "*" })
6006
6043
  })
6007
6044
  ],
6008
- module_name: from_moz(M.source)
6045
+ module_name: from_moz(M.source),
6046
+ assert_clause: assert_clause_from_moz(M.assertions)
6009
6047
  });
6010
6048
  },
6011
6049
  ExportNamedDeclaration: function(M) {
@@ -6019,7 +6057,8 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
6019
6057
  name: from_moz(specifier.local)
6020
6058
  });
6021
6059
  }) : null,
6022
- module_name: from_moz(M.source)
6060
+ module_name: from_moz(M.source),
6061
+ assert_clause: assert_clause_from_moz(M.assertions)
6023
6062
  });
6024
6063
  },
6025
6064
  ExportDefaultDeclaration: function(M) {
@@ -6311,12 +6350,30 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
6311
6350
  };
6312
6351
  });
6313
6352
 
6353
+ const assert_clause_to_moz = assert_clause => {
6354
+ const assertions = [];
6355
+ if (assert_clause) {
6356
+ for (const { key, value } of assert_clause.properties) {
6357
+ const key_moz = is_basic_identifier_string(key)
6358
+ ? { type: "Identifier", name: key }
6359
+ : { type: "Literal", value: key, raw: JSON.stringify(key) };
6360
+ assertions.push({
6361
+ type: "ImportAttribute",
6362
+ key: key_moz,
6363
+ value: to_moz(value)
6364
+ });
6365
+ }
6366
+ }
6367
+ return assertions;
6368
+ };
6369
+
6314
6370
  def_to_moz(AST_Export, function To_Moz_ExportDeclaration(M) {
6315
6371
  if (M.exported_names) {
6316
6372
  if (M.exported_names[0].name.name === "*") {
6317
6373
  return {
6318
6374
  type: "ExportAllDeclaration",
6319
- source: to_moz(M.module_name)
6375
+ source: to_moz(M.module_name),
6376
+ assertions: assert_clause_to_moz(M.assert_clause)
6320
6377
  };
6321
6378
  }
6322
6379
  return {
@@ -6329,7 +6386,8 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
6329
6386
  };
6330
6387
  }),
6331
6388
  declaration: to_moz(M.exported_definition),
6332
- source: to_moz(M.module_name)
6389
+ source: to_moz(M.module_name),
6390
+ assertions: assert_clause_to_moz(M.assert_clause)
6333
6391
  };
6334
6392
  }
6335
6393
  return {
@@ -6363,7 +6421,8 @@ def_transform(AST_PrefixedTemplateString, function(self, tw) {
6363
6421
  return {
6364
6422
  type: "ImportDeclaration",
6365
6423
  specifiers: specifiers,
6366
- source: to_moz(M.module_name)
6424
+ source: to_moz(M.module_name),
6425
+ assertions: assert_clause_to_moz(M.assert_clause)
6367
6426
  };
6368
6427
  });
6369
6428
 
@@ -6916,10 +6975,52 @@ function is_some_comments(comment) {
6916
6975
  // multiline comment
6917
6976
  return (
6918
6977
  (comment.type === "comment2" || comment.type === "comment1")
6919
- && /@preserve|@lic|@cc_on|^\**!/i.test(comment.value)
6978
+ && /@preserve|@copyright|@lic|@cc_on|^\**!/i.test(comment.value)
6920
6979
  );
6921
6980
  }
6922
6981
 
6982
+ class Rope {
6983
+ constructor() {
6984
+ this.committed = "";
6985
+ this.current = "";
6986
+ }
6987
+
6988
+ append(str) {
6989
+ this.current += str;
6990
+ }
6991
+
6992
+ insertAt(char, index) {
6993
+ const { committed, current } = this;
6994
+ if (index < committed.length) {
6995
+ this.committed = committed.slice(0, index) + char + committed.slice(index);
6996
+ } else if (index === committed.length) {
6997
+ this.committed += char;
6998
+ } else {
6999
+ index -= committed.length;
7000
+ this.committed += current.slice(0, index) + char;
7001
+ this.current = current.slice(index);
7002
+ }
7003
+ }
7004
+
7005
+ charAt(index) {
7006
+ const { committed } = this;
7007
+ if (index < committed.length) return committed[index];
7008
+ return this.current[index - committed.length];
7009
+ }
7010
+
7011
+ curLength() {
7012
+ return this.current.length;
7013
+ }
7014
+
7015
+ length() {
7016
+ return this.committed.length + this.current.length;
7017
+ }
7018
+
7019
+ toString() {
7020
+ return this.committed + this.current;
7021
+ }
7022
+ }
7023
+
6923
7024
  function OutputStream(options) {
6924
7025
 
6925
7026
  var readonly = !options;
@@ -6984,11 +7085,11 @@ function OutputStream(options) {
6984
7085
  var current_col = 0;
6985
7086
  var current_line = 1;
6986
7087
  var current_pos = 0;
6987
- var OUTPUT = "";
7088
+ var OUTPUT = new Rope();
6988
7089
  let printed_comments = new Set();
6989
7090
 
6990
- var to_utf8 = options.ascii_only ? function(str, identifier) {
6991
- if (options.ecma >= 2015 && !options.safari10) {
7091
+ var to_utf8 = options.ascii_only ? function(str, identifier = false, regexp = false) {
7092
+ if (options.ecma >= 2015 && !options.safari10 && !regexp) {
6992
7093
  str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
6993
7094
  var code = get_full_char_code(ch, 0).toString(16);
6994
7095
  return "\\u{" + code + "}";
@@ -7115,19 +7216,18 @@ function OutputStream(options) {
7115
7216
  var ensure_line_len = options.max_line_len ? function() {
7116
7217
  if (current_col > options.max_line_len) {
7117
7218
  if (might_add_newline) {
7118
- var left = OUTPUT.slice(0, might_add_newline);
7119
- var right = OUTPUT.slice(might_add_newline);
7219
+ OUTPUT.insertAt("\n", might_add_newline);
7220
+ const curLength = OUTPUT.curLength();
7120
7221
  if (mappings) {
7121
- var delta = right.length - current_col;
7222
+ var delta = curLength - current_col;
7122
7223
  mappings.forEach(function(mapping) {
7123
7224
  mapping.line++;
7124
7225
  mapping.col += delta;
7125
7226
  });
7126
7227
  }
7127
- OUTPUT = left + "\n" + right;
7128
7228
  current_line++;
7129
7229
  current_pos++;
7130
- current_col = right.length;
7230
+ current_col = curLength;
7131
7231
  }
7132
7232
  }
7133
7233
  if (might_add_newline) {
@@ -7161,13 +7261,13 @@ function OutputStream(options) {
7161
7261
 
7162
7262
  if (prev === ":" && ch === "}" || (!ch || !";}".includes(ch)) && prev !== ";") {
7163
7263
  if (options.semicolons || requireSemicolonChars.has(ch)) {
7164
- OUTPUT += ";";
7264
+ OUTPUT.append(";");
7165
7265
  current_col++;
7166
7266
  current_pos++;
7167
7267
  } else {
7168
7268
  ensure_line_len();
7169
7269
  if (current_col > 0) {
7170
- OUTPUT += "\n";
7270
+ OUTPUT.append("\n");
7171
7271
  current_pos++;
7172
7272
  current_line++;
7173
7273
  current_col = 0;
@@ -7191,7 +7291,7 @@ function OutputStream(options) {
7191
7291
  || (ch == "/" && ch == prev)
7192
7292
  || ((ch == "+" || ch == "-") && ch == last)
7193
7293
  ) {
7194
- OUTPUT += " ";
7294
+ OUTPUT.append(" ");
7195
7295
  current_col++;
7196
7296
  current_pos++;
7197
7297
  }
@@ -7209,7 +7309,7 @@ function OutputStream(options) {
7209
7309
  if (!might_add_newline) do_add_mapping();
7210
7310
  }
7211
7311
 
7212
- OUTPUT += str;
7312
+ OUTPUT.append(str);
7213
7313
  has_parens = str[str.length - 1] == "(";
7214
7314
  current_pos += str.length;
7215
7315
  var a = str.split(/\r?\n/), n = a.length - 1;
@@ -7249,15 +7349,15 @@ function OutputStream(options) {
7249
7349
 
7250
7350
  var newline = options.beautify ? function() {
7251
7351
  if (newline_insert < 0) return print("\n");
7252
- if (OUTPUT[newline_insert] != "\n") {
7253
- OUTPUT = OUTPUT.slice(0, newline_insert) + "\n" + OUTPUT.slice(newline_insert);
7352
+ if (OUTPUT.charAt(newline_insert) != "\n") {
7353
+ OUTPUT.insertAt("\n", newline_insert);
7254
7354
  current_pos++;
7255
7355
  current_line++;
7256
7356
  }
7257
7357
  newline_insert++;
7258
7358
  } : options.max_line_len ? function() {
7259
7359
  ensure_line_len();
7260
- might_add_newline = OUTPUT.length;
7360
+ might_add_newline = OUTPUT.length();
7261
7361
  } : noop;
7262
7362
 
7263
7363
  var semicolon = options.beautify ? function() {
@@ -7323,13 +7423,14 @@ function OutputStream(options) {
7323
7423
  if (might_add_newline) {
7324
7424
  ensure_line_len();
7325
7425
  }
7326
- return OUTPUT;
7426
+ return OUTPUT.toString();
7327
7427
  }
7328
7428
 
7329
7429
  function has_nlb() {
7330
- let n = OUTPUT.length - 1;
7430
+ const output = OUTPUT.toString();
7431
+ let n = output.length - 1;
7331
7432
  while (n >= 0) {
7332
- const code = OUTPUT.charCodeAt(n);
7433
+ const code = output.charCodeAt(n);
7333
7434
  if (code === CODE_LINE_BREAK) {
7334
7435
  return true;
7335
7436
  }
@@ -7466,7 +7567,7 @@ function OutputStream(options) {
7466
7567
  !/comment[134]/.test(c.type)
7467
7568
  ))) return;
7468
7569
  printed_comments.add(comments);
7469
- var insert = OUTPUT.length;
7570
+ var insert = OUTPUT.length();
7470
7571
  comments.filter(comment_filter, node).forEach(function(c, i) {
7471
7572
  if (printed_comments.has(c)) return;
7472
7573
  printed_comments.add(c);
@@ -7495,7 +7596,7 @@ function OutputStream(options) {
7495
7596
  need_space = true;
7496
7597
  }
7497
7598
  });
7498
- if (OUTPUT.length > insert) newline_insert = insert;
7599
+ if (OUTPUT.length() > insert) newline_insert = insert;
7499
7600
  }
7500
7601
 
7501
7602
  var stack = [];
@@ -7525,7 +7626,7 @@ function OutputStream(options) {
7525
7626
  var encoded = encode_string(str, quote);
7526
7627
  if (escape_directive === true && !encoded.includes("\\")) {
7527
7628
  // Insert semicolons to break directive prologue
7528
- if (!EXPECT_DIRECTIVE.test(OUTPUT)) {
7629
+ if (!EXPECT_DIRECTIVE.test(OUTPUT.toString())) {
7529
7630
  force_semicolon();
7530
7631
  }
7531
7632
  force_semicolon();
@@ -8381,6 +8482,10 @@ function OutputStream(options) {
8381
8482
  output.space();
8382
8483
  }
8383
8484
  self.module_name.print(output);
8485
+ if (self.assert_clause) {
8486
+ output.print("assert");
8487
+ self.assert_clause.print(output);
8488
+ }
8384
8489
  output.semicolon();
8385
8490
  });
8386
8491
  DEFPRINT(AST_ImportMeta, function(self, output) {
@@ -8446,6 +8551,10 @@ function OutputStream(options) {
8446
8551
  output.space();
8447
8552
  self.module_name.print(output);
8448
8553
  }
8554
+ if (self.assert_clause) {
8555
+ output.print("assert");
8556
+ self.assert_clause.print(output);
8557
+ }
8449
8558
  if (self.exported_value
8450
8559
  && !(self.exported_value instanceof AST_Defun ||
8451
8560
  self.exported_value instanceof AST_Function ||
@@ -8907,7 +9016,7 @@ function OutputStream(options) {
8907
9016
  flags = flags ? sort_regexp_flags(flags) : "";
8908
9017
  source = source.replace(r_slash_script, slash_script_replace);
8909
9018
 
8910
- output.print(output.to_utf8(`/${source}/${flags}`));
9019
+ output.print(output.to_utf8(`/${source}/${flags}`, false, true));
8911
9020
 
8912
9021
  const parent = output.parent();
8913
9022
  if (
@@ -9996,6 +10105,8 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
9996
10105
  }
9997
10106
 
9998
10107
  const mangled_names = this.mangled_names = new Set();
10108
+ unmangleable_names = new Set();
10109
+
9999
10110
  if (options.cache) {
10000
10111
  this.globals.forEach(collect);
10001
10112
  if (options.cache.props) {
@@ -10048,7 +10159,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
10048
10159
  this.walk(tw);
10049
10160
 
10050
10161
  if (options.keep_fnames || options.keep_classnames) {
10051
- unmangleable_names = new Set();
10052
10162
  // Collect a set of short names which are unmangleable,
10053
10163
  // for use in avoiding collisions in next_mangled.
10054
10164
  to_mangle.forEach(def => {
@@ -10064,9 +10174,9 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
10064
10174
  unmangleable_names = null;
10065
10175
 
10066
10176
  function collect(symbol) {
10067
- const should_mangle = !options.reserved.has(symbol.name)
10068
- && !(symbol.export & MASK_EXPORT_DONT_MANGLE);
10069
- if (should_mangle) {
10177
+ if (symbol.export & MASK_EXPORT_DONT_MANGLE) {
10178
+ unmangleable_names.add(symbol.name);
10179
+ } else if (!options.reserved.has(symbol.name)) {
10070
10180
  to_mangle.push(symbol);
10071
10181
  }
10072
10182
  }
@@ -11104,6 +11214,7 @@ const is_pure_native_fn = make_nested_lookup({
11104
11214
  "isExtensible",
11105
11215
  "isFrozen",
11106
11216
  "isSealed",
11217
+ "hasOwn",
11107
11218
  "keys",
11108
11219
  ],
11109
11220
  String: [
@@ -16131,7 +16242,7 @@ def_optimize(AST_Switch, function(self, compressor) {
16131
16242
  // that way the next micro-optimization will merge them.
16132
16243
  // ** bail micro-optimization if not a simple switch case with breaks
16133
16244
  if (body.every((branch, i) =>
16134
- (branch === default_or_exact || !branch.expression.has_side_effects(compressor))
16245
+ (branch === default_or_exact || branch.expression instanceof AST_Constant)
16135
16246
  && (branch.body.length === 0 || aborts(branch) || body.length - 1 === i))
16136
16247
  ) {
16137
16248
  for (let i = 0; i < body.length; i++) {
@@ -16219,12 +16330,16 @@ def_optimize(AST_Switch, function(self, compressor) {
16219
16330
 
16220
16331
 
16221
16332
  // Prune side-effect free branches that fall into default.
16222
- if (default_or_exact) {
16333
+ DEFAULT: if (default_or_exact) {
16223
16334
  let default_index = body.indexOf(default_or_exact);
16224
16335
  let default_body_index = default_index;
16225
16336
  for (; default_body_index < body.length - 1; default_body_index++) {
16226
16337
  if (!is_inert_body(body[default_body_index])) break;
16227
16338
  }
16339
+ if (default_body_index < body.length - 1) {
16340
+ break DEFAULT;
16341
+ }
16342
+
16228
16343
  let side_effect_index = body.length - 1;
16229
16344
  for (; side_effect_index >= 0; side_effect_index--) {
16230
16345
  let branch = body[side_effect_index];
@@ -17271,16 +17386,16 @@ def_optimize(AST_UnaryPostfix, function(self, compressor) {
17271
17386
 
17272
17387
  def_optimize(AST_UnaryPrefix, function(self, compressor) {
17273
17388
  var e = self.expression;
17274
- if (self.operator == "delete"
17275
- && !(e instanceof AST_SymbolRef
17276
- || e instanceof AST_PropAccess
17277
- || is_identifier_atom(e))) {
17278
- if (e instanceof AST_Sequence) {
17279
- const exprs = e.expressions.slice();
17280
- exprs.push(make_node(AST_True, self));
17281
- return make_sequence(self, exprs).optimize(compressor);
17282
- }
17283
- return make_sequence(self, [ e, make_node(AST_True, self) ]).optimize(compressor);
17389
+ if (
17390
+ self.operator == "delete" &&
17391
+ !(
17392
+ e instanceof AST_SymbolRef ||
17393
+ e instanceof AST_PropAccess ||
17394
+ e instanceof AST_Chain ||
17395
+ is_identifier_atom(e)
17396
+ )
17397
+ ) {
17398
+ return make_sequence(self, [e, make_node(AST_True, self)]).optimize(compressor);
17284
17399
  }
17285
17400
  var seq = self.lift_sequences(compressor);
17286
17401
  if (seq !== self) {
@@ -18112,7 +18227,15 @@ function is_reachable(self, defs) {
18112
18227
  if (node instanceof AST_Scope && node !== self) {
18113
18228
  var parent = info.parent();
18114
18229
 
18115
- if (parent instanceof AST_Call && parent.expression === node) return;
18230
+ if (
18231
+ parent instanceof AST_Call
18232
+ && parent.expression === node
18233
+ // Async/Generators aren't guaranteed to sync evaluate all of
18234
+ // their body steps, so it's possible they close over the variable.
18235
+ && !(node.async || node.is_generator)
18236
+ ) {
18237
+ return;
18238
+ }
18116
18239
 
18117
18240
  if (walk(node, find_ref)) return walk_abort;
18118
18241
 
@@ -18764,7 +18887,16 @@ def_optimize(AST_Sub, function(self, compressor) {
18764
18887
  });
18765
18888
 
18766
18889
  def_optimize(AST_Chain, function (self, compressor) {
18767
- if (is_nullish(self.expression, compressor)) return make_node(AST_Undefined, self);
18890
+ if (is_nullish(self.expression, compressor)) {
18891
+ let parent = compressor.parent();
18892
+ // It's valid to delete a nullish optional chain, but if we optimized
18893
+ // this to `delete undefined` then it would appear to be a syntax error
18894
+ // when we try to optimize the delete. Thankfully, `delete 0` is fine.
18895
+ if (parent instanceof AST_UnaryPrefix && parent.operator === "delete") {
18896
+ return make_node_from_constant(0, self);
18897
+ }
18898
+ return make_node(AST_Undefined, self);
18899
+ }
18768
18900
  return self;
18769
18901
  });
18770
18902
 
@@ -27423,7 +27555,54 @@ function cache_to_json(cache) {
27423
27555
  };
27424
27556
  }
27425
27557
 
27426
- async function minify(files, options) {
27558
+ function log_input(files, options, fs, debug_folder) {
27559
+ if (!(fs && fs.writeFileSync && fs.mkdirSync)) {
27560
+ return;
27561
+ }
27562
+
27563
+ try {
27564
+ fs.mkdirSync(debug_folder);
27565
+ } catch (e) {
27566
+ if (e.code !== "EEXIST") throw e;
27567
+ }
27568
+
27569
+ const log_path = `${debug_folder}/terser-debug-${(Math.random() * 9999999) | 0}.log`;
27570
+
27571
+ options = options || {};
27572
+
27573
+ const options_str = JSON.stringify(options, (_key, thing) => {
27574
+ if (typeof thing === "function") return "[Function " + thing.toString() + "]";
27575
+ if (thing instanceof RegExp) return "[RegExp " + thing.toString() + "]";
27576
+ return thing;
27577
+ }, 4);
27578
+
27579
+ const files_str = (file) => {
27580
+ if (typeof file === "object" && options.parse && options.parse.spidermonkey) {
27581
+ return JSON.stringify(file, null, 2);
27582
+ } else if (typeof file === "object") {
27583
+ return Object.keys(file)
27584
+ .map((key) => key + ": " + files_str(file[key]))
27585
+ .join("\n\n");
27586
+ } else if (typeof file === "string") {
27587
+ return "```\n" + file + "\n```";
27588
+ } else {
27589
+ return file; // What do?
27590
+ }
27591
+ };
27592
+
27593
+ fs.writeFileSync(log_path, "Options: \n" + options_str + "\n\nInput files:\n\n" + files_str(files) + "\n");
27594
+ }
27595
+
27596
+ async function minify(files, options, _fs_module) {
27597
+ if (
27598
+ _fs_module
27599
+ && typeof process === "object"
27600
+ && process.env
27601
+ && typeof process.env.TERSER_DEBUG_DIR === "string"
27602
+ ) {
27603
+ log_input(files, options, _fs_module, process.env.TERSER_DEBUG_DIR);
27604
+ }
27605
+
27427
27606
  options = defaults(options, {
27428
27607
  compress: {},
27429
27608
  ecma: undefined,
@@ -27446,6 +27625,7 @@ async function minify(files, options) {
27446
27625
  warnings: false,
27447
27626
  wrap: false,
27448
27627
  }, true);
27628
+
27449
27629
  var timings = options.timings && {
27450
27630
  start: Date.now()
27451
27631
  };
@@ -27847,7 +28027,7 @@ async function run_cli({ program, packageJson, fs, path }) {
27847
28027
 
27848
28028
  let result;
27849
28029
  try {
27850
- result = await minify(files, options);
28030
+ result = await minify(files, options, fs);
27851
28031
  } catch (ex) {
27852
28032
  if (ex.name == "SyntaxError") {
27853
28033
  print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
@@ -27910,14 +28090,18 @@ async function run_cli({ program, packageJson, fs, path }) {
27910
28090
  }, 2));
27911
28091
  } else if (program.output == "spidermonkey") {
27912
28092
  try {
27913
- const minified = await minify(result.code, {
27914
- compress: false,
27915
- mangle: false,
27916
- format: {
27917
- ast: true,
27918
- code: false
27919
- }
27920
- });
28093
+ const minified = await minify(
28094
+ result.code,
28095
+ {
28096
+ compress: false,
28097
+ mangle: false,
28098
+ format: {
28099
+ ast: true,
28100
+ code: false
28101
+ }
28102
+ },
28103
+ fs
28104
+ );
27921
28105
  console.log(JSON.stringify(minified.ast.to_mozilla_ast(), null, 2));
27922
28106
  } catch (ex) {
27923
28107
  fatal(ex);