terser 5.9.0 → 5.10.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## v5.10.0
4
+
5
+ - Massive optimization to max_line_len (#1109)
6
+ - Basic support for import assertions
7
+ - Marked ES2022 Object.hasOwn as a pure function
8
+ - Fix `delete optional?.property`
9
+ - New CI/CD pipeline with github actions (#1057)
10
+ - Fix reordering of switch branches (#1092), (#1084)
11
+ - Fix error when creating a class property called `get`
12
+ - Acorn dependency is now an optional peerDependency
13
+ - Fix mangling collision with exported variables (#1072)
14
+ - Fix an issue with `return someVariable = (async () => { ... })()` (#1073)
15
+
3
16
  ## v5.9.0
4
17
 
5
18
  - Collapsing switch cases with the same bodies (even if they're not next to each other) (#1070).
package/bin/terser.mjs ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+
3
+ "use strict";
4
+
5
+ import '../tools/exit.cjs'
6
+ import fs from 'fs'
7
+ import path from 'path'
8
+ import program from 'commander'
9
+
10
+ import { _run_cli as run_cli } from '../main.js'
11
+
12
+ const packageJson = {
13
+ name: 'terser',
14
+ version: 'development-cli'
15
+ }
16
+ run_cli({ program, packageJson, fs, path }).catch((error) => {
17
+ console.error(error);
18
+ process.exitCode = 1;
19
+ });
@@ -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
 
@@ -6920,6 +6979,48 @@ function is_some_comments(comment) {
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,7 +7085,7 @@ 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
7091
  var to_utf8 = options.ascii_only ? function(str, identifier) {
@@ -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 ||
@@ -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
 
package/lib/ast.js CHANGED
@@ -889,12 +889,13 @@ var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", {
889
889
  },
890
890
  });
891
891
 
892
- var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", {
892
+ var AST_Import = DEFNODE("Import", "imported_name imported_names module_name assert_clause", {
893
893
  $documentation: "An `import` statement",
894
894
  $propdoc: {
895
895
  imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.",
896
896
  imported_names: "[AST_NameMapping*] The names of non-default imported variables",
897
897
  module_name: "[AST_String] String literal describing where this module came from",
898
+ assert_clause: "[AST_Object?] The import assertion"
898
899
  },
899
900
  _walk: function(visitor) {
900
901
  return visitor._visit(this, function() {
@@ -923,14 +924,15 @@ var AST_ImportMeta = DEFNODE("ImportMeta", null, {
923
924
  $documentation: "A reference to import.meta",
924
925
  });
925
926
 
926
- var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name", {
927
+ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name assert_clause", {
927
928
  $documentation: "An `export` statement",
928
929
  $propdoc: {
929
930
  exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition",
930
931
  exported_value: "[AST_Node?] An exported value",
931
932
  exported_names: "[AST_NameMapping*?] List of exported names",
932
933
  module_name: "[AST_String?] Name of the file to load exports from",
933
- is_default: "[Boolean] Whether this is the default exported value of this module"
934
+ is_default: "[Boolean] Whether this is the default exported value of this module",
935
+ assert_clause: "[AST_Object?] The import assertion"
934
936
  },
935
937
  _walk: function (visitor) {
936
938
  return visitor._visit(this, function () {
@@ -1606,7 +1606,7 @@ def_optimize(AST_Switch, function(self, compressor) {
1606
1606
  // that way the next micro-optimization will merge them.
1607
1607
  // ** bail micro-optimization if not a simple switch case with breaks
1608
1608
  if (body.every((branch, i) =>
1609
- (branch === default_or_exact || !branch.expression.has_side_effects(compressor))
1609
+ (branch === default_or_exact || branch.expression instanceof AST_Constant)
1610
1610
  && (branch.body.length === 0 || aborts(branch) || body.length - 1 === i))
1611
1611
  ) {
1612
1612
  for (let i = 0; i < body.length; i++) {
@@ -1694,12 +1694,16 @@ def_optimize(AST_Switch, function(self, compressor) {
1694
1694
 
1695
1695
 
1696
1696
  // Prune side-effect free branches that fall into default.
1697
- if (default_or_exact) {
1697
+ DEFAULT: if (default_or_exact) {
1698
1698
  let default_index = body.indexOf(default_or_exact);
1699
1699
  let default_body_index = default_index;
1700
1700
  for (; default_body_index < body.length - 1; default_body_index++) {
1701
1701
  if (!is_inert_body(body[default_body_index])) break;
1702
1702
  }
1703
+ if (default_body_index < body.length - 1) {
1704
+ break DEFAULT;
1705
+ }
1706
+
1703
1707
  let side_effect_index = body.length - 1;
1704
1708
  for (; side_effect_index >= 0; side_effect_index--) {
1705
1709
  let branch = body[side_effect_index];
@@ -2746,16 +2750,16 @@ def_optimize(AST_UnaryPostfix, function(self, compressor) {
2746
2750
 
2747
2751
  def_optimize(AST_UnaryPrefix, function(self, compressor) {
2748
2752
  var e = self.expression;
2749
- if (self.operator == "delete"
2750
- && !(e instanceof AST_SymbolRef
2751
- || e instanceof AST_PropAccess
2752
- || is_identifier_atom(e))) {
2753
- if (e instanceof AST_Sequence) {
2754
- const exprs = e.expressions.slice();
2755
- exprs.push(make_node(AST_True, self));
2756
- return make_sequence(self, exprs).optimize(compressor);
2757
- }
2758
- return make_sequence(self, [ e, make_node(AST_True, self) ]).optimize(compressor);
2753
+ if (
2754
+ self.operator == "delete" &&
2755
+ !(
2756
+ e instanceof AST_SymbolRef ||
2757
+ e instanceof AST_PropAccess ||
2758
+ e instanceof AST_Chain ||
2759
+ is_identifier_atom(e)
2760
+ )
2761
+ ) {
2762
+ return make_sequence(self, [e, make_node(AST_True, self)]).optimize(compressor);
2759
2763
  }
2760
2764
  var seq = self.lift_sequences(compressor);
2761
2765
  if (seq !== self) {
@@ -3587,7 +3591,15 @@ function is_reachable(self, defs) {
3587
3591
  if (node instanceof AST_Scope && node !== self) {
3588
3592
  var parent = info.parent();
3589
3593
 
3590
- if (parent instanceof AST_Call && parent.expression === node) return;
3594
+ if (
3595
+ parent instanceof AST_Call
3596
+ && parent.expression === node
3597
+ // Async/Generators aren't guaranteed to sync evaluate all of
3598
+ // their body steps, so it's possible they close over the variable.
3599
+ && !(node.async || node.is_generator)
3600
+ ) {
3601
+ return;
3602
+ }
3591
3603
 
3592
3604
  if (walk(node, find_ref)) return walk_abort;
3593
3605
 
@@ -4239,7 +4251,16 @@ def_optimize(AST_Sub, function(self, compressor) {
4239
4251
  });
4240
4252
 
4241
4253
  def_optimize(AST_Chain, function (self, compressor) {
4242
- if (is_nullish(self.expression, compressor)) return make_node(AST_Undefined, self);
4254
+ if (is_nullish(self.expression, compressor)) {
4255
+ let parent = compressor.parent();
4256
+ // It's valid to delete a nullish optional chain, but if we optimized
4257
+ // this to `delete undefined` then it would appear to be a syntax error
4258
+ // when we try to optimize the delete. Thankfully, `delete 0` is fine.
4259
+ if (parent instanceof AST_UnaryPrefix && parent.operator === "delete") {
4260
+ return make_node_from_constant(0, self);
4261
+ }
4262
+ return make_node(AST_Undefined, self);
4263
+ }
4243
4264
  return self;
4244
4265
  });
4245
4266
 
@@ -154,6 +154,7 @@ export const is_pure_native_fn = make_nested_lookup({
154
154
  "isExtensible",
155
155
  "isFrozen",
156
156
  "isSealed",
157
+ "hasOwn",
157
158
  "keys",
158
159
  ],
159
160
  String: [
@@ -158,6 +158,7 @@ import {
158
158
  AST_With,
159
159
  AST_Yield,
160
160
  } from "./ast.js";
161
+ import { is_basic_identifier_string } from "./parse.js";
161
162
 
162
163
  (function() {
163
164
 
@@ -179,6 +180,24 @@ import {
179
180
  return body;
180
181
  };
181
182
 
183
+ const assert_clause_from_moz = (assertions) => {
184
+ if (assertions && assertions.length > 0) {
185
+ return new AST_Object({
186
+ start: my_start_token(assertions),
187
+ end: my_end_token(assertions),
188
+ properties: assertions.map((assertion_kv) =>
189
+ new AST_ObjectKeyVal({
190
+ start: my_start_token(assertion_kv),
191
+ end: my_end_token(assertion_kv),
192
+ key: assertion_kv.key.name || assertion_kv.key.value,
193
+ value: from_moz(assertion_kv.value)
194
+ })
195
+ )
196
+ });
197
+ }
198
+ return null;
199
+ };
200
+
182
201
  var MOZ_TO_ME = {
183
202
  Program: function(M) {
184
203
  return new AST_Toplevel({
@@ -499,7 +518,8 @@ import {
499
518
  end : my_end_token(M),
500
519
  imported_name: imported_name,
501
520
  imported_names : imported_names,
502
- module_name : from_moz(M.source)
521
+ module_name : from_moz(M.source),
522
+ assert_clause: assert_clause_from_moz(M.assertions)
503
523
  });
504
524
  },
505
525
  ExportAllDeclaration: function(M) {
@@ -512,7 +532,8 @@ import {
512
532
  foreign_name: new AST_SymbolExportForeign({ name: "*" })
513
533
  })
514
534
  ],
515
- module_name: from_moz(M.source)
535
+ module_name: from_moz(M.source),
536
+ assert_clause: assert_clause_from_moz(M.assertions)
516
537
  });
517
538
  },
518
539
  ExportNamedDeclaration: function(M) {
@@ -526,7 +547,8 @@ import {
526
547
  name: from_moz(specifier.local)
527
548
  });
528
549
  }) : null,
529
- module_name: from_moz(M.source)
550
+ module_name: from_moz(M.source),
551
+ assert_clause: assert_clause_from_moz(M.assertions)
530
552
  });
531
553
  },
532
554
  ExportDefaultDeclaration: function(M) {
@@ -818,12 +840,30 @@ import {
818
840
  };
819
841
  });
820
842
 
843
+ const assert_clause_to_moz = assert_clause => {
844
+ const assertions = [];
845
+ if (assert_clause) {
846
+ for (const { key, value } of assert_clause.properties) {
847
+ const key_moz = is_basic_identifier_string(key)
848
+ ? { type: "Identifier", name: key }
849
+ : { type: "Literal", value: key, raw: JSON.stringify(key) };
850
+ assertions.push({
851
+ type: "ImportAttribute",
852
+ key: key_moz,
853
+ value: to_moz(value)
854
+ });
855
+ }
856
+ }
857
+ return assertions;
858
+ };
859
+
821
860
  def_to_moz(AST_Export, function To_Moz_ExportDeclaration(M) {
822
861
  if (M.exported_names) {
823
862
  if (M.exported_names[0].name.name === "*") {
824
863
  return {
825
864
  type: "ExportAllDeclaration",
826
- source: to_moz(M.module_name)
865
+ source: to_moz(M.module_name),
866
+ assertions: assert_clause_to_moz(M.assert_clause)
827
867
  };
828
868
  }
829
869
  return {
@@ -836,7 +876,8 @@ import {
836
876
  };
837
877
  }),
838
878
  declaration: to_moz(M.exported_definition),
839
- source: to_moz(M.module_name)
879
+ source: to_moz(M.module_name),
880
+ assertions: assert_clause_to_moz(M.assert_clause)
840
881
  };
841
882
  }
842
883
  return {
@@ -870,7 +911,8 @@ import {
870
911
  return {
871
912
  type: "ImportDeclaration",
872
913
  specifiers: specifiers,
873
- source: to_moz(M.module_name)
914
+ source: to_moz(M.module_name),
915
+ assertions: assert_clause_to_moz(M.assert_clause)
874
916
  };
875
917
  });
876
918
 
package/lib/output.js CHANGED
@@ -176,6 +176,48 @@ function is_some_comments(comment) {
176
176
  );
177
177
  }
178
178
 
179
+ class Rope {
180
+ constructor() {
181
+ this.committed = "";
182
+ this.current = "";
183
+ }
184
+
185
+ append(str) {
186
+ this.current += str;
187
+ }
188
+
189
+ insertAt(char, index) {
190
+ const { committed, current } = this;
191
+ if (index < committed.length) {
192
+ this.committed = committed.slice(0, index) + char + committed.slice(index);
193
+ } else if (index === committed.length) {
194
+ this.committed += char;
195
+ } else {
196
+ index -= committed.length;
197
+ this.committed += current.slice(0, index) + char;
198
+ this.current = current.slice(index);
199
+ }
200
+ }
201
+
202
+ charAt(index) {
203
+ const { committed } = this;
204
+ if (index < committed.length) return committed[index];
205
+ return this.current[index - committed.length];
206
+ }
207
+
208
+ curLength() {
209
+ return this.current.length;
210
+ }
211
+
212
+ length() {
213
+ return this.committed.length + this.current.length;
214
+ }
215
+
216
+ toString() {
217
+ return this.committed + this.current;
218
+ }
219
+ }
220
+
179
221
  function OutputStream(options) {
180
222
 
181
223
  var readonly = !options;
@@ -240,7 +282,7 @@ function OutputStream(options) {
240
282
  var current_col = 0;
241
283
  var current_line = 1;
242
284
  var current_pos = 0;
243
- var OUTPUT = "";
285
+ var OUTPUT = new Rope();
244
286
  let printed_comments = new Set();
245
287
 
246
288
  var to_utf8 = options.ascii_only ? function(str, identifier) {
@@ -371,19 +413,18 @@ function OutputStream(options) {
371
413
  var ensure_line_len = options.max_line_len ? function() {
372
414
  if (current_col > options.max_line_len) {
373
415
  if (might_add_newline) {
374
- var left = OUTPUT.slice(0, might_add_newline);
375
- var right = OUTPUT.slice(might_add_newline);
416
+ OUTPUT.insertAt("\n", might_add_newline);
417
+ const curLength = OUTPUT.curLength();
376
418
  if (mappings) {
377
- var delta = right.length - current_col;
419
+ var delta = curLength - current_col;
378
420
  mappings.forEach(function(mapping) {
379
421
  mapping.line++;
380
422
  mapping.col += delta;
381
423
  });
382
424
  }
383
- OUTPUT = left + "\n" + right;
384
425
  current_line++;
385
426
  current_pos++;
386
- current_col = right.length;
427
+ current_col = curLength;
387
428
  }
388
429
  }
389
430
  if (might_add_newline) {
@@ -417,13 +458,13 @@ function OutputStream(options) {
417
458
 
418
459
  if (prev === ":" && ch === "}" || (!ch || !";}".includes(ch)) && prev !== ";") {
419
460
  if (options.semicolons || requireSemicolonChars.has(ch)) {
420
- OUTPUT += ";";
461
+ OUTPUT.append(";");
421
462
  current_col++;
422
463
  current_pos++;
423
464
  } else {
424
465
  ensure_line_len();
425
466
  if (current_col > 0) {
426
- OUTPUT += "\n";
467
+ OUTPUT.append("\n");
427
468
  current_pos++;
428
469
  current_line++;
429
470
  current_col = 0;
@@ -447,7 +488,7 @@ function OutputStream(options) {
447
488
  || (ch == "/" && ch == prev)
448
489
  || ((ch == "+" || ch == "-") && ch == last)
449
490
  ) {
450
- OUTPUT += " ";
491
+ OUTPUT.append(" ");
451
492
  current_col++;
452
493
  current_pos++;
453
494
  }
@@ -465,7 +506,7 @@ function OutputStream(options) {
465
506
  if (!might_add_newline) do_add_mapping();
466
507
  }
467
508
 
468
- OUTPUT += str;
509
+ OUTPUT.append(str);
469
510
  has_parens = str[str.length - 1] == "(";
470
511
  current_pos += str.length;
471
512
  var a = str.split(/\r?\n/), n = a.length - 1;
@@ -505,15 +546,15 @@ function OutputStream(options) {
505
546
 
506
547
  var newline = options.beautify ? function() {
507
548
  if (newline_insert < 0) return print("\n");
508
- if (OUTPUT[newline_insert] != "\n") {
509
- OUTPUT = OUTPUT.slice(0, newline_insert) + "\n" + OUTPUT.slice(newline_insert);
549
+ if (OUTPUT.charAt(newline_insert) != "\n") {
550
+ OUTPUT.insertAt("\n", newline_insert);
510
551
  current_pos++;
511
552
  current_line++;
512
553
  }
513
554
  newline_insert++;
514
555
  } : options.max_line_len ? function() {
515
556
  ensure_line_len();
516
- might_add_newline = OUTPUT.length;
557
+ might_add_newline = OUTPUT.length();
517
558
  } : noop;
518
559
 
519
560
  var semicolon = options.beautify ? function() {
@@ -579,13 +620,14 @@ function OutputStream(options) {
579
620
  if (might_add_newline) {
580
621
  ensure_line_len();
581
622
  }
582
- return OUTPUT;
623
+ return OUTPUT.toString();
583
624
  }
584
625
 
585
626
  function has_nlb() {
586
- let n = OUTPUT.length - 1;
627
+ const output = OUTPUT.toString();
628
+ let n = output.length - 1;
587
629
  while (n >= 0) {
588
- const code = OUTPUT.charCodeAt(n);
630
+ const code = output.charCodeAt(n);
589
631
  if (code === CODE_LINE_BREAK) {
590
632
  return true;
591
633
  }
@@ -722,7 +764,7 @@ function OutputStream(options) {
722
764
  !/comment[134]/.test(c.type)
723
765
  ))) return;
724
766
  printed_comments.add(comments);
725
- var insert = OUTPUT.length;
767
+ var insert = OUTPUT.length();
726
768
  comments.filter(comment_filter, node).forEach(function(c, i) {
727
769
  if (printed_comments.has(c)) return;
728
770
  printed_comments.add(c);
@@ -751,7 +793,7 @@ function OutputStream(options) {
751
793
  need_space = true;
752
794
  }
753
795
  });
754
- if (OUTPUT.length > insert) newline_insert = insert;
796
+ if (OUTPUT.length() > insert) newline_insert = insert;
755
797
  }
756
798
 
757
799
  var stack = [];
@@ -781,7 +823,7 @@ function OutputStream(options) {
781
823
  var encoded = encode_string(str, quote);
782
824
  if (escape_directive === true && !encoded.includes("\\")) {
783
825
  // Insert semicolons to break directive prologue
784
- if (!EXPECT_DIRECTIVE.test(OUTPUT)) {
826
+ if (!EXPECT_DIRECTIVE.test(OUTPUT.toString())) {
785
827
  force_semicolon();
786
828
  }
787
829
  force_semicolon();
@@ -1637,6 +1679,10 @@ function OutputStream(options) {
1637
1679
  output.space();
1638
1680
  }
1639
1681
  self.module_name.print(output);
1682
+ if (self.assert_clause) {
1683
+ output.print("assert");
1684
+ self.assert_clause.print(output);
1685
+ }
1640
1686
  output.semicolon();
1641
1687
  });
1642
1688
  DEFPRINT(AST_ImportMeta, function(self, output) {
@@ -1702,6 +1748,10 @@ function OutputStream(options) {
1702
1748
  output.space();
1703
1749
  self.module_name.print(output);
1704
1750
  }
1751
+ if (self.assert_clause) {
1752
+ output.print("assert");
1753
+ self.assert_clause.print(output);
1754
+ }
1705
1755
  if (self.exported_value
1706
1756
  && !(self.exported_value instanceof AST_Defun ||
1707
1757
  self.exported_value instanceof AST_Function ||
package/lib/parse.js CHANGED
@@ -1222,7 +1222,7 @@ function parse($TEXT, options) {
1222
1222
  }
1223
1223
  if (S.token.value == "import" && !is_token(peek(), "punc", "(") && !is_token(peek(), "punc", ".")) {
1224
1224
  next();
1225
- var node = import_();
1225
+ var node = import_statement();
1226
1226
  semicolon();
1227
1227
  return node;
1228
1228
  }
@@ -1374,7 +1374,7 @@ function parse($TEXT, options) {
1374
1374
  case "export":
1375
1375
  if (!is_token(peek(), "punc", "(")) {
1376
1376
  next();
1377
- var node = export_();
1377
+ var node = export_statement();
1378
1378
  if (is("punc", ";")) semicolon();
1379
1379
  return node;
1380
1380
  }
@@ -2551,7 +2551,7 @@ function parse($TEXT, options) {
2551
2551
  };
2552
2552
 
2553
2553
  const is_not_method_start = () =>
2554
- !is("punc", "(") && !is("punc", ",") && !is("punc", "}") && !is("operator", "=");
2554
+ !is("punc", "(") && !is("punc", ",") && !is("punc", "}") && !is("punc", ";") && !is("operator", "=");
2555
2555
 
2556
2556
  var is_async = false;
2557
2557
  var is_static = false;
@@ -2666,7 +2666,15 @@ function parse($TEXT, options) {
2666
2666
  }
2667
2667
  }
2668
2668
 
2669
- function import_() {
2669
+ function maybe_import_assertion() {
2670
+ if (is("name", "assert") && !has_newline_before(S.token)) {
2671
+ next();
2672
+ return object_or_destructuring_();
2673
+ }
2674
+ return null;
2675
+ }
2676
+
2677
+ function import_statement() {
2670
2678
  var start = prev();
2671
2679
 
2672
2680
  var imported_name;
@@ -2689,16 +2697,20 @@ function parse($TEXT, options) {
2689
2697
  unexpected();
2690
2698
  }
2691
2699
  next();
2700
+
2701
+ const assert_clause = maybe_import_assertion();
2702
+
2692
2703
  return new AST_Import({
2693
- start: start,
2694
- imported_name: imported_name,
2695
- imported_names: imported_names,
2704
+ start,
2705
+ imported_name,
2706
+ imported_names,
2696
2707
  module_name: new AST_String({
2697
2708
  start: mod_str,
2698
2709
  value: mod_str.value,
2699
2710
  quote: mod_str.quote,
2700
2711
  end: mod_str,
2701
2712
  }),
2713
+ assert_clause,
2702
2714
  end: S.token,
2703
2715
  });
2704
2716
  }
@@ -2806,7 +2818,7 @@ function parse($TEXT, options) {
2806
2818
  return names;
2807
2819
  }
2808
2820
 
2809
- function export_() {
2821
+ function export_statement() {
2810
2822
  var start = S.token;
2811
2823
  var is_default;
2812
2824
  var exported_names;
@@ -2824,6 +2836,8 @@ function parse($TEXT, options) {
2824
2836
  }
2825
2837
  next();
2826
2838
 
2839
+ const assert_clause = maybe_import_assertion();
2840
+
2827
2841
  return new AST_Export({
2828
2842
  start: start,
2829
2843
  is_default: is_default,
@@ -2835,6 +2849,7 @@ function parse($TEXT, options) {
2835
2849
  end: mod_str,
2836
2850
  }),
2837
2851
  end: prev(),
2852
+ assert_clause
2838
2853
  });
2839
2854
  } else {
2840
2855
  return new AST_Export({
@@ -2880,6 +2895,7 @@ function parse($TEXT, options) {
2880
2895
  exported_value: exported_value,
2881
2896
  exported_definition: exported_definition,
2882
2897
  end: prev(),
2898
+ assert_clause: null
2883
2899
  });
2884
2900
  }
2885
2901
 
package/lib/scope.js CHANGED
@@ -781,6 +781,8 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
781
781
  }
782
782
 
783
783
  const mangled_names = this.mangled_names = new Set();
784
+ unmangleable_names = new Set();
785
+
784
786
  if (options.cache) {
785
787
  this.globals.forEach(collect);
786
788
  if (options.cache.props) {
@@ -833,7 +835,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
833
835
  this.walk(tw);
834
836
 
835
837
  if (options.keep_fnames || options.keep_classnames) {
836
- unmangleable_names = new Set();
837
838
  // Collect a set of short names which are unmangleable,
838
839
  // for use in avoiding collisions in next_mangled.
839
840
  to_mangle.forEach(def => {
@@ -849,9 +850,9 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
849
850
  unmangleable_names = null;
850
851
 
851
852
  function collect(symbol) {
852
- const should_mangle = !options.reserved.has(symbol.name)
853
- && !(symbol.export & MASK_EXPORT_DONT_MANGLE);
854
- if (should_mangle) {
853
+ if (symbol.export & MASK_EXPORT_DONT_MANGLE) {
854
+ unmangleable_names.add(symbol.name);
855
+ } else if (!options.reserved.has(symbol.name)) {
855
856
  to_mangle.push(symbol);
856
857
  }
857
858
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "homepage": "https://terser.org",
5
5
  "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
6
6
  "license": "BSD-2-Clause",
7
- "version": "5.9.0",
7
+ "version": "5.10.0",
8
8
  "engines": {
9
9
  "node": ">=10"
10
10
  },
@@ -49,7 +49,6 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "@ls-lint/ls-lint": "^1.10.0",
52
- "acorn": "^8.5.0",
53
52
  "astring": "^1.7.5",
54
53
  "eslint": "^7.32.0",
55
54
  "eslump": "^3.0.0",
@@ -60,6 +59,14 @@
60
59
  "rollup": "2.56.3",
61
60
  "semver": "^7.3.4"
62
61
  },
62
+ "peerDependencies": {
63
+ "acorn": "^8.5.0"
64
+ },
65
+ "peerDependenciesMeta": {
66
+ "acorn": {
67
+ "optional": true
68
+ }
69
+ },
63
70
  "scripts": {
64
71
  "test": "node test/compress.js && mocha test/mocha",
65
72
  "test:compress": "node test/compress.js",