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.
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 () {
package/lib/cli.js CHANGED
@@ -224,7 +224,7 @@ export async function run_cli({ program, packageJson, fs, path }) {
224
224
 
225
225
  let result;
226
226
  try {
227
- result = await minify(files, options);
227
+ result = await minify(files, options, fs);
228
228
  } catch (ex) {
229
229
  if (ex.name == "SyntaxError") {
230
230
  print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
@@ -287,14 +287,18 @@ export async function run_cli({ program, packageJson, fs, path }) {
287
287
  }, 2));
288
288
  } else if (program.output == "spidermonkey") {
289
289
  try {
290
- const minified = await minify(result.code, {
291
- compress: false,
292
- mangle: false,
293
- format: {
294
- ast: true,
295
- code: false
296
- }
297
- });
290
+ const minified = await minify(
291
+ result.code,
292
+ {
293
+ compress: false,
294
+ mangle: false,
295
+ format: {
296
+ ast: true,
297
+ code: false
298
+ }
299
+ },
300
+ fs
301
+ );
298
302
  console.log(JSON.stringify(minified.ast.to_mozilla_ast(), null, 2));
299
303
  } catch (ex) {
300
304
  fatal(ex);
@@ -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: [
package/lib/minify.js CHANGED
@@ -61,7 +61,54 @@ function cache_to_json(cache) {
61
61
  };
62
62
  }
63
63
 
64
- async function minify(files, options) {
64
+ function log_input(files, options, fs, debug_folder) {
65
+ if (!(fs && fs.writeFileSync && fs.mkdirSync)) {
66
+ return;
67
+ }
68
+
69
+ try {
70
+ fs.mkdirSync(debug_folder);
71
+ } catch (e) {
72
+ if (e.code !== "EEXIST") throw e;
73
+ }
74
+
75
+ const log_path = `${debug_folder}/terser-debug-${(Math.random() * 9999999) | 0}.log`;
76
+
77
+ options = options || {};
78
+
79
+ const options_str = JSON.stringify(options, (_key, thing) => {
80
+ if (typeof thing === "function") return "[Function " + thing.toString() + "]";
81
+ if (thing instanceof RegExp) return "[RegExp " + thing.toString() + "]";
82
+ return thing;
83
+ }, 4);
84
+
85
+ const files_str = (file) => {
86
+ if (typeof file === "object" && options.parse && options.parse.spidermonkey) {
87
+ return JSON.stringify(file, null, 2);
88
+ } else if (typeof file === "object") {
89
+ return Object.keys(file)
90
+ .map((key) => key + ": " + files_str(file[key]))
91
+ .join("\n\n");
92
+ } else if (typeof file === "string") {
93
+ return "```\n" + file + "\n```";
94
+ } else {
95
+ return file; // What do?
96
+ }
97
+ };
98
+
99
+ fs.writeFileSync(log_path, "Options: \n" + options_str + "\n\nInput files:\n\n" + files_str(files) + "\n");
100
+ }
101
+
102
+ async function minify(files, options, _fs_module) {
103
+ if (
104
+ _fs_module
105
+ && typeof process === "object"
106
+ && process.env
107
+ && typeof process.env.TERSER_DEBUG_DIR === "string"
108
+ ) {
109
+ log_input(files, options, _fs_module, process.env.TERSER_DEBUG_DIR);
110
+ }
111
+
65
112
  options = defaults(options, {
66
113
  compress: {},
67
114
  ecma: undefined,
@@ -84,6 +131,7 @@ async function minify(files, options) {
84
131
  warnings: false,
85
132
  wrap: false,
86
133
  }, true);
134
+
87
135
  var timings = options.timings && {
88
136
  start: Date.now()
89
137
  };
@@ -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
@@ -172,10 +172,52 @@ function is_some_comments(comment) {
172
172
  // multiline comment
173
173
  return (
174
174
  (comment.type === "comment2" || comment.type === "comment1")
175
- && /@preserve|@lic|@cc_on|^\**!/i.test(comment.value)
175
+ && /@preserve|@copyright|@lic|@cc_on|^\**!/i.test(comment.value)
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,11 +282,11 @@ 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
- var to_utf8 = options.ascii_only ? function(str, identifier) {
247
- if (options.ecma >= 2015 && !options.safari10) {
288
+ var to_utf8 = options.ascii_only ? function(str, identifier = false, regexp = false) {
289
+ if (options.ecma >= 2015 && !options.safari10 && !regexp) {
248
290
  str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
249
291
  var code = get_full_char_code(ch, 0).toString(16);
250
292
  return "\\u{" + code + "}";
@@ -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 ||
@@ -2163,7 +2213,7 @@ function OutputStream(options) {
2163
2213
  flags = flags ? sort_regexp_flags(flags) : "";
2164
2214
  source = source.replace(r_slash_script, slash_script_replace);
2165
2215
 
2166
- output.print(output.to_utf8(`/${source}/${flags}`));
2216
+ output.print(output.to_utf8(`/${source}/${flags}`, false, true));
2167
2217
 
2168
2218
  const parent = output.parent();
2169
2219
  if (
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